Salome HOME
Task 3.2. To keep compounds’ sub-shapes for all operations (issue #3139) occ/compounds_processing
authorazv <azv@opencascade.com>
Wed, 26 Feb 2020 11:23:32 +0000 (14:23 +0300)
committerazv <azv@opencascade.com>
Wed, 26 Feb 2020 13:17:30 +0000 (16:17 +0300)
Refactor the Fillet and the Chamfer features.

33 files changed:
src/FeaturesAPI/FeaturesAPI.i
src/FeaturesAPI/FeaturesAPI_Chamfer.cpp
src/FeaturesAPI/FeaturesAPI_Chamfer.h
src/FeaturesAPI/FeaturesAPI_Fillet.cpp
src/FeaturesAPI/FeaturesAPI_Fillet.h
src/FeaturesPlugin/CMakeLists.txt
src/FeaturesPlugin/FeaturesPlugin_Chamfer.cpp
src/FeaturesPlugin/FeaturesPlugin_Chamfer.h
src/FeaturesPlugin/FeaturesPlugin_Fillet.cpp
src/FeaturesPlugin/FeaturesPlugin_Fillet.h
src/FeaturesPlugin/FeaturesPlugin_Validators.cpp
src/FeaturesPlugin/FeaturesPlugin_VersionedChFi.cpp [new file with mode: 0644]
src/FeaturesPlugin/FeaturesPlugin_VersionedChFi.h [new file with mode: 0644]
src/FeaturesPlugin/Test/TestChamfer_MultiLevelCompound_v0_1.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestChamfer_MultiLevelCompound_v0_2.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestChamfer_MultiLevelCompound_v0_3.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestChamfer_MultiLevelCompound_v0_4.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestChamfer_MultiLevelCompound_v95_1.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestChamfer_MultiLevelCompound_v95_2.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestChamfer_MultiLevelCompound_v95_3.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestChamfer_MultiLevelCompound_v95_4.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestFillet_MultiLevelCompound_v0_1.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestFillet_MultiLevelCompound_v0_2.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestFillet_MultiLevelCompound_v0_3.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestFillet_MultiLevelCompound_v0_4.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestFillet_MultiLevelCompound_v95_1.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestFillet_MultiLevelCompound_v95_2.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestFillet_MultiLevelCompound_v95_3.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestFillet_MultiLevelCompound_v95_4.py [new file with mode: 0644]
src/GeomAPI/GeomAPI_ShapeHierarchy.cpp
src/GeomAPI/GeomAPI_ShapeHierarchy.h
src/GeomAlgoAPI/GeomAlgoAPI_Chamfer.cpp
src/GeomAlgoAPI/GeomAlgoAPI_Fillet.cpp

index c084ba96ca3d5667bdbb6735fd25133ed9d31780..010ddfa51867f5c1ab8392265d1dd105f148373b 100644 (file)
 %include "std_shared_ptr.i"
 
 // functions with named parameters
+%feature("kwargs") addChamfer;
 %feature("kwargs") addCommon;
 %feature("kwargs") addCut;
+%feature("kwargs") addFillet;
 %feature("kwargs") addFuse;
 %feature("kwargs") addIntersection;
 %feature("kwargs") addMultiRotation;
index 0d1e815c11f38777273ff58170387f09e5a3a003..4a3b02efd36a8da5e309b5181fe0f75a64cc5452 100644 (file)
@@ -107,6 +107,9 @@ void FeaturesAPI_Chamfer::dump(ModelHighAPI_Dumper& theDumper) const
     theDumper << ", False, " << anAttrD << ", " << anAttrAngle;
   }
 
+  if (!aBase->data()->version().empty())
+    theDumper << ", keepSubResults = True";
+
   theDumper << ")" << std::endl;
 }
 
@@ -123,9 +126,12 @@ ChamferPtr addChamfer(const std::shared_ptr<ModelAPI_Document>& thePart,
                       const std::list<ModelHighAPI_Selection>& theBaseObjects,
                       const bool performDistances,
                       const ModelHighAPI_Double& theVal1,
-                      const ModelHighAPI_Double& theVal2)
+                      const ModelHighAPI_Double& theVal2,
+                      const bool keepSubResults)
 {
   std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(FeaturesAPI_Chamfer::ID());
+  if (!keepSubResults)
+    aFeature->data()->setVersion("");
   return ChamferPtr(new FeaturesAPI_Chamfer(aFeature, theBaseObjects, performDistances,
                                             theVal1, theVal2));
 }
index 3baf2dde95cbe584d7fa29717d470f0383e3f25b..0e1da899ce6f9d78bdec7e9ffa31b76ff3cef9f6 100644 (file)
@@ -102,6 +102,7 @@ ChamferPtr addChamfer(const std::shared_ptr<ModelAPI_Document>& thePart,
                       const std::list<ModelHighAPI_Selection>& theBaseObjects,
                       const bool performDistances,
                       const ModelHighAPI_Double& theVal1,
-                      const ModelHighAPI_Double& theVal2);
+                      const ModelHighAPI_Double& theVal2,
+                      const bool keepSubResults = false);
 
 #endif // FeaturesAPI_Chamfer_H_
index 914db27e7a2f2b49f4009988d570841cb413247c..d84e0017540195506e9f04f2f325d9817a6d0334 100644 (file)
@@ -112,6 +112,9 @@ void FeaturesAPI_Fillet::dump(ModelHighAPI_Dumper& theDumper) const
     theDumper << ", " << anAttrRadius1 << ", " << anAttrRadius2;
   }
 
+  if (!aBase->data()->version().empty())
+    theDumper << ", keepSubResults = True";
+
   theDumper << ")" << std::endl;
 }
 
@@ -124,19 +127,20 @@ void FeaturesAPI_Fillet::execIfBaseNotEmpty()
 
 //==================================================================================================
 
-FilletPtr addFillet(const std::shared_ptr<ModelAPI_Document>& thePart,
-                    const std::list<ModelHighAPI_Selection>& theBaseObjects,
-                    const ModelHighAPI_Double& theRadius)
-{
-  std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(FeaturesAPI_Fillet::ID());
-  return FilletPtr(new FeaturesAPI_Fillet(aFeature, theBaseObjects, theRadius));
-}
-
 FilletPtr addFillet(const std::shared_ptr<ModelAPI_Document>& thePart,
                     const std::list<ModelHighAPI_Selection>& theBaseObjects,
                     const ModelHighAPI_Double& theRadius1,
-                    const ModelHighAPI_Double& theRadius2)
+                    const ModelHighAPI_Double& theRadius2,
+                    const bool keepSubResults)
 {
   std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(FeaturesAPI_Fillet::ID());
-  return FilletPtr(new FeaturesAPI_Fillet(aFeature, theBaseObjects, theRadius1, theRadius2));
+  if (!keepSubResults)
+    aFeature->data()->setVersion("");
+
+  FilletPtr aFillet;
+  if (theRadius2.value() < 0.0)
+    aFillet.reset(new FeaturesAPI_Fillet(aFeature, theBaseObjects, theRadius1));
+  else
+    aFillet.reset(new FeaturesAPI_Fillet(aFeature, theBaseObjects, theRadius1, theRadius2));
+  return aFillet;
 }
index 7670f2dcb8923843bf35b30aa79c1c73b2c3b609..b9adb3ff3a8f224e875fefac07489759f0f08492 100644 (file)
 
 #include <FeaturesPlugin_Fillet.h>
 
+#include <ModelHighAPI_Double.h>
 #include <ModelHighAPI_Interface.h>
 #include <ModelHighAPI_Macro.h>
 
-class ModelHighAPI_Double;
 class ModelHighAPI_Selection;
 
 /// \class FeaturesAPI_Fillet
@@ -97,19 +97,13 @@ private:
 /// Pointer on Fillet object.
 typedef std::shared_ptr<FeaturesAPI_Fillet> FilletPtr;
 
-/// \ingroup CPPHighAPI
-/// \brief Create Fillet feature.
-FEATURESAPI_EXPORT
-FilletPtr addFillet(const std::shared_ptr<ModelAPI_Document>& thePart,
-                    const std::list<ModelHighAPI_Selection>& theBaseObjects,
-                    const ModelHighAPI_Double& theRadius);
-
 /// \ingroup CPPHighAPI
 /// \brief Create Fillet feature.
 FEATURESAPI_EXPORT
 FilletPtr addFillet(const std::shared_ptr<ModelAPI_Document>& thePart,
                     const std::list<ModelHighAPI_Selection>& theBaseObjects,
                     const ModelHighAPI_Double& theRadius1,
-                    const ModelHighAPI_Double& theRadius2);
+                    const ModelHighAPI_Double& theRadius2 = ModelHighAPI_Double(-1.0),
+                    const bool keepSubResults = false);
 
 #endif // FeaturesAPI_Fillet_H_
index af203545b98fcd4b51390325fabef4f95545265c..e472d6fc1e3904be345c51b6504e9a18616878cc 100644 (file)
@@ -64,6 +64,7 @@ SET(PROJECT_HEADERS
     FeaturesPlugin_Copy.h
     FeaturesPlugin_ImportResult.h
     FeaturesPlugin_Defeaturing.h
+    FeaturesPlugin_VersionedChFi.h
 )
 
 SET(PROJECT_SOURCES
@@ -109,6 +110,7 @@ SET(PROJECT_SOURCES
     FeaturesPlugin_Copy.cpp
     FeaturesPlugin_ImportResult.cpp
     FeaturesPlugin_Defeaturing.cpp
+    FeaturesPlugin_VersionedChFi.cpp
 )
 
 SET(XML_RESOURCES
@@ -637,4 +639,20 @@ ADD_UNIT_TESTS(TestExtrusion.py
                TestIntersection_MultiLevelCompound_v0_2.py
                TestIntersection_MultiLevelCompound_v95_1.py
                TestIntersection_MultiLevelCompound_v95_2.py
+               TestFillet_MultiLevelCompound_v0_1.py
+               TestFillet_MultiLevelCompound_v0_2.py
+               TestFillet_MultiLevelCompound_v0_3.py
+               TestFillet_MultiLevelCompound_v0_4.py
+               TestFillet_MultiLevelCompound_v95_1.py
+               TestFillet_MultiLevelCompound_v95_2.py
+               TestFillet_MultiLevelCompound_v95_3.py
+               TestFillet_MultiLevelCompound_v95_4.py
+               TestChamfer_MultiLevelCompound_v0_1.py
+               TestChamfer_MultiLevelCompound_v0_2.py
+               TestChamfer_MultiLevelCompound_v0_3.py
+               TestChamfer_MultiLevelCompound_v0_4.py
+               TestChamfer_MultiLevelCompound_v95_1.py
+               TestChamfer_MultiLevelCompound_v95_2.py
+               TestChamfer_MultiLevelCompound_v95_3.py
+               TestChamfer_MultiLevelCompound_v95_4.py
 )
index ecfc217e4c62e1ef23499429d9dff2d9eca1a9fb..4598f93b111565112d911ed50fc4d199a47761d6 100644 (file)
 //
 
 #include "FeaturesPlugin_Chamfer.h"
-#include "FeaturesPlugin_Tools.h"
-
-#include <ModelAPI_Data.h>
+////#include "FeaturesPlugin_Tools.h"
+////
+////#include <ModelAPI_Data.h>
 #include <ModelAPI_AttributeDouble.h>
 #include <ModelAPI_AttributeSelectionList.h>
 #include <ModelAPI_AttributeString.h>
-#include <ModelAPI_ResultBody.h>
-#include <ModelAPI_Session.h>
-#include <ModelAPI_Tools.h>
-#include <ModelAPI_Validator.h>
-
-#include <GeomAlgoAPI_CompoundBuilder.h>
+////#include <ModelAPI_ResultBody.h>
+////#include <ModelAPI_Session.h>
+////#include <ModelAPI_Tools.h>
+////#include <ModelAPI_Validator.h>
+////
+////#include <GeomAlgoAPI_CompoundBuilder.h>
 #include <GeomAlgoAPI_Chamfer.h>
-#include <GeomAlgoAPI_MakeShapeList.h>
+#include <GeomAlgoAPI_MakeShape.h>
 #include <GeomAlgoAPI_Tools.h>
-
-#include <GeomAPI_DataMapOfShapeMapOfShapes.h>
+////
+////#include <GeomAPI_DataMapOfShapeMapOfShapes.h>
 #include <GeomAPI_ShapeExplorer.h>
-#include <GeomAPI_ShapeIterator.h>
-
-// Obtain all sub-shapes from the shape and append them to the list
-static void collectSubs(const GeomShapePtr& theShape,
-                              ListOfShape& theSubs,
-                        const GeomAPI_Shape::ShapeType theShapeType)
-{
-  GeomAPI_ShapeExplorer anExp(theShape, theShapeType);
-  for (; anExp.more(); anExp.next()) {
-    GeomShapePtr aShape = anExp.current();
-    // Store all shapes with FORWARD orientation to avoid duplication of shared edges/vertices
-    aShape->setOrientation(GeomAPI_Shape::FORWARD);
-    theSubs.push_back(aShape);
-  }
-}
+////#include <GeomAPI_ShapeIterator.h>
+////
+////// Obtain all sub-shapes from the shape and append them to the list
+////static void collectSubs(const GeomShapePtr& theShape,
+////                              ListOfShape& theSubs,
+////                        const GeomAPI_Shape::ShapeType theShapeType)
+////{
+////  GeomAPI_ShapeExplorer anExp(theShape, theShapeType);
+////  for (; anExp.more(); anExp.next()) {
+////    GeomShapePtr aShape = anExp.current();
+////    // Store all shapes with FORWARD orientation to avoid duplication of shared edges/vertices
+////    aShape->setOrientation(GeomAPI_Shape::FORWARD);
+////    theSubs.push_back(aShape);
+////  }
+////}
 
 // Extract edges from the list
-static ListOfShape selectEdges(const ListOfShape& theShapes)
+static void extractEdgesAndFaces(const ListOfShape& theShapes,
+                                 ListOfShape& theEdges,
+                                 std::map<GeomShapePtr, GeomShapePtr>& theMapEdgeFace)
 {
-  ListOfShape anEdges;
   for (ListOfShape::const_iterator anIt = theShapes.begin(); anIt != theShapes.end(); ++anIt)
     if ((*anIt)->isEdge())
-      anEdges.push_back(*anIt);
-  return anEdges;
-}
-
-// If theShape is a compound of a single sub-shape, return this sub-shape
-static GeomShapePtr unwrapCompound(const GeomShapePtr& theShape)
-{
-  GeomShapePtr aShape = theShape;
-  if(aShape->shapeType() == GeomAPI_Shape::COMPOUND) {
-    int aSubResultsNb = 0;
-    GeomAPI_ShapeIterator anIt(aShape);
-    for(; anIt.more(); anIt.next())
-      ++aSubResultsNb;
-
-    if(aSubResultsNb == 1) {
-      anIt.init(aShape);
-      aShape = anIt.current();
+      theEdges.push_back(*anIt);
+    else {
+      for (GeomAPI_ShapeExplorer anExp(*anIt, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) {
+        GeomShapePtr aCurrent = anExp.current();
+        theEdges.push_back(aCurrent);
+        theMapEdgeFace[aCurrent] = *anIt;
+      }
     }
-  }
-  return aShape;
 }
 
 
@@ -89,151 +78,65 @@ void FeaturesPlugin_Chamfer::initAttributes()
 {
   data()->addAttribute(FeaturesPlugin_Chamfer::CREATION_METHOD(),
                        ModelAPI_AttributeString::typeId());
-  data()->addAttribute(FeaturesPlugin_Chamfer::OBJECT_LIST_ID(),
+  AttributePtr aSelectionList = data()->addAttribute(FeaturesPlugin_Chamfer::OBJECT_LIST_ID(),
                        ModelAPI_AttributeSelectionList::typeId());
   data()->addAttribute(FeaturesPlugin_Chamfer::D1_ID(), ModelAPI_AttributeDouble::typeId());
   data()->addAttribute(FeaturesPlugin_Chamfer::D2_ID(), ModelAPI_AttributeDouble::typeId());
   data()->addAttribute(FeaturesPlugin_Chamfer::D_ID(), ModelAPI_AttributeDouble::typeId());
   data()->addAttribute(FeaturesPlugin_Chamfer::ANGLE_ID(), ModelAPI_AttributeDouble::typeId());
-}
 
+  initVersion(aSelectionList);
+}
 
-void FeaturesPlugin_Chamfer::execute()
+AttributePtr FeaturesPlugin_Chamfer::objectsAttribute()
 {
-   AttributeStringPtr aCreationMethod = string(CREATION_METHOD());
-   if (!aCreationMethod)
-     return;
-
-   std::list<std::pair<GeomShapePtr, ListOfShape> > aSolidsAndSubs;
-   std::map<GeomShapePtr, GeomShapePtr> aMapEdgeFace;
-
-   // getting objects and sort them according to parent solids
-   AttributeSelectionListPtr anObjectsSelList = selectionList(OBJECT_LIST_ID());
-   for (int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); ++anObjectsIndex) {
-     AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anObjectsIndex);
-     GeomShapePtr anObject = anObjectAttr->value();
-     if (!anObject)
-       return;
-
-     ResultPtr aContext = anObjectAttr->context();
-     GeomShapePtr aParent;
-     if (aContext.get()) {
-       ResultBodyPtr aCtxOwner = ModelAPI_Tools::bodyOwner(aContext);
-       aParent = aCtxOwner ? aCtxOwner->shape() : aContext->shape();
-     } else { // get it from a feature
-       FeaturePtr aFeature = anObjectAttr->contextFeature();
-       if (aFeature.get()) {
-         aParent = aFeature->firstResult()->shape();
-       }
-     }
-     if (!aParent)
-       return;
-
-     // searching this parent is already in the list aSolidsAndSubs
-     std::list<std::pair<GeomShapePtr, ListOfShape> >::iterator aSearch = aSolidsAndSubs.begin();
-     ListOfShape* aFound;
-     for(; aSearch != aSolidsAndSubs.end(); aSearch++) {
-       if (aSearch->first->isSame(aParent)) {
-         aFound = &(aSearch->second);
-         break;
-       }
-     }
-     if (aSearch == aSolidsAndSubs.end()) { // not found, so, add a new one
-       aSolidsAndSubs.push_back(std::pair<GeomShapePtr, ListOfShape>(aParent, ListOfShape()));
-       aFound = &(aSolidsAndSubs.back().second);
-     }
-
-    ListOfShape anEdgesAndVertices;
-    collectSubs(anObject, anEdgesAndVertices, GeomAPI_Shape::EDGE);
-    collectSubs(anObject, anEdgesAndVertices, GeomAPI_Shape::VERTEX);
-    for (ListOfShape::iterator aEIt = anEdgesAndVertices.begin();
-         aEIt != anEdgesAndVertices.end(); ++aEIt)
-      aFound->push_back(*aEIt);
-
-     if (anObject->isFace()) {
-       for (ListOfShape::iterator aEIt = anEdgesAndVertices.begin();
-          aEIt != anEdgesAndVertices.end(); ++aEIt) {
-         if ((*aEIt)->isEdge()) {
-           aMapEdgeFace[(*aEIt)] = anObject;
-         }
-       }
-     }
-   }
-
-   //bool isOption1 = true;
-   double aD1 = 0.0, aD2 = 0.0, aD = 0.0, anAngle = 0.0;
-   if (aCreationMethod->value() == CREATION_METHOD_DISTANCE_DISTANCE()) {
-     aD1 = real(FeaturesPlugin_Chamfer::D1_ID())->value();
-     aD2 = real(FeaturesPlugin_Chamfer::D2_ID())->value();
-   } else {
-     aD = real(FeaturesPlugin_Chamfer::D_ID())->value();
-     anAngle = real(FeaturesPlugin_Chamfer::ANGLE_ID())->value();
-   }
-
-   // Perform chamfer operation
-   GeomAlgoAPI_MakeShapeList aMakeShapeList;
-   std::shared_ptr<GeomAlgoAPI_Chamfer> aChamferBuilder;
-   int aResultIndex = 0;
-   std::string anError;
-
-
-   std::vector<FeaturesPlugin_Tools::ResultBaseAlgo> aResultBaseAlgoList;
-   ListOfShape anOriginalShapesList, aResultShapesList;
-
-   std::list<std::pair<GeomShapePtr, ListOfShape> >::iterator anIt = aSolidsAndSubs.begin();
-   for (; anIt != aSolidsAndSubs.end(); ++anIt) {
-     GeomShapePtr aSolid = anIt->first;
-     ListOfShape aFilletEdgesAndVertices = anIt->second;
-
-     ListOfShape aFilletEdges = selectEdges(aFilletEdgesAndVertices);
-     if (aCreationMethod->value() == CREATION_METHOD_DISTANCE_DISTANCE()) {
-       aChamferBuilder.reset(new GeomAlgoAPI_Chamfer(
-         aSolid, aFilletEdges, aMapEdgeFace, true, aD1, aD2));
-     } else {
-       aChamferBuilder.reset(new GeomAlgoAPI_Chamfer(
-         aSolid, aFilletEdges, aMapEdgeFace, false, aD, anAngle));
-     }
-
-     if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aChamferBuilder, getKind(), anError)) {
-       setError(anError);
-       return;
-     }
+  return attribute(OBJECT_LIST_ID());
+}
 
-    GeomShapePtr aResult = unwrapCompound(aChamferBuilder->shape());
-    std::shared_ptr<ModelAPI_ResultBody> aResultBody =
-        document()->createBody(data(), aResultIndex);
+const std::string& FeaturesPlugin_Chamfer::modifiedShapePrefix() const
+{
+  static const std::string& THE_PREFIX("Chamfer");
+  return THE_PREFIX;
+}
 
-    ListOfShape aBaseShapes;
-    aBaseShapes.push_back(aSolid);
-    FeaturesPlugin_Tools::loadModifiedShapes(aResultBody, aBaseShapes, ListOfShape(),
-                                             aChamferBuilder, aResult, "Chamfer");
+GeomMakeShapePtr FeaturesPlugin_Chamfer::performOperation(const GeomShapePtr& theSolid,
+                                                          const ListOfShape& theEdges)
+{
+  AttributeStringPtr aCreationMethod = string(CREATION_METHOD());
+  if (!aCreationMethod)
+    return GeomMakeShapePtr();
+
+  bool isDistDist = aCreationMethod->value() == CREATION_METHOD_DISTANCE_DISTANCE();
+  double aD1 = 0.0, aD2 = 0.0, aD = 0.0, anAngle = 0.0;
+  if (isDistDist) {
+    aD1 = real(FeaturesPlugin_Chamfer::D1_ID())->value();
+    aD2 = real(FeaturesPlugin_Chamfer::D2_ID())->value();
+  }
+  else {
+    aD = real(FeaturesPlugin_Chamfer::D_ID())->value();
+    anAngle = real(FeaturesPlugin_Chamfer::ANGLE_ID())->value();
+  }
 
-    setResult(aResultBody, aResultIndex);
-    aResultIndex++;
+  // Perform chamfer operation
+  std::shared_ptr<GeomAlgoAPI_Chamfer> aChamferBuilder;
+  std::string anError;
 
-    FeaturesPlugin_Tools::ResultBaseAlgo aRBA;
-    aRBA.resultBody = aResultBody;
-    aRBA.baseShape = aSolid;
-    aRBA.makeShape = aChamferBuilder;
-    aResultBaseAlgoList.push_back(aRBA);
-    aResultShapesList.push_back(aResult);
-    anOriginalShapesList.push_back(aSolid);
+  ListOfShape aChamferEdges;
+  std::map<GeomShapePtr, GeomShapePtr> aMapEdgeFace;
+  extractEdgesAndFaces(theEdges, aChamferEdges, aMapEdgeFace);
 
-    const std::string aFilletFaceName = "Chamfer";
-    ListOfShape::iterator aSelectedBase = aFilletEdges.begin();
-    for(; aSelectedBase != aFilletEdges.end(); aSelectedBase++) {
-      GeomShapePtr aBase = *aSelectedBase;
-      // Store new faces generated from edges and vertices
-      aResultBody->loadGeneratedShapes(
-        aChamferBuilder, aBase, GeomAPI_Shape::EDGE, aFilletFaceName, true);
-    }
+  if (isDistDist) {
+    aChamferBuilder.reset(new GeomAlgoAPI_Chamfer(
+        theSolid, aChamferEdges, aMapEdgeFace, true, aD1, aD2));
+  }
+  else {
+    aChamferBuilder.reset(new GeomAlgoAPI_Chamfer(
+        theSolid, aChamferEdges, aMapEdgeFace, false, aD, anAngle));
   }
 
-  // Store deleted shapes after all results has been proceeded. This is to avoid issue when in one
-  // result shape has been deleted, but in another it was modified or stayed.
-  GeomShapePtr aResultShapesCompound = GeomAlgoAPI_CompoundBuilder::compound(aResultShapesList);
-  FeaturesPlugin_Tools::loadDeletedShapes(aResultBaseAlgoList,
-      anOriginalShapesList, aResultShapesCompound);
-
-  removeResults(aResultIndex);
+  if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aChamferBuilder, getKind(), anError)) {
+    setError(anError);
+    return GeomMakeShapePtr();
+  }
+  return aChamferBuilder;
 }
index eea23daf7737c1aa00395697b83c090c096c82bc..1a4e2aa7ced302c5dd0c669ac25024cfa17fa37f 100644 (file)
 #ifndef FeaturesPlugin_Chamfer_H_
 #define FeaturesPlugin_Chamfer_H_
 
-#include "FeaturesPlugin.h"
-
-#include <GeomAPI_Shape.h>
-
-#include <ModelAPI_Feature.h>
-
-class GeomAlgoAPI_MakeShape;
-class GeomAPI_DataMapOfShapeMapOfShapes;
+#include "FeaturesPlugin_VersionedChFi.h"
 
 /// \class FeaturesPlugin_Chamfer
 /// \ingroup Plugins
 /// \brief Feature for applying the Chamfer operations on Solids.
 ///        Supports two distances chamfer and distance-angle chamfer.
-class FeaturesPlugin_Chamfer : public ModelAPI_Feature
+class FeaturesPlugin_Chamfer : public FeaturesPlugin_VersionedChFi
 {
 public:
   /// Feature kind.
@@ -103,9 +96,6 @@ public:
     return MY_ANGLE_ID;
   }
 
-  /// Performs the algorithm and stores results it in the data structure.
-  FEATURESPLUGIN_EXPORT virtual void execute();
-
   /// Request for initialization of data model of the feature: adding all attributes.
   FEATURESPLUGIN_EXPORT virtual void initAttributes();
 
@@ -113,11 +103,15 @@ public:
   FeaturesPlugin_Chamfer();
 
 private:
-  /// Load Naming data structure of the feature to the document
-  void loadNamingDS(std::shared_ptr<ModelAPI_ResultBody> theResultBody,
-                    const std::shared_ptr<GeomAPI_Shape> theBaseShape,
-                    const std::shared_ptr<GeomAPI_Shape> theResultShape,
-                    const std::shared_ptr<GeomAlgoAPI_MakeShape>& theMakeShape);
+  /// Return attribute storing the selected objects of the operation.
+  virtual std::shared_ptr<ModelAPI_Attribute> objectsAttribute();
+
+  /// Return name of modified shape prefix name
+  virtual const std::string& modifiedShapePrefix() const;
+
+  /// Run chamfer/fillet operation and returns the modification algorithm if succeed.
+  virtual std::shared_ptr<GeomAlgoAPI_MakeShape>
+      performOperation(const GeomShapePtr& theSolid, const ListOfShape& theEdges);
 };
 
 #endif
index 8dcd2fae4e5383a3ebe1aa74ecf7d24b1c2a7114..1d5118f032d52d4e561700456e8f6aae47ad6799 100644 (file)
 //
 
 #include "FeaturesPlugin_Fillet.h"
-#include "FeaturesPlugin_Tools.h"
 
-#include <ModelAPI_Data.h>
 #include <ModelAPI_AttributeDouble.h>
 #include <ModelAPI_AttributeSelectionList.h>
 #include <ModelAPI_AttributeString.h>
-#include <ModelAPI_ResultBody.h>
 #include <ModelAPI_Session.h>
-#include <ModelAPI_Tools.h>
 #include <ModelAPI_Validator.h>
 
-#include <GeomAlgoAPI_CompoundBuilder.h>
 #include <GeomAlgoAPI_Fillet.h>
-#include <GeomAlgoAPI_MakeShapeList.h>
+#include <GeomAlgoAPI_MakeShape.h>
 #include <GeomAlgoAPI_Tools.h>
 
-#include <GeomAPI_DataMapOfShapeMapOfShapes.h>
 #include <GeomAPI_ShapeExplorer.h>
-#include <GeomAPI_ShapeIterator.h>
-
-
-// Obtain all sub-shapes from the shape and append them to the list
-static void collectSubs(const GeomShapePtr& theShape,
-                              ListOfShape& theSubs,
-                        const GeomAPI_Shape::ShapeType theShapeType)
-{
-  GeomAPI_ShapeExplorer anExp(theShape, theShapeType);
-  for (; anExp.more(); anExp.next()) {
-    GeomShapePtr aShape = anExp.current();
-    // Store all shapes with FORWARD orientation to avoid duplication of shared edges/vertices
-    aShape->setOrientation(GeomAPI_Shape::FORWARD);
-    theSubs.push_back(aShape);
-  }
-}
 
 // Extract edges from the list
-static ListOfShape selectEdges(const ListOfShape& theShapes)
+static ListOfShape extractEdges(const ListOfShape& theShapes)
 {
   ListOfShape anEdges;
   for (ListOfShape::const_iterator anIt = theShapes.begin(); anIt != theShapes.end(); ++anIt)
-    if ((*anIt)->isEdge())
-      anEdges.push_back(*anIt);
+    for (GeomAPI_ShapeExplorer anExp(*anIt, GeomAPI_Shape::EDGE); anExp.more(); anExp.next())
+      anEdges.push_back(anExp.current());
   return anEdges;
 }
 
-// If theShape is a compound of a single sub-shape, return this sub-shape
-static GeomShapePtr unwrapCompound(const GeomShapePtr& theShape)
-{
-  GeomShapePtr aShape = theShape;
-  if(aShape->shapeType() == GeomAPI_Shape::COMPOUND) {
-    int aSubResultsNb = 0;
-    GeomAPI_ShapeIterator anIt(aShape);
-    for(; anIt.more(); anIt.next())
-      ++aSubResultsNb;
-
-    if(aSubResultsNb == 1) {
-      anIt.init(aShape);
-      aShape = anIt.current();
-    }
-  }
-  return aShape;
-}
-
 
 FeaturesPlugin_Fillet::FeaturesPlugin_Fillet()
 {
@@ -89,136 +49,56 @@ FeaturesPlugin_Fillet::FeaturesPlugin_Fillet()
 void FeaturesPlugin_Fillet::initAttributes()
 {
   data()->addAttribute(CREATION_METHOD(), ModelAPI_AttributeString::typeId());
-  data()->addAttribute(OBJECT_LIST_ID(), ModelAPI_AttributeSelectionList::typeId());
+  AttributePtr aSelectionList =
+      data()->addAttribute(OBJECT_LIST_ID(), ModelAPI_AttributeSelectionList::typeId());
   data()->addAttribute(START_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
   data()->addAttribute(END_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
 
   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), END_RADIUS_ID());
+
+  initVersion(aSelectionList);
 }
 
+AttributePtr FeaturesPlugin_Fillet::objectsAttribute()
+{
+  return attribute(OBJECT_LIST_ID());
+}
+
+const std::string& FeaturesPlugin_Fillet::modifiedShapePrefix() const
+{
+  static const std::string& THE_PREFIX("Fillet");
+  return THE_PREFIX;
+}
 
-void FeaturesPlugin_Fillet::execute()
+GeomMakeShapePtr FeaturesPlugin_Fillet::performOperation(const GeomShapePtr& theSolid,
+                                                         const ListOfShape& theEdges)
 {
   AttributeStringPtr aCreationMethod = string(CREATION_METHOD());
   if (!aCreationMethod)
-    return;
-
-  std::list<std::pair<GeomShapePtr, ListOfShape> > aSolidsAndSubs;
-
-  // getting objects and sort them according to parent solids
-  AttributeSelectionListPtr anObjectsSelList = selectionList(OBJECT_LIST_ID());
-  for (int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); ++anObjectsIndex) {
-    AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anObjectsIndex);
-    GeomShapePtr anObject = anObjectAttr->value();
-    if (!anObject)
-      return;
-
-    ResultPtr aContext = anObjectAttr->context();
-    GeomShapePtr aParent;
-    if (aContext.get()) {
-      ResultBodyPtr aCtxOwner = ModelAPI_Tools::bodyOwner(aContext);
-      aParent = aCtxOwner ? aCtxOwner->shape() : aContext->shape();
-    } else { // get it from a feature
-      FeaturePtr aFeature = anObjectAttr->contextFeature();
-      if (aFeature.get()) {
-        aParent = aFeature->firstResult()->shape();
-      }
-    }
-    if (!aParent)
-      return;
-
-    // searching this parent is already in the list aSolidsAndSubs
-    std::list<std::pair<GeomShapePtr, ListOfShape> >::iterator aSearch = aSolidsAndSubs.begin();
-    ListOfShape* aFound;
-    for(; aSearch != aSolidsAndSubs.end(); aSearch++) {
-      if (aSearch->first->isSame(aParent)) {
-        aFound = &(aSearch->second);
-        break;
-      }
-    }
-    if (aSearch == aSolidsAndSubs.end()) { // not found, so, add a new one
-      aSolidsAndSubs.push_back(std::pair<GeomShapePtr, ListOfShape>(aParent, ListOfShape()));
-      aFound = &(aSolidsAndSubs.back().second);
-    }
-
-    ListOfShape anEdgesAndVertices;
-    collectSubs(anObject, anEdgesAndVertices, GeomAPI_Shape::EDGE);
-    collectSubs(anObject, anEdgesAndVertices, GeomAPI_Shape::VERTEX);
-    for (ListOfShape::iterator aEIt = anEdgesAndVertices.begin();
-         aEIt != anEdgesAndVertices.end(); ++aEIt)
-      aFound->push_back(*aEIt);
-  }
+    return GeomMakeShapePtr();
 
-  bool isFixedRadius = true;
+  bool isFixedRadius = aCreationMethod->value() == CREATION_METHOD_SINGLE_RADIUS();
   double aRadius1 = 0.0, aRadius2 = 0.0;
-  if (aCreationMethod->value() == CREATION_METHOD_SINGLE_RADIUS())
+  if (isFixedRadius)
     aRadius1 = real(RADIUS_ID())->value();
   else {
     aRadius1 = real(START_RADIUS_ID())->value();
     aRadius2 = real(END_RADIUS_ID())->value();
-    isFixedRadius = false;
   }
 
   // Perform fillet operation
-  GeomAlgoAPI_MakeShapeList aMakeShapeList;
   std::shared_ptr<GeomAlgoAPI_Fillet> aFilletBuilder;
-  int aResultIndex = 0;
   std::string anError;
 
-  std::vector<FeaturesPlugin_Tools::ResultBaseAlgo> aResultBaseAlgoList;
-  ListOfShape anOriginalShapesList, aResultShapesList;
-
-  std::list<std::pair<GeomShapePtr, ListOfShape> >::iterator anIt = aSolidsAndSubs.begin();
-  for (; anIt != aSolidsAndSubs.end(); ++anIt) {
-    GeomShapePtr aSolid = anIt->first;
-    ListOfShape aFilletEdgesAndVertices = anIt->second;
-
-    ListOfShape aFilletEdges = selectEdges(aFilletEdgesAndVertices);
-    if (isFixedRadius)
-      aFilletBuilder.reset(new GeomAlgoAPI_Fillet(aSolid, aFilletEdges, aRadius1));
-    else
-      aFilletBuilder.reset(new GeomAlgoAPI_Fillet(aSolid, aFilletEdges, aRadius1, aRadius2));
-
-    if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aFilletBuilder, getKind(), anError)) {
-      setError(anError);
-      return;
-    }
-
-    GeomShapePtr aResult = unwrapCompound(aFilletBuilder->shape());
-    std::shared_ptr<ModelAPI_ResultBody> aResultBody =
-        document()->createBody(data(), aResultIndex);
-
-    ListOfShape aBaseShapes;
-    aBaseShapes.push_back(aSolid);
-    FeaturesPlugin_Tools::loadModifiedShapes(aResultBody, aBaseShapes, ListOfShape(),
-                                             aFilletBuilder, aResult, "Fillet");
-
-    setResult(aResultBody, aResultIndex);
-    aResultIndex++;
-
-    FeaturesPlugin_Tools::ResultBaseAlgo aRBA;
-    aRBA.resultBody = aResultBody;
-    aRBA.baseShape = aSolid;
-    aRBA.makeShape = aFilletBuilder;
-    aResultBaseAlgoList.push_back(aRBA);
-    aResultShapesList.push_back(aResult);
-    anOriginalShapesList.push_back(aSolid);
-
-    const std::string aFilletFaceName = "Fillet";
-    ListOfShape::iterator aSelectedBase = aFilletEdges.begin();
-    for(; aSelectedBase != aFilletEdges.end(); aSelectedBase++) {
-      GeomShapePtr aBase = *aSelectedBase;
-      // Store new faces generated from edges and vertices
-      aResultBody->loadGeneratedShapes(
-        aFilletBuilder, aBase, GeomAPI_Shape::EDGE, aFilletFaceName, true);
-    }
-  }
-
-  // Store deleted shapes after all results has been proceeded. This is to avoid issue when in one
-  // result shape has been deleted, but in another it was modified or stayed.
-  GeomShapePtr aResultShapesCompound = GeomAlgoAPI_CompoundBuilder::compound(aResultShapesList);
-  FeaturesPlugin_Tools::loadDeletedShapes(aResultBaseAlgoList,
-      anOriginalShapesList, aResultShapesCompound);
+  ListOfShape aFilletEdges = extractEdges(theEdges);
+  if (isFixedRadius)
+    aFilletBuilder.reset(new GeomAlgoAPI_Fillet(theSolid, aFilletEdges, aRadius1));
+  else
+    aFilletBuilder.reset(new GeomAlgoAPI_Fillet(theSolid, aFilletEdges, aRadius1, aRadius2));
 
-  removeResults(aResultIndex);
+  if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aFilletBuilder, getKind(), anError)) {
+    setError(anError);
+    return GeomMakeShapePtr();
+  }
+  return aFilletBuilder;
 }
index ac7be4493b6ea43e7259d3688ca5dcdb38f47b4f..536f6739121ebb02102904ef08525a3a5438344e 100644 (file)
 #ifndef FeaturesPlugin_Fillet_H_
 #define FeaturesPlugin_Fillet_H_
 
-#include "FeaturesPlugin.h"
-
-#include <GeomAPI_Shape.h>
-
-#include <ModelAPI_Feature.h>
-
-class GeomAlgoAPI_MakeShape;
-class GeomAPI_DataMapOfShapeMapOfShapes;
+#include "FeaturesPlugin_VersionedChFi.h"
 
 /// \class FeaturesPlugin_Fillet
 /// \ingroup Plugins
 /// \brief Feature for applying the Fillet operations on Solids.
 ///        Supports fixed radius fillet and varying 2-radius fillet.
-class FeaturesPlugin_Fillet : public ModelAPI_Feature
+class FeaturesPlugin_Fillet : public FeaturesPlugin_VersionedChFi
 {
 public:
   /// Feature kind.
@@ -95,9 +88,6 @@ public:
     return START_RADIUS_ID();
   }
 
-  /// Performs the fillet algorithm and stores it in the data structure.
-  FEATURESPLUGIN_EXPORT virtual void execute();
-
   /// Request for initialization of data model of the feature: adding all attributes.
   FEATURESPLUGIN_EXPORT virtual void initAttributes();
 
@@ -105,11 +95,15 @@ public:
   FeaturesPlugin_Fillet();
 
 private:
-  /// Load Naming data structure of the feature to the document
-  void loadNamingDS(std::shared_ptr<ModelAPI_ResultBody> theResultBody,
-                    const std::shared_ptr<GeomAPI_Shape> theBaseShape,
-                    const std::shared_ptr<GeomAPI_Shape> theResultShape,
-                    const std::shared_ptr<GeomAlgoAPI_MakeShape>& theMakeShape);
+  /// Return attribute storing the selected objects of the operation.
+  virtual std::shared_ptr<ModelAPI_Attribute> objectsAttribute();
+
+  /// Return name of modified shape prefix name
+  virtual const std::string& modifiedShapePrefix() const;
+
+  /// Run chamfer/fillet operation and returns the modification algorithm if succeed.
+  virtual std::shared_ptr<GeomAlgoAPI_MakeShape>
+      performOperation(const GeomShapePtr& theSolid, const ListOfShape& theEdges);
 };
 
 #endif
index 6426d94739bba43533d8efb7910e3ad6f1be5298..37871a044fe88414bd38211bcb3294f0d0f95c23 100644 (file)
@@ -913,8 +913,9 @@ bool FeaturesPlugin_ValidatorFilletSelection::isValid(const AttributePtr& theAtt
       }
     }
 
-    ResultBodyPtr aContextOwner = ModelAPI_Tools::bodyOwner(aContext);
-    GeomShapePtr anOwner = aContextOwner.get() ? aContextOwner->shape() : aContext->shape();
+    ResultBodyPtr aContextOwner = ModelAPI_Tools::bodyOwner(aContext, true);
+    GeomShapePtr anOwner = aContext->shape();
+    GeomShapePtr aTopLevelOwner = aContextOwner.get() ? aContextOwner->shape() : anOwner;
 
     if (!anOwner) {
       theError = "Error: wrong feature is selected.";
@@ -928,8 +929,8 @@ bool FeaturesPlugin_ValidatorFilletSelection::isValid(const AttributePtr& theAtt
     }
 
     if (!aBaseSolid)
-      aBaseSolid = anOwner;
-    else if (!aBaseSolid->isEqual(anOwner)) {
+      aBaseSolid = aTopLevelOwner;
+    else if (!aBaseSolid->isEqual(aTopLevelOwner)) {
       theError = "Error: Sub-shapes of different solids have been selected.";
       return false;
     }
diff --git a/src/FeaturesPlugin/FeaturesPlugin_VersionedChFi.cpp b/src/FeaturesPlugin/FeaturesPlugin_VersionedChFi.cpp
new file mode 100644 (file)
index 0000000..729e9d5
--- /dev/null
@@ -0,0 +1,155 @@
+// Copyright (C) 2017-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
+//
+
+#include "FeaturesPlugin_VersionedChFi.h"
+#include "FeaturesPlugin_Tools.h"
+
+#include <ModelAPI_AttributeSelectionList.h>
+#include <ModelAPI_Tools.h>
+
+#include <GeomAlgoAPI_MakeShapeList.h>
+
+#include <GeomAPI_ShapeExplorer.h>
+
+
+static const std::string CHAMFERFILLET_VERSION_1("v9.5");
+
+
+// Obtain all sub-shapes from the shape and append them to the list
+static void collectSubs(const GeomShapePtr& theShape,
+                              ListOfShape& theSubs,
+                        const GeomAPI_Shape::ShapeType theShapeType)
+{
+  GeomAPI_ShapeExplorer anExp(theShape, theShapeType);
+  for (; anExp.more(); anExp.next()) {
+    GeomShapePtr aShape = anExp.current();
+    // Store all shapes with FORWARD orientation to avoid duplication of shared edges/vertices
+    aShape->setOrientation(GeomAPI_Shape::FORWARD);
+    theSubs.push_back(aShape);
+  }
+}
+
+
+void FeaturesPlugin_VersionedChFi::initVersion(const AttributePtr& theObjectsAttr)
+{
+  if (!theObjectsAttr->isInitialized()) {
+    // new feature, not read from file
+    data()->setVersion(CHAMFERFILLET_VERSION_1);
+  }
+}
+
+void FeaturesPlugin_VersionedChFi::execute()
+{
+  GeomAPI_ShapeHierarchy anObjectHierarchy;
+  if (!processAttribute(objectsAttribute(), anObjectHierarchy))
+    return;
+
+  // Perform the operation
+  std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList);
+  int aResultIndex = 0;
+  std::string anError;
+
+  ListOfShape anEdges;
+  ListOfShape anOriginalSolids;
+  for (GeomAPI_ShapeHierarchy::iterator anIt = anObjectHierarchy.begin();
+       anIt != anObjectHierarchy.end(); ++anIt) {
+    GeomShapePtr aSolid = anObjectHierarchy.parent(*anIt);
+    const ListOfShape& aSubs = anObjectHierarchy.objects(aSolid);
+
+    std::shared_ptr<GeomAlgoAPI_MakeShape> anAlgo = performOperation(aSolid, aSubs);
+    if (!anAlgo)
+      return; // something gone wrong
+
+    anObjectHierarchy.markModified(aSolid, anAlgo->shape());
+    aMakeShapeList->appendAlgo(anAlgo);
+
+    anOriginalSolids.push_back(aSolid);
+    anEdges.insert(anEdges.end(), aSubs.begin(), aSubs.end());
+  }
+
+  // Build results of the operaion.
+  const std::string& aPrefix = modifiedShapePrefix();
+  ListOfShape aTopLevel;
+  anObjectHierarchy.topLevelObjects(aTopLevel);
+  for (ListOfShape::iterator anIt = aTopLevel.begin(); anIt != aTopLevel.end(); ++anIt) {
+    ResultBodyPtr aResultBody = document()->createBody(data(), aResultIndex);
+    FeaturesPlugin_Tools::loadModifiedShapes(aResultBody, anOriginalSolids, ListOfShape(),
+                                             aMakeShapeList, *anIt, aPrefix);
+    setResult(aResultBody, aResultIndex++);
+
+    for (ListOfShape::iterator anIt = anEdges.begin(); anIt != anEdges.end(); ++anIt) {
+      GeomShapePtr aBase = *anIt;
+      // Store new faces generated from edges and vertices
+      aResultBody->loadGeneratedShapes(aMakeShapeList, aBase, GeomAPI_Shape::EDGE, aPrefix, true);
+    }
+
+    FeaturesPlugin_Tools::loadDeletedShapes(aResultBody, GeomShapePtr(), anOriginalSolids,
+                                            aMakeShapeList, *anIt);
+  }
+
+  removeResults(aResultIndex);
+}
+
+
+bool FeaturesPlugin_VersionedChFi::processAttribute(const AttributePtr& theAttribute,
+                                                    GeomAPI_ShapeHierarchy& theObjects)
+{
+  bool isStoreFullHierarchy = data()->version() == CHAMFERFILLET_VERSION_1;
+
+  AttributeSelectionListPtr anObjectsSelList =
+      std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
+  for (int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); ++anObjectsIndex) {
+    AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anObjectsIndex);
+    GeomShapePtr anObject = anObjectAttr->value();
+    if (!anObject)
+      return false;
+
+    ResultPtr aContext = anObjectAttr->context();
+    GeomShapePtr aParent;
+    if (aContext.get()) {
+      ResultBodyPtr aCtxOwner = ModelAPI_Tools::bodyOwner(aContext);
+      if (aCtxOwner && aCtxOwner->shape()->shapeType() == GeomAPI_Shape::COMPSOLID)
+        aContext = aCtxOwner;
+      aParent = aContext->shape();
+      if (!aParent)
+        return false;
+
+      // store full shape hierarchy for the corresponding version only
+      theObjects.addObject(anObject);
+      theObjects.addParent(anObject, aParent);
+      if (isStoreFullHierarchy)
+        ModelAPI_Tools::fillShapeHierarchy(aParent, aContext, theObjects);
+    } else { // get it from a feature
+      FeaturePtr aFeature = anObjectAttr->contextFeature();
+      if (aFeature.get()) {
+        aParent = aFeature->firstResult()->shape();
+        if (!aParent)
+          return false;
+
+        ListOfShape anEdges;
+        collectSubs(aParent, anEdges, GeomAPI_Shape::EDGE);
+        for (ListOfShape::iterator anIt = anEdges.begin(); anIt != anEdges.end(); ++anIt) {
+          theObjects.addObject(*anIt);
+          theObjects.addParent(*anIt, aParent);
+        }
+      }
+    }
+  }
+  return true;
+}
diff --git a/src/FeaturesPlugin/FeaturesPlugin_VersionedChFi.h b/src/FeaturesPlugin/FeaturesPlugin_VersionedChFi.h
new file mode 100644 (file)
index 0000000..d81342d
--- /dev/null
@@ -0,0 +1,63 @@
+// Copyright (C) 2017-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
+//
+
+#ifndef FeaturesPlugin_VersionedChFi_H_
+#define FeaturesPlugin_VersionedChFi_H_
+
+#include "FeaturesPlugin.h"
+
+#include <GeomAPI_Shape.h>
+#include <GeomAPI_ShapeHierarchy.h>
+
+#include <ModelAPI_Feature.h>
+
+class GeomAlgoAPI_MakeShape;
+
+/// \class FeaturesPlugin_VersionedChFi
+/// \ingroup Plugins
+/// \brief Base feature for the Fillet and the Chamfer operations
+///        which supports versioning.
+class FeaturesPlugin_VersionedChFi : public ModelAPI_Feature
+{
+public:
+  /// Performs the fillet algorithm and stores it in the data structure.
+  FEATURESPLUGIN_EXPORT virtual void execute();
+
+protected:
+  FeaturesPlugin_VersionedChFi() {}
+
+  /// Intialize the version for the newly created feature.
+  void initVersion(const std::shared_ptr<ModelAPI_Attribute>& theObjectsAttr);
+
+  /// Process SelectionList attribute and fill the objects hierarchy.
+  bool processAttribute(const std::shared_ptr<ModelAPI_Attribute>& theAttribute,
+                        GeomAPI_ShapeHierarchy& theObjects);
+
+  /// Return attribute storing the selected objects of the operation.
+  virtual std::shared_ptr<ModelAPI_Attribute> objectsAttribute() = 0;
+
+  /// Return name of modified shape prefix name
+  virtual const std::string& modifiedShapePrefix() const = 0;
+
+  /// Run chamfer/fillet operation and returns the modification algorithm if succeed.
+  virtual std::shared_ptr<GeomAlgoAPI_MakeShape>
+      performOperation(const GeomShapePtr& theSolid, const ListOfShape& theEdges) = 0;
+};
+
+#endif
diff --git a/src/FeaturesPlugin/Test/TestChamfer_MultiLevelCompound_v0_1.py b/src/FeaturesPlugin/Test/TestChamfer_MultiLevelCompound_v0_1.py
new file mode 100644 (file)
index 0000000..bc024cc
--- /dev/null
@@ -0,0 +1,147 @@
+# Copyright (C) 2020  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 salome.shaper import model
+from GeomAPI import *
+from GeomAlgoAPI 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"))
+SketchPoint_1 = Sketch_1.addPoint(44.29784155360136, 17.09942588468031)
+SketchArc_1 = Sketch_1.addArc(44.29784155360136, 17.09942588468031, 47.1668727423061, 12.27945348765633, 45.38299232715926, 22.60269052200972, False)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchArc_1.center())
+SketchLine_1 = Sketch_1.addLine(42.5764228403785, 22.14892077680068, 39.70739165167375, 16.41085839939117)
+SketchLine_2 = Sketch_1.addLine(39.70739165167375, 16.41085839939117, 43.03546783057126, 12.04993099255995)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(28.57555063949931, 12.96802097294547, 15.72229091410204, 12.96802097294547)
+SketchLine_4 = Sketch_1.addLine(15.72229091410204, 12.96802097294547, 15.72229091410204, 21.46035329151154)
+SketchLine_5 = Sketch_1.addLine(15.72229091410204, 21.46035329151154, 28.57555063949931, 21.46035329151154)
+SketchLine_6 = Sketch_1.addLine(28.57555063949931, 21.46035329151154, 28.57555063949931, 12.96802097294547)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_6.result())
+SketchLine_7 = Sketch_1.addLine(-10.67279602198167, 14.78814178154371, -28.34602814440294, 14.78814178154371)
+SketchLine_8 = Sketch_1.addLine(-28.34602814440294, 14.78814178154371, -28.34602814440294, 25.13271321305362)
+SketchLine_9 = Sketch_1.addLine(-28.34602814440294, 25.13271321305362, -10.67279602198167, 25.13271321305362)
+SketchLine_10 = Sketch_1.addLine(-10.67279602198167, 25.13271321305362, -10.67279602198167, 14.78814178154371)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_10.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())
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchLine_9.endPoint(), SketchLine_10.startPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_7.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_8.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_9.result())
+SketchConstraintVertical_4 = Sketch_1.setVertical(SketchLine_10.result())
+SketchLine_11 = Sketch_1.addLine(-17.67323212242127, 25.13271321305362, -21.80463703415611, 14.78814178154371)
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchLine_11.startPoint(), SketchLine_9.result())
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchLine_11.endPoint(), SketchLine_7.result())
+model.do()
+Vertex_1 = model.addVertex(Part_1_doc, [model.selection("VERTEX", "Sketch_1/SketchArc_1")], False)
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchArc_1_2")], False)
+Wire_1 = model.addWire(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2")], False)
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_6r-SketchLine_5r-SketchLine_4r-SketchLine_3r")])
+Shell_1 = model.addShell(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_10r-SketchLine_9r-SketchLine_11f-SketchLine_7r"), model.selection("FACE", "Sketch_1/Face-SketchLine_11r-SketchLine_9r-SketchLine_8r-SketchLine_7r")])
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 50)
+Box_2 = model.addBox(Part_1_doc, 10, 10, 10)
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Box_2_1"), model.selection("SOLID", "Cylinder_1_1")])
+Box_3 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_2 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_3_1")], model.selection("EDGE", "PartSet/OY"), 50)
+AngularCopy_1 = model.addMultiRotation(Part_1_doc, [model.selection("SOLID", "Translation_2_1")], model.selection("EDGE", "PartSet/OZ"), 30, 3)
+model.end()
+
+TOLERANCE = 1.e-7
+DISTANCE_1 = 2
+DISTANCE_2 = 1
+
+model.begin()
+Chamfer_1 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Edge_1_1")], True, DISTANCE_1, DISTANCE_2)
+model.end()
+assert(Chamfer_1.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_2 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Wire_1_1/Modified_Edge&Sketch_1/SketchLine_1")], True, DISTANCE_1, DISTANCE_2)
+model.end()
+assert(Chamfer_2.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_3 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Face_1_1/Modified_Edge&Sketch_1/SketchLine_3")], True, DISTANCE_1, DISTANCE_2)
+model.end()
+assert(Chamfer_3.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_4 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Shell_1_1/Modified_Edge&Sketch_1/SketchLine_10")], True, DISTANCE_1, DISTANCE_2)
+model.end()
+assert(Chamfer_4.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_5 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[Translation_1_1/MF:Translated&Box_1_1/Front][Translation_1_1/MF:Translated&Box_1_1/Top]"), model.selection("FACE", "Translation_1_1/MF:Translated&Box_1_1/Right")], True, DISTANCE_1, DISTANCE_2)
+model.testNbResults(Chamfer_5, 1)
+model.testNbSubResults(Chamfer_5, [0])
+model.testNbSubShapes(Chamfer_5, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Chamfer_5, GeomAPI_Shape.FACE, [12])
+model.testNbSubShapes(Chamfer_5, GeomAPI_Shape.EDGE, [50])
+model.testNbSubShapes(Chamfer_5, GeomAPI_Shape.VERTEX, [100])
+model.testResultsVolumes(Chamfer_5, [955.8333333])
+refPoint = GeomAPI_Pnt(54.9539378, 4.833682, 4.95710549)
+midPoint = Chamfer_5.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+
+Chamfer_6 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[Partition_1_1_2/Modified_Face&Box_2_1/Top][Box_2_1/Front]"), model.selection("FACE", "Box_2_1/Right")], True, DISTANCE_1, DISTANCE_2)
+model.testNbResults(Chamfer_6, 1)
+model.testNbSubResults(Chamfer_6, [3])
+model.testNbSubShapes(Chamfer_6, GeomAPI_Shape.SOLID, [3])
+model.testNbSubShapes(Chamfer_6, GeomAPI_Shape.FACE, [23])
+model.testNbSubShapes(Chamfer_6, GeomAPI_Shape.EDGE, [90])
+model.testNbSubShapes(Chamfer_6, GeomAPI_Shape.VERTEX, [180])
+model.testResultsVolumes(Chamfer_6, [1545.0486226])
+refPoint = GeomAPI_Pnt(2.5, 2.5, 5)
+midPoint = Chamfer_6.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+
+Chamfer_7 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[AngularCopy_1_1_1/MF:Rotated&Box_3_1/Back][AngularCopy_1_1_1/MF:Rotated&Box_3_1/Top]"), model.selection("FACE", "AngularCopy_1_1_2/MF:Rotated&Box_3_1/Left")], True, DISTANCE_1, DISTANCE_2)
+model.testNbResults(Chamfer_7, 2)
+model.testNbSubResults(Chamfer_7, [0, 0])
+model.testNbSubShapes(Chamfer_7, GeomAPI_Shape.SOLID, [1, 1])
+model.testNbSubShapes(Chamfer_7, GeomAPI_Shape.FACE, [7, 10])
+model.testNbSubShapes(Chamfer_7, GeomAPI_Shape.EDGE, [30, 40])
+model.testNbSubShapes(Chamfer_7, GeomAPI_Shape.VERTEX, [60, 80])
+model.testResultsVolumes(Chamfer_7, [990, 965.33333333])
+model.end()
+
+model.begin()
+Chamfer_8 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[Chamfer_1_1/MF:Chamfer&Box_1_1/Top][Chamfer_1_1/MF:Chamfer&Box_1_1/Left]"), model.selection("EDGE", "[AngularCopy_1_1_3/MF:Rotated&Box_3_1/Left][AngularCopy_1_1_3/MF:Rotated&Box_3_1/Top]")], True, DISTANCE_1, DISTANCE_2)
+model.end()
+assert(Chamfer_8.feature().error() != "")
+model.undo()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestChamfer_MultiLevelCompound_v0_2.py b/src/FeaturesPlugin/Test/TestChamfer_MultiLevelCompound_v0_2.py
new file mode 100644 (file)
index 0000000..b451733
--- /dev/null
@@ -0,0 +1,155 @@
+# Copyright (C) 2020  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 salome.shaper import model
+from GeomAPI import *
+from GeomAlgoAPI 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"))
+SketchPoint_1 = Sketch_1.addPoint(44.29784155360136, 17.09942588468031)
+SketchArc_1 = Sketch_1.addArc(44.29784155360136, 17.09942588468031, 47.1668727423061, 12.27945348765633, 45.38299232715926, 22.60269052200972, False)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchArc_1.center())
+SketchLine_1 = Sketch_1.addLine(42.5764228403785, 22.14892077680068, 39.70739165167375, 16.41085839939117)
+SketchLine_2 = Sketch_1.addLine(39.70739165167375, 16.41085839939117, 43.03546783057126, 12.04993099255995)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(28.57555063949931, 12.96802097294547, 15.72229091410204, 12.96802097294547)
+SketchLine_4 = Sketch_1.addLine(15.72229091410204, 12.96802097294547, 15.72229091410204, 21.46035329151154)
+SketchLine_5 = Sketch_1.addLine(15.72229091410204, 21.46035329151154, 28.57555063949931, 21.46035329151154)
+SketchLine_6 = Sketch_1.addLine(28.57555063949931, 21.46035329151154, 28.57555063949931, 12.96802097294547)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_6.result())
+SketchLine_7 = Sketch_1.addLine(-10.67279602198167, 14.78814178154371, -28.34602814440294, 14.78814178154371)
+SketchLine_8 = Sketch_1.addLine(-28.34602814440294, 14.78814178154371, -28.34602814440294, 25.13271321305362)
+SketchLine_9 = Sketch_1.addLine(-28.34602814440294, 25.13271321305362, -10.67279602198167, 25.13271321305362)
+SketchLine_10 = Sketch_1.addLine(-10.67279602198167, 25.13271321305362, -10.67279602198167, 14.78814178154371)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_10.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())
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchLine_9.endPoint(), SketchLine_10.startPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_7.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_8.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_9.result())
+SketchConstraintVertical_4 = Sketch_1.setVertical(SketchLine_10.result())
+SketchLine_11 = Sketch_1.addLine(-17.67323212242127, 25.13271321305362, -21.80463703415611, 14.78814178154371)
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchLine_11.startPoint(), SketchLine_9.result())
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchLine_11.endPoint(), SketchLine_7.result())
+model.do()
+Vertex_1 = model.addVertex(Part_1_doc, [model.selection("VERTEX", "Sketch_1/SketchArc_1")], False)
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchArc_1_2")], False)
+Wire_1 = model.addWire(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2")], False)
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_6r-SketchLine_5r-SketchLine_4r-SketchLine_3r")])
+Shell_1 = model.addShell(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_10r-SketchLine_9r-SketchLine_11f-SketchLine_7r"), model.selection("FACE", "Sketch_1/Face-SketchLine_11r-SketchLine_9r-SketchLine_8r-SketchLine_7r")])
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 50)
+Box_2 = model.addBox(Part_1_doc, 10, 10, 10)
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Box_2_1"), model.selection("SOLID", "Cylinder_1_1")])
+Box_3 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_2 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_3_1")], model.selection("EDGE", "PartSet/OY"), 50)
+AngularCopy_1 = model.addMultiRotation(Part_1_doc, [model.selection("SOLID", "Translation_2_1")], model.selection("EDGE", "PartSet/OZ"), 30, 3)
+Compound_1_objects = [model.selection("VERTEX", "Vertex_1_1"), model.selection("EDGE", "Edge_1_1"), model.selection("WIRE", "Wire_1_1"), model.selection("FACE", "Face_1_1"), model.selection("SHELL", "Shell_1_1"), model.selection("SOLID", "Translation_1_1"), model.selection("COMPSOLID", "Partition_1_1"), model.selection("COMPOUND", "AngularCopy_1_1")]
+Compound_1 = model.addCompound(Part_1_doc, Compound_1_objects)
+model.end()
+
+TOLERANCE = 1.e-7
+DISTANCE_1 = 2
+DISTANCE_2 = 1
+
+model.begin()
+Chamfer_1 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Compound_1_1_2")], True, DISTANCE_1, DISTANCE_2)
+model.end()
+assert(Chamfer_1.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_2 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Compound_1_1_3/Modified_Edge&Sketch_1/SketchLine_1")], True, DISTANCE_1, DISTANCE_2)
+model.end()
+assert(Chamfer_2.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_3 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Compound_1_1_4/Modified_Edge&Sketch_1/SketchLine_3")], True, DISTANCE_1, DISTANCE_2)
+model.end()
+assert(Chamfer_3.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_4 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Compound_1_1_5/Modified_Edge&Sketch_1/SketchLine_10")], True, DISTANCE_1, DISTANCE_2)
+model.end()
+assert(Chamfer_4.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_5 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[Compound_1_1_6/Modified_Face&Box_1_1/Front][Compound_1_1_6/Modified_Face&Box_1_1/Top]"), model.selection("FACE", "Compound_1_1_6/Modified_Face&Box_1_1/Back")], True, DISTANCE_1, DISTANCE_2)
+model.testNbResults(Chamfer_5, 1)
+model.testNbSubResults(Chamfer_5, [0])
+model.testNbSubShapes(Chamfer_5, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Chamfer_5, GeomAPI_Shape.FACE, [11])
+model.testNbSubShapes(Chamfer_5, GeomAPI_Shape.EDGE, [46])
+model.testNbSubShapes(Chamfer_5, GeomAPI_Shape.VERTEX, [92])
+model.testResultsVolumes(Chamfer_5, [955.333333333])
+refPoint = GeomAPI_Pnt(55.1200279, 5, 4.954640614)
+midPoint = Chamfer_5.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+
+Recover_1 = model.addRecover(Part_1_doc, Chamfer_5, [Compound_1.result()], True)
+Chamfer_6 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[Recover_1_1_7_2/Modified_Face&Box_2_1/Top][Recover_1_1_7_2/Modified_Face&Box_2_1/Front]"), model.selection("FACE", "Recover_1_1_7_2/Modified_Face&Box_2_1/Right")], True, DISTANCE_1, DISTANCE_2)
+model.testNbResults(Chamfer_6, 1)
+model.testNbSubResults(Chamfer_6, [3])
+model.testNbSubShapes(Chamfer_6, GeomAPI_Shape.SOLID, [3])
+model.testNbSubShapes(Chamfer_6, GeomAPI_Shape.FACE, [23])
+model.testNbSubShapes(Chamfer_6, GeomAPI_Shape.EDGE, [90])
+model.testNbSubShapes(Chamfer_6, GeomAPI_Shape.VERTEX, [180])
+model.testResultsVolumes(Chamfer_6, [1545.0486226])
+refPoint = GeomAPI_Pnt(2.5, 2.5, 5)
+midPoint = Chamfer_6.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+
+Recover_2 = model.addRecover(Part_1_doc, Chamfer_6, [Compound_1.result()], True)
+Chamfer_7 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[Recover_2_1_8_1/Modified_Face&Box_3_1/Back][Recover_2_1_8_1/Modified_Face&Box_3_1/Top]"), model.selection("FACE", "Recover_2_1_8_2/Modified_Face&Box_3_1/Left")], True, DISTANCE_1, DISTANCE_2)
+model.testNbResults(Chamfer_7, 2)
+model.testNbSubResults(Chamfer_7, [0, 0])
+model.testNbSubShapes(Chamfer_7, GeomAPI_Shape.SOLID, [1, 1])
+model.testNbSubShapes(Chamfer_7, GeomAPI_Shape.FACE, [7, 10])
+model.testNbSubShapes(Chamfer_7, GeomAPI_Shape.EDGE, [30, 40])
+model.testNbSubShapes(Chamfer_7, GeomAPI_Shape.VERTEX, [60, 80])
+model.testResultsVolumes(Chamfer_7, [990, 965.33333333])
+
+Recover_3 = model.addRecover(Part_1_doc, Chamfer_7, [Compound_1.result()], True)
+Chamfer_8 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Recover_3_1_6/Modified_Edge&Chamfer_1_1/ChamferSelected_1"), model.selection("EDGE", "[Recover_3_1_8_2/Modified_Face&Box_3_1/Left][Recover_3_1_8_2/Modified_Face&Box_3_1/Top]")], True, DISTANCE_1, DISTANCE_2)
+model.testNbResults(Chamfer_8, 2)
+model.testNbSubResults(Chamfer_8, [0, 0])
+model.testNbSubShapes(Chamfer_8, GeomAPI_Shape.SOLID, [1, 1])
+model.testNbSubShapes(Chamfer_8, GeomAPI_Shape.FACE, [7, 7])
+model.testNbSubShapes(Chamfer_8, GeomAPI_Shape.EDGE, [30, 30])
+model.testNbSubShapes(Chamfer_8, GeomAPI_Shape.VERTEX, [60, 60])
+model.testResultsVolumes(Chamfer_8, [990, 990])
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestChamfer_MultiLevelCompound_v0_3.py b/src/FeaturesPlugin/Test/TestChamfer_MultiLevelCompound_v0_3.py
new file mode 100644 (file)
index 0000000..3521432
--- /dev/null
@@ -0,0 +1,147 @@
+# Copyright (C) 2020  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 salome.shaper import model
+from GeomAPI import *
+from GeomAlgoAPI 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"))
+SketchPoint_1 = Sketch_1.addPoint(44.29784155360136, 17.09942588468031)
+SketchArc_1 = Sketch_1.addArc(44.29784155360136, 17.09942588468031, 47.1668727423061, 12.27945348765633, 45.38299232715926, 22.60269052200972, False)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchArc_1.center())
+SketchLine_1 = Sketch_1.addLine(42.5764228403785, 22.14892077680068, 39.70739165167375, 16.41085839939117)
+SketchLine_2 = Sketch_1.addLine(39.70739165167375, 16.41085839939117, 43.03546783057126, 12.04993099255995)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(28.57555063949931, 12.96802097294547, 15.72229091410204, 12.96802097294547)
+SketchLine_4 = Sketch_1.addLine(15.72229091410204, 12.96802097294547, 15.72229091410204, 21.46035329151154)
+SketchLine_5 = Sketch_1.addLine(15.72229091410204, 21.46035329151154, 28.57555063949931, 21.46035329151154)
+SketchLine_6 = Sketch_1.addLine(28.57555063949931, 21.46035329151154, 28.57555063949931, 12.96802097294547)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_6.result())
+SketchLine_7 = Sketch_1.addLine(-10.67279602198167, 14.78814178154371, -28.34602814440294, 14.78814178154371)
+SketchLine_8 = Sketch_1.addLine(-28.34602814440294, 14.78814178154371, -28.34602814440294, 25.13271321305362)
+SketchLine_9 = Sketch_1.addLine(-28.34602814440294, 25.13271321305362, -10.67279602198167, 25.13271321305362)
+SketchLine_10 = Sketch_1.addLine(-10.67279602198167, 25.13271321305362, -10.67279602198167, 14.78814178154371)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_10.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())
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchLine_9.endPoint(), SketchLine_10.startPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_7.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_8.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_9.result())
+SketchConstraintVertical_4 = Sketch_1.setVertical(SketchLine_10.result())
+SketchLine_11 = Sketch_1.addLine(-17.67323212242127, 25.13271321305362, -21.80463703415611, 14.78814178154371)
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchLine_11.startPoint(), SketchLine_9.result())
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchLine_11.endPoint(), SketchLine_7.result())
+model.do()
+Vertex_1 = model.addVertex(Part_1_doc, [model.selection("VERTEX", "Sketch_1/SketchArc_1")], False)
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchArc_1_2")], False)
+Wire_1 = model.addWire(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2")], False)
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_6r-SketchLine_5r-SketchLine_4r-SketchLine_3r")])
+Shell_1 = model.addShell(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_10r-SketchLine_9r-SketchLine_11f-SketchLine_7r"), model.selection("FACE", "Sketch_1/Face-SketchLine_11r-SketchLine_9r-SketchLine_8r-SketchLine_7r")])
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 50)
+Box_2 = model.addBox(Part_1_doc, 10, 10, 10)
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Box_2_1"), model.selection("SOLID", "Cylinder_1_1")])
+Box_3 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_2 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_3_1")], model.selection("EDGE", "PartSet/OY"), 50)
+AngularCopy_1 = model.addMultiRotation(Part_1_doc, [model.selection("SOLID", "Translation_2_1")], model.selection("EDGE", "PartSet/OZ"), 30, 3)
+model.end()
+
+TOLERANCE = 1.e-7
+DISTANCE = 2
+ANGLE = 30
+
+model.begin()
+Chamfer_1 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Edge_1_1")], False, DISTANCE, ANGLE)
+model.end()
+assert(Chamfer_1.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_2 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Wire_1_1/Modified_Edge&Sketch_1/SketchLine_1")], False, DISTANCE, ANGLE)
+model.end()
+assert(Chamfer_2.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_3 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Face_1_1/Modified_Edge&Sketch_1/SketchLine_3")], False, DISTANCE, ANGLE)
+model.end()
+assert(Chamfer_3.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_4 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Shell_1_1/Modified_Edge&Sketch_1/SketchLine_10")], False, DISTANCE, ANGLE)
+model.end()
+assert(Chamfer_4.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_5 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[Translation_1_1/MF:Translated&Box_1_1/Front][Translation_1_1/MF:Translated&Box_1_1/Top]"), model.selection("FACE", "Translation_1_1/MF:Translated&Box_1_1/Right")], False, DISTANCE, ANGLE)
+model.testNbResults(Chamfer_5, 1)
+model.testNbSubResults(Chamfer_5, [0])
+model.testNbSubShapes(Chamfer_5, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Chamfer_5, GeomAPI_Shape.FACE, [12])
+model.testNbSubShapes(Chamfer_5, GeomAPI_Shape.EDGE, [48])
+model.testNbSubShapes(Chamfer_5, GeomAPI_Shape.VERTEX, [96])
+model.testResultsVolumes(Chamfer_5, [949.312264841])
+refPoint = GeomAPI_Pnt(54.9483743992, 4.810295773, 4.951504868)
+midPoint = Chamfer_5.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+
+Chamfer_6 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[Partition_1_1_2/Modified_Face&Box_2_1/Top][Box_2_1/Front]"), model.selection("FACE", "Box_2_1/Right")], False, DISTANCE, ANGLE)
+model.testNbResults(Chamfer_6, 1)
+model.testNbSubResults(Chamfer_6, [3])
+model.testNbSubShapes(Chamfer_6, GeomAPI_Shape.SOLID, [3])
+model.testNbSubShapes(Chamfer_6, GeomAPI_Shape.FACE, [23])
+model.testNbSubShapes(Chamfer_6, GeomAPI_Shape.EDGE, [90])
+model.testNbSubShapes(Chamfer_6, GeomAPI_Shape.VERTEX, [180])
+model.testResultsVolumes(Chamfer_6, [1538.36088744])
+refPoint = GeomAPI_Pnt(2.5, 2.5, 5)
+midPoint = Chamfer_6.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+
+Chamfer_7 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[AngularCopy_1_1_1/MF:Rotated&Box_3_1/Back][AngularCopy_1_1_1/MF:Rotated&Box_3_1/Top]"), model.selection("FACE", "AngularCopy_1_1_2/MF:Rotated&Box_3_1/Left")], False, DISTANCE, ANGLE)
+model.testNbResults(Chamfer_7, 2)
+model.testNbSubResults(Chamfer_7, [0, 0])
+model.testNbSubShapes(Chamfer_7, GeomAPI_Shape.SOLID, [1, 1])
+model.testNbSubShapes(Chamfer_7, GeomAPI_Shape.FACE, [7, 10])
+model.testNbSubShapes(Chamfer_7, GeomAPI_Shape.EDGE, [30, 40])
+model.testNbSubShapes(Chamfer_7, GeomAPI_Shape.VERTEX, [60, 80])
+model.testResultsVolumes(Chamfer_7, [988.4529946162, 959.970381336])
+model.end()
+
+model.begin()
+Chamfer_8 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[Chamfer_1_1/MF:Chamfer&Box_1_1/Top][Chamfer_1_1/MF:Chamfer&Box_1_1/Left]"), model.selection("EDGE", "[AngularCopy_1_1_3/MF:Rotated&Box_3_1/Left][AngularCopy_1_1_3/MF:Rotated&Box_3_1/Top]")], False, DISTANCE, ANGLE)
+model.end()
+assert(Chamfer_8.feature().error() != "")
+model.undo()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestChamfer_MultiLevelCompound_v0_4.py b/src/FeaturesPlugin/Test/TestChamfer_MultiLevelCompound_v0_4.py
new file mode 100644 (file)
index 0000000..5903898
--- /dev/null
@@ -0,0 +1,155 @@
+# Copyright (C) 2020  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 salome.shaper import model
+from GeomAPI import *
+from GeomAlgoAPI 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"))
+SketchPoint_1 = Sketch_1.addPoint(44.29784155360136, 17.09942588468031)
+SketchArc_1 = Sketch_1.addArc(44.29784155360136, 17.09942588468031, 47.1668727423061, 12.27945348765633, 45.38299232715926, 22.60269052200972, False)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchArc_1.center())
+SketchLine_1 = Sketch_1.addLine(42.5764228403785, 22.14892077680068, 39.70739165167375, 16.41085839939117)
+SketchLine_2 = Sketch_1.addLine(39.70739165167375, 16.41085839939117, 43.03546783057126, 12.04993099255995)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(28.57555063949931, 12.96802097294547, 15.72229091410204, 12.96802097294547)
+SketchLine_4 = Sketch_1.addLine(15.72229091410204, 12.96802097294547, 15.72229091410204, 21.46035329151154)
+SketchLine_5 = Sketch_1.addLine(15.72229091410204, 21.46035329151154, 28.57555063949931, 21.46035329151154)
+SketchLine_6 = Sketch_1.addLine(28.57555063949931, 21.46035329151154, 28.57555063949931, 12.96802097294547)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_6.result())
+SketchLine_7 = Sketch_1.addLine(-10.67279602198167, 14.78814178154371, -28.34602814440294, 14.78814178154371)
+SketchLine_8 = Sketch_1.addLine(-28.34602814440294, 14.78814178154371, -28.34602814440294, 25.13271321305362)
+SketchLine_9 = Sketch_1.addLine(-28.34602814440294, 25.13271321305362, -10.67279602198167, 25.13271321305362)
+SketchLine_10 = Sketch_1.addLine(-10.67279602198167, 25.13271321305362, -10.67279602198167, 14.78814178154371)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_10.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())
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchLine_9.endPoint(), SketchLine_10.startPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_7.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_8.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_9.result())
+SketchConstraintVertical_4 = Sketch_1.setVertical(SketchLine_10.result())
+SketchLine_11 = Sketch_1.addLine(-17.67323212242127, 25.13271321305362, -21.80463703415611, 14.78814178154371)
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchLine_11.startPoint(), SketchLine_9.result())
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchLine_11.endPoint(), SketchLine_7.result())
+model.do()
+Vertex_1 = model.addVertex(Part_1_doc, [model.selection("VERTEX", "Sketch_1/SketchArc_1")], False)
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchArc_1_2")], False)
+Wire_1 = model.addWire(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2")], False)
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_6r-SketchLine_5r-SketchLine_4r-SketchLine_3r")])
+Shell_1 = model.addShell(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_10r-SketchLine_9r-SketchLine_11f-SketchLine_7r"), model.selection("FACE", "Sketch_1/Face-SketchLine_11r-SketchLine_9r-SketchLine_8r-SketchLine_7r")])
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 50)
+Box_2 = model.addBox(Part_1_doc, 10, 10, 10)
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Box_2_1"), model.selection("SOLID", "Cylinder_1_1")])
+Box_3 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_2 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_3_1")], model.selection("EDGE", "PartSet/OY"), 50)
+AngularCopy_1 = model.addMultiRotation(Part_1_doc, [model.selection("SOLID", "Translation_2_1")], model.selection("EDGE", "PartSet/OZ"), 30, 3)
+Compound_1_objects = [model.selection("VERTEX", "Vertex_1_1"), model.selection("EDGE", "Edge_1_1"), model.selection("WIRE", "Wire_1_1"), model.selection("FACE", "Face_1_1"), model.selection("SHELL", "Shell_1_1"), model.selection("SOLID", "Translation_1_1"), model.selection("COMPSOLID", "Partition_1_1"), model.selection("COMPOUND", "AngularCopy_1_1")]
+Compound_1 = model.addCompound(Part_1_doc, Compound_1_objects)
+model.end()
+
+TOLERANCE = 1.e-7
+DISTANCE = 2
+ANGLE = 30
+
+model.begin()
+Chamfer_1 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Compound_1_1_2")], False, DISTANCE, ANGLE)
+model.end()
+assert(Chamfer_1.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_2 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Compound_1_1_3/Modified_Edge&Sketch_1/SketchLine_1")], False, DISTANCE, ANGLE)
+model.end()
+assert(Chamfer_2.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_3 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Compound_1_1_4/Modified_Edge&Sketch_1/SketchLine_3")], False, DISTANCE, ANGLE)
+model.end()
+assert(Chamfer_3.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_4 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Compound_1_1_5/Modified_Edge&Sketch_1/SketchLine_10")], False, DISTANCE, ANGLE)
+model.end()
+assert(Chamfer_4.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_5 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[Compound_1_1_6/Modified_Face&Box_1_1/Front][Compound_1_1_6/Modified_Face&Box_1_1/Top]"), model.selection("FACE", "Compound_1_1_6/Modified_Face&Box_1_1/Back")], False, DISTANCE, ANGLE)
+model.testNbResults(Chamfer_5, 1)
+model.testNbSubResults(Chamfer_5, [0])
+model.testNbSubShapes(Chamfer_5, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Chamfer_5, GeomAPI_Shape.FACE, [11])
+model.testNbSubShapes(Chamfer_5, GeomAPI_Shape.EDGE, [46])
+model.testNbSubShapes(Chamfer_5, GeomAPI_Shape.VERTEX, [92])
+model.testResultsVolumes(Chamfer_5, [948.423375952])
+refPoint = GeomAPI_Pnt(55.13797373, 5, 4.94724189)
+midPoint = Chamfer_5.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+
+Recover_1 = model.addRecover(Part_1_doc, Chamfer_5, [Compound_1.result()], True)
+Chamfer_6 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[Recover_1_1_7_2/Modified_Face&Box_2_1/Top][Recover_1_1_7_2/Modified_Face&Box_2_1/Front]"), model.selection("FACE", "Recover_1_1_7_2/Modified_Face&Box_2_1/Right")], False, DISTANCE, ANGLE)
+model.testNbResults(Chamfer_6, 1)
+model.testNbSubResults(Chamfer_6, [3])
+model.testNbSubShapes(Chamfer_6, GeomAPI_Shape.SOLID, [3])
+model.testNbSubShapes(Chamfer_6, GeomAPI_Shape.FACE, [23])
+model.testNbSubShapes(Chamfer_6, GeomAPI_Shape.EDGE, [90])
+model.testNbSubShapes(Chamfer_6, GeomAPI_Shape.VERTEX, [180])
+model.testResultsVolumes(Chamfer_6, [1538.36088744])
+refPoint = GeomAPI_Pnt(2.5, 2.5, 5)
+midPoint = Chamfer_6.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+
+Recover_2 = model.addRecover(Part_1_doc, Chamfer_6, [Compound_1.result()], True)
+Chamfer_7 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[Recover_2_1_8_1/Modified_Face&Box_3_1/Back][Recover_2_1_8_1/Modified_Face&Box_3_1/Top]"), model.selection("FACE", "Recover_2_1_8_2/Modified_Face&Box_3_1/Left")], False, DISTANCE, ANGLE)
+model.testNbResults(Chamfer_7, 2)
+model.testNbSubResults(Chamfer_7, [0, 0])
+model.testNbSubShapes(Chamfer_7, GeomAPI_Shape.SOLID, [1, 1])
+model.testNbSubShapes(Chamfer_7, GeomAPI_Shape.FACE, [7, 10])
+model.testNbSubShapes(Chamfer_7, GeomAPI_Shape.EDGE, [30, 40])
+model.testNbSubShapes(Chamfer_7, GeomAPI_Shape.VERTEX, [60, 80])
+model.testResultsVolumes(Chamfer_7, [988.4529946162, 959.970381336])
+
+Recover_3 = model.addRecover(Part_1_doc, Chamfer_7, [Compound_1.result()], True)
+Chamfer_8 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Recover_3_1_6/Modified_Edge&Chamfer_1_1/ChamferSelected_1"), model.selection("EDGE", "[Recover_3_1_8_2/Modified_Face&Box_3_1/Left][Recover_3_1_8_2/Modified_Face&Box_3_1/Top]")], False, DISTANCE, ANGLE)
+model.testNbResults(Chamfer_8, 2)
+model.testNbSubResults(Chamfer_8, [0, 0])
+model.testNbSubShapes(Chamfer_8, GeomAPI_Shape.SOLID, [1, 1])
+model.testNbSubShapes(Chamfer_8, GeomAPI_Shape.FACE, [7, 7])
+model.testNbSubShapes(Chamfer_8, GeomAPI_Shape.EDGE, [30, 30])
+model.testNbSubShapes(Chamfer_8, GeomAPI_Shape.VERTEX, [60, 60])
+model.testResultsVolumes(Chamfer_8, [988.4529946162, 988.4529946162])
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestChamfer_MultiLevelCompound_v95_1.py b/src/FeaturesPlugin/Test/TestChamfer_MultiLevelCompound_v95_1.py
new file mode 100644 (file)
index 0000000..bfbffbf
--- /dev/null
@@ -0,0 +1,150 @@
+# Copyright (C) 2020  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 salome.shaper import model
+from GeomAPI import *
+from GeomAlgoAPI 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"))
+SketchPoint_1 = Sketch_1.addPoint(44.29784155360136, 17.09942588468031)
+SketchArc_1 = Sketch_1.addArc(44.29784155360136, 17.09942588468031, 47.1668727423061, 12.27945348765633, 45.38299232715926, 22.60269052200972, False)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchArc_1.center())
+SketchLine_1 = Sketch_1.addLine(42.5764228403785, 22.14892077680068, 39.70739165167375, 16.41085839939117)
+SketchLine_2 = Sketch_1.addLine(39.70739165167375, 16.41085839939117, 43.03546783057126, 12.04993099255995)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(28.57555063949931, 12.96802097294547, 15.72229091410204, 12.96802097294547)
+SketchLine_4 = Sketch_1.addLine(15.72229091410204, 12.96802097294547, 15.72229091410204, 21.46035329151154)
+SketchLine_5 = Sketch_1.addLine(15.72229091410204, 21.46035329151154, 28.57555063949931, 21.46035329151154)
+SketchLine_6 = Sketch_1.addLine(28.57555063949931, 21.46035329151154, 28.57555063949931, 12.96802097294547)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_6.result())
+SketchLine_7 = Sketch_1.addLine(-10.67279602198167, 14.78814178154371, -28.34602814440294, 14.78814178154371)
+SketchLine_8 = Sketch_1.addLine(-28.34602814440294, 14.78814178154371, -28.34602814440294, 25.13271321305362)
+SketchLine_9 = Sketch_1.addLine(-28.34602814440294, 25.13271321305362, -10.67279602198167, 25.13271321305362)
+SketchLine_10 = Sketch_1.addLine(-10.67279602198167, 25.13271321305362, -10.67279602198167, 14.78814178154371)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_10.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())
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchLine_9.endPoint(), SketchLine_10.startPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_7.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_8.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_9.result())
+SketchConstraintVertical_4 = Sketch_1.setVertical(SketchLine_10.result())
+SketchLine_11 = Sketch_1.addLine(-17.67323212242127, 25.13271321305362, -21.80463703415611, 14.78814178154371)
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchLine_11.startPoint(), SketchLine_9.result())
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchLine_11.endPoint(), SketchLine_7.result())
+model.do()
+Vertex_1 = model.addVertex(Part_1_doc, [model.selection("VERTEX", "Sketch_1/SketchArc_1")], False)
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchArc_1_2")], False)
+Wire_1 = model.addWire(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2")], False)
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_6r-SketchLine_5r-SketchLine_4r-SketchLine_3r")])
+Shell_1 = model.addShell(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_10r-SketchLine_9r-SketchLine_11f-SketchLine_7r"), model.selection("FACE", "Sketch_1/Face-SketchLine_11r-SketchLine_9r-SketchLine_8r-SketchLine_7r")])
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 50)
+Box_2 = model.addBox(Part_1_doc, 10, 10, 10)
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Box_2_1"), model.selection("SOLID", "Cylinder_1_1")], keepSubResults = True)
+Box_3 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_2 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_3_1")], model.selection("EDGE", "PartSet/OY"), 50)
+AngularCopy_1 = model.addMultiRotation(Part_1_doc, [model.selection("SOLID", "Translation_2_1")], model.selection("EDGE", "PartSet/OZ"), 30, 3)
+model.end()
+
+TOLERANCE = 1.e-7
+DISTANCE_1 = 2
+DISTANCE_2 = 1
+
+model.begin()
+Chamfer_1 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Edge_1_1")], True, DISTANCE_1, DISTANCE_2, keepSubResults = True)
+model.end()
+assert(Chamfer_1.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_2 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Wire_1_1/Modified_Edge&Sketch_1/SketchLine_1")], True, DISTANCE_1, DISTANCE_2, keepSubResults = True)
+model.end()
+assert(Chamfer_2.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_3 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Face_1_1/Modified_Edge&Sketch_1/SketchLine_3")], True, DISTANCE_1, DISTANCE_2, keepSubResults = True)
+model.end()
+assert(Chamfer_3.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_4 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Shell_1_1/Modified_Edge&Sketch_1/SketchLine_10")], True, DISTANCE_1, DISTANCE_2, keepSubResults = True)
+model.end()
+assert(Chamfer_4.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_5 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[Translation_1_1/MF:Translated&Box_1_1/Front][Translation_1_1/MF:Translated&Box_1_1/Top]"), model.selection("FACE", "Translation_1_1/MF:Translated&Box_1_1/Right")], True, DISTANCE_1, DISTANCE_2, keepSubResults = True)
+model.testNbResults(Chamfer_5, 1)
+model.testNbSubResults(Chamfer_5, [0])
+model.testNbSubShapes(Chamfer_5, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Chamfer_5, GeomAPI_Shape.FACE, [12])
+model.testNbSubShapes(Chamfer_5, GeomAPI_Shape.EDGE, [50])
+model.testNbSubShapes(Chamfer_5, GeomAPI_Shape.VERTEX, [100])
+model.testResultsVolumes(Chamfer_5, [955.8333333])
+refPoint = GeomAPI_Pnt(54.9539378, 4.833682, 4.95710549)
+midPoint = Chamfer_5.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+
+Chamfer_6 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[Partition_1_1_2/Modified_Face&Box_2_1/Top][Box_2_1/Front]"), model.selection("FACE", "Box_2_1/Right")], True, DISTANCE_1, DISTANCE_2, keepSubResults = True)
+model.testNbResults(Chamfer_6, 1)
+model.testNbSubResults(Chamfer_6, [3])
+model.testNbSubShapes(Chamfer_6, GeomAPI_Shape.SOLID, [3])
+model.testNbSubShapes(Chamfer_6, GeomAPI_Shape.FACE, [23])
+model.testNbSubShapes(Chamfer_6, GeomAPI_Shape.EDGE, [90])
+model.testNbSubShapes(Chamfer_6, GeomAPI_Shape.VERTEX, [180])
+model.testResultsVolumes(Chamfer_6, [1545.0486226])
+refPoint = GeomAPI_Pnt(2.5, 2.5, 5)
+midPoint = Chamfer_6.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+
+Chamfer_7 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[AngularCopy_1_1_1/MF:Rotated&Box_3_1/Back][AngularCopy_1_1_1/MF:Rotated&Box_3_1/Top]"), model.selection("FACE", "AngularCopy_1_1_2/MF:Rotated&Box_3_1/Left")], True, DISTANCE_1, DISTANCE_2, keepSubResults = True)
+model.testNbResults(Chamfer_7, 1)
+model.testNbSubResults(Chamfer_7, [3])
+model.testNbSubShapes(Chamfer_7, GeomAPI_Shape.SOLID, [3])
+model.testNbSubShapes(Chamfer_7, GeomAPI_Shape.FACE, [23])
+model.testNbSubShapes(Chamfer_7, GeomAPI_Shape.EDGE, [94])
+model.testNbSubShapes(Chamfer_7, GeomAPI_Shape.VERTEX, [188])
+model.testResultsVolumes(Chamfer_7, [2955.33333333])
+refPoint = GeomAPI_Pnt(-20.9807621135, 42.5, 5)
+midPoint = Chamfer_7.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+model.end()
+
+model.begin()
+Chamfer_8 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[Chamfer_1_1/MF:Chamfer&Box_1_1/Top][Chamfer_1_1/MF:Chamfer&Box_1_1/Left]"), model.selection("EDGE", "[AngularCopy_1_1_3/MF:Rotated&Box_3_1/Left][AngularCopy_1_1_3/MF:Rotated&Box_3_1/Top]")], True, DISTANCE_1, DISTANCE_2, keepSubResults = True)
+model.end()
+assert(Chamfer_8.feature().error() != "")
+model.undo()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestChamfer_MultiLevelCompound_v95_2.py b/src/FeaturesPlugin/Test/TestChamfer_MultiLevelCompound_v95_2.py
new file mode 100644 (file)
index 0000000..1767d54
--- /dev/null
@@ -0,0 +1,168 @@
+# Copyright (C) 2020  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 salome.shaper import model
+from GeomAPI import *
+from GeomAlgoAPI 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"))
+SketchPoint_1 = Sketch_1.addPoint(44.29784155360136, 17.09942588468031)
+SketchArc_1 = Sketch_1.addArc(44.29784155360136, 17.09942588468031, 47.1668727423061, 12.27945348765633, 45.38299232715926, 22.60269052200972, False)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchArc_1.center())
+SketchLine_1 = Sketch_1.addLine(42.5764228403785, 22.14892077680068, 39.70739165167375, 16.41085839939117)
+SketchLine_2 = Sketch_1.addLine(39.70739165167375, 16.41085839939117, 43.03546783057126, 12.04993099255995)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(28.57555063949931, 12.96802097294547, 15.72229091410204, 12.96802097294547)
+SketchLine_4 = Sketch_1.addLine(15.72229091410204, 12.96802097294547, 15.72229091410204, 21.46035329151154)
+SketchLine_5 = Sketch_1.addLine(15.72229091410204, 21.46035329151154, 28.57555063949931, 21.46035329151154)
+SketchLine_6 = Sketch_1.addLine(28.57555063949931, 21.46035329151154, 28.57555063949931, 12.96802097294547)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_6.result())
+SketchLine_7 = Sketch_1.addLine(-10.67279602198167, 14.78814178154371, -28.34602814440294, 14.78814178154371)
+SketchLine_8 = Sketch_1.addLine(-28.34602814440294, 14.78814178154371, -28.34602814440294, 25.13271321305362)
+SketchLine_9 = Sketch_1.addLine(-28.34602814440294, 25.13271321305362, -10.67279602198167, 25.13271321305362)
+SketchLine_10 = Sketch_1.addLine(-10.67279602198167, 25.13271321305362, -10.67279602198167, 14.78814178154371)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_10.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())
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchLine_9.endPoint(), SketchLine_10.startPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_7.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_8.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_9.result())
+SketchConstraintVertical_4 = Sketch_1.setVertical(SketchLine_10.result())
+SketchLine_11 = Sketch_1.addLine(-17.67323212242127, 25.13271321305362, -21.80463703415611, 14.78814178154371)
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchLine_11.startPoint(), SketchLine_9.result())
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchLine_11.endPoint(), SketchLine_7.result())
+model.do()
+Vertex_1 = model.addVertex(Part_1_doc, [model.selection("VERTEX", "Sketch_1/SketchArc_1")], False)
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchArc_1_2")], False)
+Wire_1 = model.addWire(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2")], False)
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_6r-SketchLine_5r-SketchLine_4r-SketchLine_3r")])
+Shell_1 = model.addShell(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_10r-SketchLine_9r-SketchLine_11f-SketchLine_7r"), model.selection("FACE", "Sketch_1/Face-SketchLine_11r-SketchLine_9r-SketchLine_8r-SketchLine_7r")])
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 50)
+Box_2 = model.addBox(Part_1_doc, 10, 10, 10)
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Box_2_1"), model.selection("SOLID", "Cylinder_1_1")], keepSubResults = True)
+Box_3 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_2 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_3_1")], model.selection("EDGE", "PartSet/OY"), 50)
+AngularCopy_1 = model.addMultiRotation(Part_1_doc, [model.selection("SOLID", "Translation_2_1")], model.selection("EDGE", "PartSet/OZ"), 30, 3)
+Compound_1_objects = [model.selection("VERTEX", "Vertex_1_1"), model.selection("EDGE", "Edge_1_1"), model.selection("WIRE", "Wire_1_1"), model.selection("FACE", "Face_1_1"), model.selection("SHELL", "Shell_1_1"), model.selection("SOLID", "Translation_1_1"), model.selection("COMPSOLID", "Partition_1_1"), model.selection("COMPOUND", "AngularCopy_1_1")]
+Compound_1 = model.addCompound(Part_1_doc, Compound_1_objects)
+model.end()
+
+TOLERANCE = 1.e-7
+DISTANCE_1 = 2
+DISTANCE_2 = 1
+
+NB_SOLIDS = 7
+NB_FACES = 44
+NB_EDGES = 177
+NB_VERTICES = 355
+VOLUME = 5589.0486226
+
+# collect reference data
+REFERENCE = []
+for ind in range(0, Compound_1.result().numberOfSubs()):
+    p = Compound_1.result().subResult(ind).resultSubShapePair()[1].middlePoint()
+    REFERENCE.append(p)
+
+def assertResult(theFeature):
+    model.testNbResults(theFeature, 1)
+    model.testNbSubResults(theFeature, [8])
+    model.testNbSubShapes(theFeature, GeomAPI_Shape.SOLID, [NB_SOLIDS])
+    model.testNbSubShapes(theFeature, GeomAPI_Shape.FACE, [NB_FACES])
+    model.testNbSubShapes(theFeature, GeomAPI_Shape.EDGE, [NB_EDGES])
+    model.testNbSubShapes(theFeature, GeomAPI_Shape.VERTEX, [NB_VERTICES])
+    model.testResultsVolumes(theFeature, [VOLUME])
+
+    for ind in range(0, theFeature.result().numberOfSubs()):
+        ref = REFERENCE[ind]
+        midPoint = theFeature.result().subResult(ind).resultSubShapePair()[0].shape().middlePoint()
+        assert(midPoint.distance(ref) < TOLERANCE), "Sub-result {}; actual ({}, {}, {}) != expected ({}, {}, {})".format(ind, midPoint.x(), midPoint.y(), midPoint.z(), ref.x(), ref.y(), ref.z())
+
+
+model.begin()
+Chamfer_1 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Compound_1_1_2")], True, DISTANCE_1, DISTANCE_2, keepSubResults = True)
+model.end()
+assert(Chamfer_1.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_2 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Compound_1_1_3/Modified_Edge&Sketch_1/SketchLine_1")], True, DISTANCE_1, DISTANCE_2, keepSubResults = True)
+model.end()
+assert(Chamfer_2.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_3 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Compound_1_1_4/Modified_Edge&Sketch_1/SketchLine_3")], True, DISTANCE_1, DISTANCE_2, keepSubResults = True)
+model.end()
+assert(Chamfer_3.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_4 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Compound_1_1_5/Modified_Edge&Sketch_1/SketchLine_10")], True, DISTANCE_1, DISTANCE_2, keepSubResults = True)
+model.end()
+assert(Chamfer_4.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_5 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[Compound_1_1_6/Modified_Face&Box_1_1/Front][Compound_1_1_6/Modified_Face&Box_1_1/Top]"), model.selection("FACE", "Compound_1_1_6/Modified_Face&Box_1_1/Back")], True, DISTANCE_1, DISTANCE_2, keepSubResults = True)
+REFERENCE[5] = GeomAPI_Pnt(55.1200279, 5, 4.954640614)
+NB_FACES += 5
+NB_EDGES += 22
+NB_VERTICES += 44
+VOLUME = 5544.3819559356
+assertResult(Chamfer_5)
+
+Chamfer_6 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[Compound_1_1_7_2/Modified_Face&Box_2_1/Top][Compound_1_1_7_2/Modified_Face&Box_2_1/Front]"), model.selection("FACE", "Compound_1_1_7_2/Modified_Face&Box_2_1/Right")], True, DISTANCE_1, DISTANCE_2, keepSubResults = True)
+NB_FACES += 6
+NB_EDGES += 24
+NB_VERTICES += 48
+VOLUME = 5500.3819559367
+assertResult(Chamfer_6)
+
+Chamfer_7 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[Compound_1_1_8_1/Modified_Face&Box_3_1/Back][Compound_1_1_8_1/Modified_Face&Box_3_1/Top]"), model.selection("FACE", "Compound_1_1_8_2/Modified_Face&Box_3_1/Left")], True, DISTANCE_1, DISTANCE_2, keepSubResults = True)
+NB_FACES += 5
+NB_EDGES += 22
+NB_VERTICES += 44
+VOLUME = 5455.71528927
+assertResult(Chamfer_7)
+
+Chamfer_8 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[Chamfer_1_1_6/MF:Chamfer&Box_1_1/Bottom][Chamfer_1_1_6/MF:Chamfer&Box_1_1/Front]"), model.selection("EDGE", "[Compound_1_1_8_3/Modified_Face&Box_3_1/Left][Compound_1_1_8_3/Modified_Face&Box_3_1/Top]")], True, DISTANCE_1, DISTANCE_2, keepSubResults = True)
+NB_FACES += 2
+NB_EDGES += 12
+NB_VERTICES += 24
+VOLUME = 5435.71528927
+REFERENCE[5] = GeomAPI_Pnt(55.07545839, 5, 5.003526)
+assertResult(Chamfer_8)
+
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestChamfer_MultiLevelCompound_v95_3.py b/src/FeaturesPlugin/Test/TestChamfer_MultiLevelCompound_v95_3.py
new file mode 100644 (file)
index 0000000..f23c428
--- /dev/null
@@ -0,0 +1,150 @@
+# Copyright (C) 2020  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 salome.shaper import model
+from GeomAPI import *
+from GeomAlgoAPI 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"))
+SketchPoint_1 = Sketch_1.addPoint(44.29784155360136, 17.09942588468031)
+SketchArc_1 = Sketch_1.addArc(44.29784155360136, 17.09942588468031, 47.1668727423061, 12.27945348765633, 45.38299232715926, 22.60269052200972, False)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchArc_1.center())
+SketchLine_1 = Sketch_1.addLine(42.5764228403785, 22.14892077680068, 39.70739165167375, 16.41085839939117)
+SketchLine_2 = Sketch_1.addLine(39.70739165167375, 16.41085839939117, 43.03546783057126, 12.04993099255995)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(28.57555063949931, 12.96802097294547, 15.72229091410204, 12.96802097294547)
+SketchLine_4 = Sketch_1.addLine(15.72229091410204, 12.96802097294547, 15.72229091410204, 21.46035329151154)
+SketchLine_5 = Sketch_1.addLine(15.72229091410204, 21.46035329151154, 28.57555063949931, 21.46035329151154)
+SketchLine_6 = Sketch_1.addLine(28.57555063949931, 21.46035329151154, 28.57555063949931, 12.96802097294547)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_6.result())
+SketchLine_7 = Sketch_1.addLine(-10.67279602198167, 14.78814178154371, -28.34602814440294, 14.78814178154371)
+SketchLine_8 = Sketch_1.addLine(-28.34602814440294, 14.78814178154371, -28.34602814440294, 25.13271321305362)
+SketchLine_9 = Sketch_1.addLine(-28.34602814440294, 25.13271321305362, -10.67279602198167, 25.13271321305362)
+SketchLine_10 = Sketch_1.addLine(-10.67279602198167, 25.13271321305362, -10.67279602198167, 14.78814178154371)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_10.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())
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchLine_9.endPoint(), SketchLine_10.startPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_7.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_8.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_9.result())
+SketchConstraintVertical_4 = Sketch_1.setVertical(SketchLine_10.result())
+SketchLine_11 = Sketch_1.addLine(-17.67323212242127, 25.13271321305362, -21.80463703415611, 14.78814178154371)
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchLine_11.startPoint(), SketchLine_9.result())
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchLine_11.endPoint(), SketchLine_7.result())
+model.do()
+Vertex_1 = model.addVertex(Part_1_doc, [model.selection("VERTEX", "Sketch_1/SketchArc_1")], False)
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchArc_1_2")], False)
+Wire_1 = model.addWire(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2")], False)
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_6r-SketchLine_5r-SketchLine_4r-SketchLine_3r")])
+Shell_1 = model.addShell(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_10r-SketchLine_9r-SketchLine_11f-SketchLine_7r"), model.selection("FACE", "Sketch_1/Face-SketchLine_11r-SketchLine_9r-SketchLine_8r-SketchLine_7r")])
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 50)
+Box_2 = model.addBox(Part_1_doc, 10, 10, 10)
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Box_2_1"), model.selection("SOLID", "Cylinder_1_1")], keepSubResults = True)
+Box_3 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_2 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_3_1")], model.selection("EDGE", "PartSet/OY"), 50)
+AngularCopy_1 = model.addMultiRotation(Part_1_doc, [model.selection("SOLID", "Translation_2_1")], model.selection("EDGE", "PartSet/OZ"), 30, 3)
+model.end()
+
+TOLERANCE = 1.e-7
+DISTANCE = 2
+ANGLE = 30
+
+model.begin()
+Chamfer_1 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Edge_1_1")], False, DISTANCE, ANGLE, keepSubResults = True)
+model.end()
+assert(Chamfer_1.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_2 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Wire_1_1/Modified_Edge&Sketch_1/SketchLine_1")], False, DISTANCE, ANGLE, keepSubResults = True)
+model.end()
+assert(Chamfer_2.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_3 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Face_1_1/Modified_Edge&Sketch_1/SketchLine_3")], False, DISTANCE, ANGLE, keepSubResults = True)
+model.end()
+assert(Chamfer_3.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_4 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Shell_1_1/Modified_Edge&Sketch_1/SketchLine_10")], False, DISTANCE, ANGLE, keepSubResults = True)
+model.end()
+assert(Chamfer_4.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_5 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[Translation_1_1/MF:Translated&Box_1_1/Front][Translation_1_1/MF:Translated&Box_1_1/Top]"), model.selection("FACE", "Translation_1_1/MF:Translated&Box_1_1/Right")], False, DISTANCE, ANGLE, keepSubResults = True)
+model.testNbResults(Chamfer_5, 1)
+model.testNbSubResults(Chamfer_5, [0])
+model.testNbSubShapes(Chamfer_5, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Chamfer_5, GeomAPI_Shape.FACE, [12])
+model.testNbSubShapes(Chamfer_5, GeomAPI_Shape.EDGE, [48])
+model.testNbSubShapes(Chamfer_5, GeomAPI_Shape.VERTEX, [96])
+model.testResultsVolumes(Chamfer_5, [949.312264841])
+refPoint = GeomAPI_Pnt(54.9483743992, 4.810295773, 4.951504868)
+midPoint = Chamfer_5.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+
+Chamfer_6 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[Partition_1_1_2/Modified_Face&Box_2_1/Top][Box_2_1/Front]"), model.selection("FACE", "Box_2_1/Right")], False, DISTANCE, ANGLE, keepSubResults = True)
+model.testNbResults(Chamfer_6, 1)
+model.testNbSubResults(Chamfer_6, [3])
+model.testNbSubShapes(Chamfer_6, GeomAPI_Shape.SOLID, [3])
+model.testNbSubShapes(Chamfer_6, GeomAPI_Shape.FACE, [23])
+model.testNbSubShapes(Chamfer_6, GeomAPI_Shape.EDGE, [90])
+model.testNbSubShapes(Chamfer_6, GeomAPI_Shape.VERTEX, [180])
+model.testResultsVolumes(Chamfer_6, [1538.36088744])
+refPoint = GeomAPI_Pnt(2.5, 2.5, 5)
+midPoint = Chamfer_6.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+
+Chamfer_7 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[AngularCopy_1_1_1/MF:Rotated&Box_3_1/Back][AngularCopy_1_1_1/MF:Rotated&Box_3_1/Top]"), model.selection("FACE", "AngularCopy_1_1_2/MF:Rotated&Box_3_1/Left")], False, DISTANCE, ANGLE, keepSubResults = True)
+model.testNbResults(Chamfer_7, 1)
+model.testNbSubResults(Chamfer_7, [3])
+model.testNbSubShapes(Chamfer_7, GeomAPI_Shape.SOLID, [3])
+model.testNbSubShapes(Chamfer_7, GeomAPI_Shape.FACE, [23])
+model.testNbSubShapes(Chamfer_7, GeomAPI_Shape.EDGE, [94])
+model.testNbSubShapes(Chamfer_7, GeomAPI_Shape.VERTEX, [188])
+model.testResultsVolumes(Chamfer_7, [2948.42337595])
+refPoint = GeomAPI_Pnt(-20.9807621135, 42.5, 5)
+midPoint = Chamfer_7.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+model.end()
+
+model.begin()
+Chamfer_8 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[Chamfer_1_1/MF:Chamfer&Box_1_1/Top][Chamfer_1_1/MF:Chamfer&Box_1_1/Left]"), model.selection("EDGE", "[AngularCopy_1_1_3/MF:Rotated&Box_3_1/Left][AngularCopy_1_1_3/MF:Rotated&Box_3_1/Top]")], False, DISTANCE, ANGLE, keepSubResults = True)
+model.end()
+assert(Chamfer_8.feature().error() != "")
+model.undo()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestChamfer_MultiLevelCompound_v95_4.py b/src/FeaturesPlugin/Test/TestChamfer_MultiLevelCompound_v95_4.py
new file mode 100644 (file)
index 0000000..1605570
--- /dev/null
@@ -0,0 +1,170 @@
+# Copyright (C) 2020  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 salome.shaper import model
+from GeomAPI import *
+from GeomAlgoAPI 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"))
+SketchPoint_1 = Sketch_1.addPoint(44.29784155360136, 17.09942588468031)
+SketchArc_1 = Sketch_1.addArc(44.29784155360136, 17.09942588468031, 47.1668727423061, 12.27945348765633, 45.38299232715926, 22.60269052200972, False)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchArc_1.center())
+SketchLine_1 = Sketch_1.addLine(42.5764228403785, 22.14892077680068, 39.70739165167375, 16.41085839939117)
+SketchLine_2 = Sketch_1.addLine(39.70739165167375, 16.41085839939117, 43.03546783057126, 12.04993099255995)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(28.57555063949931, 12.96802097294547, 15.72229091410204, 12.96802097294547)
+SketchLine_4 = Sketch_1.addLine(15.72229091410204, 12.96802097294547, 15.72229091410204, 21.46035329151154)
+SketchLine_5 = Sketch_1.addLine(15.72229091410204, 21.46035329151154, 28.57555063949931, 21.46035329151154)
+SketchLine_6 = Sketch_1.addLine(28.57555063949931, 21.46035329151154, 28.57555063949931, 12.96802097294547)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_6.result())
+SketchLine_7 = Sketch_1.addLine(-10.67279602198167, 14.78814178154371, -28.34602814440294, 14.78814178154371)
+SketchLine_8 = Sketch_1.addLine(-28.34602814440294, 14.78814178154371, -28.34602814440294, 25.13271321305362)
+SketchLine_9 = Sketch_1.addLine(-28.34602814440294, 25.13271321305362, -10.67279602198167, 25.13271321305362)
+SketchLine_10 = Sketch_1.addLine(-10.67279602198167, 25.13271321305362, -10.67279602198167, 14.78814178154371)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_10.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())
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchLine_9.endPoint(), SketchLine_10.startPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_7.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_8.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_9.result())
+SketchConstraintVertical_4 = Sketch_1.setVertical(SketchLine_10.result())
+SketchLine_11 = Sketch_1.addLine(-17.67323212242127, 25.13271321305362, -21.80463703415611, 14.78814178154371)
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchLine_11.startPoint(), SketchLine_9.result())
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchLine_11.endPoint(), SketchLine_7.result())
+model.do()
+Vertex_1 = model.addVertex(Part_1_doc, [model.selection("VERTEX", "Sketch_1/SketchArc_1")], False)
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchArc_1_2")], False)
+Wire_1 = model.addWire(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2")], False)
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_6r-SketchLine_5r-SketchLine_4r-SketchLine_3r")])
+Shell_1 = model.addShell(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_10r-SketchLine_9r-SketchLine_11f-SketchLine_7r"), model.selection("FACE", "Sketch_1/Face-SketchLine_11r-SketchLine_9r-SketchLine_8r-SketchLine_7r")])
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 50)
+Box_2 = model.addBox(Part_1_doc, 10, 10, 10)
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Box_2_1"), model.selection("SOLID", "Cylinder_1_1")], keepSubResults = True)
+Box_3 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_2 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_3_1")], model.selection("EDGE", "PartSet/OY"), 50)
+AngularCopy_1 = model.addMultiRotation(Part_1_doc, [model.selection("SOLID", "Translation_2_1")], model.selection("EDGE", "PartSet/OZ"), 30, 3)
+Compound_1_objects = [model.selection("VERTEX", "Vertex_1_1"), model.selection("EDGE", "Edge_1_1"), model.selection("WIRE", "Wire_1_1"), model.selection("FACE", "Face_1_1"), model.selection("SHELL", "Shell_1_1"), model.selection("SOLID", "Translation_1_1"), model.selection("COMPSOLID", "Partition_1_1"), model.selection("COMPOUND", "AngularCopy_1_1")]
+Compound_1 = model.addCompound(Part_1_doc, Compound_1_objects)
+model.end()
+
+TOLERANCE = 1.e-7
+DISTANCE = 2
+ANGLE = 30
+
+NB_SOLIDS = 7
+NB_FACES = 44
+NB_EDGES = 177
+NB_VERTICES = 355
+VOLUME = 5589.0486226
+
+# collect reference data
+REFERENCE = []
+for ind in range(0, Compound_1.result().numberOfSubs()):
+    p = Compound_1.result().subResult(ind).resultSubShapePair()[1].middlePoint()
+    REFERENCE.append(p)
+
+def assertResult(theFeature):
+    model.testNbResults(theFeature, 1)
+    model.testNbSubResults(theFeature, [8])
+    model.testNbSubShapes(theFeature, GeomAPI_Shape.SOLID, [NB_SOLIDS])
+    model.testNbSubShapes(theFeature, GeomAPI_Shape.FACE, [NB_FACES])
+    model.testNbSubShapes(theFeature, GeomAPI_Shape.EDGE, [NB_EDGES])
+    model.testNbSubShapes(theFeature, GeomAPI_Shape.VERTEX, [NB_VERTICES])
+    model.testResultsVolumes(theFeature, [VOLUME])
+
+    for ind in range(0, theFeature.result().numberOfSubs()):
+        ref = REFERENCE[ind]
+        midPoint = theFeature.result().subResult(ind).resultSubShapePair()[0].shape().middlePoint()
+        assert(midPoint.distance(ref) < TOLERANCE), "Sub-result {}; actual ({}, {}, {}) != expected ({}, {}, {})".format(ind, midPoint.x(), midPoint.y(), midPoint.z(), ref.x(), ref.y(), ref.z())
+
+
+model.begin()
+Chamfer_1 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Compound_1_1_2")], False, DISTANCE, ANGLE, keepSubResults = True)
+model.end()
+assert(Chamfer_1.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_2 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Compound_1_1_3/Modified_Edge&Sketch_1/SketchLine_1")], False, DISTANCE, ANGLE, keepSubResults = True)
+model.end()
+assert(Chamfer_2.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_3 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Compound_1_1_4/Modified_Edge&Sketch_1/SketchLine_3")], False, DISTANCE, ANGLE, keepSubResults = True)
+model.end()
+assert(Chamfer_3.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_4 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "Compound_1_1_5/Modified_Edge&Sketch_1/SketchLine_10")], False, DISTANCE, ANGLE, keepSubResults = True)
+model.end()
+assert(Chamfer_4.feature().error() != "")
+model.undo()
+
+model.begin()
+Chamfer_5 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[Compound_1_1_6/Modified_Face&Box_1_1/Front][Compound_1_1_6/Modified_Face&Box_1_1/Top]"), model.selection("FACE", "Compound_1_1_6/Modified_Face&Box_1_1/Back")], False, DISTANCE, ANGLE, keepSubResults = True)
+REFERENCE[5] = GeomAPI_Pnt(55.13797373, 5, 4.94724189)
+NB_FACES += 5
+NB_EDGES += 22
+NB_VERTICES += 44
+VOLUME = 5537.4719985546
+assertResult(Chamfer_5)
+
+Chamfer_6 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[Compound_1_1_7_2/Modified_Face&Box_2_1/Top][Compound_1_1_7_2/Modified_Face&Box_2_1/Front]"), model.selection("FACE", "Compound_1_1_7_2/Modified_Face&Box_2_1/Right")], False, DISTANCE, ANGLE, keepSubResults = True)
+REFERENCE[6] = GeomAPI_Pnt(2.5, 2.5, 5)
+NB_FACES += 6
+NB_EDGES += 24
+NB_VERTICES += 48
+VOLUME = 5486.784263397
+assertResult(Chamfer_6)
+
+Chamfer_7 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[Compound_1_1_8_1/Modified_Face&Box_3_1/Back][Compound_1_1_8_1/Modified_Face&Box_3_1/Top]"), model.selection("FACE", "Compound_1_1_8_2/Modified_Face&Box_3_1/Left")], False, DISTANCE, ANGLE, keepSubResults = True)
+REFERENCE[7] = GeomAPI_Pnt(-20.9807621135, 42.5, 5)
+NB_FACES += 5
+NB_EDGES += 22
+NB_VERTICES += 44
+VOLUME = 5435.2076393494
+assertResult(Chamfer_7)
+
+Chamfer_8 = model.addChamfer(Part_1_doc, [model.selection("EDGE", "[Chamfer_1_1_6/MF:Chamfer&Box_1_1/Bottom][Chamfer_1_1_6/MF:Chamfer&Box_1_1/Front]"), model.selection("EDGE", "[Compound_1_1_8_3/Modified_Face&Box_3_1/Left][Compound_1_1_8_3/Modified_Face&Box_3_1/Top]")], False, DISTANCE, ANGLE, keepSubResults = True)
+NB_FACES += 2
+NB_EDGES += 12
+NB_VERTICES += 24
+VOLUME = 5412.11362858
+REFERENCE[5] = GeomAPI_Pnt(55.0862659, 5, 5.00347277)
+assertResult(Chamfer_8)
+
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestFillet_MultiLevelCompound_v0_1.py b/src/FeaturesPlugin/Test/TestFillet_MultiLevelCompound_v0_1.py
new file mode 100644 (file)
index 0000000..2c44913
--- /dev/null
@@ -0,0 +1,146 @@
+# Copyright (C) 2020  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 salome.shaper import model
+from GeomAPI import *
+from GeomAlgoAPI 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"))
+SketchPoint_1 = Sketch_1.addPoint(44.29784155360136, 17.09942588468031)
+SketchArc_1 = Sketch_1.addArc(44.29784155360136, 17.09942588468031, 47.1668727423061, 12.27945348765633, 45.38299232715926, 22.60269052200972, False)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchArc_1.center())
+SketchLine_1 = Sketch_1.addLine(42.5764228403785, 22.14892077680068, 39.70739165167375, 16.41085839939117)
+SketchLine_2 = Sketch_1.addLine(39.70739165167375, 16.41085839939117, 43.03546783057126, 12.04993099255995)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(28.57555063949931, 12.96802097294547, 15.72229091410204, 12.96802097294547)
+SketchLine_4 = Sketch_1.addLine(15.72229091410204, 12.96802097294547, 15.72229091410204, 21.46035329151154)
+SketchLine_5 = Sketch_1.addLine(15.72229091410204, 21.46035329151154, 28.57555063949931, 21.46035329151154)
+SketchLine_6 = Sketch_1.addLine(28.57555063949931, 21.46035329151154, 28.57555063949931, 12.96802097294547)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_6.result())
+SketchLine_7 = Sketch_1.addLine(-10.67279602198167, 14.78814178154371, -28.34602814440294, 14.78814178154371)
+SketchLine_8 = Sketch_1.addLine(-28.34602814440294, 14.78814178154371, -28.34602814440294, 25.13271321305362)
+SketchLine_9 = Sketch_1.addLine(-28.34602814440294, 25.13271321305362, -10.67279602198167, 25.13271321305362)
+SketchLine_10 = Sketch_1.addLine(-10.67279602198167, 25.13271321305362, -10.67279602198167, 14.78814178154371)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_10.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())
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchLine_9.endPoint(), SketchLine_10.startPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_7.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_8.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_9.result())
+SketchConstraintVertical_4 = Sketch_1.setVertical(SketchLine_10.result())
+SketchLine_11 = Sketch_1.addLine(-17.67323212242127, 25.13271321305362, -21.80463703415611, 14.78814178154371)
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchLine_11.startPoint(), SketchLine_9.result())
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchLine_11.endPoint(), SketchLine_7.result())
+model.do()
+Vertex_1 = model.addVertex(Part_1_doc, [model.selection("VERTEX", "Sketch_1/SketchArc_1")], False)
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchArc_1_2")], False)
+Wire_1 = model.addWire(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2")], False)
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_6r-SketchLine_5r-SketchLine_4r-SketchLine_3r")])
+Shell_1 = model.addShell(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_10r-SketchLine_9r-SketchLine_11f-SketchLine_7r"), model.selection("FACE", "Sketch_1/Face-SketchLine_11r-SketchLine_9r-SketchLine_8r-SketchLine_7r")])
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 50)
+Box_2 = model.addBox(Part_1_doc, 10, 10, 10)
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Box_2_1"), model.selection("SOLID", "Cylinder_1_1")])
+Box_3 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_2 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_3_1")], model.selection("EDGE", "PartSet/OY"), 50)
+AngularCopy_1 = model.addMultiRotation(Part_1_doc, [model.selection("SOLID", "Translation_2_1")], model.selection("EDGE", "PartSet/OZ"), 30, 3)
+model.end()
+
+TOLERANCE = 1.e-7
+RADIUS = 2
+
+model.begin()
+Fillet_1 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Edge_1_1")], RADIUS)
+model.end()
+assert(Fillet_1.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_2 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Wire_1_1/Modified_Edge&Sketch_1/SketchLine_1")], RADIUS)
+model.end()
+assert(Fillet_2.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_3 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Face_1_1/Modified_Edge&Sketch_1/SketchLine_3")], RADIUS)
+model.end()
+assert(Fillet_3.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_4 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Shell_1_1/Modified_Edge&Sketch_1/SketchLine_10")], RADIUS)
+model.end()
+assert(Fillet_4.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_5 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Translation_1_1/MF:Translated&Box_1_1/Front][Translation_1_1/MF:Translated&Box_1_1/Top]"), model.selection("FACE", "Translation_1_1/MF:Translated&Box_1_1/Right")], RADIUS)
+model.testNbResults(Fillet_5, 1)
+model.testNbSubResults(Fillet_5, [0])
+model.testNbSubShapes(Fillet_5, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Fillet_5, GeomAPI_Shape.FACE, [12])
+model.testNbSubShapes(Fillet_5, GeomAPI_Shape.EDGE, [49])
+model.testNbSubShapes(Fillet_5, GeomAPI_Shape.VERTEX, [98])
+model.testResultsVolumes(Fillet_5, [960.71975512471])
+refPoint = GeomAPI_Pnt(54.962243976, 4.8550769, 4.9622439887)
+midPoint = Fillet_5.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+
+Fillet_6 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Partition_1_1_2/Modified_Face&Box_2_1/Top][Box_2_1/Front]"), model.selection("FACE", "Box_2_1/Right")], RADIUS)
+model.testNbResults(Fillet_6, 1)
+model.testNbSubResults(Fillet_6, [3])
+model.testNbSubShapes(Fillet_6, GeomAPI_Shape.SOLID, [3])
+model.testNbSubShapes(Fillet_6, GeomAPI_Shape.FACE, [23])
+model.testNbSubShapes(Fillet_6, GeomAPI_Shape.EDGE, [91])
+model.testNbSubShapes(Fillet_6, GeomAPI_Shape.VERTEX, [182])
+model.testResultsVolumes(Fillet_6, [1549.768377728])
+refPoint = GeomAPI_Pnt(2.5, 2.5, 5)
+midPoint = Fillet_6.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+
+Fillet_7 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[AngularCopy_1_1_1/MF:Rotated&Box_3_1/Back][AngularCopy_1_1_1/MF:Rotated&Box_3_1/Top]"), model.selection("FACE", "AngularCopy_1_1_2/MF:Rotated&Box_3_1/Left")], RADIUS)
+model.testNbResults(Fillet_7, 2)
+model.testNbSubResults(Fillet_7, [0, 0])
+model.testNbSubShapes(Fillet_7, GeomAPI_Shape.SOLID, [1, 1])
+model.testNbSubShapes(Fillet_7, GeomAPI_Shape.FACE, [7, 10])
+model.testNbSubShapes(Fillet_7, GeomAPI_Shape.EDGE, [30, 40])
+model.testNbSubShapes(Fillet_7, GeomAPI_Shape.VERTEX, [60, 80])
+model.testResultsVolumes(Fillet_7, [991.415926537164, 968.731557])
+model.end()
+
+model.begin()
+Fillet_8 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Fillet_1_1/MF:Fillet&Box_1_1/Top][Fillet_1_1/MF:Fillet&Box_1_1/Left]"), model.selection("EDGE", "[AngularCopy_1_1_3/MF:Rotated&Box_3_1/Left][AngularCopy_1_1_3/MF:Rotated&Box_3_1/Top]")], RADIUS)
+model.end()
+assert(Fillet_8.feature().error() != "")
+model.undo()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestFillet_MultiLevelCompound_v0_2.py b/src/FeaturesPlugin/Test/TestFillet_MultiLevelCompound_v0_2.py
new file mode 100644 (file)
index 0000000..4db0ecb
--- /dev/null
@@ -0,0 +1,155 @@
+# Copyright (C) 2020  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 salome.shaper import model
+from GeomAPI import *
+from GeomAlgoAPI 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"))
+SketchPoint_1 = Sketch_1.addPoint(44.29784155360136, 17.09942588468031)
+SketchArc_1 = Sketch_1.addArc(44.29784155360136, 17.09942588468031, 47.1668727423061, 12.27945348765633, 45.38299232715926, 22.60269052200972, False)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchArc_1.center())
+SketchLine_1 = Sketch_1.addLine(42.5764228403785, 22.14892077680068, 39.70739165167375, 16.41085839939117)
+SketchLine_2 = Sketch_1.addLine(39.70739165167375, 16.41085839939117, 43.03546783057126, 12.04993099255995)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(28.57555063949931, 12.96802097294547, 15.72229091410204, 12.96802097294547)
+SketchLine_4 = Sketch_1.addLine(15.72229091410204, 12.96802097294547, 15.72229091410204, 21.46035329151154)
+SketchLine_5 = Sketch_1.addLine(15.72229091410204, 21.46035329151154, 28.57555063949931, 21.46035329151154)
+SketchLine_6 = Sketch_1.addLine(28.57555063949931, 21.46035329151154, 28.57555063949931, 12.96802097294547)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_6.result())
+SketchLine_7 = Sketch_1.addLine(-10.67279602198167, 14.78814178154371, -28.34602814440294, 14.78814178154371)
+SketchLine_8 = Sketch_1.addLine(-28.34602814440294, 14.78814178154371, -28.34602814440294, 25.13271321305362)
+SketchLine_9 = Sketch_1.addLine(-28.34602814440294, 25.13271321305362, -10.67279602198167, 25.13271321305362)
+SketchLine_10 = Sketch_1.addLine(-10.67279602198167, 25.13271321305362, -10.67279602198167, 14.78814178154371)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_10.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())
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchLine_9.endPoint(), SketchLine_10.startPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_7.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_8.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_9.result())
+SketchConstraintVertical_4 = Sketch_1.setVertical(SketchLine_10.result())
+SketchLine_11 = Sketch_1.addLine(-17.67323212242127, 25.13271321305362, -21.80463703415611, 14.78814178154371)
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchLine_11.startPoint(), SketchLine_9.result())
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchLine_11.endPoint(), SketchLine_7.result())
+model.do()
+Vertex_1 = model.addVertex(Part_1_doc, [model.selection("VERTEX", "Sketch_1/SketchArc_1")], False)
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchArc_1_2")], False)
+Wire_1 = model.addWire(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2")], False)
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_6r-SketchLine_5r-SketchLine_4r-SketchLine_3r")])
+Shell_1 = model.addShell(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_10r-SketchLine_9r-SketchLine_11f-SketchLine_7r"), model.selection("FACE", "Sketch_1/Face-SketchLine_11r-SketchLine_9r-SketchLine_8r-SketchLine_7r")])
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 50)
+Box_2 = model.addBox(Part_1_doc, 10, 10, 10)
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Box_2_1"), model.selection("SOLID", "Cylinder_1_1")])
+Box_3 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_2 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_3_1")], model.selection("EDGE", "PartSet/OY"), 50)
+AngularCopy_1 = model.addMultiRotation(Part_1_doc, [model.selection("SOLID", "Translation_2_1")], model.selection("EDGE", "PartSet/OZ"), 30, 3)
+Compound_1_objects = [model.selection("VERTEX", "Vertex_1_1"), model.selection("EDGE", "Edge_1_1"), model.selection("WIRE", "Wire_1_1"), model.selection("FACE", "Face_1_1"), model.selection("SHELL", "Shell_1_1"), model.selection("SOLID", "Translation_1_1"), model.selection("COMPSOLID", "Partition_1_1"), model.selection("COMPOUND", "AngularCopy_1_1")]
+Compound_1 = model.addCompound(Part_1_doc, Compound_1_objects)
+model.end()
+
+TOLERANCE = 1.e-7
+RADIUS = 2
+
+
+model.begin()
+Fillet_1 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Compound_1_1_2")], RADIUS)
+model.end()
+assert(Fillet_1.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_2 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Compound_1_1_3/Modified_Edge&Sketch_1/SketchLine_1")], RADIUS)
+model.end()
+assert(Fillet_2.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_3 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Compound_1_1_4/Modified_Edge&Sketch_1/SketchLine_3")], RADIUS)
+model.end()
+assert(Fillet_3.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_4 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Compound_1_1_5/Modified_Edge&Sketch_1/SketchLine_10")], RADIUS)
+model.end()
+assert(Fillet_4.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_5 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Compound_1_1_6/Modified_Face&Box_1_1/Front][Compound_1_1_6/Modified_Face&Box_1_1/Top]"), model.selection("FACE", "Compound_1_1_6/Modified_Face&Box_1_1/Back")], RADIUS)
+model.testNbResults(Fillet_5, 1)
+model.testNbSubResults(Fillet_5, [0])
+model.testNbSubShapes(Fillet_5, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Fillet_5, GeomAPI_Shape.FACE, [11])
+model.testNbSubShapes(Fillet_5, GeomAPI_Shape.EDGE, [46])
+model.testNbSubShapes(Fillet_5, GeomAPI_Shape.VERTEX, [92])
+model.testResultsVolumes(Fillet_5, [960.147483562])
+refPoint = GeomAPI_Pnt(55.106983719, 5, 4.95929198)
+midPoint = Fillet_5.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+
+Recover_1 = model.addRecover(Part_1_doc, Fillet_5, [Compound_1.result()], True)
+Fillet_6 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Recover_1_1_7_2/Modified_Face&Box_2_1/Top][Recover_1_1_7_2/Modified_Face&Box_2_1/Front]"), model.selection("FACE", "Recover_1_1_7_2/Modified_Face&Box_2_1/Right")], RADIUS)
+model.testNbResults(Fillet_6, 1)
+model.testNbSubResults(Fillet_6, [3])
+model.testNbSubShapes(Fillet_6, GeomAPI_Shape.SOLID, [3])
+model.testNbSubShapes(Fillet_6, GeomAPI_Shape.FACE, [23])
+model.testNbSubShapes(Fillet_6, GeomAPI_Shape.EDGE, [91])
+model.testNbSubShapes(Fillet_6, GeomAPI_Shape.VERTEX, [182])
+model.testResultsVolumes(Fillet_6, [1549.768377728])
+refPoint = GeomAPI_Pnt(2.5, 2.5, 5)
+midPoint = Fillet_6.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+
+Recover_2 = model.addRecover(Part_1_doc, Fillet_6, [Compound_1.result()], True)
+Fillet_7 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Recover_2_1_8_1/Modified_Face&Box_3_1/Back][Recover_2_1_8_1/Modified_Face&Box_3_1/Top]"), model.selection("FACE", "Recover_2_1_8_2/Modified_Face&Box_3_1/Left")], RADIUS)
+model.testNbResults(Fillet_7, 2)
+model.testNbSubResults(Fillet_7, [0, 0])
+model.testNbSubShapes(Fillet_7, GeomAPI_Shape.SOLID, [1, 1])
+model.testNbSubShapes(Fillet_7, GeomAPI_Shape.FACE, [7, 10])
+model.testNbSubShapes(Fillet_7, GeomAPI_Shape.EDGE, [30, 40])
+model.testNbSubShapes(Fillet_7, GeomAPI_Shape.VERTEX, [60, 80])
+model.testResultsVolumes(Fillet_7, [991.415926537164, 968.731557])
+
+Recover_3 = model.addRecover(Part_1_doc, Fillet_7, [Compound_1.result()], True)
+Fillet_8 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Recover_3_1_6/Modified_Edge&Fillet_1_1/FilletSelected_1"), model.selection("EDGE", "[Recover_3_1_8_2/Modified_Face&Box_3_1/Left][Recover_3_1_8_2/Modified_Face&Box_3_1/Top]")], RADIUS)
+model.testNbResults(Fillet_8, 2)
+model.testNbSubResults(Fillet_8, [0, 0])
+model.testNbSubShapes(Fillet_8, GeomAPI_Shape.SOLID, [1, 1])
+model.testNbSubShapes(Fillet_8, GeomAPI_Shape.FACE, [7, 7])
+model.testNbSubShapes(Fillet_8, GeomAPI_Shape.EDGE, [30, 30])
+model.testNbSubShapes(Fillet_8, GeomAPI_Shape.VERTEX, [60, 60])
+model.testResultsVolumes(Fillet_8, [991.415926537164, 991.415926537164])
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestFillet_MultiLevelCompound_v0_3.py b/src/FeaturesPlugin/Test/TestFillet_MultiLevelCompound_v0_3.py
new file mode 100644 (file)
index 0000000..b156345
--- /dev/null
@@ -0,0 +1,147 @@
+# Copyright (C) 2020  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 salome.shaper import model
+from GeomAPI import *
+from GeomAlgoAPI 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"))
+SketchPoint_1 = Sketch_1.addPoint(44.29784155360136, 17.09942588468031)
+SketchArc_1 = Sketch_1.addArc(44.29784155360136, 17.09942588468031, 47.1668727423061, 12.27945348765633, 45.38299232715926, 22.60269052200972, False)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchArc_1.center())
+SketchLine_1 = Sketch_1.addLine(42.5764228403785, 22.14892077680068, 39.70739165167375, 16.41085839939117)
+SketchLine_2 = Sketch_1.addLine(39.70739165167375, 16.41085839939117, 43.03546783057126, 12.04993099255995)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(28.57555063949931, 12.96802097294547, 15.72229091410204, 12.96802097294547)
+SketchLine_4 = Sketch_1.addLine(15.72229091410204, 12.96802097294547, 15.72229091410204, 21.46035329151154)
+SketchLine_5 = Sketch_1.addLine(15.72229091410204, 21.46035329151154, 28.57555063949931, 21.46035329151154)
+SketchLine_6 = Sketch_1.addLine(28.57555063949931, 21.46035329151154, 28.57555063949931, 12.96802097294547)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_6.result())
+SketchLine_7 = Sketch_1.addLine(-10.67279602198167, 14.78814178154371, -28.34602814440294, 14.78814178154371)
+SketchLine_8 = Sketch_1.addLine(-28.34602814440294, 14.78814178154371, -28.34602814440294, 25.13271321305362)
+SketchLine_9 = Sketch_1.addLine(-28.34602814440294, 25.13271321305362, -10.67279602198167, 25.13271321305362)
+SketchLine_10 = Sketch_1.addLine(-10.67279602198167, 25.13271321305362, -10.67279602198167, 14.78814178154371)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_10.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())
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchLine_9.endPoint(), SketchLine_10.startPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_7.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_8.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_9.result())
+SketchConstraintVertical_4 = Sketch_1.setVertical(SketchLine_10.result())
+SketchLine_11 = Sketch_1.addLine(-17.67323212242127, 25.13271321305362, -21.80463703415611, 14.78814178154371)
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchLine_11.startPoint(), SketchLine_9.result())
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchLine_11.endPoint(), SketchLine_7.result())
+model.do()
+Vertex_1 = model.addVertex(Part_1_doc, [model.selection("VERTEX", "Sketch_1/SketchArc_1")], False)
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchArc_1_2")], False)
+Wire_1 = model.addWire(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2")], False)
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_6r-SketchLine_5r-SketchLine_4r-SketchLine_3r")])
+Shell_1 = model.addShell(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_10r-SketchLine_9r-SketchLine_11f-SketchLine_7r"), model.selection("FACE", "Sketch_1/Face-SketchLine_11r-SketchLine_9r-SketchLine_8r-SketchLine_7r")])
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 50)
+Box_2 = model.addBox(Part_1_doc, 10, 10, 10)
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Box_2_1"), model.selection("SOLID", "Cylinder_1_1")])
+Box_3 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_2 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_3_1")], model.selection("EDGE", "PartSet/OY"), 50)
+AngularCopy_1 = model.addMultiRotation(Part_1_doc, [model.selection("SOLID", "Translation_2_1")], model.selection("EDGE", "PartSet/OZ"), 30, 3)
+model.end()
+
+TOLERANCE = 1.e-7
+RADIUS_1 = 2
+RADIUS_2 = 1
+
+model.begin()
+Fillet_1 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Edge_1_1")], RADIUS_1, RADIUS_2)
+model.end()
+assert(Fillet_1.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_2 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Wire_1_1/Modified_Edge&Sketch_1/SketchLine_1")], RADIUS_1, RADIUS_2)
+model.end()
+assert(Fillet_2.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_3 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Face_1_1/Modified_Edge&Sketch_1/SketchLine_3")], RADIUS_1, RADIUS_2)
+model.end()
+assert(Fillet_3.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_4 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Shell_1_1/Modified_Edge&Sketch_1/SketchLine_10")], RADIUS_1, RADIUS_2)
+model.end()
+assert(Fillet_4.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_5 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Translation_1_1/MF:Translated&Box_1_1/Front][Translation_1_1/MF:Translated&Box_1_1/Top]"), model.selection("FACE", "Translation_1_1/MF:Translated&Box_1_1/Right")], RADIUS_1, RADIUS_2)
+model.testNbResults(Fillet_5, 1)
+model.testNbSubResults(Fillet_5, [0])
+model.testNbSubShapes(Fillet_5, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Fillet_5, GeomAPI_Shape.FACE, [12])
+model.testNbSubShapes(Fillet_5, GeomAPI_Shape.EDGE, [53])
+model.testNbSubShapes(Fillet_5, GeomAPI_Shape.VERTEX, [106])
+model.testResultsVolumes(Fillet_5, [976.519471836586])
+refPoint = GeomAPI_Pnt(54.98720346, 4.918055722, 4.987203302)
+midPoint = Fillet_5.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+
+Fillet_6 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Partition_1_1_2/Modified_Face&Box_2_1/Top][Box_2_1/Front]"), model.selection("FACE", "Box_2_1/Right")], RADIUS_1, RADIUS_2)
+model.testNbResults(Fillet_6, 1)
+model.testNbSubResults(Fillet_6, [3])
+model.testNbSubShapes(Fillet_6, GeomAPI_Shape.SOLID, [3])
+model.testNbSubShapes(Fillet_6, GeomAPI_Shape.FACE, [23])
+model.testNbSubShapes(Fillet_6, GeomAPI_Shape.EDGE, [95])
+model.testNbSubShapes(Fillet_6, GeomAPI_Shape.VERTEX, [190])
+model.testResultsVolumes(Fillet_6, [1565.568094166])
+refPoint = GeomAPI_Pnt(2.7448, 2.7448, 5)
+midPoint = Fillet_6.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+
+Fillet_7 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[AngularCopy_1_1_1/MF:Rotated&Box_3_1/Back][AngularCopy_1_1_1/MF:Rotated&Box_3_1/Top]"), model.selection("FACE", "AngularCopy_1_1_2/MF:Rotated&Box_3_1/Left")], RADIUS_1, RADIUS_2)
+model.testNbResults(Fillet_7, 2)
+model.testNbSubResults(Fillet_7, [0, 0])
+model.testNbSubShapes(Fillet_7, GeomAPI_Shape.SOLID, [1, 1])
+model.testNbSubShapes(Fillet_7, GeomAPI_Shape.FACE, [7, 10])
+model.testNbSubShapes(Fillet_7, GeomAPI_Shape.EDGE, [30, 44])
+model.testNbSubShapes(Fillet_7, GeomAPI_Shape.VERTEX, [60, 88])
+model.testResultsVolumes(Fillet_7, [994.948408157, 981.120160322])
+model.end()
+
+model.begin()
+Fillet_8 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Fillet_1_1/MF:Fillet&Box_1_1/Top][Fillet_1_1/MF:Fillet&Box_1_1/Left]"), model.selection("EDGE", "[AngularCopy_1_1_3/MF:Rotated&Box_3_1/Left][AngularCopy_1_1_3/MF:Rotated&Box_3_1/Top]")], RADIUS_1, RADIUS_2)
+model.end()
+assert(Fillet_8.feature().error() != "")
+model.undo()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestFillet_MultiLevelCompound_v0_4.py b/src/FeaturesPlugin/Test/TestFillet_MultiLevelCompound_v0_4.py
new file mode 100644 (file)
index 0000000..b1b177b
--- /dev/null
@@ -0,0 +1,155 @@
+# Copyright (C) 2020  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 salome.shaper import model
+from GeomAPI import *
+from GeomAlgoAPI 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"))
+SketchPoint_1 = Sketch_1.addPoint(44.29784155360136, 17.09942588468031)
+SketchArc_1 = Sketch_1.addArc(44.29784155360136, 17.09942588468031, 47.1668727423061, 12.27945348765633, 45.38299232715926, 22.60269052200972, False)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchArc_1.center())
+SketchLine_1 = Sketch_1.addLine(42.5764228403785, 22.14892077680068, 39.70739165167375, 16.41085839939117)
+SketchLine_2 = Sketch_1.addLine(39.70739165167375, 16.41085839939117, 43.03546783057126, 12.04993099255995)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(28.57555063949931, 12.96802097294547, 15.72229091410204, 12.96802097294547)
+SketchLine_4 = Sketch_1.addLine(15.72229091410204, 12.96802097294547, 15.72229091410204, 21.46035329151154)
+SketchLine_5 = Sketch_1.addLine(15.72229091410204, 21.46035329151154, 28.57555063949931, 21.46035329151154)
+SketchLine_6 = Sketch_1.addLine(28.57555063949931, 21.46035329151154, 28.57555063949931, 12.96802097294547)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_6.result())
+SketchLine_7 = Sketch_1.addLine(-10.67279602198167, 14.78814178154371, -28.34602814440294, 14.78814178154371)
+SketchLine_8 = Sketch_1.addLine(-28.34602814440294, 14.78814178154371, -28.34602814440294, 25.13271321305362)
+SketchLine_9 = Sketch_1.addLine(-28.34602814440294, 25.13271321305362, -10.67279602198167, 25.13271321305362)
+SketchLine_10 = Sketch_1.addLine(-10.67279602198167, 25.13271321305362, -10.67279602198167, 14.78814178154371)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_10.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())
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchLine_9.endPoint(), SketchLine_10.startPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_7.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_8.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_9.result())
+SketchConstraintVertical_4 = Sketch_1.setVertical(SketchLine_10.result())
+SketchLine_11 = Sketch_1.addLine(-17.67323212242127, 25.13271321305362, -21.80463703415611, 14.78814178154371)
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchLine_11.startPoint(), SketchLine_9.result())
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchLine_11.endPoint(), SketchLine_7.result())
+model.do()
+Vertex_1 = model.addVertex(Part_1_doc, [model.selection("VERTEX", "Sketch_1/SketchArc_1")], False)
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchArc_1_2")], False)
+Wire_1 = model.addWire(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2")], False)
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_6r-SketchLine_5r-SketchLine_4r-SketchLine_3r")])
+Shell_1 = model.addShell(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_10r-SketchLine_9r-SketchLine_11f-SketchLine_7r"), model.selection("FACE", "Sketch_1/Face-SketchLine_11r-SketchLine_9r-SketchLine_8r-SketchLine_7r")])
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 50)
+Box_2 = model.addBox(Part_1_doc, 10, 10, 10)
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Box_2_1"), model.selection("SOLID", "Cylinder_1_1")])
+Box_3 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_2 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_3_1")], model.selection("EDGE", "PartSet/OY"), 50)
+AngularCopy_1 = model.addMultiRotation(Part_1_doc, [model.selection("SOLID", "Translation_2_1")], model.selection("EDGE", "PartSet/OZ"), 30, 3)
+Compound_1_objects = [model.selection("VERTEX", "Vertex_1_1"), model.selection("EDGE", "Edge_1_1"), model.selection("WIRE", "Wire_1_1"), model.selection("FACE", "Face_1_1"), model.selection("SHELL", "Shell_1_1"), model.selection("SOLID", "Translation_1_1"), model.selection("COMPSOLID", "Partition_1_1"), model.selection("COMPOUND", "AngularCopy_1_1")]
+Compound_1 = model.addCompound(Part_1_doc, Compound_1_objects)
+model.end()
+
+TOLERANCE = 1.e-7
+RADIUS_1 = 2
+RADIUS_2 = 1
+
+model.begin()
+Fillet_1 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Compound_1_1_2")], RADIUS_1, RADIUS_2)
+model.end()
+assert(Fillet_1.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_2 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Compound_1_1_3/Modified_Edge&Sketch_1/SketchLine_1")], RADIUS_1, RADIUS_2)
+model.end()
+assert(Fillet_2.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_3 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Compound_1_1_4/Modified_Edge&Sketch_1/SketchLine_3")], RADIUS_1, RADIUS_2)
+model.end()
+assert(Fillet_3.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_4 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Compound_1_1_5/Modified_Edge&Sketch_1/SketchLine_10")], RADIUS_1, RADIUS_2)
+model.end()
+assert(Fillet_4.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_5 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Compound_1_1_6/Modified_Face&Box_1_1/Front][Compound_1_1_6/Modified_Face&Box_1_1/Top]"), model.selection("FACE", "Compound_1_1_6/Modified_Face&Box_1_1/Back")], RADIUS_1, RADIUS_2)
+model.testNbResults(Fillet_5, 1)
+model.testNbSubResults(Fillet_5, [0])
+model.testNbSubShapes(Fillet_5, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Fillet_5, GeomAPI_Shape.FACE, [11])
+model.testNbSubShapes(Fillet_5, GeomAPI_Shape.EDGE, [50])
+model.testNbSubShapes(Fillet_5, GeomAPI_Shape.VERTEX, [100])
+model.testResultsVolumes(Fillet_5, [976.068565925934])
+refPoint = GeomAPI_Pnt(55.0654360945, 5.015632459, 4.985518188)
+midPoint = Fillet_5.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+
+Recover_1 = model.addRecover(Part_1_doc, Fillet_5, [Compound_1.result()], True)
+Fillet_6 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Recover_1_1_7_2/Modified_Face&Box_2_1/Top][Recover_1_1_7_2/Modified_Face&Box_2_1/Front]"), model.selection("FACE", "Recover_1_1_7_2/Modified_Face&Box_2_1/Right")], RADIUS_1, RADIUS_2)
+model.testNbResults(Fillet_6, 1)
+model.testNbSubResults(Fillet_6, [3])
+model.testNbSubShapes(Fillet_6, GeomAPI_Shape.SOLID, [3])
+model.testNbSubShapes(Fillet_6, GeomAPI_Shape.FACE, [23])
+model.testNbSubShapes(Fillet_6, GeomAPI_Shape.EDGE, [95])
+model.testNbSubShapes(Fillet_6, GeomAPI_Shape.VERTEX, [190])
+model.testResultsVolumes(Fillet_6, [1565.568094166])
+refPoint = GeomAPI_Pnt(2.7448, 2.7448, 5)
+midPoint = Fillet_6.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+
+Recover_2 = model.addRecover(Part_1_doc, Fillet_6, [Compound_1.result()], True)
+Fillet_7 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Recover_2_1_8_1/Modified_Face&Box_3_1/Back][Recover_2_1_8_1/Modified_Face&Box_3_1/Top]"), model.selection("FACE", "Recover_2_1_8_2/Modified_Face&Box_3_1/Left")], RADIUS_1, RADIUS_2)
+model.testNbResults(Fillet_7, 2)
+model.testNbSubResults(Fillet_7, [0, 0])
+model.testNbSubShapes(Fillet_7, GeomAPI_Shape.SOLID, [1, 1])
+model.testNbSubShapes(Fillet_7, GeomAPI_Shape.FACE, [7, 10])
+model.testNbSubShapes(Fillet_7, GeomAPI_Shape.EDGE, [30, 44])
+model.testNbSubShapes(Fillet_7, GeomAPI_Shape.VERTEX, [60, 88])
+model.testResultsVolumes(Fillet_7, [994.948408157, 981.12016032])
+
+Recover_3 = model.addRecover(Part_1_doc, Fillet_7, [Compound_1.result()], True)
+Fillet_8 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Recover_3_1_6/Modified_Edge&Fillet_1_1/FilletSelected_1"), model.selection("EDGE", "[Recover_3_1_8_2/Modified_Face&Box_3_1/Left][Recover_3_1_8_2/Modified_Face&Box_3_1/Top]")], RADIUS_1, RADIUS_2)
+model.testNbResults(Fillet_8, 2)
+model.testNbSubResults(Fillet_8, [0, 0])
+model.testNbSubShapes(Fillet_8, GeomAPI_Shape.SOLID, [1, 1])
+model.testNbSubShapes(Fillet_8, GeomAPI_Shape.FACE, [7, 7])
+model.testNbSubShapes(Fillet_8, GeomAPI_Shape.EDGE, [30, 30])
+model.testNbSubShapes(Fillet_8, GeomAPI_Shape.VERTEX, [60, 60])
+model.testResultsVolumes(Fillet_8, [994.948408157, 994.948408157])
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestFillet_MultiLevelCompound_v95_1.py b/src/FeaturesPlugin/Test/TestFillet_MultiLevelCompound_v95_1.py
new file mode 100644 (file)
index 0000000..dc852ed
--- /dev/null
@@ -0,0 +1,149 @@
+# Copyright (C) 2020  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 salome.shaper import model
+from GeomAPI import *
+from GeomAlgoAPI 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"))
+SketchPoint_1 = Sketch_1.addPoint(44.29784155360136, 17.09942588468031)
+SketchArc_1 = Sketch_1.addArc(44.29784155360136, 17.09942588468031, 47.1668727423061, 12.27945348765633, 45.38299232715926, 22.60269052200972, False)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchArc_1.center())
+SketchLine_1 = Sketch_1.addLine(42.5764228403785, 22.14892077680068, 39.70739165167375, 16.41085839939117)
+SketchLine_2 = Sketch_1.addLine(39.70739165167375, 16.41085839939117, 43.03546783057126, 12.04993099255995)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(28.57555063949931, 12.96802097294547, 15.72229091410204, 12.96802097294547)
+SketchLine_4 = Sketch_1.addLine(15.72229091410204, 12.96802097294547, 15.72229091410204, 21.46035329151154)
+SketchLine_5 = Sketch_1.addLine(15.72229091410204, 21.46035329151154, 28.57555063949931, 21.46035329151154)
+SketchLine_6 = Sketch_1.addLine(28.57555063949931, 21.46035329151154, 28.57555063949931, 12.96802097294547)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_6.result())
+SketchLine_7 = Sketch_1.addLine(-10.67279602198167, 14.78814178154371, -28.34602814440294, 14.78814178154371)
+SketchLine_8 = Sketch_1.addLine(-28.34602814440294, 14.78814178154371, -28.34602814440294, 25.13271321305362)
+SketchLine_9 = Sketch_1.addLine(-28.34602814440294, 25.13271321305362, -10.67279602198167, 25.13271321305362)
+SketchLine_10 = Sketch_1.addLine(-10.67279602198167, 25.13271321305362, -10.67279602198167, 14.78814178154371)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_10.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())
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchLine_9.endPoint(), SketchLine_10.startPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_7.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_8.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_9.result())
+SketchConstraintVertical_4 = Sketch_1.setVertical(SketchLine_10.result())
+SketchLine_11 = Sketch_1.addLine(-17.67323212242127, 25.13271321305362, -21.80463703415611, 14.78814178154371)
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchLine_11.startPoint(), SketchLine_9.result())
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchLine_11.endPoint(), SketchLine_7.result())
+model.do()
+Vertex_1 = model.addVertex(Part_1_doc, [model.selection("VERTEX", "Sketch_1/SketchArc_1")], False)
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchArc_1_2")], False)
+Wire_1 = model.addWire(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2")], False)
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_6r-SketchLine_5r-SketchLine_4r-SketchLine_3r")])
+Shell_1 = model.addShell(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_10r-SketchLine_9r-SketchLine_11f-SketchLine_7r"), model.selection("FACE", "Sketch_1/Face-SketchLine_11r-SketchLine_9r-SketchLine_8r-SketchLine_7r")])
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 50)
+Box_2 = model.addBox(Part_1_doc, 10, 10, 10)
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Box_2_1"), model.selection("SOLID", "Cylinder_1_1")], keepSubResults = True)
+Box_3 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_2 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_3_1")], model.selection("EDGE", "PartSet/OY"), 50)
+AngularCopy_1 = model.addMultiRotation(Part_1_doc, [model.selection("SOLID", "Translation_2_1")], model.selection("EDGE", "PartSet/OZ"), 30, 3)
+model.end()
+
+TOLERANCE = 1.e-7
+RADIUS = 2
+
+model.begin()
+Fillet_1 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Edge_1_1")], RADIUS, keepSubResults = True)
+model.end()
+assert(Fillet_1.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_2 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Wire_1_1/Modified_Edge&Sketch_1/SketchLine_1")], RADIUS, keepSubResults = True)
+model.end()
+assert(Fillet_2.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_3 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Face_1_1/Modified_Edge&Sketch_1/SketchLine_3")], RADIUS, keepSubResults = True)
+model.end()
+assert(Fillet_3.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_4 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Shell_1_1/Modified_Edge&Sketch_1/SketchLine_10")], RADIUS, keepSubResults = True)
+model.end()
+assert(Fillet_4.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_5 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Translation_1_1/MF:Translated&Box_1_1/Front][Translation_1_1/MF:Translated&Box_1_1/Top]"), model.selection("FACE", "Translation_1_1/MF:Translated&Box_1_1/Right")], RADIUS, keepSubResults = True)
+model.testNbResults(Fillet_5, 1)
+model.testNbSubResults(Fillet_5, [0])
+model.testNbSubShapes(Fillet_5, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Fillet_5, GeomAPI_Shape.FACE, [12])
+model.testNbSubShapes(Fillet_5, GeomAPI_Shape.EDGE, [49])
+model.testNbSubShapes(Fillet_5, GeomAPI_Shape.VERTEX, [98])
+model.testResultsVolumes(Fillet_5, [960.71975512471])
+refPoint = GeomAPI_Pnt(54.962243976, 4.8550769, 4.9622439887)
+midPoint = Fillet_5.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+
+Fillet_6 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Partition_1_1_2/Modified_Face&Box_2_1/Top][Box_2_1/Front]"), model.selection("FACE", "Box_2_1/Right")], RADIUS, keepSubResults = True)
+model.testNbResults(Fillet_6, 1)
+model.testNbSubResults(Fillet_6, [3])
+model.testNbSubShapes(Fillet_6, GeomAPI_Shape.SOLID, [3])
+model.testNbSubShapes(Fillet_6, GeomAPI_Shape.FACE, [23])
+model.testNbSubShapes(Fillet_6, GeomAPI_Shape.EDGE, [91])
+model.testNbSubShapes(Fillet_6, GeomAPI_Shape.VERTEX, [182])
+model.testResultsVolumes(Fillet_6, [1549.768377728])
+refPoint = GeomAPI_Pnt(2.5, 2.5, 5)
+midPoint = Fillet_6.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+
+Fillet_7 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[AngularCopy_1_1_1/MF:Rotated&Box_3_1/Back][AngularCopy_1_1_1/MF:Rotated&Box_3_1/Top]"), model.selection("FACE", "AngularCopy_1_1_2/MF:Rotated&Box_3_1/Left")], RADIUS, keepSubResults = True)
+model.testNbResults(Fillet_7, 1)
+model.testNbSubResults(Fillet_7, [3])
+model.testNbSubShapes(Fillet_7, GeomAPI_Shape.SOLID, [3])
+model.testNbSubShapes(Fillet_7, GeomAPI_Shape.FACE, [23])
+model.testNbSubShapes(Fillet_7, GeomAPI_Shape.EDGE, [94])
+model.testNbSubShapes(Fillet_7, GeomAPI_Shape.VERTEX, [188])
+model.testResultsVolumes(Fillet_7, [2960.14748356])
+refPoint = GeomAPI_Pnt(-20.9807621135, 42.5, 5)
+midPoint = Fillet_7.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+model.end()
+
+model.begin()
+Fillet_8 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Fillet_1_1/MF:Fillet&Box_1_1/Top][Fillet_1_1/MF:Fillet&Box_1_1/Left]"), model.selection("EDGE", "[AngularCopy_1_1_3/MF:Rotated&Box_3_1/Left][AngularCopy_1_1_3/MF:Rotated&Box_3_1/Top]")], RADIUS, keepSubResults = True)
+model.end()
+assert(Fillet_8.feature().error() != "")
+model.undo()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestFillet_MultiLevelCompound_v95_2.py b/src/FeaturesPlugin/Test/TestFillet_MultiLevelCompound_v95_2.py
new file mode 100644 (file)
index 0000000..2ed5303
--- /dev/null
@@ -0,0 +1,167 @@
+# Copyright (C) 2020  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 salome.shaper import model
+from GeomAPI import *
+from GeomAlgoAPI 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"))
+SketchPoint_1 = Sketch_1.addPoint(44.29784155360136, 17.09942588468031)
+SketchArc_1 = Sketch_1.addArc(44.29784155360136, 17.09942588468031, 47.1668727423061, 12.27945348765633, 45.38299232715926, 22.60269052200972, False)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchArc_1.center())
+SketchLine_1 = Sketch_1.addLine(42.5764228403785, 22.14892077680068, 39.70739165167375, 16.41085839939117)
+SketchLine_2 = Sketch_1.addLine(39.70739165167375, 16.41085839939117, 43.03546783057126, 12.04993099255995)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(28.57555063949931, 12.96802097294547, 15.72229091410204, 12.96802097294547)
+SketchLine_4 = Sketch_1.addLine(15.72229091410204, 12.96802097294547, 15.72229091410204, 21.46035329151154)
+SketchLine_5 = Sketch_1.addLine(15.72229091410204, 21.46035329151154, 28.57555063949931, 21.46035329151154)
+SketchLine_6 = Sketch_1.addLine(28.57555063949931, 21.46035329151154, 28.57555063949931, 12.96802097294547)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_6.result())
+SketchLine_7 = Sketch_1.addLine(-10.67279602198167, 14.78814178154371, -28.34602814440294, 14.78814178154371)
+SketchLine_8 = Sketch_1.addLine(-28.34602814440294, 14.78814178154371, -28.34602814440294, 25.13271321305362)
+SketchLine_9 = Sketch_1.addLine(-28.34602814440294, 25.13271321305362, -10.67279602198167, 25.13271321305362)
+SketchLine_10 = Sketch_1.addLine(-10.67279602198167, 25.13271321305362, -10.67279602198167, 14.78814178154371)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_10.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())
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchLine_9.endPoint(), SketchLine_10.startPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_7.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_8.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_9.result())
+SketchConstraintVertical_4 = Sketch_1.setVertical(SketchLine_10.result())
+SketchLine_11 = Sketch_1.addLine(-17.67323212242127, 25.13271321305362, -21.80463703415611, 14.78814178154371)
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchLine_11.startPoint(), SketchLine_9.result())
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchLine_11.endPoint(), SketchLine_7.result())
+model.do()
+Vertex_1 = model.addVertex(Part_1_doc, [model.selection("VERTEX", "Sketch_1/SketchArc_1")], False)
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchArc_1_2")], False)
+Wire_1 = model.addWire(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2")], False)
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_6r-SketchLine_5r-SketchLine_4r-SketchLine_3r")])
+Shell_1 = model.addShell(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_10r-SketchLine_9r-SketchLine_11f-SketchLine_7r"), model.selection("FACE", "Sketch_1/Face-SketchLine_11r-SketchLine_9r-SketchLine_8r-SketchLine_7r")])
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 50)
+Box_2 = model.addBox(Part_1_doc, 10, 10, 10)
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Box_2_1"), model.selection("SOLID", "Cylinder_1_1")], keepSubResults = True)
+Box_3 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_2 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_3_1")], model.selection("EDGE", "PartSet/OY"), 50)
+AngularCopy_1 = model.addMultiRotation(Part_1_doc, [model.selection("SOLID", "Translation_2_1")], model.selection("EDGE", "PartSet/OZ"), 30, 3)
+Compound_1_objects = [model.selection("VERTEX", "Vertex_1_1"), model.selection("EDGE", "Edge_1_1"), model.selection("WIRE", "Wire_1_1"), model.selection("FACE", "Face_1_1"), model.selection("SHELL", "Shell_1_1"), model.selection("SOLID", "Translation_1_1"), model.selection("COMPSOLID", "Partition_1_1"), model.selection("COMPOUND", "AngularCopy_1_1")]
+Compound_1 = model.addCompound(Part_1_doc, Compound_1_objects)
+model.end()
+
+TOLERANCE = 1.e-7
+RADIUS = 2
+
+NB_SOLIDS = 7
+NB_FACES = 44
+NB_EDGES = 177
+NB_VERTICES = 355
+VOLUME = 5589.0486226
+
+# collect reference data
+REFERENCE = []
+for ind in range(0, Compound_1.result().numberOfSubs()):
+    p = Compound_1.result().subResult(ind).resultSubShapePair()[1].middlePoint()
+    REFERENCE.append(p)
+
+def assertResult(theFeature):
+    model.testNbResults(theFeature, 1)
+    model.testNbSubResults(theFeature, [8])
+    model.testNbSubShapes(theFeature, GeomAPI_Shape.SOLID, [NB_SOLIDS])
+    model.testNbSubShapes(theFeature, GeomAPI_Shape.FACE, [NB_FACES])
+    model.testNbSubShapes(theFeature, GeomAPI_Shape.EDGE, [NB_EDGES])
+    model.testNbSubShapes(theFeature, GeomAPI_Shape.VERTEX, [NB_VERTICES])
+    model.testResultsVolumes(theFeature, [VOLUME])
+
+    for ind in range(0, theFeature.result().numberOfSubs()):
+        ref = REFERENCE[ind]
+        midPoint = theFeature.result().subResult(ind).resultSubShapePair()[0].shape().middlePoint()
+        assert(midPoint.distance(ref) < TOLERANCE), "Sub-result {}; actual ({}, {}, {}) != expected ({}, {}, {})".format(ind, midPoint.x(), midPoint.y(), midPoint.z(), ref.x(), ref.y(), ref.z())
+
+
+model.begin()
+Fillet_1 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Compound_1_1_2")], RADIUS, keepSubResults = True)
+model.end()
+assert(Fillet_1.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_2 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Compound_1_1_3/Modified_Edge&Sketch_1/SketchLine_1")], RADIUS, keepSubResults = True)
+model.end()
+assert(Fillet_2.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_3 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Compound_1_1_4/Modified_Edge&Sketch_1/SketchLine_3")], RADIUS, keepSubResults = True)
+model.end()
+assert(Fillet_3.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_4 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Compound_1_1_5/Modified_Edge&Sketch_1/SketchLine_10")], RADIUS, keepSubResults = True)
+model.end()
+assert(Fillet_4.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_5 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Compound_1_1_6/Modified_Face&Box_1_1/Front][Compound_1_1_6/Modified_Face&Box_1_1/Top]"), model.selection("FACE", "Compound_1_1_6/Modified_Face&Box_1_1/Back")], RADIUS, keepSubResults = True)
+REFERENCE[5] = GeomAPI_Pnt(55.1069837186, 5, 4.959291982496)
+NB_FACES += 5
+NB_EDGES += 22
+NB_VERTICES += 44
+VOLUME = 5549.19610616474
+assertResult(Fillet_5)
+
+Fillet_6 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Compound_1_1_7_2/Modified_Face&Box_2_1/Top][Compound_1_1_7_2/Modified_Face&Box_2_1/Front]"), model.selection("FACE", "Compound_1_1_7_2/Modified_Face&Box_2_1/Right")], RADIUS, keepSubResults = True)
+NB_FACES += 6
+NB_EDGES += 25
+NB_VERTICES += 50
+VOLUME = 5509.91586129
+assertResult(Fillet_6)
+
+Fillet_7 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Compound_1_1_8_1/Modified_Face&Box_3_1/Back][Compound_1_1_8_1/Modified_Face&Box_3_1/Top]"), model.selection("FACE", "Compound_1_1_8_2/Modified_Face&Box_3_1/Left")], RADIUS, keepSubResults = True)
+NB_FACES += 5
+NB_EDGES += 22
+NB_VERTICES += 44
+VOLUME = 5470.063344851
+assertResult(Fillet_7)
+
+Fillet_8 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Fillet_1_1_6/MF:Fillet&Box_1_1/Bottom][Fillet_1_1_6/MF:Fillet&Box_1_1/Front]"), model.selection("EDGE", "[Compound_1_1_8_3/Modified_Face&Box_3_1/Left][Compound_1_1_8_3/Modified_Face&Box_3_1/Top]")], RADIUS, keepSubResults = True)
+NB_FACES += 2
+NB_EDGES += 12
+NB_VERTICES += 24
+VOLUME = 5452.8951979263
+REFERENCE[5] = GeomAPI_Pnt(55.0668735866, 5, 5)
+assertResult(Fillet_8)
+
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestFillet_MultiLevelCompound_v95_3.py b/src/FeaturesPlugin/Test/TestFillet_MultiLevelCompound_v95_3.py
new file mode 100644 (file)
index 0000000..4ad3637
--- /dev/null
@@ -0,0 +1,150 @@
+# Copyright (C) 2020  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 salome.shaper import model
+from GeomAPI import *
+from GeomAlgoAPI 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"))
+SketchPoint_1 = Sketch_1.addPoint(44.29784155360136, 17.09942588468031)
+SketchArc_1 = Sketch_1.addArc(44.29784155360136, 17.09942588468031, 47.1668727423061, 12.27945348765633, 45.38299232715926, 22.60269052200972, False)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchArc_1.center())
+SketchLine_1 = Sketch_1.addLine(42.5764228403785, 22.14892077680068, 39.70739165167375, 16.41085839939117)
+SketchLine_2 = Sketch_1.addLine(39.70739165167375, 16.41085839939117, 43.03546783057126, 12.04993099255995)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(28.57555063949931, 12.96802097294547, 15.72229091410204, 12.96802097294547)
+SketchLine_4 = Sketch_1.addLine(15.72229091410204, 12.96802097294547, 15.72229091410204, 21.46035329151154)
+SketchLine_5 = Sketch_1.addLine(15.72229091410204, 21.46035329151154, 28.57555063949931, 21.46035329151154)
+SketchLine_6 = Sketch_1.addLine(28.57555063949931, 21.46035329151154, 28.57555063949931, 12.96802097294547)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_6.result())
+SketchLine_7 = Sketch_1.addLine(-10.67279602198167, 14.78814178154371, -28.34602814440294, 14.78814178154371)
+SketchLine_8 = Sketch_1.addLine(-28.34602814440294, 14.78814178154371, -28.34602814440294, 25.13271321305362)
+SketchLine_9 = Sketch_1.addLine(-28.34602814440294, 25.13271321305362, -10.67279602198167, 25.13271321305362)
+SketchLine_10 = Sketch_1.addLine(-10.67279602198167, 25.13271321305362, -10.67279602198167, 14.78814178154371)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_10.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())
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchLine_9.endPoint(), SketchLine_10.startPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_7.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_8.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_9.result())
+SketchConstraintVertical_4 = Sketch_1.setVertical(SketchLine_10.result())
+SketchLine_11 = Sketch_1.addLine(-17.67323212242127, 25.13271321305362, -21.80463703415611, 14.78814178154371)
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchLine_11.startPoint(), SketchLine_9.result())
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchLine_11.endPoint(), SketchLine_7.result())
+model.do()
+Vertex_1 = model.addVertex(Part_1_doc, [model.selection("VERTEX", "Sketch_1/SketchArc_1")], False)
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchArc_1_2")], False)
+Wire_1 = model.addWire(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2")], False)
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_6r-SketchLine_5r-SketchLine_4r-SketchLine_3r")])
+Shell_1 = model.addShell(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_10r-SketchLine_9r-SketchLine_11f-SketchLine_7r"), model.selection("FACE", "Sketch_1/Face-SketchLine_11r-SketchLine_9r-SketchLine_8r-SketchLine_7r")])
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 50)
+Box_2 = model.addBox(Part_1_doc, 10, 10, 10)
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Box_2_1"), model.selection("SOLID", "Cylinder_1_1")], keepSubResults = True)
+Box_3 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_2 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_3_1")], model.selection("EDGE", "PartSet/OY"), 50)
+AngularCopy_1 = model.addMultiRotation(Part_1_doc, [model.selection("SOLID", "Translation_2_1")], model.selection("EDGE", "PartSet/OZ"), 30, 3)
+model.end()
+
+TOLERANCE = 1.e-7
+RADIUS_1 = 2
+RADIUS_2 = 1
+
+model.begin()
+Fillet_1 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Edge_1_1")], RADIUS_1, RADIUS_2, keepSubResults = True)
+model.end()
+assert(Fillet_1.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_2 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Wire_1_1/Modified_Edge&Sketch_1/SketchLine_1")], RADIUS_1, RADIUS_2, keepSubResults = True)
+model.end()
+assert(Fillet_2.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_3 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Face_1_1/Modified_Edge&Sketch_1/SketchLine_3")], RADIUS_1, RADIUS_2, keepSubResults = True)
+model.end()
+assert(Fillet_3.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_4 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Shell_1_1/Modified_Edge&Sketch_1/SketchLine_10")], RADIUS_1, RADIUS_2, keepSubResults = True)
+model.end()
+assert(Fillet_4.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_5 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Translation_1_1/MF:Translated&Box_1_1/Front][Translation_1_1/MF:Translated&Box_1_1/Top]"), model.selection("FACE", "Translation_1_1/MF:Translated&Box_1_1/Right")], RADIUS_1, RADIUS_2, keepSubResults = True)
+model.testNbResults(Fillet_5, 1)
+model.testNbSubResults(Fillet_5, [0])
+model.testNbSubShapes(Fillet_5, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Fillet_5, GeomAPI_Shape.FACE, [12])
+model.testNbSubShapes(Fillet_5, GeomAPI_Shape.EDGE, [53])
+model.testNbSubShapes(Fillet_5, GeomAPI_Shape.VERTEX, [106])
+model.testResultsVolumes(Fillet_5, [976.519471836586])
+refPoint = GeomAPI_Pnt(54.98720346, 4.918055722, 4.987203302)
+midPoint = Fillet_5.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+
+Fillet_6 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Partition_1_1_2/Modified_Face&Box_2_1/Top][Box_2_1/Front]"), model.selection("FACE", "Box_2_1/Right")], RADIUS_1, RADIUS_2, keepSubResults = True)
+model.testNbResults(Fillet_6, 1)
+model.testNbSubResults(Fillet_6, [3])
+model.testNbSubShapes(Fillet_6, GeomAPI_Shape.SOLID, [3])
+model.testNbSubShapes(Fillet_6, GeomAPI_Shape.FACE, [23])
+model.testNbSubShapes(Fillet_6, GeomAPI_Shape.EDGE, [95])
+model.testNbSubShapes(Fillet_6, GeomAPI_Shape.VERTEX, [190])
+model.testResultsVolumes(Fillet_6, [1565.568094166])
+refPoint = GeomAPI_Pnt(2.7448, 2.7448, 5)
+midPoint = Fillet_6.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+
+Fillet_7 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[AngularCopy_1_1_1/MF:Rotated&Box_3_1/Back][AngularCopy_1_1_1/MF:Rotated&Box_3_1/Top]"), model.selection("FACE", "AngularCopy_1_1_2/MF:Rotated&Box_3_1/Left")], RADIUS_1, RADIUS_2, keepSubResults = True)
+model.testNbResults(Fillet_7, 1)
+model.testNbSubResults(Fillet_7, [3])
+model.testNbSubShapes(Fillet_7, GeomAPI_Shape.SOLID, [3])
+model.testNbSubShapes(Fillet_7, GeomAPI_Shape.FACE, [23])
+model.testNbSubShapes(Fillet_7, GeomAPI_Shape.EDGE, [98])
+model.testNbSubShapes(Fillet_7, GeomAPI_Shape.VERTEX, [196])
+model.testResultsVolumes(Fillet_7, [2976.0685684791988])
+refPoint = GeomAPI_Pnt(-20.9807621135, 42.806, 5)
+midPoint = Fillet_7.defaultResult().shape().middlePoint()
+assert(midPoint.distance(refPoint) < TOLERANCE)
+model.end()
+
+model.begin()
+Fillet_8 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Fillet_1_1/MF:Fillet&Box_1_1/Top][Fillet_1_1/MF:Fillet&Box_1_1/Left]"), model.selection("EDGE", "[AngularCopy_1_1_3/MF:Rotated&Box_3_1/Left][AngularCopy_1_1_3/MF:Rotated&Box_3_1/Top]")], RADIUS_1, RADIUS_2, keepSubResults = True)
+model.end()
+assert(Fillet_8.feature().error() != "")
+model.undo()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestFillet_MultiLevelCompound_v95_4.py b/src/FeaturesPlugin/Test/TestFillet_MultiLevelCompound_v95_4.py
new file mode 100644 (file)
index 0000000..ebd1bf9
--- /dev/null
@@ -0,0 +1,171 @@
+# Copyright (C) 2020  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 salome.shaper import model
+from GeomAPI import *
+from GeomAlgoAPI 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"))
+SketchPoint_1 = Sketch_1.addPoint(44.29784155360136, 17.09942588468031)
+SketchArc_1 = Sketch_1.addArc(44.29784155360136, 17.09942588468031, 47.1668727423061, 12.27945348765633, 45.38299232715926, 22.60269052200972, False)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchArc_1.center())
+SketchLine_1 = Sketch_1.addLine(42.5764228403785, 22.14892077680068, 39.70739165167375, 16.41085839939117)
+SketchLine_2 = Sketch_1.addLine(39.70739165167375, 16.41085839939117, 43.03546783057126, 12.04993099255995)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(28.57555063949931, 12.96802097294547, 15.72229091410204, 12.96802097294547)
+SketchLine_4 = Sketch_1.addLine(15.72229091410204, 12.96802097294547, 15.72229091410204, 21.46035329151154)
+SketchLine_5 = Sketch_1.addLine(15.72229091410204, 21.46035329151154, 28.57555063949931, 21.46035329151154)
+SketchLine_6 = Sketch_1.addLine(28.57555063949931, 21.46035329151154, 28.57555063949931, 12.96802097294547)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_6.result())
+SketchLine_7 = Sketch_1.addLine(-10.67279602198167, 14.78814178154371, -28.34602814440294, 14.78814178154371)
+SketchLine_8 = Sketch_1.addLine(-28.34602814440294, 14.78814178154371, -28.34602814440294, 25.13271321305362)
+SketchLine_9 = Sketch_1.addLine(-28.34602814440294, 25.13271321305362, -10.67279602198167, 25.13271321305362)
+SketchLine_10 = Sketch_1.addLine(-10.67279602198167, 25.13271321305362, -10.67279602198167, 14.78814178154371)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_10.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())
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchLine_9.endPoint(), SketchLine_10.startPoint())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_7.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_8.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_9.result())
+SketchConstraintVertical_4 = Sketch_1.setVertical(SketchLine_10.result())
+SketchLine_11 = Sketch_1.addLine(-17.67323212242127, 25.13271321305362, -21.80463703415611, 14.78814178154371)
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchLine_11.startPoint(), SketchLine_9.result())
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchLine_11.endPoint(), SketchLine_7.result())
+model.do()
+Vertex_1 = model.addVertex(Part_1_doc, [model.selection("VERTEX", "Sketch_1/SketchArc_1")], False)
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchArc_1_2")], False)
+Wire_1 = model.addWire(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2")], False)
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_6r-SketchLine_5r-SketchLine_4r-SketchLine_3r")])
+Shell_1 = model.addShell(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_10r-SketchLine_9r-SketchLine_11f-SketchLine_7r"), model.selection("FACE", "Sketch_1/Face-SketchLine_11r-SketchLine_9r-SketchLine_8r-SketchLine_7r")])
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 50)
+Box_2 = model.addBox(Part_1_doc, 10, 10, 10)
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Box_2_1"), model.selection("SOLID", "Cylinder_1_1")], keepSubResults = True)
+Box_3 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_2 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_3_1")], model.selection("EDGE", "PartSet/OY"), 50)
+AngularCopy_1 = model.addMultiRotation(Part_1_doc, [model.selection("SOLID", "Translation_2_1")], model.selection("EDGE", "PartSet/OZ"), 30, 3)
+Compound_1_objects = [model.selection("VERTEX", "Vertex_1_1"), model.selection("EDGE", "Edge_1_1"), model.selection("WIRE", "Wire_1_1"), model.selection("FACE", "Face_1_1"), model.selection("SHELL", "Shell_1_1"), model.selection("SOLID", "Translation_1_1"), model.selection("COMPSOLID", "Partition_1_1"), model.selection("COMPOUND", "AngularCopy_1_1")]
+Compound_1 = model.addCompound(Part_1_doc, Compound_1_objects)
+model.end()
+
+TOLERANCE = 1.e-7
+RADIUS_1 = 2
+RADIUS_2 = 1
+
+NB_SOLIDS = 7
+NB_FACES = 44
+NB_EDGES = 177
+NB_VERTICES = 355
+VOLUME = 5589.0486226
+
+# collect reference data
+REFERENCE = []
+for ind in range(0, Compound_1.result().numberOfSubs()):
+    p = Compound_1.result().subResult(ind).resultSubShapePair()[1].middlePoint()
+    REFERENCE.append(p)
+
+def assertResult(theFeature):
+    model.testNbResults(theFeature, 1)
+    model.testNbSubResults(theFeature, [8])
+    model.testNbSubShapes(theFeature, GeomAPI_Shape.SOLID, [NB_SOLIDS])
+    model.testNbSubShapes(theFeature, GeomAPI_Shape.FACE, [NB_FACES])
+    model.testNbSubShapes(theFeature, GeomAPI_Shape.EDGE, [NB_EDGES])
+    model.testNbSubShapes(theFeature, GeomAPI_Shape.VERTEX, [NB_VERTICES])
+    model.testResultsVolumes(theFeature, [VOLUME])
+
+    for ind in range(0, theFeature.result().numberOfSubs()):
+        ref = REFERENCE[ind]
+        midPoint = theFeature.result().subResult(ind).resultSubShapePair()[0].shape().middlePoint()
+        assert(midPoint.distance(ref) < TOLERANCE), "Sub-result {}; actual ({}, {}, {}) != expected ({}, {}, {})".format(ind, midPoint.x(), midPoint.y(), midPoint.z(), ref.x(), ref.y(), ref.z())
+
+
+model.begin()
+Fillet_1 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Compound_1_1_2")], RADIUS_1, RADIUS_2, keepSubResults = True)
+model.end()
+assert(Fillet_1.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_2 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Compound_1_1_3/Modified_Edge&Sketch_1/SketchLine_1")], RADIUS_1, RADIUS_2, keepSubResults = True)
+model.end()
+assert(Fillet_2.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_3 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Compound_1_1_4/Modified_Edge&Sketch_1/SketchLine_3")], RADIUS_1, RADIUS_2, keepSubResults = True)
+model.end()
+assert(Fillet_3.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_4 = model.addFillet(Part_1_doc, [model.selection("EDGE", "Compound_1_1_5/Modified_Edge&Sketch_1/SketchLine_10")], RADIUS_1, RADIUS_2, keepSubResults = True)
+model.end()
+assert(Fillet_4.feature().error() != "")
+model.undo()
+
+model.begin()
+Fillet_5 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Compound_1_1_6/Modified_Face&Box_1_1/Front][Compound_1_1_6/Modified_Face&Box_1_1/Top]"), model.selection("FACE", "Compound_1_1_6/Modified_Face&Box_1_1/Back")], RADIUS_1, RADIUS_2, keepSubResults = True)
+REFERENCE[5] = GeomAPI_Pnt(55.0654360945, 5.015632459, 4.985518188)
+NB_FACES += 5
+NB_EDGES += 26
+NB_VERTICES += 52
+VOLUME = 5565.117188528191
+assertResult(Fillet_5)
+
+Fillet_6 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Compound_1_1_7_2/Modified_Face&Box_2_1/Top][Compound_1_1_7_2/Modified_Face&Box_2_1/Front]"), model.selection("FACE", "Compound_1_1_7_2/Modified_Face&Box_2_1/Right")], RADIUS_1, RADIUS_2, keepSubResults = True)
+REFERENCE[6] = GeomAPI_Pnt(2.7448, 2.7448, 5)
+NB_FACES += 6
+NB_EDGES += 29
+NB_VERTICES += 58
+VOLUME = 5541.63666
+assertResult(Fillet_6)
+
+Fillet_7 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Compound_1_1_8_1/Modified_Face&Box_3_1/Back][Compound_1_1_8_1/Modified_Face&Box_3_1/Top]"), model.selection("FACE", "Compound_1_1_8_2/Modified_Face&Box_3_1/Left")], RADIUS_1, RADIUS_2, keepSubResults = True)
+REFERENCE[7] = GeomAPI_Pnt(-20.9807621135, 42.806, 5)
+NB_FACES += 5
+NB_EDGES += 26
+NB_VERTICES += 52
+VOLUME = 5517.70522857
+assertResult(Fillet_7)
+
+Fillet_8 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Fillet_1_1_6/MF:Fillet&Box_1_1/Bottom][Fillet_1_1_6/MF:Fillet&Box_1_1/Front]"), model.selection("EDGE", "[Compound_1_1_8_3/Modified_Face&Box_3_1/Left][Compound_1_1_8_3/Modified_Face&Box_3_1/Top]")], RADIUS_1, RADIUS_2, keepSubResults = True)
+NB_FACES += 2
+NB_EDGES += 12
+NB_VERTICES += 24
+VOLUME = 5507.602043482
+REFERENCE[5] = GeomAPI_Pnt(55.041662114, 5.021870383, 5.009557179275)
+REFERENCE[7] = GeomAPI_Pnt(-20.9807621135, 42.5409962, 5)
+assertResult(Fillet_8)
+
+model.end()
+
+assert(model.checkPythonDump())
index cac15eabe4d78435489629b17e9fae0374b55e51..53522d415840a2c24139d8a14ef338e8cd15e3e2 100644 (file)
@@ -60,6 +60,19 @@ GeomShapePtr GeomAPI_ShapeHierarchy::parent(const GeomShapePtr& theShape,
   return aParent;
 }
 
+GeomShapePtr GeomAPI_ShapeHierarchy::root(const GeomShapePtr& theShape,
+                                          bool theMarkProcessed)
+{
+  GeomShapePtr aParent = parent(theShape, theMarkProcessed);
+  GeomShapePtr aRoot = aParent;
+  while (aParent) {
+    aParent = parent(aRoot, theMarkProcessed);
+    if (aParent)
+      aRoot = aParent;
+  }
+  return aRoot;
+}
+
 void GeomAPI_ShapeHierarchy::markProcessed(const GeomShapePtr& theShape)
 {
   myProcessedObjects.insert(theShape);
@@ -84,6 +97,17 @@ void GeomAPI_ShapeHierarchy::markModified(const GeomShapePtr& theSource,
   myModifiedObjects[theSource] = theModified;
 }
 
+const ListOfShape& GeomAPI_ShapeHierarchy::objects(GeomShapePtr theParent) const
+{
+  MapShapeToIndex::const_iterator aFoundIndex = myParentIndices.find(theParent);
+  if (aFoundIndex == myParentIndices.end()) {
+    static const ListOfShape THE_DUMMY = ListOfShape();
+    return THE_DUMMY; // no such shape
+  }
+
+  return mySubshapes[aFoundIndex->second].second;
+}
+
 void GeomAPI_ShapeHierarchy::objectsByType(
     ListOfShape& theShapesByType,
     ListOfShape& theOtherShapes,
@@ -146,17 +170,16 @@ void GeomAPI_ShapeHierarchy::topLevelObjects(ListOfShape& theDestination) const
   iterator anIt = aThis->begin(), aEnd = aThis->end();
   for (; anIt != aEnd; ++anIt) {
     GeomShapePtr aShape = *anIt;
-    GeomShapePtr aParent = aThis->parent(aShape);
-    GeomShapePtr aRoot = aParent;
-    while (aParent) {
-      aParent = aThis->parent(aRoot);
-      if (aParent)
-        aRoot = aParent;
-    }
-
+    GeomShapePtr aRoot = aThis->root(aShape);
     if (aRoot) {
-      // compose a compund with the modified shapes
-      aShape = collectSubs(aRoot, SetOfShape(), myModifiedObjects);
+      // check the current shape was modified
+      MapShapeToShape::const_iterator aFound = myModifiedObjects.find(aRoot);
+      if (aFound != myModifiedObjects.end())
+        aShape = aFound->second;
+      else {
+        // compose a compund with the modified shapes
+        aShape = collectSubs(aRoot, SetOfShape(), myModifiedObjects);
+      }
     }
     else {
       // check the current shape was modified
index b1492fe8cb002c60900000e3e84aabaec55106a6..091d61fc119b8ada243a0f7eacc7998261c806fc 100644 (file)
@@ -60,6 +60,9 @@ public:
   /// Return parent shape for the given, or empty if it is a high-level shape.
   /// By default, the parent and all its subshapes are marked as processed for further skip.
   GEOMAPI_EXPORT GeomShapePtr parent(const GeomShapePtr& theShape, bool theMarkProcessed = true);
+  /// Get root shape for the specified sub-shape.
+  /// By default, the parent and all its subshapes are marked as processed for further skip.
+  GEOMAPI_EXPORT GeomShapePtr root(const GeomShapePtr& theShape, bool theMarkProcessed = true);
 
   /// Mark the shape as already processed
   GEOMAPI_EXPORT void markProcessed(const GeomShapePtr& theShape);
@@ -85,6 +88,8 @@ public:
 
   /// Return list of objects
   const ListOfShape& objects() const { return myObjects; }
+  /// Return list of low-level objects for the parent shape
+  GEOMAPI_EXPORT const ListOfShape& objects(GeomShapePtr theParent) const;
   /// Separate objects of the given range of types and all other objects
   GEOMAPI_EXPORT void objectsByType(ListOfShape& theShapesByType, ListOfShape& theOtherShapes,
       const GeomAPI_Shape::ShapeType theMinType = GeomAPI_Shape::COMPOUND,
index ef52c2393217483e80d1134b9fa644642bf8603c..88245cd714dfbe0df5559b677c106d06f454657a 100644 (file)
@@ -18,6 +18,7 @@
 //
 
 #include "GeomAlgoAPI_Chamfer.h"
+#include "GeomAlgoAPI_DFLoader.h"
 
 #include <BRep_Tool.hxx>
 #include <BRepFilletAPI_MakeChamfer.hxx>
@@ -87,7 +88,7 @@ void GeomAlgoAPI_Chamfer::build(const GeomShapePtr& theBaseSolid,
   aChamferBuilder->Build();
   if (!aChamferBuilder->IsDone())
     return;
-  const TopoDS_Shape& aResult = aChamferBuilder->Shape();
+  TopoDS_Shape aResult = GeomAlgoAPI_DFLoader::refineResult(aChamferBuilder->Shape());
 
   std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape());
   aShape->setImpl(new TopoDS_Shape(aResult));
index 19e6cdf0c155d93602adff7afe6fe4aae05b218e..5ed0055e25d8afcdae1eaa1fd4d2df179d0f8e51 100644 (file)
@@ -17,7 +17,8 @@
 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 
-#include "GeomAlgoAPI_Fillet.h"
+#include <GeomAlgoAPI_Fillet.h>
+#include <GeomAlgoAPI_DFLoader.h>
 
 #include <BRepFilletAPI_MakeFillet.hxx>
 
@@ -76,7 +77,7 @@ void GeomAlgoAPI_Fillet::build(const GeomShapePtr& theBaseSolid,
   aFilletBuilder->Build();
   if (!aFilletBuilder->IsDone())
     return;
-  const TopoDS_Shape& aResult = aFilletBuilder->Shape();
+  TopoDS_Shape aResult = GeomAlgoAPI_DFLoader::refineResult(aFilletBuilder->Shape());
 
   std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape());
   aShape->setImpl(new TopoDS_Shape(aResult));