Salome HOME
Task 3.8. Extrusion to any face
authorazv <azv@opencascade.com>
Tue, 28 May 2019 15:23:11 +0000 (18:23 +0300)
committerazv <azv@opencascade.com>
Tue, 28 May 2019 15:23:59 +0000 (18:23 +0300)
38 files changed:
src/FeaturesPlugin/CMakeLists.txt
src/FeaturesPlugin/FeaturesPlugin_CompositeSketch.cpp
src/FeaturesPlugin/FeaturesPlugin_Extrusion.cpp
src/FeaturesPlugin/FeaturesPlugin_Extrusion.h
src/FeaturesPlugin/FeaturesPlugin_ExtrusionBoolean.cpp
src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp
src/FeaturesPlugin/FeaturesPlugin_Tools.cpp
src/FeaturesPlugin/FeaturesPlugin_Tools.h
src/FeaturesPlugin/FeaturesPlugin_Validators.cpp
src/FeaturesPlugin/FeaturesPlugin_Validators.h
src/FeaturesPlugin/Test/TestExtrusion_ByFaces01.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestExtrusion_ByFaces02.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestExtrusion_ByFaces03.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestExtrusion_ByFaces04.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestExtrusion_ByFaces05.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestExtrusion_ByFaces06.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestExtrusion_ByFaces07.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestExtrusion_ByFaces08.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestExtrusion_ByFaces09.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestExtrusion_ByFaces10.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestExtrusion_ByFaces11.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestExtrusion_ByFaces12.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestExtrusion_ByFaces13.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestExtrusion_ByFaces14.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestExtrusion_ByFaces15.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestExtrusion_ByFaces16.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestExtrusion_ByFaces17.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestExtrusion_ByFaces18.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestExtrusion_ByFaces19.py [new file with mode: 0644]
src/FeaturesPlugin/doc/extrusionFeature.rst
src/FeaturesPlugin/extrusion_widget.xml
src/GeomAlgoAPI/CMakeLists.txt
src/GeomAlgoAPI/GeomAlgoAPI_Offset.cpp [new file with mode: 0644]
src/GeomAlgoAPI/GeomAlgoAPI_Offset.h [new file with mode: 0644]
src/GeomAlgoAPI/GeomAlgoAPI_Prism.cpp
src/GeomAlgoAPI/GeomAlgoAPI_Prism.h
src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp
src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h

index 26c65c2b2741cc5b4d407d2bc73b6d2258c889c2..1b383d5450893f195205060deb4956e56dd9a0fe 100644 (file)
@@ -181,6 +181,25 @@ ADD_UNIT_TESTS(TestExtrusion.py
                TestExtrusionFuse_ByPlanesAndOffsets.py
                TestExtrusion_ErrorMsg.py
                TestExtrusion_ZeroOffsetError.py
+               TestExtrusion_ByFaces01.py
+               TestExtrusion_ByFaces02.py
+               TestExtrusion_ByFaces03.py
+               TestExtrusion_ByFaces04.py
+               TestExtrusion_ByFaces05.py
+               TestExtrusion_ByFaces06.py
+               TestExtrusion_ByFaces07.py
+               TestExtrusion_ByFaces08.py
+               TestExtrusion_ByFaces09.py
+               TestExtrusion_ByFaces10.py
+               TestExtrusion_ByFaces11.py
+               TestExtrusion_ByFaces12.py
+               TestExtrusion_ByFaces13.py
+               TestExtrusion_ByFaces14.py
+               TestExtrusion_ByFaces15.py
+               TestExtrusion_ByFaces16.py
+               TestExtrusion_ByFaces17.py
+               TestExtrusion_ByFaces18.py
+               TestExtrusion_ByFaces19.py
                TestRevolution.py
                TestRevolution_ByAngle.py
                TestRevolutionOfPoint.py
index 1a2d4589f5e3a0cf0a1a009065e8c767dd218b9f..1a6767086da52f312287e1cf2fc74cab74fc31dc 100644 (file)
@@ -18,6 +18,7 @@
 //
 
 #include <FeaturesPlugin_CompositeSketch.h>
+#include <FeaturesPlugin_Tools.h>
 
 #include <ModelAPI_AttributeSelectionList.h>
 #include <ModelAPI_AttributeReference.h>
 #include <ModelAPI_Session.h>
 #include <ModelAPI_Validator.h>
 
-#include <GeomAlgoAPI_CompoundBuilder.h>
 #include <GeomAlgoAPI_Revolution.h>
-#include <GeomAlgoAPI_ShapeTools.h>
-#include <GeomAlgoAPI_SketchBuilder.h>
 
-#include <GeomAPI_PlanarEdges.h>
 #include <GeomAPI_ShapeExplorer.h>
 
-#include <map>
-#include <sstream>
 
 static void storeSubShape(const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape,
                           ResultBodyPtr theResultBody,
@@ -132,101 +127,12 @@ void FeaturesPlugin_CompositeSketch::removeFeature(std::shared_ptr<ModelAPI_Feat
 void FeaturesPlugin_CompositeSketch::getBaseShapes(ListOfShape& theBaseShapesList,
                                                    const bool theIsMakeShells)
 {
-  theBaseShapesList.clear();
-
-  ListOfShape aBaseFacesList;
-  std::map<ResultConstructionPtr, ListOfShape> aSketchWiresMap;
   AttributeSelectionListPtr aBaseObjectsSelectionList = selectionList(BASE_OBJECTS_ID());
-  if(!aBaseObjectsSelectionList.get()) {
-    setError("Error: Could not get base objects selection list.");
-    return;
-  }
-  if(aBaseObjectsSelectionList->size() == 0) {
-    setError("Error: Base objects list is empty.");
-    return;
-  }
-  for(int anIndex = 0; anIndex < aBaseObjectsSelectionList->size(); anIndex++) {
-    AttributeSelectionPtr aBaseObjectSelection = aBaseObjectsSelectionList->value(anIndex);
-    if(!aBaseObjectSelection.get()) {
-      setError("Error: Selected base object is empty.");
-      return;
-    }
-    GeomShapePtr aBaseShape = aBaseObjectSelection->value();
-    if(aBaseShape.get() && !aBaseShape->isNull()) {
-      GeomAPI_Shape::ShapeType aST = aBaseShape->shapeType();
-      if(aST == GeomAPI_Shape::SOLID || aST == GeomAPI_Shape::COMPSOLID) {
-        setError("Error: Selected shapes has unsupported type.");
-        return;
-      }
-      ResultConstructionPtr aConstruction =
-        std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aBaseObjectSelection->context());
-      if(aConstruction.get() && !aBaseShape->isEqual(aConstruction->shape()) &&
-          aST == GeomAPI_Shape::WIRE) {
-        // It is a wire on the sketch, store it to make face later.
-        aSketchWiresMap[aConstruction].push_back(aBaseShape);
-        continue;
-      } else {
-      aST == GeomAPI_Shape::FACE ? aBaseFacesList.push_back(aBaseShape) :
-                                   theBaseShapesList.push_back(aBaseShape);
-      }
-    } else {
-      // This may be the whole sketch result selected, check and get faces.
-      ResultConstructionPtr aConstruction =
-        std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aBaseObjectSelection->context());
-      if(!aConstruction.get()) {
-        setError("Error: Selected sketches does not have results.");
-        return;
-      }
-      int aFacesNum = aConstruction->facesNum();
-      if(aFacesNum == 0) {
-        // Probably it can be construction.
-        aBaseShape = aConstruction->shape();
-        if(aBaseShape.get() && !aBaseShape->isNull()) {
-          GeomAPI_Shape::ShapeType aST = aBaseShape->shapeType();
-          if(aST != GeomAPI_Shape::VERTEX && aST != GeomAPI_Shape::EDGE &&
-             aST != GeomAPI_Shape::WIRE &&
-             aST != GeomAPI_Shape::FACE && aST != GeomAPI_Shape::SHELL) {
-            setError("Error: Selected shapes has unsupported type.");
-            return;
-          }
-          aST == GeomAPI_Shape::FACE ? aBaseFacesList.push_back(aBaseShape) :
-                                       theBaseShapesList.push_back(aBaseShape);
-        }
-      } else {
-        for(int aFaceIndex = 0; aFaceIndex < aFacesNum; aFaceIndex++) {
-          GeomShapePtr aBaseFace = aConstruction->face(aFaceIndex);
-          if(!aBaseFace.get() || aBaseFace->isNull()) {
-            setError("Error: One of the faces on selected sketch is null.");
-            return;
-          }
-          aBaseFacesList.push_back(aBaseFace);
-        }
-      }
-    }
-  }
-
-  // Make faces from sketch wires.
-  for(std::map<ResultConstructionPtr, ListOfShape>::const_iterator anIt = aSketchWiresMap.cbegin();
-      anIt != aSketchWiresMap.cend(); ++anIt) {
-    const std::shared_ptr<GeomAPI_PlanarEdges> aSketchPlanarEdges =
-      std::dynamic_pointer_cast<GeomAPI_PlanarEdges>((*anIt).first->shape());
-    const ListOfShape& aWiresList = (*anIt).second;
-    ListOfShape aFaces;
-    GeomAlgoAPI_ShapeTools::makeFacesWithHoles(aSketchPlanarEdges->origin(),
-                                               aSketchPlanarEdges->norm(),
-                                               aWiresList,
-                                               aFaces);
-    aBaseFacesList.insert(aBaseFacesList.end(), aFaces.begin(), aFaces.end());
-  }
-
-  // Searching faces with common edges.
-  if(theIsMakeShells && aBaseFacesList.size() > 1) {
-    GeomShapePtr aFacesCompound = GeomAlgoAPI_CompoundBuilder::compound(aBaseFacesList);
-    GeomAlgoAPI_ShapeTools::combineShapes(aFacesCompound, GeomAPI_Shape::SHELL, theBaseShapesList);
-  } else {
-    theBaseShapesList.insert(theBaseShapesList.end(), aBaseFacesList.begin(),
-                             aBaseFacesList.end());
-  }
+  std::string anError;
+  bool isOk = FeaturesPlugin_Tools::getShape(
+      aBaseObjectsSelectionList, theIsMakeShells, theBaseShapesList, anError);
+  if (!isOk)
+    setError(anError);
 }
 
 //=================================================================================================
index 3ff47274e205bde1c282998eb26c699a0910af94..dc754bf94cdf24b8189206f4d9d18af911304026 100644 (file)
@@ -18,6 +18,7 @@
 //
 
 #include "FeaturesPlugin_Extrusion.h"
+#include "FeaturesPlugin_Tools.h"
 
 #include <ModelAPI_AttributeDouble.h>
 #include <ModelAPI_AttributeSelection.h>
@@ -66,11 +67,11 @@ void FeaturesPlugin_Extrusion::initAttributes()
 //=================================================================================================
 void FeaturesPlugin_Extrusion::execute()
 {
-  ListOfShape aBaseShapesList;
+  ListOfShape aBaseShapesList, aBoundaryShapes;
   ListOfMakeShape aMakeShapesList;
 
   // Make extrusions.
-  if(!makeExtrusions(aBaseShapesList, aMakeShapesList)) {
+  if(!makeExtrusions(aBaseShapesList, aBoundaryShapes, aMakeShapesList)) {
     return;
   }
 
@@ -80,7 +81,10 @@ void FeaturesPlugin_Extrusion::execute()
   ListOfMakeShape::const_iterator anAlgoIt = aMakeShapesList.cbegin();
   for(; aBaseIt != aBaseShapesList.cend() && anAlgoIt != aMakeShapesList.cend();
         ++aBaseIt, ++anAlgoIt) {
-    storeResult(*aBaseIt, *anAlgoIt, aResultIndex++);
+    if (aBoundaryShapes.empty())
+      storeResult(*aBaseIt, *anAlgoIt, aResultIndex++);
+    else
+      storeResultWithBoundaries(*aBaseIt, aBoundaryShapes, *anAlgoIt, aResultIndex++);
   }
 
   removeResults(aResultIndex);
@@ -88,6 +92,7 @@ void FeaturesPlugin_Extrusion::execute()
 
 //=================================================================================================
 bool FeaturesPlugin_Extrusion::makeExtrusions(ListOfShape& theBaseShapes,
+                                              ListOfShape& theBoundaryShapes,
                                               ListOfMakeShape& theMakeShapes)
 {
   theMakeShapes.clear();
@@ -165,6 +170,10 @@ bool FeaturesPlugin_Extrusion::makeExtrusions(ListOfShape& theBaseShapes,
       }
     }
   }
+  if (aToShape)
+    theBoundaryShapes.push_back(aToShape);
+  if (aFromShape)
+    theBoundaryShapes.push_back(aFromShape);
 
   // Generating result for each base shape.
   std::string anError;
@@ -185,3 +194,23 @@ bool FeaturesPlugin_Extrusion::makeExtrusions(ListOfShape& theBaseShapes,
 
   return true;
 }
+
+//=================================================================================================
+void FeaturesPlugin_Extrusion::storeResultWithBoundaries(
+    const GeomShapePtr theBaseShape,
+    const ListOfShape& theBoundaryShapes,
+    const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape,
+    const int theIndex)
+{
+  // Create result body.
+  ResultBodyPtr aResultBody = document()->createBody(data(), theIndex);
+
+  // Store modified shapes.
+  FeaturesPlugin_Tools::loadModifiedShapes(aResultBody, theBoundaryShapes, ListOfShape(),
+                                           theMakeShape, theMakeShape->shape());
+
+  // Store generated edges/faces.
+  storeGenerationHistory(aResultBody, theBaseShape, theMakeShape);
+
+  setResult(aResultBody, theIndex);
+}
index 216d1704c232a2e2ce65c88a5269702cd4ab392d..d0a6e374530dcb3d161aa2397426660cb74691a1 100644 (file)
@@ -132,10 +132,18 @@ public:
 protected:
   /// Generates extrusions.
   /// \param[out] theBaseShapes list of base shapes.
+  /// \param[out] theBoundaryShapes list of faces limiting the extrusion
   /// \param[out] theMakeShapes list of according algos.
   /// \return false in case one of algo failed.
   bool makeExtrusions(ListOfShape& theBaseShapes,
+                      ListOfShape& theBoundaryShapes,
                       ListOfMakeShape& theMakeShapes);
+
+  /// Stores result of generation.
+  void storeResultWithBoundaries(const GeomShapePtr theBaseShape,
+                                 const ListOfShape& theBoundaryShapes,
+                                 const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape,
+                                 const int theIndex = 0);
 };
 
 #endif
index 774328da0922b16af88e643b5338705d44642358..edbdcf948aaeefa4c9a8c490237543c7a5eee256 100644 (file)
@@ -31,7 +31,8 @@ void FeaturesPlugin_ExtrusionBoolean::initAttributes()
 bool FeaturesPlugin_ExtrusionBoolean::makeGeneration(ListOfShape& theBaseShapes,
                                                      ListOfMakeShape& theMakeShapes)
 {
-  return makeExtrusions(theBaseShapes, theMakeShapes);
+  ListOfShape aBoundaryShapes;
+  return makeExtrusions(theBaseShapes, aBoundaryShapes, theMakeShapes);
 }
 
 //=================================================================================================
index 9efa6c1fd47c59d9db731d9bc38dfcf1c96664ed..87db42a877e209be75b8d0261aac0777cd56eb00 100644 (file)
@@ -77,6 +77,8 @@ FeaturesPlugin_Plugin::FeaturesPlugin_Plugin()
                               new FeaturesPlugin_ValidatorPipeLocationsNumber);
   aFactory->registerValidator("FeaturesPlugin_ValidatorExtrusionDir",
                               new FeaturesPlugin_ValidatorExtrusionDir);
+  aFactory->registerValidator("FeaturesPlugin_ValidatorExtrusionBoundary",
+                              new FeaturesPlugin_ValidatorExtrusionBoundaryFace);
   aFactory->registerValidator("FeaturesPlugin_ValidatorBooleanSelection",
                               new FeaturesPlugin_ValidatorBooleanSelection);
   aFactory->registerValidator("FeaturesPlugin_ValidatorPartitionSelection",
index dc1b1a7e16efd8149b6eefb799c1afccbbb98635..55a1738426044d18276c31f08beaa65c2c16d58c 100644 (file)
 
 #include "FeaturesPlugin_Tools.h"
 
+#include <ModelAPI_AttributeSelectionList.h>
 #include <ModelAPI_ResultBody.h>
+#include <ModelAPI_ResultConstruction.h>
 
+#include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAlgoAPI_ShapeTools.h>
+
+#include <GeomAPI_PlanarEdges.h>
 #include <GeomAPI_ShapeIterator.h>
 
 //==================================================================================================
@@ -133,3 +139,105 @@ void FeaturesPlugin_Tools::loadDeletedShapes(
                       theResultShapesCompound);
   }
 }
+
+//==================================================================================================
+bool FeaturesPlugin_Tools::getShape(const AttributeSelectionListPtr theSelectionList,
+                                    const bool theShareTopology,
+                                    ListOfShape& theShapesList,
+                                    std::string& theError)
+{
+  theShapesList.clear();
+
+  ListOfShape aBaseFacesList;
+  std::map<ResultConstructionPtr, ListOfShape> aSketchWiresMap;
+  if(!theSelectionList.get()) {
+    theError = "Error: Could not get base objects selection list.";
+    return false;
+  }
+  if(theSelectionList->size() == 0) {
+    theError = "Error: Base objects list is empty.";
+    return false;
+  }
+  for(int anIndex = 0; anIndex < theSelectionList->size(); anIndex++) {
+    AttributeSelectionPtr aBaseObjectSelection = theSelectionList->value(anIndex);
+    if(!aBaseObjectSelection.get()) {
+      theError = "Error: Selected base object is empty.";
+      return false;
+    }
+    GeomShapePtr aBaseShape = aBaseObjectSelection->value();
+    if(aBaseShape.get() && !aBaseShape->isNull()) {
+      GeomAPI_Shape::ShapeType aST = aBaseShape->shapeType();
+      if(aST == GeomAPI_Shape::SOLID || aST == GeomAPI_Shape::COMPSOLID) {
+        theError = "Error: Selected shapes has unsupported type.";
+        return false;
+      }
+      ResultConstructionPtr aConstruction =
+        std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aBaseObjectSelection->context());
+      if(aConstruction.get() && !aBaseShape->isEqual(aConstruction->shape()) &&
+          aST == GeomAPI_Shape::WIRE) {
+        // It is a wire on the sketch, store it to make face later.
+        aSketchWiresMap[aConstruction].push_back(aBaseShape);
+        continue;
+      } else {
+      aST == GeomAPI_Shape::FACE ? aBaseFacesList.push_back(aBaseShape) :
+                                   theShapesList.push_back(aBaseShape);
+      }
+    } else {
+      // This may be the whole sketch result selected, check and get faces.
+      ResultConstructionPtr aConstruction =
+        std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aBaseObjectSelection->context());
+      if(!aConstruction.get()) {
+        theError = "Error: Selected sketches does not have results.";
+        return false;
+      }
+      int aFacesNum = aConstruction->facesNum();
+      if(aFacesNum == 0) {
+        // Probably it can be construction.
+        aBaseShape = aConstruction->shape();
+        if(aBaseShape.get() && !aBaseShape->isNull()) {
+          GeomAPI_Shape::ShapeType aST = aBaseShape->shapeType();
+          if(aST != GeomAPI_Shape::VERTEX && aST != GeomAPI_Shape::EDGE &&
+             aST != GeomAPI_Shape::WIRE &&
+             aST != GeomAPI_Shape::FACE && aST != GeomAPI_Shape::SHELL) {
+            theError = "Error: Selected shapes has unsupported type.";
+            return false;
+          }
+          aST == GeomAPI_Shape::FACE ? aBaseFacesList.push_back(aBaseShape) :
+                                       theShapesList.push_back(aBaseShape);
+        }
+      } else {
+        for(int aFaceIndex = 0; aFaceIndex < aFacesNum; aFaceIndex++) {
+          GeomShapePtr aBaseFace = aConstruction->face(aFaceIndex);
+          if(!aBaseFace.get() || aBaseFace->isNull()) {
+            theError = "Error: One of the faces on selected sketch is null.";
+            return false;
+          }
+          aBaseFacesList.push_back(aBaseFace);
+        }
+      }
+    }
+  }
+
+  // Make faces from sketch wires.
+  for(std::map<ResultConstructionPtr, ListOfShape>::const_iterator anIt = aSketchWiresMap.cbegin();
+      anIt != aSketchWiresMap.cend(); ++anIt) {
+    const std::shared_ptr<GeomAPI_PlanarEdges> aSketchPlanarEdges =
+        std::dynamic_pointer_cast<GeomAPI_PlanarEdges>((*anIt).first->shape());
+    const ListOfShape& aWiresList = (*anIt).second;
+    ListOfShape aFaces;
+    GeomAlgoAPI_ShapeTools::makeFacesWithHoles(aSketchPlanarEdges->origin(),
+                                               aSketchPlanarEdges->norm(),
+                                               aWiresList,
+                                               aFaces);
+    aBaseFacesList.insert(aBaseFacesList.end(), aFaces.begin(), aFaces.end());
+  }
+
+  // Searching faces with common edges.
+  if(theShareTopology && aBaseFacesList.size() > 1) {
+    GeomShapePtr aFacesCompound = GeomAlgoAPI_CompoundBuilder::compound(aBaseFacesList);
+    GeomAlgoAPI_ShapeTools::combineShapes(aFacesCompound, GeomAPI_Shape::SHELL, theShapesList);
+  } else {
+    theShapesList.insert(theShapesList.end(), aBaseFacesList.begin(), aBaseFacesList.end());
+  }
+  return true;
+}
index dd04de569f511a3517ccc12b7604ac69afe31ea3..36ad73bdd053cbbdaf17b54bae6ae975ef5c01b0 100644 (file)
@@ -45,7 +45,7 @@ public:
                                  const GeomShapePtr& theBaseShape,
                                  const GeomMakeShapePtr& theMakeShape,
                                  const std::string theName);
-    /// Stores deleted shapes.
+  /// Stores deleted shapes.
   static void loadDeletedShapes(ResultBodyPtr theResultBody,
                                 const GeomShapePtr theBaseShape,
                                 const ListOfShape& theTools,
@@ -56,6 +56,12 @@ public:
   static void loadDeletedShapes(std::vector<ResultBaseAlgo>& theResultBaseAlgoList,
                                 const ListOfShape& theTools,
                                 const GeomShapePtr theResultShapesCompound);
+
+  /// Obtain shapes from the selection list attribute.
+  static bool getShape(const std::shared_ptr<ModelAPI_AttributeSelectionList> theSelectionList,
+                       const bool theShareTopology,
+                       ListOfShape& theShapesList,
+                       std::string& theError);
 };
 
 #endif /* FeaturesPlugin_Tools_H_ */
index ee82a62f5c8c415cd3a897a4818c44d102358822..30993f225bd44544afc1544cedc0f00bb8a5a095 100644 (file)
 #include "FeaturesPlugin_BooleanFuse.h"
 #include "FeaturesPlugin_BooleanCommon.h"
 #include "FeaturesPlugin_BooleanSmash.h"
+#include "FeaturesPlugin_Extrusion.h"
 #include "FeaturesPlugin_Pipe.h"
 #include "FeaturesPlugin_Union.h"
 
 #include <Events_InfoMessage.h>
 
 #include <ModelAPI_Attribute.h>
+#include <ModelAPI_AttributeDouble.h>>
 #include <ModelAPI_AttributeInteger.h>
 #include <ModelAPI_AttributeSelectionList.h>
 #include <ModelAPI_AttributeString.h>
@@ -52,6 +54,7 @@
 #include <GeomAPI_ShapeIterator.h>
 
 #include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAlgoAPI_Prism.h>
 #include <GeomAlgoAPI_ShapeBuilder.h>
 #include <GeomAlgoAPI_ShapeTools.h>
 #include <GeomAlgoAPI_WireBuilder.h>
@@ -686,6 +689,99 @@ bool FeaturesPlugin_ValidatorExtrusionDir::isShapesCanBeEmpty(const AttributePtr
   return true;
 }
 
+//==================================================================================================
+bool FeaturesPlugin_ValidatorExtrusionBoundaryFace::isValid(
+    const AttributePtr& theAttribute,
+    const std::list<std::string>& theArguments,
+    Events_InfoMessage& theError) const
+{
+  FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
+
+  // Collect all necessary attributes and try to build prism
+
+  // base face
+  AttributeSelectionListPtr aBaseShapeAttr =
+      aFeature->selectionList(FeaturesPlugin_Extrusion::BASE_OBJECTS_ID());
+  ListOfShape aBaseShapeList;
+  std::string anError;
+  if (!FeaturesPlugin_Tools::getShape(aBaseShapeAttr, true, aBaseShapeList, anError)) {
+    theError = anError;
+    return false;
+  }
+
+  // direction
+  AttributeSelectionPtr aSelection =
+      aFeature->selection(FeaturesPlugin_Extrusion::DIRECTION_OBJECT_ID());
+  GeomShapePtr aShape = aSelection->value();
+  if (!aShape.get() && aSelection->context().get())
+    aShape = aSelection->context()->shape();
+
+  GeomEdgePtr anEdge;
+  if (aShape.get()) {
+    if (aShape->isEdge())
+      anEdge = aShape->edge();
+    else if (aShape->isCompound()) {
+      GeomAPI_ShapeIterator anIt(aShape);
+      anEdge = anIt.current()->edge();
+    }
+  }
+
+  std::shared_ptr<GeomAPI_Dir> aDir;
+  if (anEdge.get() && anEdge->isLine())
+    aDir = anEdge->line()->direction();
+
+  // from/to shapes
+  GeomShapePtr aFromShape, aToShape;
+  aSelection = aFeature->selection(FeaturesPlugin_Extrusion::TO_OBJECT_ID());
+  if (aSelection.get()) {
+    aToShape = aSelection->value();
+    if (!aToShape.get() && aSelection->context().get())
+      aToShape = aSelection->context()->shape();
+    if (aToShape.get() && aToShape->isCompound()) {
+      GeomAPI_ShapeIterator anIt(aToShape);
+      aToShape = anIt.current();
+    }
+    if (aToShape.get() && !aToShape->isFace()) {
+      theError = "\"To\" shape is not a face";
+      return false;
+    }
+  }
+  aSelection = aFeature->selection(FeaturesPlugin_Extrusion::FROM_OBJECT_ID());
+  if (aSelection.get()) {
+    aFromShape = aSelection->value();
+    if (!aFromShape.get() && aSelection->context().get())
+      aFromShape = aSelection->context()->shape();
+    if (aFromShape.get() && aFromShape->isCompound()) {
+      GeomAPI_ShapeIterator anIt(aFromShape);
+      aFromShape = anIt.current();
+    }
+    if (aFromShape.get() && !aFromShape->isFace()) {
+      theError = "\"From\" shape is not a face";
+      return false;
+    }
+  }
+
+  double aToSize = aFeature->real(FeaturesPlugin_Extrusion::TO_OFFSET_ID())->value();
+  double aFromSize = aFeature->real(FeaturesPlugin_Extrusion::FROM_OFFSET_ID())->value();
+
+  // check extrusion
+  for (ListOfShape::iterator anIt = aBaseShapeList.begin(); anIt != aBaseShapeList.end(); anIt++) {
+    std::shared_ptr<GeomAPI_Shape> aBaseShape = *anIt;
+
+    std::shared_ptr<GeomAlgoAPI_Prism> aPrismAlgo(
+        new GeomAlgoAPI_Prism(aBaseShape, aDir, aToShape, aToSize, aFromShape, aFromSize));
+    bool isFailed = GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aPrismAlgo,
+                                                                    FeaturesPlugin_Extrusion::ID(),
+                                                                    anError);
+    if (isFailed) {
+      theError = anError;
+      return false;
+    }
+  }
+
+  return true;
+}
+
 //==================================================================================================
 bool FeaturesPlugin_ValidatorBooleanSelection::isValid(const AttributePtr& theAttribute,
                                                        const std::list<std::string>& theArguments,
index a0a4006b5902c8ed3fba385373531d35dfcb55ba..6af8824545464855b49d437f244a6cbe4674c609 100644 (file)
@@ -141,6 +141,21 @@ private:
                           Events_InfoMessage& theError) const;
 };
 
+/// \class FeaturesPlugin_ValidatorExtrusionBoundaryFace
+/// \ingroup Validators
+/// \brief A validator for extrusion from/to face attribute.
+class FeaturesPlugin_ValidatorExtrusionBoundaryFace: public ModelAPI_AttributeValidator
+{
+public:
+  //! \return true if attribute listed in the parameter arguments are planar.
+  //! \param[in] theFeature the checked feature.
+  //! \param[in] theArguments arguments of the attribute.
+  //! \param[out] theError error message.
+  virtual bool isValid(const AttributePtr& theAttribute,
+                       const std::list<std::string>& theArguments,
+                       Events_InfoMessage& theError) const;
+};
+
 /// \class FeaturesPlugin_ValidatorBooleanSelection
 /// \ingroup Validators
 /// \brief Validates selection for boolean operation.
diff --git a/src/FeaturesPlugin/Test/TestExtrusion_ByFaces01.py b/src/FeaturesPlugin/Test/TestExtrusion_ByFaces01.py
new file mode 100644 (file)
index 0000000..c7b08bb
--- /dev/null
@@ -0,0 +1,134 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamR = model.addParameter(Part_1_doc, "R", "50")
+ParamFrom = model.addParameter(Part_1_doc, "offsetFrom", "0")
+ParamTo = model.addParameter(Part_1_doc, "offsetTo", "0")
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), "R", 100, 180)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchLine_1 = Sketch_1.addLine(20, 40, -30, 40)
+SketchLine_2 = Sketch_1.addLine(-30, 40, -30, 20)
+SketchLine_3 = Sketch_1.addLine(-30, 20, 20, 20)
+SketchLine_4 = Sketch_1.addLine(20, 20, 20, 40)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_3.result(), 50)
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_2.result(), 20)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_3.endPoint(), 20)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_3.endPoint(), 20)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "Sketch_1")], model.selection(), model.selection("FACE", "Cylinder_1_1/Face_1"), "offsetTo", model.selection(), "offsetFrom")
+
+from GeomAPI import GeomAPI_Shape
+
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [6])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [24])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [48])
+model.testResultsVolumes(Extrusion_1, [47540.6])
+
+# change radius of cylinder
+ParamR.setValue(10)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [12])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [24])
+model.testResultsVolumes(Extrusion_1, [3141.59265])
+
+# check the intersected boundaries are processed well
+ParamR.setValue(30)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [5])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [18])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [36])
+model.testResultsVolumes(Extrusion_1, [25176.8518])
+
+ParamR.setValue(40);
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [6])
+model.testResultsVolumes(Extrusion_1, [36812.03])
+
+# change offsetting "To" face
+ParamTo.setValue(-20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [4])
+model.testResultsVolumes(Extrusion_1, [12566.37])
+
+ParamTo.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [6])
+model.testResultsVolumes(Extrusion_1, [57985.85])
+
+# offset "From" face
+ParamFrom.setValue(-20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [6])
+model.testResultsVolumes(Extrusion_1, [37985.85])
+
+ParamFrom.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [6])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [24])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [48])
+model.testResultsVolumes(Extrusion_1, [77985.85])
+
+model.testHaveNamingSubshapes(Extrusion_1, model, Part_1_doc)
+
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestExtrusion_ByFaces02.py b/src/FeaturesPlugin/Test/TestExtrusion_ByFaces02.py
new file mode 100644 (file)
index 0000000..a55c34e
--- /dev/null
@@ -0,0 +1,124 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamR = model.addParameter(Part_1_doc, "R", "50")
+ParamFrom = model.addParameter(Part_1_doc, "offsetFrom", "0")
+ParamTo = model.addParameter(Part_1_doc, "offsetTo", "0")
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), "R", 100, 180)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Cylinder_1_1")], model.selection("EDGE", "PartSet/OY"), 50)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchLine_1 = Sketch_1.addLine(20, 40, -30, 40)
+SketchLine_2 = Sketch_1.addLine(-30, 40, -30, 20)
+SketchLine_3 = Sketch_1.addLine(-30, 20, 20, 20)
+SketchLine_4 = Sketch_1.addLine(20, 20, 20, 40)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_3.result(), 50)
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_2.result(), 20)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_3.endPoint(), 20)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_3.endPoint(), 20)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "Sketch_1")], model.selection(), model.selection("FACE", "Translation_1_1/MF:Translated&Cylinder_1_1/Face_1"), "offsetTo", model.selection(), "offsetFrom")
+
+from GeomAPI import GeomAPI_Shape
+
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [6])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [24])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [48])
+model.testResultsVolumes(Extrusion_1, [97540.6])
+
+# change radius of cylinder and check failure
+ParamR.setValue(10)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure, check the intersected boundaries are processed well
+ParamR.setValue(30)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [6])
+model.testResultsVolumes(Extrusion_1, [75176.8518])
+
+ParamR.setValue(40);
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [6])
+model.testResultsVolumes(Extrusion_1, [86812.03])
+
+# change offsetting "To" face and check failure
+ParamTo.setValue(-20)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure
+ParamTo.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [6])
+model.testResultsVolumes(Extrusion_1, [107985.85])
+
+# offset "From" face
+ParamFrom.setValue(-20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [6])
+model.testResultsVolumes(Extrusion_1, [87985.85])
+
+ParamFrom.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [6])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [24])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [48])
+model.testResultsVolumes(Extrusion_1, [127985.85])
+
+model.testHaveNamingSubshapes(Extrusion_1, model, Part_1_doc)
+
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestExtrusion_ByFaces03.py b/src/FeaturesPlugin/Test/TestExtrusion_ByFaces03.py
new file mode 100644 (file)
index 0000000..83608d6
--- /dev/null
@@ -0,0 +1,154 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamR = model.addParameter(Part_1_doc, "R", "50")
+ParamSize = model.addParameter(Part_1_doc, "Size", "50")
+ParamFrom = model.addParameter(Part_1_doc, "offsetFrom", "0")
+ParamTo = model.addParameter(Part_1_doc, "offsetTo", "0")
+Sphere_1 = model.addSphere(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), "R")
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Sphere_1_1"), model.selection("FACE", "PartSet/XOZ")])
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/XOZ"), 10, False)
+Sketch_1 = model.addSketch(Part_1_doc, model.selection("FACE", "Plane_1"))
+SketchLine_1 = Sketch_1.addLine(50, -50, -50, -50)
+SketchLine_2 = Sketch_1.addLine(-50, -50, -50, 50)
+SketchLine_3 = Sketch_1.addLine(-50, 50, 50, 50)
+SketchLine_4 = Sketch_1.addLine(50, 50, 50, -50)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_4.result(), "Size", True)
+SketchConstraintDistance_2 = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_2.result(), "Size", True)
+SketchConstraintDistance_3 = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_1.result(), "Size", True)
+SketchConstraintDistance_4 = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_3.result(), "Size", True)
+model.do()
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchLine_3r-SketchLine_2r-SketchLine_1r")])
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchLine_5 = Sketch_2.addLine(20, -15, 20, 20)
+SketchLine_6 = Sketch_2.addLine(20, 20, -15, 20)
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintVertical_3 = Sketch_2.setVertical(SketchLine_5.result())
+SketchConstraintHorizontal_3 = Sketch_2.setHorizontal(SketchLine_6.result())
+SketchArc_1 = Sketch_2.addArc(0, 0, -15, 20, 20, -15, False)
+SketchConstraintCoincidence_6 = Sketch_2.setCoincident(SketchLine_6.endPoint(), SketchArc_1.startPoint())
+SketchConstraintCoincidence_7 = Sketch_2.setCoincident(SketchArc_1.endPoint(), SketchLine_5.startPoint())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_5.result(), SketchLine_6.result())
+SketchConstraintDistance_5 = Sketch_2.setDistance(SketchArc_1.center(), SketchLine_5.result(), 20, True)
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_8 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchArc_1.center())
+SketchConstraintRadius_1 = Sketch_2.setRadius(SketchArc_1.results()[1], 25)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_5r-SketchLine_6f-SketchArc_1_2f")], model.selection(), model.selection("FACE", "Partition_1_1_2/Modified_Face&Sphere_1_1/Face_1"), "offsetTo", model.selection("FACE", "Face_1_1"), "offsetFrom")
+
+from GeomAPI import GeomAPI_Shape
+
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [5])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [18])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [36])
+model.testResultsVolumes(Extrusion_1, [100878.6])
+
+# change radius of sphere and check failure
+ParamR.setValue(10)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure, check the intersected boundaries are processed well
+ParamR.setValue(30)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [5])
+model.testResultsVolumes(Extrusion_1, [60964.23998])
+
+ParamR.setValue(40);
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [5])
+model.testResultsVolumes(Extrusion_1, [81651.666])
+
+# change size of the face
+ParamSize.setValue(10)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [5])
+model.testResultsVolumes(Extrusion_1, [81651.666])
+
+# change offsetting "To" face and check failure
+ParamTo.setValue(-20)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure
+ParamTo.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [5])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [22])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [44])
+model.testResultsVolumes(Extrusion_1, [119535.04])
+
+# offset "From" face
+ParamFrom.setValue(-20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [5])
+model.testResultsVolumes(Extrusion_1, [84126.377])
+
+ParamFrom.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [5])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [22])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [44])
+model.testResultsVolumes(Extrusion_1, [154943.7])
+
+model.testHaveNamingSubshapes(Extrusion_1, model, Part_1_doc)
+
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestExtrusion_ByFaces04.py b/src/FeaturesPlugin/Test/TestExtrusion_ByFaces04.py
new file mode 100644 (file)
index 0000000..7e8a0eb
--- /dev/null
@@ -0,0 +1,132 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+from GeomAPI import GeomAPI_Shape
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamR = model.addParameter(Part_1_doc, "R", "50")
+ParamSize = model.addParameter(Part_1_doc, "Size", "50")
+ParamFrom = model.addParameter(Part_1_doc, "offsetFrom", "0")
+ParamTo = model.addParameter(Part_1_doc, "offsetTo", "0")
+Sphere_1 = model.addSphere(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), "R")
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Sphere_1_1"), model.selection("FACE", "PartSet/XOZ")])
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/XOZ"), 30, False)
+Sketch_1 = model.addSketch(Part_1_doc, model.selection("FACE", "Plane_1"))
+SketchLine_1 = Sketch_1.addLine(50, -50, -50, -50)
+SketchLine_2 = Sketch_1.addLine(-50, -50, -50, 50)
+SketchLine_3 = Sketch_1.addLine(-50, 50, 50, 50)
+SketchLine_4 = Sketch_1.addLine(50, 50, 50, -50)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_4.result(), "Size", True)
+SketchConstraintDistance_2 = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_2.result(), "Size", True)
+SketchConstraintDistance_3 = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_1.result(), "Size", True)
+SketchConstraintDistance_4 = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_3.result(), "Size", True)
+model.do()
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchLine_3r-SketchLine_2r-SketchLine_1r")])
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchLine_5 = Sketch_2.addLine(20, -40.3112887414928, 20, 20)
+SketchLine_6 = Sketch_2.addLine(20, 20, -40.31128874149281, 20.00000000000001)
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintVertical_3 = Sketch_2.setVertical(SketchLine_5.result())
+SketchConstraintHorizontal_3 = Sketch_2.setHorizontal(SketchLine_6.result())
+SketchArc_1 = Sketch_2.addArc(0, 0, -40.31128874149281, 20.00000000000001, 20, -40.3112887414928, False)
+SketchConstraintCoincidence_6 = Sketch_2.setCoincident(SketchLine_6.endPoint(), SketchArc_1.startPoint())
+SketchConstraintCoincidence_7 = Sketch_2.setCoincident(SketchArc_1.endPoint(), SketchLine_5.startPoint())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_5.result(), SketchLine_6.result())
+SketchConstraintDistance_5 = Sketch_2.setDistance(SketchArc_1.center(), SketchLine_5.result(), 20, True)
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_8 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchArc_1.center())
+SketchConstraintRadius_1 = Sketch_2.setRadius(SketchArc_1.results()[1], 45)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_5r-SketchLine_6f-SketchArc_1_2f")], model.selection(), model.selection("FACE", "Partition_1_1_1/Modified_Face&Sphere_1_1/Face_1"), "offsetTo", model.selection("FACE", "Face_1_1"), "offsetFrom")
+
+# extrusion have to fail because of several results with shared topology
+assert(Extrusion_1.feature().error() != "")
+
+# change radius of sphere and check failure
+ParamR.setValue(10)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+ParamR.setValue(45)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# change offsetting "To" face and check failure
+ParamTo.setValue(-20)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure
+ParamTo.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [5])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [22])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [44])
+model.testResultsVolumes(Extrusion_1, [105008.93])
+
+# offset "From" face
+ParamFrom.setValue(-20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [5])
+model.testResultsVolumes(Extrusion_1, [179594.5])
+
+# check failure
+ParamFrom.setValue(20)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure
+ParamTo.setValue(0)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [5])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [21])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [42])
+model.testResultsVolumes(Extrusion_1, [62569.416])
+
+model.testHaveNamingSubshapes(Extrusion_1, model, Part_1_doc)
+
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestExtrusion_ByFaces05.py b/src/FeaturesPlugin/Test/TestExtrusion_ByFaces05.py
new file mode 100644 (file)
index 0000000..fff109f
--- /dev/null
@@ -0,0 +1,161 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamRSph = model.addParameter(Part_1_doc, "rSphere", "50")
+ParamRCyl = model.addParameter(Part_1_doc, "rCyl", "30")
+ParamRCir = model.addParameter(Part_1_doc, "rCircle", "10")
+ParamFrom = model.addParameter(Part_1_doc, "offsetFrom", "0")
+ParamTo = model.addParameter(Part_1_doc, "offsetTo", "0")
+Sphere_1 = model.addSphere(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), "rSphere")
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), "rCyl", 100)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchCircle_1 = Sketch_1.addCircle(15, 20, 10)
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], "rCircle")
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchCircle_1.center(), 15)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchCircle_1.center(), 20)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2r")], model.selection(), model.selection("FACE", "Sphere_1_1/Face_1"), "offsetTo", model.selection("FACE", "Cylinder_1_1/Face_1"), "offsetFrom")
+
+from GeomAPI import GeomAPI_Shape
+
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [6])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [12])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [24])
+model.testResultsVolumes(Extrusion_1, [10878.5462])
+
+# change radius of sketch circle
+ParamRCir.setValue(17)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [5])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [18])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [36])
+model.testResultsVolumes(Extrusion_1, [32102.718377])
+
+# change radius of sphere and check failure
+ParamRSph.setValue(10)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [6])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [18])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [36])
+model.testResultsVolumes(Extrusion_1, [42694.3277614])
+
+# change radius of sketch circle and check failure
+ParamRCir.setValue(10)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure
+ParamRSph.setValue(45);
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [6])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [12])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [24])
+model.testResultsVolumes(Extrusion_1, [7083.567843])
+
+# change radius of cylinder
+ParamRCyl.setValue(10)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [5])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [12])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [24])
+model.testResultsVolumes(Extrusion_1, [22295.845141])
+
+ParamRCyl.setValue(50)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [6])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [12])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [24])
+model.testResultsVolumes(Extrusion_1, [6805.1007457])
+
+# change offsetting "To" face
+ParamTo.setValue(-20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [5])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [18])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [36])
+model.testResultsVolumes(Extrusion_1, [26158.63076])
+
+# revert failure
+ParamTo.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [6])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [16])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [32])
+model.testResultsVolumes(Extrusion_1, [7626.2279286])
+
+# offset "From" face
+ParamFrom.setValue(-20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [6])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [20])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [40])
+model.testResultsVolumes(Extrusion_1, [21514.8965])
+
+ParamFrom.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [6])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [20])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [40])
+model.testResultsVolumes(Extrusion_1, [5427.194275658])
+
+model.testHaveNamingSubshapes(Extrusion_1, model, Part_1_doc)
+
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestExtrusion_ByFaces06.py b/src/FeaturesPlugin/Test/TestExtrusion_ByFaces06.py
new file mode 100644 (file)
index 0000000..095c967
--- /dev/null
@@ -0,0 +1,115 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamR = model.addParameter(Part_1_doc, "R", "50")
+ParamFrom = model.addParameter(Part_1_doc, "offsetFrom", "0")
+ParamTo = model.addParameter(Part_1_doc, "offsetTo", "0")
+Cone_1 = model.addCone(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), "R", "R/5", "R")
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Cone_1_1"), model.selection("FACE", "PartSet/XOZ")])
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/XOZ"), 20, False)
+Plane_5 = model.addPlane(Part_1_doc, model.selection("FACE", "Plane_1"), model.selection("EDGE", "PartSet/OZ"), 330)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchLine_1 = Sketch_1.addLine(10, 8.819660112501044, 10, 30)
+SketchLine_2 = Sketch_1.addLine(10, 30, -11.18033988749895, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_1.result())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_2.result())
+SketchArc_1 = Sketch_1.addArc(0, 20, -11.18033988749895, 30, 10, 8.819660112501044, False)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchArc_1.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_1.startPoint())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_2.result())
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchArc_1.center(), SketchLine_1.result(), 10, True)
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchArc_1.results()[1], 15)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OZ"), False)
+SketchLine_3 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchArc_1.center(), SketchLine_3.result())
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchAPI_Line(SketchLine_3).startPoint(), SketchArc_1.center(), 20)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchArc_1_2f")], model.selection(), model.selection("FACE", "Partition_1_1_2/Modified_Face&Cone_1_1/Face_1"), "offsetTo", model.selection("FACE", "Plane_2"), "offsetFrom")
+
+from GeomAPI import GeomAPI_Shape
+
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [5])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [20])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [40])
+model.testResultsVolumes(Extrusion_1, [31363.4963946])
+
+# change radius of sphere and check failure
+ParamR.setValue(10)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure, check the intersected boundaries are processed well
+ParamR.setValue(40)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [5])
+model.testResultsVolumes(Extrusion_1, [25645.0102138])
+
+# change offsetting "To" face and check failure
+ParamTo.setValue(-20)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure
+ParamTo.setValue(8)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [5])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [20])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [40])
+model.testResultsVolumes(Extrusion_1, [31501.9671234])
+
+# offset "From" face
+ParamFrom.setValue(-20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [5])
+model.testResultsVolumes(Extrusion_1, [18737.752452])
+
+ParamFrom.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [5])
+model.testResultsVolumes(Extrusion_1, [44266.1817647])
+
+model.testHaveNamingSubshapes(Extrusion_1, model, Part_1_doc)
+
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestExtrusion_ByFaces07.py b/src/FeaturesPlugin/Test/TestExtrusion_ByFaces07.py
new file mode 100644 (file)
index 0000000..0318fcd
--- /dev/null
@@ -0,0 +1,143 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamR = model.addParameter(Part_1_doc, "R", "50")
+ParamFrom = model.addParameter(Part_1_doc, "offsetFrom", "0")
+ParamTo = model.addParameter(Part_1_doc, "offsetTo", "0")
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), "R", 100, 180)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchLine_1 = Sketch_1.addLine(20, 40, -30, 40)
+SketchLine_2 = Sketch_1.addLine(-30, 40, -30, 20)
+SketchLine_3 = Sketch_1.addLine(-30, 20, 20, 20)
+SketchLine_4 = Sketch_1.addLine(20, 20, 20, 40)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_3.result(), 50)
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_2.result(), 20)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_3.endPoint(), 20)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_3.endPoint(), 20)
+SketchLine_5 = Sketch_1.addLine(-10, 20, 5, 40)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_5.startPoint(), SketchLine_3.result())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_1.result())
+SketchConstraintDistanceHorizontal_2 = Sketch_1.setHorizontalDistance(SketchLine_2.endPoint(), SketchLine_5.startPoint(), 20)
+SketchConstraintDistanceHorizontal_3 = Sketch_1.setHorizontalDistance(SketchLine_5.endPoint(), SketchLine_1.startPoint(), 15)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "Sketch_1")], model.selection(), model.selection("FACE", "Cylinder_1_1/Face_1"), "offsetTo", model.selection(), "offsetFrom")
+
+from GeomAPI import GeomAPI_Shape
+
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [12])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [48])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [96])
+model.testResultsVolumes(Extrusion_1, [47540.6])
+
+# change radius of cylinder
+ParamR.setValue(10)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [9])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [28])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [56])
+model.testResultsVolumes(Extrusion_1, [3141.59265])
+
+# check the intersected boundaries are processed well
+ParamR.setValue(30)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [11])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [42])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [84])
+model.testResultsVolumes(Extrusion_1, [25176.8518])
+
+ParamR.setValue(40);
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [12])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [48])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [96])
+model.testResultsVolumes(Extrusion_1, [36812.03])
+
+# change offsetting "To" face
+ParamTo.setValue(-20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [10])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [36])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [72])
+model.testResultsVolumes(Extrusion_1, [12566.37])
+
+ParamTo.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [12])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [48])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [96])
+model.testResultsVolumes(Extrusion_1, [57985.85])
+
+# offset "From" face
+ParamFrom.setValue(-20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [12])
+model.testResultsVolumes(Extrusion_1, [37985.85])
+
+ParamFrom.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [12])
+model.testResultsVolumes(Extrusion_1, [77985.85])
+
+model.testHaveNamingSubshapes(Extrusion_1, model, Part_1_doc)
+
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestExtrusion_ByFaces08.py b/src/FeaturesPlugin/Test/TestExtrusion_ByFaces08.py
new file mode 100644 (file)
index 0000000..18ce0b4
--- /dev/null
@@ -0,0 +1,129 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamR = model.addParameter(Part_1_doc, "R", "50")
+ParamFrom = model.addParameter(Part_1_doc, "offsetFrom", "0")
+ParamTo = model.addParameter(Part_1_doc, "offsetTo", "0")
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), "R", 100, 180)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Cylinder_1_1")], model.selection("EDGE", "PartSet/OY"), 50)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchLine_1 = Sketch_1.addLine(20, 40, -30, 40)
+SketchLine_2 = Sketch_1.addLine(-30, 40, -30, 20)
+SketchLine_3 = Sketch_1.addLine(-30, 20, 20, 20)
+SketchLine_4 = Sketch_1.addLine(20, 20, 20, 40)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_3.result(), 50)
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_2.result(), 20)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_3.endPoint(), 20)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_3.endPoint(), 20)
+SketchLine_5 = Sketch_1.addLine(-10, 20, 5, 40)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_5.startPoint(), SketchLine_3.result())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_1.result())
+SketchConstraintDistanceHorizontal_2 = Sketch_1.setHorizontalDistance(SketchLine_2.endPoint(), SketchLine_5.startPoint(), 20)
+SketchConstraintDistanceHorizontal_3 = Sketch_1.setHorizontalDistance(SketchLine_5.endPoint(), SketchLine_1.startPoint(), 15)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f-SketchLine_5f"), model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_5r-SketchLine_3f-SketchLine_4f")], model.selection(), model.selection("FACE", "Translation_1_1/MF:Translated&Cylinder_1_1/Face_1"), "offsetTo", model.selection(), "offsetFrom")
+
+from GeomAPI import GeomAPI_Shape
+
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [12])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [48])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [96])
+model.testResultsVolumes(Extrusion_1, [97540.6])
+
+# change radius of cylinder and check failure
+ParamR.setValue(10)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure, check the intersected boundaries are processed well
+ParamR.setValue(30)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [12])
+model.testResultsVolumes(Extrusion_1, [75176.8518])
+
+ParamR.setValue(40);
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [12])
+model.testResultsVolumes(Extrusion_1, [86812.03])
+
+# change offsetting "To" face and check failure
+ParamTo.setValue(-25)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure
+ParamTo.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [12])
+model.testResultsVolumes(Extrusion_1, [107985.85])
+
+# offset "From" face
+ParamFrom.setValue(-20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [12])
+model.testResultsVolumes(Extrusion_1, [87985.85])
+
+ParamFrom.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [12])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [48])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [96])
+model.testResultsVolumes(Extrusion_1, [127985.85])
+
+model.testHaveNamingSubshapes(Extrusion_1, model, Part_1_doc)
+
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestExtrusion_ByFaces09.py b/src/FeaturesPlugin/Test/TestExtrusion_ByFaces09.py
new file mode 100644 (file)
index 0000000..da81086
--- /dev/null
@@ -0,0 +1,157 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamR = model.addParameter(Part_1_doc, "R", "50")
+ParamSize = model.addParameter(Part_1_doc, "Size", "50")
+ParamFrom = model.addParameter(Part_1_doc, "offsetFrom", "0")
+ParamTo = model.addParameter(Part_1_doc, "offsetTo", "0")
+Sphere_1 = model.addSphere(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), "R")
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Sphere_1_1"), model.selection("FACE", "PartSet/XOZ")])
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/XOZ"), 10, False)
+Sketch_1 = model.addSketch(Part_1_doc, model.selection("FACE", "Plane_1"))
+SketchLine_1 = Sketch_1.addLine(50, -50, -50, -50)
+SketchLine_2 = Sketch_1.addLine(-50, -50, -50, 50)
+SketchLine_3 = Sketch_1.addLine(-50, 50, 50, 50)
+SketchLine_4 = Sketch_1.addLine(50, 50, 50, -50)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_4.result(), "Size", True)
+SketchConstraintDistance_2 = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_2.result(), "Size", True)
+SketchConstraintDistance_3 = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_1.result(), "Size", True)
+SketchConstraintDistance_4 = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_3.result(), "Size", True)
+model.do()
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchLine_3r-SketchLine_2r-SketchLine_1r")])
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchLine_5 = Sketch_2.addLine(20, -15, 20, 20)
+SketchLine_6 = Sketch_2.addLine(20, 20, -15, 20)
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintVertical_3 = Sketch_2.setVertical(SketchLine_5.result())
+SketchConstraintHorizontal_3 = Sketch_2.setHorizontal(SketchLine_6.result())
+SketchArc_1 = Sketch_2.addArc(0, 0, -15, 20, 20, -15, False)
+SketchConstraintCoincidence_6 = Sketch_2.setCoincident(SketchLine_6.endPoint(), SketchArc_1.startPoint())
+SketchConstraintCoincidence_7 = Sketch_2.setCoincident(SketchArc_1.endPoint(), SketchLine_5.startPoint())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_5.result(), SketchLine_6.result())
+SketchConstraintDistance_5 = Sketch_2.setDistance(SketchArc_1.center(), SketchLine_5.result(), 20, True)
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_8 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchArc_1.center())
+SketchConstraintRadius_1 = Sketch_2.setRadius(SketchArc_1.results()[1], 25)
+SketchLine_7 = Sketch_2.addLine(-15, 20, 20, -15)
+SketchConstraintCoincidence_9 = Sketch_2.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+SketchConstraintCoincidence_10 = Sketch_2.setCoincident(SketchLine_5.startPoint(), SketchLine_7.endPoint())
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchArc_1_2f-SketchLine_7r"), model.selection("FACE", "Sketch_2/Face-SketchLine_5r-SketchLine_6f-SketchLine_7f")], model.selection(), model.selection("FACE", "Partition_1_1_2/Modified_Face&Sphere_1_1/Face_1"), "offsetTo", model.selection("FACE", "Face_1_1"), "offsetFrom")
+
+from GeomAPI import GeomAPI_Shape
+
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [9])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [30])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [60])
+model.testResultsVolumes(Extrusion_1, [100878.6])
+
+# change radius of sphere and check failure
+ParamR.setValue(10)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure, check the intersected boundaries are processed well
+ParamR.setValue(30)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [9])
+model.testResultsVolumes(Extrusion_1, [60964.23998])
+
+ParamR.setValue(40);
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [9])
+model.testResultsVolumes(Extrusion_1, [81651.666])
+
+# change size of the face
+ParamSize.setValue(10)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [9])
+model.testResultsVolumes(Extrusion_1, [81651.666])
+
+# change offsetting "To" face and check failure
+ParamTo.setValue(-20)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure
+ParamTo.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [9])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [34])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [68])
+model.testResultsVolumes(Extrusion_1, [119535.04])
+
+# offset "From" face
+ParamFrom.setValue(-20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [9])
+model.testResultsVolumes(Extrusion_1, [84126.377])
+
+ParamFrom.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [9])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [34])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [68])
+model.testResultsVolumes(Extrusion_1, [154943.7])
+
+model.testHaveNamingSubshapes(Extrusion_1, model, Part_1_doc)
+
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestExtrusion_ByFaces10.py b/src/FeaturesPlugin/Test/TestExtrusion_ByFaces10.py
new file mode 100644 (file)
index 0000000..e618ca6
--- /dev/null
@@ -0,0 +1,136 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+from GeomAPI import GeomAPI_Shape
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamR = model.addParameter(Part_1_doc, "R", "50")
+ParamSize = model.addParameter(Part_1_doc, "Size", "50")
+ParamFrom = model.addParameter(Part_1_doc, "offsetFrom", "0")
+ParamTo = model.addParameter(Part_1_doc, "offsetTo", "0")
+Sphere_1 = model.addSphere(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), "R")
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Sphere_1_1"), model.selection("FACE", "PartSet/XOZ")])
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/XOZ"), 30, False)
+Sketch_1 = model.addSketch(Part_1_doc, model.selection("FACE", "Plane_1"))
+SketchLine_1 = Sketch_1.addLine(50, -50, -50, -50)
+SketchLine_2 = Sketch_1.addLine(-50, -50, -50, 50)
+SketchLine_3 = Sketch_1.addLine(-50, 50, 50, 50)
+SketchLine_4 = Sketch_1.addLine(50, 50, 50, -50)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_4.result(), "Size", True)
+SketchConstraintDistance_2 = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_2.result(), "Size", True)
+SketchConstraintDistance_3 = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_1.result(), "Size", True)
+SketchConstraintDistance_4 = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_3.result(), "Size", True)
+model.do()
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchLine_3r-SketchLine_2r-SketchLine_1r")])
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchLine_5 = Sketch_2.addLine(20, -40.3112887414928, 20, 20)
+SketchLine_6 = Sketch_2.addLine(20, 20, -40.31128874149281, 20.00000000000001)
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintVertical_3 = Sketch_2.setVertical(SketchLine_5.result())
+SketchConstraintHorizontal_3 = Sketch_2.setHorizontal(SketchLine_6.result())
+SketchArc_1 = Sketch_2.addArc(0, 0, -40.31128874149281, 20.00000000000001, 20, -40.3112887414928, False)
+SketchConstraintCoincidence_6 = Sketch_2.setCoincident(SketchLine_6.endPoint(), SketchArc_1.startPoint())
+SketchConstraintCoincidence_7 = Sketch_2.setCoincident(SketchArc_1.endPoint(), SketchLine_5.startPoint())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_5.result(), SketchLine_6.result())
+SketchConstraintDistance_5 = Sketch_2.setDistance(SketchArc_1.center(), SketchLine_5.result(), 20, True)
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_8 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchArc_1.center())
+SketchConstraintRadius_1 = Sketch_2.setRadius(SketchArc_1.results()[1], 45)
+SketchLine_7 = Sketch_2.addLine(20, 20, -31.81980515339464, -31.81980515339464)
+SketchConstraintCoincidence_9 = Sketch_2.setCoincident(SketchLine_5.endPoint(), SketchLine_7.startPoint())
+SketchConstraintCoincidence_10 = Sketch_2.setCoincident(SketchLine_7.endPoint(), SketchArc_1.results()[1])
+SketchConstraintCoincidence_11 = Sketch_2.setCoincident(SketchArc_1.center(), SketchLine_7.result())
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "Sketch_2")], model.selection(), model.selection("FACE", "Partition_1_1_1/Modified_Face&Sphere_1_1/Face_1"), "offsetTo", model.selection("FACE", "Face_1_1"), "offsetFrom")
+
+# extrusion have to fail because of several results with shared topology
+assert(Extrusion_1.feature().error() != "")
+
+# change radius of sphere and check failure
+ParamR.setValue(10)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+ParamR.setValue(45)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# change offsetting "To" face and check failure
+ParamTo.setValue(-20)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure
+ParamTo.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [10])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [40])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [80])
+model.testResultsVolumes(Extrusion_1, [105008.93])
+
+# offset "From" face
+ParamFrom.setValue(-20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [10])
+model.testResultsVolumes(Extrusion_1, [179594.5])
+
+# check failure
+ParamFrom.setValue(20)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure
+ParamTo.setValue(0)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [10])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [39])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [78])
+model.testResultsVolumes(Extrusion_1, [62569.416])
+
+model.testHaveNamingSubshapes(Extrusion_1, model, Part_1_doc)
+
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestExtrusion_ByFaces11.py b/src/FeaturesPlugin/Test/TestExtrusion_ByFaces11.py
new file mode 100644 (file)
index 0000000..f66471f
--- /dev/null
@@ -0,0 +1,166 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamRSph = model.addParameter(Part_1_doc, "rSphere", "50")
+ParamRCyl = model.addParameter(Part_1_doc, "rCyl", "30")
+ParamRCir = model.addParameter(Part_1_doc, "rCircle", "10")
+ParamFrom = model.addParameter(Part_1_doc, "offsetFrom", "0")
+ParamTo = model.addParameter(Part_1_doc, "offsetTo", "0")
+Sphere_1 = model.addSphere(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), "rSphere")
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), "rCyl", 100)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchCircle_1 = Sketch_1.addCircle(15, 20, 10)
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], "rCircle")
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchCircle_1.center(), 15)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchCircle_1.center(), 20)
+SketchLine_1 = Sketch_1.addLine(6.339745962155468, 15, 23.66025403784453, 15)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchCircle_1.results()[1])
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchCircle_1.results()[1])
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchCircle_1.center(), SketchLine_1.result(), "rCircle/2", True)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2r-SketchCircle_1_2r-SketchLine_1r"), model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2r-SketchLine_1f")], model.selection(), model.selection("FACE", "Sphere_1_1/Face_1"), "offsetTo", model.selection("FACE", "Cylinder_1_1/Face_1"), "offsetFrom")
+
+from GeomAPI import GeomAPI_Shape
+
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [18])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [60])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [120])
+model.testResultsVolumes(Extrusion_1, [10878.5462])
+
+# change radius of sketch circle
+ParamRCir.setValue(17)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [3])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [3])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [17])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [66])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [132])
+model.testResultsVolumes(Extrusion_1, [32102.71838])
+
+# change radius of sphere and check failure
+ParamRSph.setValue(15)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [13])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [61])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [122])
+model.testResultsVolumes(Extrusion_1, [41289.10946])
+
+# change radius of sketch circle and check failure
+ParamRCir.setValue(10)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure
+ParamRSph.setValue(45);
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [18])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [60])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [120])
+model.testResultsVolumes(Extrusion_1, [7083.567842])
+
+# change radius of cylinder
+ParamRCyl.setValue(10)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [13])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [54])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [108])
+model.testResultsVolumes(Extrusion_1, [22295.845141])
+
+ParamRCyl.setValue(50)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [18])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [60])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [120])
+model.testResultsVolumes(Extrusion_1, [6805.1007457])
+
+# change offsetting "To" face
+ParamTo.setValue(-20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [14])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [60])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [120])
+model.testResultsVolumes(Extrusion_1, [26158.63076])
+
+# revert failure
+ParamTo.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [18])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [64])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [128])
+model.testResultsVolumes(Extrusion_1, [7626.2279286])
+
+# offset "From" face
+ParamFrom.setValue(-20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [18])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [68])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [136])
+model.testResultsVolumes(Extrusion_1, [21514.8965])
+
+ParamFrom.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [18])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [68])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [136])
+model.testResultsVolumes(Extrusion_1, [5427.194275658])
+
+model.testHaveNamingSubshapes(Extrusion_1, model, Part_1_doc)
+
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestExtrusion_ByFaces12.py b/src/FeaturesPlugin/Test/TestExtrusion_ByFaces12.py
new file mode 100644 (file)
index 0000000..5473797
--- /dev/null
@@ -0,0 +1,120 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamR = model.addParameter(Part_1_doc, "R", "50")
+ParamFrom = model.addParameter(Part_1_doc, "offsetFrom", "0")
+ParamTo = model.addParameter(Part_1_doc, "offsetTo", "0")
+Cone_1 = model.addCone(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), "R", "R/5", "R")
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Cone_1_1"), model.selection("FACE", "PartSet/XOZ")])
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/XOZ"), 20, False)
+Plane_5 = model.addPlane(Part_1_doc, model.selection("FACE", "Plane_1"), model.selection("EDGE", "PartSet/OZ"), 330)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchLine_1 = Sketch_1.addLine(10, 8.819660112501044, 10, 30)
+SketchLine_2 = Sketch_1.addLine(10, 30, -11.18033988749895, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_1.result())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_2.result())
+SketchArc_1 = Sketch_1.addArc(0, 20, -11.18033988749895, 30, 10, 8.819660112501044, False)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchArc_1.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_1.startPoint())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_2.result())
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchArc_1.center(), SketchLine_1.result(), 10, True)
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchArc_1.results()[1], 15)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OZ"), False)
+SketchLine_3 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchArc_1.center(), SketchLine_3.result())
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchAPI_Line(SketchLine_3).startPoint(), SketchArc_1.center(), 20)
+SketchLine_4 = Sketch_1.addLine(-11.18033988749895, 30, 10, 8.819660112501044)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_4.endPoint())
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "Sketch_1")], model.selection(), model.selection("FACE", "Partition_1_1_2/Modified_Face&Cone_1_1/Face_1"), "offsetTo", model.selection("FACE", "Plane_2"), "offsetFrom")
+
+from GeomAPI import GeomAPI_Shape
+
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [9])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [32])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [64])
+model.testResultsVolumes(Extrusion_1, [31363.4963946])
+
+# change radius of sphere and check failure
+ParamR.setValue(10)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure, check the intersected boundaries are processed well
+ParamR.setValue(40)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [9])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [32])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [64])
+model.testResultsVolumes(Extrusion_1, [25645.0102138])
+
+# change offsetting "To" face and check failure
+ParamTo.setValue(-20)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure
+ParamTo.setValue(8)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [9])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [32])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [64])
+model.testResultsVolumes(Extrusion_1, [31501.9671234])
+
+# offset "From" face
+ParamFrom.setValue(-20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [9])
+model.testResultsVolumes(Extrusion_1, [18737.752452])
+
+ParamFrom.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [9])
+model.testResultsVolumes(Extrusion_1, [44266.1817647])
+
+model.testHaveNamingSubshapes(Extrusion_1, model, Part_1_doc)
+
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestExtrusion_ByFaces13.py b/src/FeaturesPlugin/Test/TestExtrusion_ByFaces13.py
new file mode 100644 (file)
index 0000000..710db14
--- /dev/null
@@ -0,0 +1,128 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamR = model.addParameter(Part_1_doc, "R", "50")
+ParamFrom = model.addParameter(Part_1_doc, "offsetFrom", "0")
+ParamTo = model.addParameter(Part_1_doc, "offsetTo", "0")
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), "R", 100, 180)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchLine_1 = Sketch_1.addLine(20, 40, -30, 40)
+SketchLine_2 = Sketch_1.addLine(-30, 40, -30, 20)
+SketchLine_3 = Sketch_1.addLine(-30, 20, 20, 20)
+SketchLine_4 = Sketch_1.addLine(20, 20, 20, 40)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_3.result(), 50)
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_2.result(), 20)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_3.endPoint(), 20)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_3.endPoint(), 20)
+model.do()
+Edge_1_objects = [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2"), model.selection("EDGE", "Sketch_1/SketchLine_3"), model.selection("EDGE", "Sketch_1/SketchLine_4")]
+Edge_1 = model.addEdge(Part_1_doc, Edge_1_objects)
+Extrusion_1_objects = [model.selection("EDGE", "Edge_1_1"), model.selection("EDGE", "Edge_1_2"), model.selection("EDGE", "Edge_1_3"), model.selection("EDGE", "Edge_1_4")]
+Extrusion_1 = model.addExtrusion(Part_1_doc, Extrusion_1_objects, model.selection("EDGE", "PartSet/OY"), model.selection("FACE", "Cylinder_1_1/Face_1"), "offsetTo", model.selection(), "offsetFrom")
+
+from GeomAPI import GeomAPI_Shape
+
+model.testNbResults(Extrusion_1, 4)
+model.testNbSubResults(Extrusion_1, [0, 0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0, 0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1, 1, 1, 1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4, 4, 4, 4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 8, 8])
+model.testResultsVolumes(Extrusion_1, [2377.030013, 800, 2377.030013, 916.515139])
+
+# change radius of cylinder
+ParamR.setValue(10)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+ParamR.setValue(30)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure and check the intersected boundaries are processed well
+ParamR.setValue(40);
+model.do()
+model.testNbResults(Extrusion_1, 4)
+model.testNbSubResults(Extrusion_1, [0, 0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0, 0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1, 1, 1, 1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4, 4, 4, 4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 8, 8])
+model.testResultsVolumes(Extrusion_1, [1840.601542, 529.150262, 1840.601542, 692.820323])
+
+# change offsetting "To" face
+ParamTo.setValue(-20)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure
+ParamTo.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 4)
+model.testNbSubResults(Extrusion_1, [0, 0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0, 0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1, 1, 1, 1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4, 4, 4, 4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 8, 8])
+model.testResultsVolumes(Extrusion_1, [2899.292521, 1039.2304845, 2899.292521, 1131.3708499])
+
+# offset "From" face
+ParamFrom.setValue(-20)
+model.do()
+model.testNbResults(Extrusion_1, 4)
+model.testNbSubResults(Extrusion_1, [0, 0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0, 0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1, 1, 1, 1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4, 4, 4, 4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 8, 8])
+model.testResultsVolumes(Extrusion_1, [3899.292521, 1439.2304845, 3899.292521, 1531.3708499])
+
+ParamFrom.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 4)
+model.testNbSubResults(Extrusion_1, [0, 0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0, 0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1, 1, 1, 1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4, 4, 4, 4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 8, 8])
+model.testResultsVolumes(Extrusion_1, [1899.292521, 639.2304845, 1899.292521, 731.3708499])
+
+model.testHaveNamingSubshapes(Extrusion_1, model, Part_1_doc)
+
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestExtrusion_ByFaces14.py b/src/FeaturesPlugin/Test/TestExtrusion_ByFaces14.py
new file mode 100644 (file)
index 0000000..7f8348c
--- /dev/null
@@ -0,0 +1,129 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamR = model.addParameter(Part_1_doc, "R", "50")
+ParamFrom = model.addParameter(Part_1_doc, "offsetFrom", "0")
+ParamTo = model.addParameter(Part_1_doc, "offsetTo", "0")
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), "R", 100, 180)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Cylinder_1_1")], model.selection("EDGE", "PartSet/OY"), 50)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchLine_1 = Sketch_1.addLine(20, 40, -30, 40)
+SketchLine_2 = Sketch_1.addLine(-30, 40, -30, 20)
+SketchLine_3 = Sketch_1.addLine(-30, 20, 20, 20)
+SketchLine_4 = Sketch_1.addLine(20, 20, 20, 40)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_3.result(), 50)
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_2.result(), 20)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_3.endPoint(), 20)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_3.endPoint(), 20)
+model.do()
+Edge_1_objects = [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2"), model.selection("EDGE", "Sketch_1/SketchLine_3"), model.selection("EDGE", "Sketch_1/SketchLine_4")]
+Edge_1 = model.addEdge(Part_1_doc, Edge_1_objects)
+Extrusion_1_objects = [model.selection("EDGE", "Edge_1_1"), model.selection("EDGE", "Edge_1_2"), model.selection("EDGE", "Edge_1_3"), model.selection("EDGE", "Edge_1_4")]
+Extrusion_1 = model.addExtrusion(Part_1_doc, Extrusion_1_objects, model.selection("EDGE", "PartSet/OY"), model.selection("FACE", "Translation_1_1/MF:Translated&Cylinder_1_1/Face_1"), "offsetTo", model.selection(), "offsetFrom")
+
+from GeomAPI import GeomAPI_Shape
+
+model.testNbResults(Extrusion_1, 4)
+model.testNbSubResults(Extrusion_1, [0, 0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0, 0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1, 1, 1, 1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4, 4, 4, 4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 8, 8])
+model.testResultsVolumes(Extrusion_1, [4877.030013, 1800, 4877.030013, 1916.515139])
+
+# change radius of cylinder and check failure
+ParamR.setValue(10)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+ParamR.setValue(30)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure, check the intersected boundaries are processed well
+ParamR.setValue(40);
+model.do()
+model.testNbResults(Extrusion_1, 4)
+model.testNbSubResults(Extrusion_1, [0, 0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0, 0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1, 1, 1, 1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4, 4, 4, 4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 8, 8])
+model.testResultsVolumes(Extrusion_1, [4340.6015418, 1529.1502622, 4340.6015418, 1692.820323])
+
+# change offsetting "To" face and check failure
+ParamTo.setValue(-20)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure
+ParamTo.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 4)
+model.testNbSubResults(Extrusion_1, [0, 0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0, 0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1, 1, 1, 1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4, 4, 4, 4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 8, 8])
+model.testResultsVolumes(Extrusion_1, [5399.2925211, 2039.2304845, 5399.2925212, 2131.37085])
+
+# offset "From" face
+ParamFrom.setValue(-20)
+model.do()
+model.testNbResults(Extrusion_1, 4)
+model.testNbSubResults(Extrusion_1, [0, 0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0, 0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1, 1, 1, 1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4, 4, 4, 4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 8, 8])
+model.testResultsVolumes(Extrusion_1, [6399.2925211, 2439.2304845, 6399.2925212, 2531.37085])
+
+ParamFrom.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 4)
+model.testNbSubResults(Extrusion_1, [0, 0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0, 0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1, 1, 1, 1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4, 4, 4, 4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 8, 8])
+model.testResultsVolumes(Extrusion_1, [4399.2925211, 1639.2304845, 4399.2925212, 1731.37085])
+
+model.testHaveNamingSubshapes(Extrusion_1, model, Part_1_doc)
+
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestExtrusion_ByFaces15.py b/src/FeaturesPlugin/Test/TestExtrusion_ByFaces15.py
new file mode 100644 (file)
index 0000000..a65ebac
--- /dev/null
@@ -0,0 +1,165 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamR = model.addParameter(Part_1_doc, "R", "50")
+ParamSize = model.addParameter(Part_1_doc, "Size", "50")
+ParamFrom = model.addParameter(Part_1_doc, "offsetFrom", "0")
+ParamTo = model.addParameter(Part_1_doc, "offsetTo", "0")
+Sphere_1 = model.addSphere(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), "R")
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Sphere_1_1"), model.selection("FACE", "PartSet/XOZ")])
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/XOZ"), 10, False)
+Sketch_1 = model.addSketch(Part_1_doc, model.selection("FACE", "Plane_1"))
+SketchLine_1 = Sketch_1.addLine(50, -50, -50, -50)
+SketchLine_2 = Sketch_1.addLine(-50, -50, -50, 50)
+SketchLine_3 = Sketch_1.addLine(-50, 50, 50, 50)
+SketchLine_4 = Sketch_1.addLine(50, 50, 50, -50)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_4.result(), "Size", True)
+SketchConstraintDistance_2 = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_2.result(), "Size", True)
+SketchConstraintDistance_3 = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_1.result(), "Size", True)
+SketchConstraintDistance_4 = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_3.result(), "Size", True)
+model.do()
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchLine_3r-SketchLine_2r-SketchLine_1r")])
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchLine_5 = Sketch_2.addLine(20, -15, 20, 20)
+SketchLine_6 = Sketch_2.addLine(20, 20, -15, 20)
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintVertical_3 = Sketch_2.setVertical(SketchLine_5.result())
+SketchConstraintHorizontal_3 = Sketch_2.setHorizontal(SketchLine_6.result())
+SketchArc_1 = Sketch_2.addArc(0, 0, -15, 20, 20, -15, False)
+SketchConstraintCoincidence_6 = Sketch_2.setCoincident(SketchLine_6.endPoint(), SketchArc_1.startPoint())
+SketchConstraintCoincidence_7 = Sketch_2.setCoincident(SketchArc_1.endPoint(), SketchLine_5.startPoint())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_5.result(), SketchLine_6.result())
+SketchConstraintDistance_5 = Sketch_2.setDistance(SketchArc_1.center(), SketchLine_5.result(), 20, True)
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_8 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchArc_1.center())
+SketchConstraintRadius_1 = Sketch_2.setRadius(SketchArc_1.results()[1], 25)
+model.do()
+Edge_1_objects = [model.selection("EDGE", "Sketch_2/SketchLine_5"), model.selection("EDGE", "Sketch_2/SketchLine_6"), model.selection("EDGE", "Sketch_2/SketchArc_1_2")]
+Edge_1 = model.addEdge(Part_1_doc, Edge_1_objects)
+Extrusion_1_objects = [model.selection("EDGE", "Edge_1_1"), model.selection("EDGE", "Edge_1_2"), model.selection("EDGE", "Edge_1_3")]
+Extrusion_1 = model.addExtrusion(Part_1_doc, Extrusion_1_objects, model.selection("EDGE", "PartSet/OY"), model.selection("FACE", "Partition_1_1_2/Modified_Face&Sphere_1_1/Face_1"), "offsetTo", model.selection("FACE", "Face_1_1"), "offsetFrom")
+
+from GeomAPI import GeomAPI_Shape
+
+model.testNbResults(Extrusion_1, 3)
+model.testNbSubResults(Extrusion_1, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1, 1, 1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4, 4, 4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 8])
+model.testResultsVolumes(Extrusion_1, [1911.43203298, 1911.43203298, 4564.43663366])
+
+# change radius of sphere and check failure
+ParamR.setValue(10)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure, check the intersected boundaries are processed well
+ParamR.setValue(30)
+model.do()
+model.testNbResults(Extrusion_1, 3)
+model.testNbSubResults(Extrusion_1, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1, 1, 1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4, 4, 4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 8])
+model.testResultsVolumes(Extrusion_1, [1034.989222291, 1034.989222291, 2276.43702246])
+
+ParamR.setValue(40);
+model.do()
+model.testNbResults(Extrusion_1, 3)
+model.testNbSubResults(Extrusion_1, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1, 1, 1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4, 4, 4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 8])
+model.testResultsVolumes(Extrusion_1, [1505.0174, 1505.0174, 3530.28837537636])
+
+# change size of the face
+ParamSize.setValue(10)
+model.do()
+model.testNbResults(Extrusion_1, 3)
+model.testNbSubResults(Extrusion_1, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1, 1, 1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4, 4, 4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 8])
+model.testResultsVolumes(Extrusion_1, [1505.0174, 1505.0174, 3530.28837537636])
+
+# change offsetting "To" face and check failure
+ParamTo.setValue(-20)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure
+ParamTo.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 3)
+model.testNbSubResults(Extrusion_1, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1, 1, 1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4, 4, 6])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 12])
+model.testResultsVolumes(Extrusion_1, [2295.81450653, 2295.81450653, 5527.16645028])
+
+# offset "From" face
+ParamFrom.setValue(-20)
+model.do()
+model.testNbResults(Extrusion_1, 3)
+model.testNbSubResults(Extrusion_1, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1, 1, 1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4, 4, 6])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 12])
+model.testResultsVolumes(Extrusion_1, [1595.81450653, 1595.81450653, 3814.47306888])
+
+ParamFrom.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 3)
+model.testNbSubResults(Extrusion_1, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1, 1, 1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4, 4, 6])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 12])
+model.testResultsVolumes(Extrusion_1, [2995.81450653, 2995.81450653, 7239.85983168])
+
+model.testHaveNamingSubshapes(Extrusion_1, model, Part_1_doc)
+
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestExtrusion_ByFaces16.py b/src/FeaturesPlugin/Test/TestExtrusion_ByFaces16.py
new file mode 100644 (file)
index 0000000..bd18ce0
--- /dev/null
@@ -0,0 +1,137 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+from GeomAPI import GeomAPI_Shape
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamR = model.addParameter(Part_1_doc, "R", "50")
+ParamSize = model.addParameter(Part_1_doc, "Size", "50")
+ParamFrom = model.addParameter(Part_1_doc, "offsetFrom", "0")
+ParamTo = model.addParameter(Part_1_doc, "offsetTo", "0")
+Sphere_1 = model.addSphere(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), "R")
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Sphere_1_1"), model.selection("FACE", "PartSet/XOZ")])
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/XOZ"), 30, False)
+Sketch_1 = model.addSketch(Part_1_doc, model.selection("FACE", "Plane_1"))
+SketchLine_1 = Sketch_1.addLine(50, -50, -50, -50)
+SketchLine_2 = Sketch_1.addLine(-50, -50, -50, 50)
+SketchLine_3 = Sketch_1.addLine(-50, 50, 50, 50)
+SketchLine_4 = Sketch_1.addLine(50, 50, 50, -50)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_4.result(), "Size", True)
+SketchConstraintDistance_2 = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_2.result(), "Size", True)
+SketchConstraintDistance_3 = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_1.result(), "Size", True)
+SketchConstraintDistance_4 = Sketch_1.setDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_3.result(), "Size", True)
+model.do()
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchLine_3r-SketchLine_2r-SketchLine_1r")])
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchLine_5 = Sketch_2.addLine(20, -40.3112887414928, 20, 20)
+SketchLine_6 = Sketch_2.addLine(20, 20, -40.31128874149281, 20.00000000000001)
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintVertical_3 = Sketch_2.setVertical(SketchLine_5.result())
+SketchConstraintHorizontal_3 = Sketch_2.setHorizontal(SketchLine_6.result())
+SketchArc_1 = Sketch_2.addArc(0, 0, -40.31128874149281, 20.00000000000001, 20, -40.3112887414928, False)
+SketchConstraintCoincidence_6 = Sketch_2.setCoincident(SketchLine_6.endPoint(), SketchArc_1.startPoint())
+SketchConstraintCoincidence_7 = Sketch_2.setCoincident(SketchArc_1.endPoint(), SketchLine_5.startPoint())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_5.result(), SketchLine_6.result())
+SketchConstraintDistance_5 = Sketch_2.setDistance(SketchArc_1.center(), SketchLine_5.result(), 20, True)
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_8 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchArc_1.center())
+SketchConstraintRadius_1 = Sketch_2.setRadius(SketchArc_1.results()[1], 45)
+model.do()
+Edge_1_objects = [model.selection("EDGE", "Sketch_2/SketchLine_5"), model.selection("EDGE", "Sketch_2/SketchLine_6"), model.selection("EDGE", "Sketch_2/SketchArc_1_2")]
+Edge_1 = model.addEdge(Part_1_doc, Edge_1_objects)
+Extrusion_1_objects = [model.selection("EDGE", "Edge_1_1"), model.selection("EDGE", "Edge_1_2"), model.selection("EDGE", "Edge_1_3")]
+Extrusion_1 = model.addExtrusion(Part_1_doc, Extrusion_1_objects, model.selection("EDGE", "PartSet/OY"), model.selection("FACE", "Partition_1_1_1/Modified_Face&Sphere_1_1/Face_1"), "offsetTo", model.selection("FACE", "Face_1_1"), "offsetFrom")
+
+# extrusion have to fail because of several results with shared topology
+assert(Extrusion_1.feature().error() != "")
+
+# change radius of sphere and check failure
+ParamR.setValue(10)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+ParamR.setValue(45)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# change offsetting "To" face and check failure
+ParamTo.setValue(-20)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure
+ParamTo.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 3)
+model.testNbSubResults(Extrusion_1, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1, 1, 1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4, 4, 6])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 12])
+model.testResultsVolumes(Extrusion_1, [1708.843326299, 1708.843325768, 1895.559443038])
+
+# offset "From" face
+ParamFrom.setValue(-20)
+model.do()
+model.testNbResults(Extrusion_1, 3)
+model.testNbSubResults(Extrusion_1, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1, 1, 1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4, 4, 6])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 12])
+model.testResultsVolumes(Extrusion_1, [2915.069101129, 2915.069100598, 4138.27332218])
+
+# check failure
+ParamFrom.setValue(20)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure
+ParamFrom.setValue(10)
+model.do()
+model.testNbResults(Extrusion_1, 3)
+model.testNbSubResults(Extrusion_1, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1, 1, 1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4, 4, 6])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 12])
+model.testResultsVolumes(Extrusion_1, [1105.7304388842, 1105.730438353, 774.2025034671])
+
+model.testHaveNamingSubshapes(Extrusion_1, model, Part_1_doc)
+
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestExtrusion_ByFaces17.py b/src/FeaturesPlugin/Test/TestExtrusion_ByFaces17.py
new file mode 100644 (file)
index 0000000..fd8effa
--- /dev/null
@@ -0,0 +1,162 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamRSph = model.addParameter(Part_1_doc, "rSphere", "50")
+ParamRCyl = model.addParameter(Part_1_doc, "rCyl", "30")
+ParamRCir = model.addParameter(Part_1_doc, "rCircle", "10")
+ParamFrom = model.addParameter(Part_1_doc, "offsetFrom", "0")
+ParamTo = model.addParameter(Part_1_doc, "offsetTo", "0")
+Sphere_1 = model.addSphere(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), "rSphere")
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), "rCyl", 100)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchCircle_1 = Sketch_1.addCircle(15, 20, 10)
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], "rCircle")
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchCircle_1.center(), 15)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchCircle_1.center(), 20)
+model.do()
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchCircle_1_2")])
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("EDGE", "Edge_1_1")], model.selection("EDGE", "PartSet/OY"), model.selection("FACE", "Sphere_1_1/Face_1"), "offsetTo", model.selection("FACE", "Cylinder_1_1/Face_1"), "offsetFrom")
+
+from GeomAPI import GeomAPI_Shape
+
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [8])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [16])
+model.testResultsVolumes(Extrusion_1, [2178.8497332])
+
+# change radius of sketch circle
+ParamRCir.setValue(17)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [10])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [20])
+model.testResultsVolumes(Extrusion_1, [3960.00723])
+
+# change radius of sphere
+ParamRSph.setValue(10)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [5])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [10])
+model.testResultsVolumes(Extrusion_1, [3658.7714])
+
+# change radius of sketch circle and check failure
+ParamRCir.setValue(10)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure
+ParamRSph.setValue(45);
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [8])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [16])
+model.testResultsVolumes(Extrusion_1, [1398.72992867])
+
+# change radius of cylinder
+ParamRCyl.setValue(10)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [6])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [12])
+model.testResultsVolumes(Extrusion_1, [4194.25709])
+
+ParamRCyl.setValue(50)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [8])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [16])
+model.testResultsVolumes(Extrusion_1, [1433.0518])
+
+# change offsetting "To" face
+ParamTo.setValue(-20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [10])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [20])
+model.testResultsVolumes(Extrusion_1, [5078.347278])
+
+# revert failure
+ParamTo.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [10])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [20])
+model.testResultsVolumes(Extrusion_1, [1504.36096473])
+
+# offset "From" face
+ParamFrom.setValue(-20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [12])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [24])
+model.testResultsVolumes(Extrusion_1, [4336.142699])
+
+ParamFrom.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [12])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [24])
+model.testResultsVolumes(Extrusion_1, [1118.8887326])
+
+model.testHaveNamingSubshapes(Extrusion_1, model, Part_1_doc)
+
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestExtrusion_ByFaces18.py b/src/FeaturesPlugin/Test/TestExtrusion_ByFaces18.py
new file mode 100644 (file)
index 0000000..2edfe7a
--- /dev/null
@@ -0,0 +1,120 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamR = model.addParameter(Part_1_doc, "R", "50")
+ParamFrom = model.addParameter(Part_1_doc, "offsetFrom", "0")
+ParamTo = model.addParameter(Part_1_doc, "offsetTo", "0")
+Cone_1 = model.addCone(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), "R", "R/5", "R")
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Cone_1_1"), model.selection("FACE", "PartSet/XOZ")])
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/XOZ"), 20, False)
+Plane_5 = model.addPlane(Part_1_doc, model.selection("FACE", "Plane_1"), model.selection("EDGE", "PartSet/OZ"), 330)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchLine_1 = Sketch_1.addLine(10, 8.819660112501044, 10, 30)
+SketchLine_2 = Sketch_1.addLine(10, 30, -11.18033988749895, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_1.result())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_2.result())
+SketchArc_1 = Sketch_1.addArc(0, 20, -11.18033988749895, 30, 10, 8.819660112501044, False)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchArc_1.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_1.startPoint())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_2.result())
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchArc_1.center(), SketchLine_1.result(), 10, True)
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchArc_1.results()[1], 15)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OZ"), False)
+SketchLine_3 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchArc_1.center(), SketchLine_3.result())
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchAPI_Line(SketchLine_3).startPoint(), SketchArc_1.center(), 20)
+model.do()
+Edge_1_objects = [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2"), model.selection("EDGE", "Sketch_1/SketchArc_1_2")]
+Edge_1 = model.addEdge(Part_1_doc, Edge_1_objects)
+Extrusion_1_objects = [model.selection("EDGE", "Edge_1_1"), model.selection("EDGE", "Edge_1_2"), model.selection("EDGE", "Edge_1_3")]
+Extrusion_1 = model.addExtrusion(Part_1_doc, Extrusion_1_objects, model.selection("EDGE", "PartSet/OY"), model.selection("FACE", "Partition_1_1_2/Modified_Face&Cone_1_1/Face_1"), "offsetTo", model.selection("FACE", "Plane_2"), "offsetFrom")
+
+from GeomAPI import GeomAPI_Shape
+
+model.testNbResults(Extrusion_1, 3)
+model.testNbSubResults(Extrusion_1, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1, 1, 1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4, 4, 5])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 10])
+model.testResultsVolumes(Extrusion_1, [1309.42058662, 1016.82520496, 2589.5946928])
+
+# change radius of sphere and check failure
+ParamR.setValue(10)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure, check the intersected boundaries are processed well
+ParamR.setValue(40)
+model.do()
+model.testNbResults(Extrusion_1, 3)
+model.testNbSubResults(Extrusion_1, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1, 1, 1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4, 4, 5])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 10])
+model.testResultsVolumes(Extrusion_1, [1081.93830116, 793.80218227, 2095.8021933])
+
+# change offsetting "To" face and check failure
+ParamTo.setValue(-20)
+model.do()
+assert(Extrusion_1.feature().error() != "")
+
+# revert failure
+ParamTo.setValue(8)
+model.do()
+model.testNbResults(Extrusion_1, 3)
+model.testNbSubResults(Extrusion_1, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1, 1, 1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4, 4, 5])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8, 8, 10])
+model.testResultsVolumes(Extrusion_1, [1314.8586588, 1022.169915122, 2601.32913399])
+
+# offset "From" face
+ParamFrom.setValue(-20)
+model.do()
+model.testNbResults(Extrusion_1, 3)
+model.testNbSubResults(Extrusion_1, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1, 1, 1])
+model.testResultsVolumes(Extrusion_1, [825.71966141, 533.030917699, 1551.6191757579])
+
+ParamFrom.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 3)
+model.testNbSubResults(Extrusion_1, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0, 0, 0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [1, 1, 1])
+model.testResultsVolumes(Extrusion_1, [1803.997656259, 1511.308912545, 3651.0390970659])
+
+model.testHaveNamingSubshapes(Extrusion_1, model, Part_1_doc)
+
+model.end()
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/Test/TestExtrusion_ByFaces19.py b/src/FeaturesPlugin/Test/TestExtrusion_ByFaces19.py
new file mode 100644 (file)
index 0000000..68584bc
--- /dev/null
@@ -0,0 +1,144 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamR = model.addParameter(Part_1_doc, "R", "50")
+ParamFrom = model.addParameter(Part_1_doc, "offsetFrom", "0")
+ParamTo = model.addParameter(Part_1_doc, "offsetTo", "0")
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), "R", 100, 180)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchLine_1 = Sketch_1.addLine(20, 40, -30, 40)
+SketchLine_2 = Sketch_1.addLine(-30, 40, -30, 20)
+SketchLine_3 = Sketch_1.addLine(-30, 20, 20, 20)
+SketchLine_4 = Sketch_1.addLine(20, 20, 20, 40)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_3.result(), 50)
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_2.result(), 20)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_3.endPoint(), 20)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_3.endPoint(), 20)
+model.do()
+Wire_1_objects = [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2"), model.selection("EDGE", "Sketch_1/SketchLine_3"), model.selection("EDGE", "Sketch_1/SketchLine_4")]
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects)
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("WIRE", "Wire_1_1")], model.selection("EDGE", "PartSet/OY"), model.selection("FACE", "Cylinder_1_1/Face_1"), "offsetTo", model.selection(), "offsetFrom")
+
+from GeomAPI import GeomAPI_Shape
+
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [16])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [32])
+model.testResultsVolumes(Extrusion_1, [6470.575165134267])
+
+# change radius of cylinder
+ParamR.setValue(10)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8])
+model.testResultsVolumes(Extrusion_1, [314.159265359])
+
+ParamR.setValue(30)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [3])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [10])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [20])
+model.testResultsVolumes(Extrusion_1, [2964.89877572])
+
+# check the intersected boundaries are processed well
+ParamR.setValue(40);
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [16])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [32])
+model.testResultsVolumes(Extrusion_1, [4903.173668915])
+
+# change offsetting "To" face
+ParamTo.setValue(-20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [2])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [8])
+model.testResultsVolumes(Extrusion_1, [1256.637061267])
+
+ParamTo.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [16])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [32])
+model.testResultsVolumes(Extrusion_1, [7969.186376787])
+
+# offset "From" face
+ParamFrom.setValue(-20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [16])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [32])
+model.testResultsVolumes(Extrusion_1, [10769.186376787])
+
+ParamFrom.setValue(20)
+model.do()
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [4])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [16])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [32])
+model.testResultsVolumes(Extrusion_1, [5169.186376787])
+
+model.testHaveNamingSubshapes(Extrusion_1, model, Part_1_doc)
+
+model.end()
+
+assert(model.checkPythonDump())
index d3b2b3f41a1552cfba9d5c382292bcef2c4efd7f..9bced660f2ab7eab34aef52a951df20d3c6b7b9c 100644 (file)
@@ -31,7 +31,7 @@ There are two variants of the property panel for Extrusion depending on the chos
 
 .. image:: images/extrusion_by_bounding_planes.png
    :align: left
-**By Bounding Planes** extrudes objects by specifying bounding planes and offsets.
+**By Bounding Faces** extrudes objects by specifying bounding faces/planes and offsets.
 
 
 By sizes
@@ -77,22 +77,25 @@ The Result of the operation will be an extruded shape:
 
 **See Also** a sample TUI Script of :ref:`tui_create_extrusion_by_sizes` operation.
 
-By bounding planes
+By bounding faces
 ------------------
 
 .. image:: images/Extrusion2.png
   :align: center
 
 .. centered::
-  Extrusion: definition by bounding planes
+  Extrusion: definition by bounding faces
 
 - **Base objects** - contains a list of objects selected in the Object Browser or in the Viewer, which will be extruded.
 - **Axis** if selected, it will be direction of extrusion, otherwise objects normals will be used.
-- **To plane** - a planar face can be selected to bound extrusion from one side.
+- **To face** - a face can be selected to bound extrusion from one side.
 - **To offset** - offset for extrusion or for bounding plane, if selected.
-- **From plane** - a planar face can be selected to bound extrusion from the other side.
+- **From face** - a face can be selected to bound extrusion from the other side.
 - **From offset** - offset for extrusion or for bounding plane, if selected.
 
+Planar face selected as a boundary of extrusion will be enlarged infinitely. As a result, extrusion bounded only by planar faces will be completed always.
+On the other hand, if the boundary face is not planar, extrusion may fail, for example, in case of the base object cannot be projected to this face along given direction.
+
 **TUI Command**:  *model.addExtrusion(part, objects, toObject, toOffset, fromObject, fromOffset);*
 
 **Arguments**:   Part + list of objects + to object + to offset + from object + from offset.
index de815a28a64143fa181cc822f4103e8982a74d2a..77e543915373c4d303ddaa44148bc339ade4304f 100644 (file)
       </groupbox>
     </box>
     <box id="ByPlanesAndOffsets"
-         title="By bounding planes and offsets"
+         title="By bounding faces and offsets"
          icon="icons/Features/plane_inverted_32x32.png">
       <groupbox title="From">
         <shape_selector id="from_object"
                         icon="icons/Features/plane.png"
-                        label="Plane face"
-                        tooltip="Bounding plane (select a planar face)"
+                        label="From face"
+                        tooltip="From face"
                         shape_types="face"
                         geometrical_selection="true"
                         default="&lt;base sketch&gt;">
-          <validator id="GeomValidators_Face" parameters="plane"/>
+          <validator id="FeaturesPlugin_ValidatorExtrusionBoundary"/>
         </shape_selector>
         <doublevalue id="from_offset"
                      label="Offset"
       <groupbox title="To">
         <shape_selector id="to_object"
                         icon="icons/Features/plane_inverted.png"
-                        label="Plane face"
-                        tooltip="Bounding plane (select a planar face)"
+                        label="To face"
+                        tooltip="To face"
                         shape_types="face"
                         geometrical_selection="true"
                         default="&lt;base sketch&gt;">
-          <validator id="GeomValidators_Face" parameters="plane"/>
+          <validator id="FeaturesPlugin_ValidatorExtrusionBoundary"/>
         </shape_selector>
         <doublevalue id="to_offset"
                      label="Offset"
index baeacfbaa9aabb1d1df959c52eedd0a303a55cbf..cecaa458f959ec2e12e2b2cc486983fd9dff5a9c 100644 (file)
@@ -78,6 +78,7 @@ SET(PROJECT_HEADERS
     GeomAlgoAPI_Filling.h
     GeomAlgoAPI_CurveBuilder.h
     GeomAlgoAPI_NExplode.h
+    GeomAlgoAPI_Offset.h
 )
 
 SET(PROJECT_SOURCES
@@ -135,6 +136,7 @@ SET(PROJECT_SOURCES
     GeomAlgoAPI_Filling.cpp
     GeomAlgoAPI_CurveBuilder.cpp
     GeomAlgoAPI_NExplode.cpp
+    GeomAlgoAPI_Offset.cpp
 )
 
 SET(PROJECT_LIBRARIES
diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Offset.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_Offset.cpp
new file mode 100644 (file)
index 0000000..7008b63
--- /dev/null
@@ -0,0 +1,55 @@
+// Copyright (C) 2019-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 "GeomAlgoAPI_Offset.h"
+
+#include <BRepOffsetAPI_MakeOffsetShape.hxx>
+
+
+GeomAlgoAPI_Offset::GeomAlgoAPI_Offset(const GeomShapePtr& theShape,
+                                       const double theOffsetValue)
+{
+  build(theShape, theOffsetValue);
+}
+
+void GeomAlgoAPI_Offset::build(const GeomShapePtr& theShape, const double theOffsetValue)
+{
+  BRepOffsetAPI_MakeOffsetShape* anOffsetAlgo = new BRepOffsetAPI_MakeOffsetShape;
+  anOffsetAlgo->PerformBySimple(theShape->impl<TopoDS_Shape>(), theOffsetValue);
+  setImpl(anOffsetAlgo);
+  setBuilderType(OCCT_BRepBuilderAPI_MakeShape);
+
+  if (anOffsetAlgo->IsDone()) {
+    const TopoDS_Shape& aResult = anOffsetAlgo->Shape();
+    std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape());
+    aShape->setImpl(new TopoDS_Shape(aResult));
+    setShape(aShape);
+    setDone(true);
+  }
+}
+
+void GeomAlgoAPI_Offset::generated(const GeomShapePtr theOldShape,
+                                   ListOfShape& theNewShapes)
+{
+  try {
+    GeomAlgoAPI_MakeShape::generated(theOldShape, theNewShapes);
+  } catch(...) {
+    // nothing is generated
+  }
+}
diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Offset.h b/src/GeomAlgoAPI/GeomAlgoAPI_Offset.h
new file mode 100644 (file)
index 0000000..7939f04
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright (C) 2019-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 GeomAlgoAPI_Offset_H_
+#define GeomAlgoAPI_Offset_H_
+
+#include <GeomAlgoAPI.h>
+#include <GeomAlgoAPI_MakeShape.h>
+
+/// \class GeomAlgoAPI_Offset
+/// \ingroup DataAlgo
+/// \brief Perform 3D offset for the shape
+class GeomAlgoAPI_Offset : public GeomAlgoAPI_MakeShape
+{
+public:
+  /// \brief Construct offset.
+  GEOMALGOAPI_EXPORT GeomAlgoAPI_Offset(const GeomShapePtr& theShape,
+                                        const double theOffsetValue);
+
+  /// \return the list of shapes generated from the shape \a theShape.
+  /// \param[in] theOldShape base shape.
+  /// \param[out] theNewShapes shapes generated from \a theShape. Does not cleared!
+  GEOMALGOAPI_EXPORT virtual void generated(const GeomShapePtr theOldShape,
+                                            ListOfShape& theNewShapes);
+
+private:
+  /// \brief Perform offset operation
+  void build(const GeomShapePtr& theShape, const double theOffsetValue);
+};
+
+#endif
index df1b159766611e80ea2d6b0631ae3a0ba6e9d1c0..500fbf8e6fac56cfa6bea0819585835fa3ba892e 100644 (file)
 
 #include "GeomAlgoAPI_Prism.h"
 
+#include <GeomAPI_Ax1.h>
+#include <GeomAPI_Dir.h>
 #include <GeomAPI_Face.h>
 #include <GeomAPI_Pln.h>
 #include <GeomAPI_Pnt.h>
 #include <GeomAPI_ShapeExplorer.h>
 #include <GeomAPI_XYZ.h>
+
+#include <GeomAlgoAPI_CompoundBuilder.h>
 #include <GeomAlgoAPI_DFLoader.h>
 #include <GeomAlgoAPI_FaceBuilder.h>
+#include <GeomAlgoAPI_Offset.h>
+#include <GeomAlgoAPI_Partition.h>
 #include <GeomAlgoAPI_ShapeTools.h>
+#include <GeomAlgoAPI_Translation.h>
 
 #include <Bnd_Box.hxx>
 #include <BRep_Builder.hxx>
 #include <TopTools_ListIteratorOfListOfShape.hxx>
 
 
+/// Expand planar face to cover the bounding box if theOriginalShape is planar.
+/// Otherwise, return the same shape;
+static GeomShapePtr buildPlanarFace(const GeomShapePtr& theOriginalShape,
+                                    const Bnd_Box& theBaseShapeBB);
+
+/// Build offset for the given shape.
+/// If the offset algorithm failed, translate the shape along the direction.
+static GeomShapePtr buildOffset(const GeomShapePtr& theShape,
+                                const double theOffset,
+                                const GeomDirPtr theDirection,
+                                GeomAlgoAPI_MakeShapeList& theMakeShapeList);
+
+/// Collect base faces of the prism.
+static void collectPrismBases(const TopoDS_Shape& theBaseShape,
+                              BRepPrimAPI_MakePrism& thePrismAlgo,
+                              ListOfShape& theBoundaries,
+                              const GeomAPI_Shape::ShapeType theTypeToExp);
+
+/// Collect all solids which contain boundaries but do not contain bases of prism.
+static GeomShapePtr collectResults(const GeomMakeShapePtr& theOperation,
+                                   const ListOfShape& theBoundaries,
+                                   const ListOfShape& theShapesToExclude,
+                                   const GeomAPI_Shape::ShapeType theTypeToExp);
+
 static void storeGenerationHistory(GeomAlgoAPI_Prism* thePrismAlgo,
                                    const TopoDS_Shape& theBase,
                                    const TopAbs_ShapeEnum theType,
@@ -64,25 +95,21 @@ static void storeGenerationHistory(GeomAlgoAPI_Prism* thePrismAlgo,
                                    const TopoDS_Face& theToFace,
                                    const TopoDS_Face& theFromFace);
 
-
-//==================================================================================================
-GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(const GeomShapePtr                 theBaseShape,
-                                     const std::shared_ptr<GeomAPI_Dir> theDirection,
-                                     const GeomShapePtr                 theToShape,
-                                     const double                       theToSize,
-                                     const GeomShapePtr                 theFromShape,
-                                     const double                       theFromSize)
+static GeomShapePtr toShape(const TopoDS_Shape& theShape)
 {
-  build(theBaseShape, theDirection, theToShape, theToSize, theFromShape, theFromSize);
+  GeomShapePtr aShape(new GeomAPI_Shape());
+  aShape->setImpl(new TopoDS_Shape(theShape));
+  return aShape;
 }
 
+
 //==================================================================================================
-void GeomAlgoAPI_Prism::build(const GeomShapePtr&                theBaseShape,
-                              const std::shared_ptr<GeomAPI_Dir> theDirection,
-                              const GeomShapePtr&                theToShape,
-                              const double                       theToSize,
-                              const GeomShapePtr&                theFromShape,
-                              const double                       theFromSize)
+GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(const GeomShapePtr theBaseShape,
+                                     const GeomDirPtr   theDirection,
+                                     const GeomShapePtr theToShape,
+                                     const double       theToSize,
+                                     const GeomShapePtr theFromShape,
+                                     const double       theFromSize)
 {
   if(!theBaseShape.get() ||
     (((!theFromShape.get() && !theToShape.get()) ||
@@ -93,21 +120,21 @@ void GeomAlgoAPI_Prism::build(const GeomShapePtr&                theBaseShape,
 
   // Getting base shape.
   const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
-  TopAbs_ShapeEnum aShapeTypeToExp;
+  GeomAPI_Shape::ShapeType aShapeTypeToExp;
   switch(aBaseShape.ShapeType()) {
     case TopAbs_VERTEX:
-      aShapeTypeToExp = TopAbs_VERTEX;
+      aShapeTypeToExp = GeomAPI_Shape::VERTEX;
       break;
     case TopAbs_EDGE:
     case TopAbs_WIRE:
-      aShapeTypeToExp = TopAbs_EDGE;
+      aShapeTypeToExp = GeomAPI_Shape::EDGE;
       break;
     case TopAbs_FACE:
     case TopAbs_SHELL:
-      aShapeTypeToExp = TopAbs_FACE;
+      aShapeTypeToExp = GeomAPI_Shape::FACE;
       break;
     case TopAbs_COMPOUND:
-      aShapeTypeToExp = TopAbs_COMPOUND;
+      aShapeTypeToExp = GeomAPI_Shape::COMPOUND;
       break;
     default:
       return;
@@ -168,8 +195,6 @@ void GeomAlgoAPI_Prism::build(const GeomShapePtr&                theBaseShape,
     aBaseLoc.reset(new GeomAPI_Pnt(aLoc.X(), aLoc.Y(), aLoc.Z()));
   }
 
-  GeomShapePtr aBasePlane = GeomAlgoAPI_FaceBuilder::planarFace(aBaseLoc, aBaseDir);
-
   gp_Vec anExtVec;
   std::shared_ptr<GeomAPI_Dir> anExtDir;
   if (theDirection.get())
@@ -187,249 +212,568 @@ void GeomAlgoAPI_Prism::build(const GeomShapePtr&                theBaseShape,
   TopoDS_Shape aResult;
   const bool isBoundingShapesSet = theFromShape.get() || theToShape.get();
   if(!isBoundingShapesSet) {
-    // Moving base shape.
-    gp_Trsf aTrsf;
-    aTrsf.SetTranslation(anExtVec * -theFromSize);
-    BRepBuilderAPI_Transform* aTransformBuilder =
-      new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
-    if(!aTransformBuilder || !aTransformBuilder->IsDone()) {
-      return;
-    }
-    this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
-      new GeomAlgoAPI_MakeShape(aTransformBuilder)));
-    TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
-
-    // Making prism.
-    BRepPrimAPI_MakePrism* aPrismBuilder =
-      new BRepPrimAPI_MakePrism(aMovedBase, anExtVec * (theFromSize + theToSize));
-    if(!aPrismBuilder || !aPrismBuilder->IsDone()) {
-      return;
-    }
-    this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
-      new GeomAlgoAPI_MakeShape(aPrismBuilder)));
-    aResult = aPrismBuilder->Shape();
-
-    // Setting naming.
-    if(aShapeTypeToExp == TopAbs_COMPOUND) {
-      storeGenerationHistory(this, aMovedBase, TopAbs_EDGE, aPrismBuilder);
-      storeGenerationHistory(this, aMovedBase, TopAbs_FACE, aPrismBuilder);
-    } else {
-      storeGenerationHistory(this, aMovedBase, aShapeTypeToExp, aPrismBuilder);
-    }
+    buildBySizes(theBaseShape, anExtDir, theToSize, theFromSize, aShapeTypeToExp);
   } else {
+    GeomShapePtr aBasePlane = GeomAlgoAPI_FaceBuilder::squareFace(aBaseLoc, aBaseDir, 100.0);
+
     GeomShapePtr aBoundingFromShape = theFromShape ? theFromShape : aBasePlane;
     GeomShapePtr aBoundingToShape   = theToShape   ? theToShape   : aBasePlane;
 
-    // Moving prism bounding faces according to "from" and "to" sizes.
-    std::shared_ptr<GeomAPI_Pln> aFromPln = GeomAPI_Face(aBoundingFromShape).getPlane();
-    std::shared_ptr<GeomAPI_Pnt> aFromLoc = aFromPln->location();
-    std::shared_ptr<GeomAPI_Dir> aFromDir = aFromPln->direction();
-
-    std::shared_ptr<GeomAPI_Pln> aToPln = GeomAPI_Face(aBoundingToShape).getPlane();
-    std::shared_ptr<GeomAPI_Pnt> aToLoc = aToPln->location();
-    std::shared_ptr<GeomAPI_Dir> aToDir = aToPln->direction();
-
-    bool aSign = aFromLoc->xyz()->dot(anExtDir->xyz()) > aToLoc->xyz()->dot(anExtDir->xyz());
-
-    std::shared_ptr<GeomAPI_Pnt> aFromPnt(
-      new GeomAPI_Pnt(aFromLoc->xyz()->added(anExtDir->xyz()->multiplied(
-                      aSign ? theFromSize : -theFromSize))));
-    aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir);
-
-    std::shared_ptr<GeomAPI_Pnt> aToPnt(
-      new GeomAPI_Pnt(aToLoc->xyz()->added(anExtDir->xyz()->multiplied(
-                      aSign ? -theToSize : theToSize))));
-    aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir);
-
-    // Getting bounding box for base shape.
-    Bnd_Box aBndBox;
-    BRepBndLib::Add(aBaseShape, aBndBox);
-    Standard_Real aXArr[2] = {aBndBox.CornerMin().X(), aBndBox.CornerMax().X()};
-    Standard_Real aYArr[2] = {aBndBox.CornerMin().Y(), aBndBox.CornerMax().Y()};
-    Standard_Real aZArr[2] = {aBndBox.CornerMin().Z(), aBndBox.CornerMax().Z()};
-    gp_Pnt aPoints[8];
-    int aNum = 0;
-    for(int i = 0; i < 2; i++) {
-      for(int j = 0; j < 2; j++) {
-        for(int k = 0; k < 2; k++) {
-          aPoints[aNum] = gp_Pnt(aXArr[i], aYArr[j], aZArr[k]);
-          aNum++;
-        }
-      }
+    bool isFromShapePlanar = aBoundingFromShape->isPlanar();
+    bool isToShapePlanar   = aBoundingToShape->isPlanar();
+
+    // Set signs of offsets if both bounding shapes are planar
+    if (isFromShapePlanar && isToShapePlanar) {
+      std::shared_ptr<GeomAPI_Pln> aFromPln = GeomAPI_Face(aBoundingFromShape).getPlane();
+      std::shared_ptr<GeomAPI_Pln> aToPln = GeomAPI_Face(aBoundingToShape).getPlane();
+      buildByPlanes(theBaseShape, anExtDir,
+                    aToPln, theToSize,
+                    aFromPln, theFromSize,
+                    aShapeTypeToExp);
     }
-
-    // Project points to bounding planes. Search max distance to them.
-    IntAna_Quadric aBndToQuadric(gp_Pln(aToPnt->impl<gp_Pnt>(), aToDir->impl<gp_Dir>()));
-    IntAna_Quadric aBndFromQuadric(gp_Pln(aFromPnt->impl<gp_Pnt>(), aFromDir->impl<gp_Dir>()));
-    Standard_Real aMaxToDist = 0, aMaxFromDist = 0;
-    for(int i = 0; i < 8; i++) {
-      gp_Lin aLine(aPoints[i], anExtVec);
-      IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric);
-      IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric);
-      if(aToIntAna.NbPoints() == 0 || aFromIntAna.NbPoints() == 0) {
-        return;
-      }
-      const gp_Pnt& aPntOnToFace = aToIntAna.Point(1);
-      const gp_Pnt& aPntOnFromFace = aFromIntAna.Point(1);
-      if(aPoints[i].Distance(aPntOnToFace) > aMaxToDist) {
-        aMaxToDist = aPoints[i].Distance(aPntOnToFace);
-      }
-      if(aPoints[i].Distance(aPntOnFromFace) > aMaxFromDist) {
-        aMaxFromDist = aPoints[i].Distance(aPntOnFromFace);
-      }
+    else {
+      buildByFaces(theBaseShape, anExtDir,
+                   aBoundingToShape, theToSize, isToShapePlanar,
+                   aBoundingFromShape, theFromSize, isFromShapePlanar,
+                   aShapeTypeToExp);
     }
+  }
+}
 
-    // We added 1 just to be sure that prism is long enough for boolean operation.
-    double aPrismLength = aMaxToDist + aMaxFromDist + 1;
+//==================================================================================================
+void GeomAlgoAPI_Prism::buildBySizes(const GeomShapePtr             theBaseShape,
+                                     const GeomDirPtr               theDirection,
+                                     const double                   theToSize,
+                                     const double                   theFromSize,
+                                     const GeomAPI_Shape::ShapeType theTypeToExp)
+{
+  const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
+  gp_Vec anExtVec = theDirection->impl<gp_Dir>();
 
-    // Moving base shape.
-    gp_Trsf aTrsf;
-    aTrsf.SetTranslation(anExtVec * -aPrismLength);
-    BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
-    if(!aTransformBuilder || !aTransformBuilder->IsDone()) {
-      return;
-    }
-    this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
+  // Moving base shape.
+  gp_Trsf aTrsf;
+  aTrsf.SetTranslation(anExtVec * -theFromSize);
+  BRepBuilderAPI_Transform* aTransformBuilder =
+      new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
+  if (!aTransformBuilder || !aTransformBuilder->IsDone()) {
+    return;
+  }
+  this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
       new GeomAlgoAPI_MakeShape(aTransformBuilder)));
-    TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
+  TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
 
-    // Making prism.
-    BRepPrimAPI_MakePrism* aPrismBuilder =
-      new BRepPrimAPI_MakePrism(aMovedBase, anExtVec * 2 * aPrismLength);
-    if(!aPrismBuilder || !aPrismBuilder->IsDone()) {
-      return;
-    }
-    this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
+  // Making prism.
+  BRepPrimAPI_MakePrism* aPrismBuilder =
+      new BRepPrimAPI_MakePrism(aMovedBase, anExtVec * (theFromSize + theToSize));
+  if (!aPrismBuilder || !aPrismBuilder->IsDone()) {
+    return;
+  }
+  this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
       new GeomAlgoAPI_MakeShape(aPrismBuilder)));
-    aResult = aPrismBuilder->Shape();
+  TopoDS_Shape aResult = aPrismBuilder->Shape();
 
-    // Orienting bounding planes.
-    std::shared_ptr<GeomAPI_Pnt> aCentreOfMass = GeomAlgoAPI_ShapeTools::centreOfMass(theBaseShape);
-    const gp_Pnt& aCentrePnt = aCentreOfMass->impl<gp_Pnt>();
-    gp_Lin aLine(aCentrePnt, anExtVec);
-    IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric);
-    IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric);
-    Standard_Real aToParameter = aToIntAna.ParamOnConic(1);
-    Standard_Real aFromParameter = aFromIntAna.ParamOnConic(1);
-    if(aToParameter > aFromParameter) {
-      gp_Vec aVec = aToDir->impl<gp_Dir>();
-      if((aVec * anExtVec) > 0) {
-        aToDir->setImpl(new gp_Dir(aVec.Reversed()));
-        aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir);
-      }
-      aVec = aFromDir->impl<gp_Dir>();
-      if((aVec * anExtVec) < 0) {
-        aFromDir->setImpl(new gp_Dir(aVec.Reversed()));
-        aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir);
-      }
-    } else {
-      gp_Vec aVec = aToDir->impl<gp_Dir>();
-      if((aVec * anExtVec) < 0) {
-        aToDir->setImpl(new gp_Dir(aVec.Reversed()));
-        aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir);
-      }
-      aVec = aFromDir->impl<gp_Dir>();
-      if((aVec * anExtVec) > 0) {
-        aFromDir->setImpl(new gp_Dir(aVec.Reversed()));
-        aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir);
+  // Setting naming.
+  if(theTypeToExp == GeomAPI_Shape::COMPOUND) {
+    storeGenerationHistory(this, aMovedBase, TopAbs_EDGE, aPrismBuilder);
+    storeGenerationHistory(this, aMovedBase, TopAbs_FACE, aPrismBuilder);
+  } else {
+    storeGenerationHistory(this, aMovedBase, (TopAbs_ShapeEnum)theTypeToExp, aPrismBuilder);
+  }
+
+  // Setting result.
+  if (!aResult.IsNull()) {
+    aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
+    this->setShape(toShape(aResult));
+    this->setDone(true);
+  }
+}
+
+//==================================================================================================
+void GeomAlgoAPI_Prism::buildByPlanes(const GeomShapePtr             theBaseShape,
+                                      const GeomDirPtr               theDirection,
+                                      const GeomPlanePtr             theToPlane,
+                                      const double                   theToSize,
+                                      const GeomPlanePtr             theFromPlane,
+                                      const double                   theFromSize,
+                                      const GeomAPI_Shape::ShapeType theTypeToExp)
+{
+  const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
+  gp_Vec anExtVec = theDirection->impl<gp_Dir>();
+
+  // Moving prism bounding faces according to "from" and "to" sizes.
+  std::shared_ptr<GeomAPI_Pnt> aFromLoc = theFromPlane->location();
+  std::shared_ptr<GeomAPI_Dir> aFromDir = theFromPlane->direction();
+
+  std::shared_ptr<GeomAPI_Pnt> aToLoc = theToPlane->location();
+  std::shared_ptr<GeomAPI_Dir> aToDir = theToPlane->direction();
+
+  std::shared_ptr<GeomAPI_XYZ> anExtDir = theDirection->xyz();
+  bool aSign = aFromLoc->xyz()->dot(anExtDir) > aToLoc->xyz()->dot(anExtDir);
+
+  std::shared_ptr<GeomAPI_Pnt> aFromPnt(
+    new GeomAPI_Pnt(aFromLoc->xyz()->added(anExtDir->multiplied(
+                    aSign ? theFromSize : -theFromSize))));
+  GeomShapePtr aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir);
+
+  std::shared_ptr<GeomAPI_Pnt> aToPnt(
+    new GeomAPI_Pnt(aToLoc->xyz()->added(anExtDir->multiplied(
+                    aSign ? -theToSize : theToSize))));
+  GeomShapePtr aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir);
+
+  // Getting bounding box for base shape.
+  Bnd_Box aBndBox;
+  BRepBndLib::Add(aBaseShape, aBndBox);
+  Standard_Real aXArr[2] = {aBndBox.CornerMin().X(), aBndBox.CornerMax().X()};
+  Standard_Real aYArr[2] = {aBndBox.CornerMin().Y(), aBndBox.CornerMax().Y()};
+  Standard_Real aZArr[2] = {aBndBox.CornerMin().Z(), aBndBox.CornerMax().Z()};
+  gp_Pnt aPoints[8];
+  int aNum = 0;
+  for(int i = 0; i < 2; i++) {
+    for(int j = 0; j < 2; j++) {
+      for(int k = 0; k < 2; k++) {
+        aPoints[aNum] = gp_Pnt(aXArr[i], aYArr[j], aZArr[k]);
+        aNum++;
       }
     }
+  }
 
-    // Making solids from bounding planes.
-    TopoDS_Shell aToShell, aFromShell;
-    TopoDS_Solid aToSolid, aFromSolid;
-    const TopoDS_Shape& aToShape   = aBoundingToShape->impl<TopoDS_Shape>();
-    const TopoDS_Shape& aFromShape = aBoundingFromShape->impl<TopoDS_Shape>();
-    TopoDS_Face aToFace   = TopoDS::Face(aToShape);
-    TopoDS_Face aFromFace = TopoDS::Face(aFromShape);
-    BRep_Builder aBoundingBuilder;
-    aBoundingBuilder.MakeShell(aToShell);
-    aBoundingBuilder.Add(aToShell, aToShape);
-    aBoundingBuilder.MakeShell(aFromShell);
-    aBoundingBuilder.Add(aFromShell, aFromShape);
-    aBoundingBuilder.MakeSolid(aToSolid);
-    aBoundingBuilder.Add(aToSolid, aToShell);
-    aBoundingBuilder.MakeSolid(aFromSolid);
-    aBoundingBuilder.Add(aFromSolid, aFromShell);
-
-    // Cutting with to plane.
-    BRepAlgoAPI_Cut* aToCutBuilder = new BRepAlgoAPI_Cut(aResult, aToSolid);
-    aToCutBuilder->Build();
-    if(!aToCutBuilder->IsDone()) {
+  // Project points to bounding planes. Search max distance to them.
+  IntAna_Quadric aBndToQuadric(gp_Pln(aToPnt->impl<gp_Pnt>(), aToDir->impl<gp_Dir>()));
+  IntAna_Quadric aBndFromQuadric(gp_Pln(aFromPnt->impl<gp_Pnt>(), aFromDir->impl<gp_Dir>()));
+  Standard_Real aMaxToDist = 0, aMaxFromDist = 0;
+  for(int i = 0; i < 8; i++) {
+    gp_Lin aLine(aPoints[i], anExtVec);
+    IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric);
+    IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric);
+    if(aToIntAna.NbPoints() == 0 || aFromIntAna.NbPoints() == 0) {
       return;
     }
-    this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
-      new GeomAlgoAPI_MakeShape(aToCutBuilder)));
-    aResult = aToCutBuilder->Shape();
-    if(aResult.ShapeType() == TopAbs_COMPOUND) {
-      aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
+    const gp_Pnt& aPntOnToFace = aToIntAna.Point(1);
+    const gp_Pnt& aPntOnFromFace = aFromIntAna.Point(1);
+    if(aPoints[i].Distance(aPntOnToFace) > aMaxToDist) {
+      aMaxToDist = aPoints[i].Distance(aPntOnToFace);
     }
-    if(aShapeTypeToExp == TopAbs_FACE || aShapeTypeToExp == TopAbs_COMPOUND) {
-      const TopTools_ListOfShape& aToShapes = aToCutBuilder->Modified(aToShape);
-      for(TopTools_ListIteratorOfListOfShape anIt(aToShapes); anIt.More(); anIt.Next()) {
-        GeomShapePtr aGeomSh(new GeomAPI_Shape());
-        aGeomSh->setImpl(new TopoDS_Shape(anIt.Value()));
-        fixOrientation(aGeomSh);
-        this->addToShape(aGeomSh);
-      }
+    if(aPoints[i].Distance(aPntOnFromFace) > aMaxFromDist) {
+      aMaxFromDist = aPoints[i].Distance(aPntOnFromFace);
     }
+  }
 
-    // Cutting with from plane.
-    BRepAlgoAPI_Cut* aFromCutBuilder = new BRepAlgoAPI_Cut(aResult, aFromSolid);
-    aFromCutBuilder->Build();
-    if(!aFromCutBuilder->IsDone()) {
-      return;
+  // We added 1 just to be sure that prism is long enough for boolean operation.
+  double aPrismLength = aMaxToDist + aMaxFromDist + 1;
+
+  // Moving base shape.
+  gp_Trsf aTrsf;
+  aTrsf.SetTranslation(anExtVec * -aPrismLength);
+  BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
+  if(!aTransformBuilder || !aTransformBuilder->IsDone()) {
+    return;
+  }
+  this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
+    new GeomAlgoAPI_MakeShape(aTransformBuilder)));
+  TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
+
+  // Making prism.
+  BRepPrimAPI_MakePrism* aPrismBuilder =
+    new BRepPrimAPI_MakePrism(aMovedBase, anExtVec * 2 * aPrismLength);
+  if(!aPrismBuilder || !aPrismBuilder->IsDone()) {
+    return;
+  }
+  this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
+    new GeomAlgoAPI_MakeShape(aPrismBuilder)));
+  TopoDS_Shape aResult = aPrismBuilder->Shape();
+
+  // Orienting bounding planes.
+  std::shared_ptr<GeomAPI_Pnt> aCentreOfMass = GeomAlgoAPI_ShapeTools::centreOfMass(theBaseShape);
+  const gp_Pnt& aCentrePnt = aCentreOfMass->impl<gp_Pnt>();
+  gp_Lin aLine(aCentrePnt, anExtVec);
+  IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric);
+  IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric);
+  Standard_Real aToParameter = aToIntAna.ParamOnConic(1);
+  Standard_Real aFromParameter = aFromIntAna.ParamOnConic(1);
+  if(aToParameter > aFromParameter) {
+    gp_Vec aVec = aToDir->impl<gp_Dir>();
+    if((aVec * anExtVec) > 0) {
+      aToDir->setImpl(new gp_Dir(aVec.Reversed()));
+      aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir);
     }
-    this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
-      new GeomAlgoAPI_MakeShape(aFromCutBuilder)));
-    aResult = aFromCutBuilder->Shape();
-    TopoDS_Iterator aCheckIt(aResult);
-    if(!aCheckIt.More()) {
-      return;
+    aVec = aFromDir->impl<gp_Dir>();
+    if((aVec * anExtVec) < 0) {
+      aFromDir->setImpl(new gp_Dir(aVec.Reversed()));
+      aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir);
     }
-    if(aResult.ShapeType() == TopAbs_COMPOUND) {
-      aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
+  } else {
+    gp_Vec aVec = aToDir->impl<gp_Dir>();
+    if((aVec * anExtVec) < 0) {
+      aToDir->setImpl(new gp_Dir(aVec.Reversed()));
+      aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir);
     }
-    if(aShapeTypeToExp == TopAbs_FACE || aShapeTypeToExp == TopAbs_COMPOUND) {
-      const TopTools_ListOfShape& aFromShapes = aFromCutBuilder->Modified(aFromShape);
-      for(TopTools_ListIteratorOfListOfShape anIt(aFromShapes); anIt.More(); anIt.Next()) {
-        GeomShapePtr aGeomSh(new GeomAPI_Shape());
-        aGeomSh->setImpl(new TopoDS_Shape(anIt.Value()));
-        fixOrientation(aGeomSh);
-        this->addFromShape(aGeomSh);
-      }
+    aVec = aFromDir->impl<gp_Dir>();
+    if((aVec * anExtVec) > 0) {
+      aFromDir->setImpl(new gp_Dir(aVec.Reversed()));
+      aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir);
     }
+  }
 
-    // Naming for extrusion from vertex, edge.
-    if(aShapeTypeToExp == TopAbs_COMPOUND) {
-      storeGenerationHistory(this, aResult, TopAbs_EDGE, aToFace, aFromFace);
-      storeGenerationHistory(this, aResult, TopAbs_FACE, aToFace, aFromFace);
-    } else {
-      storeGenerationHistory(this, aResult, aShapeTypeToExp, aToFace, aFromFace);
+  // Making solids from bounding planes.
+  TopoDS_Shell aToShell, aFromShell;
+  TopoDS_Solid aToSolid, aFromSolid;
+  const TopoDS_Shape& aToShape   = aBoundingToShape->impl<TopoDS_Shape>();
+  const TopoDS_Shape& aFromShape = aBoundingFromShape->impl<TopoDS_Shape>();
+  TopoDS_Face aToFace   = TopoDS::Face(aToShape);
+  TopoDS_Face aFromFace = TopoDS::Face(aFromShape);
+  BRep_Builder aBoundingBuilder;
+  aBoundingBuilder.MakeShell(aToShell);
+  aBoundingBuilder.Add(aToShell, aToShape);
+  aBoundingBuilder.MakeShell(aFromShell);
+  aBoundingBuilder.Add(aFromShell, aFromShape);
+  aBoundingBuilder.MakeSolid(aToSolid);
+  aBoundingBuilder.Add(aToSolid, aToShell);
+  aBoundingBuilder.MakeSolid(aFromSolid);
+  aBoundingBuilder.Add(aFromSolid, aFromShell);
+
+  // Cutting with to plane.
+  BRepAlgoAPI_Cut* aToCutBuilder = new BRepAlgoAPI_Cut(aResult, aToSolid);
+  aToCutBuilder->Build();
+  if(!aToCutBuilder->IsDone()) {
+    return;
+  }
+  this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
+    new GeomAlgoAPI_MakeShape(aToCutBuilder)));
+  aResult = aToCutBuilder->Shape();
+  if(aResult.ShapeType() == TopAbs_COMPOUND) {
+    aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
+  }
+  if (theTypeToExp == GeomAPI_Shape::FACE || theTypeToExp == GeomAPI_Shape::COMPOUND) {
+    const TopTools_ListOfShape& aToShapes = aToCutBuilder->Modified(aToShape);
+    for(TopTools_ListIteratorOfListOfShape anIt(aToShapes); anIt.More(); anIt.Next()) {
+      GeomShapePtr aGeomSh = toShape(anIt.Value());
+      fixOrientation(aGeomSh);
+      this->addToShape(aGeomSh);
     }
+  }
 
-    if(aResult.ShapeType() == TopAbs_COMPOUND) {
-      std::shared_ptr<GeomAPI_Shape> aGeomShape(new GeomAPI_Shape);
-      aGeomShape->setImpl(new TopoDS_Shape(aResult));
-      ListOfShape aResults;
-      aGeomShape = GeomAlgoAPI_ShapeTools::combineShapes(aGeomShape,
-                                                         GeomAPI_Shape::COMPSOLID,
-                                                         aResults);
-      aResult = aGeomShape->impl<TopoDS_Shape>();
+  // Cutting with from plane.
+  BRepAlgoAPI_Cut* aFromCutBuilder = new BRepAlgoAPI_Cut(aResult, aFromSolid);
+  aFromCutBuilder->Build();
+  if(!aFromCutBuilder->IsDone()) {
+    return;
+  }
+  this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
+    new GeomAlgoAPI_MakeShape(aFromCutBuilder)));
+  aResult = aFromCutBuilder->Shape();
+  TopoDS_Iterator aCheckIt(aResult);
+  if(!aCheckIt.More()) {
+    return;
+  }
+  if(aResult.ShapeType() == TopAbs_COMPOUND) {
+    aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
+  }
+  if (theTypeToExp == GeomAPI_Shape::FACE || theTypeToExp == GeomAPI_Shape::COMPOUND) {
+    const TopTools_ListOfShape& aFromShapes = aFromCutBuilder->Modified(aFromShape);
+    for(TopTools_ListIteratorOfListOfShape anIt(aFromShapes); anIt.More(); anIt.Next()) {
+      GeomShapePtr aGeomSh = toShape(anIt.Value());
+      fixOrientation(aGeomSh);
+      this->addFromShape(aGeomSh);
     }
   }
 
+  // Naming for extrusion from vertex, edge.
+  if(theTypeToExp == GeomAPI_Shape::COMPOUND) {
+    storeGenerationHistory(this, aResult, TopAbs_EDGE, aToFace, aFromFace);
+    storeGenerationHistory(this, aResult, TopAbs_FACE, aToFace, aFromFace);
+  } else {
+    storeGenerationHistory(this, aResult, (TopAbs_ShapeEnum)theTypeToExp, aToFace, aFromFace);
+  }
+
+  if(aResult.ShapeType() == TopAbs_COMPOUND) {
+    GeomShapePtr aGeomShape = toShape(aResult);
+    ListOfShape aResults;
+    aGeomShape = GeomAlgoAPI_ShapeTools::combineShapes(aGeomShape,
+                                                        GeomAPI_Shape::COMPSOLID,
+                                                        aResults);
+    aResult = aGeomShape->impl<TopoDS_Shape>();
+  }
+
   // Setting result.
   if (!aResult.IsNull()) {
     aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
-    GeomShapePtr aGeomSh(new GeomAPI_Shape());
-    aGeomSh->setImpl(new TopoDS_Shape(aResult));
-    this->setShape(aGeomSh);
+    this->setShape(toShape(aResult));
     this->setDone(true);
   }
 }
 
+//==================================================================================================
+void GeomAlgoAPI_Prism::buildByFaces(const GeomShapePtr             theBaseShape,
+                                     const GeomDirPtr               theDirection,
+                                     const GeomShapePtr             theToShape,
+                                     const double                   theToSize,
+                                     const bool                     theToIsPlanar,
+                                     const GeomShapePtr             theFromShape,
+                                     const double                   theFromSize,
+                                     const bool                     theFromIsPlanar,
+                                     const GeomAPI_Shape::ShapeType theTypeToExp)
+{
+  const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
+  gp_Vec anExtVec = theDirection->impl<gp_Dir>();
+
+  // Moving prism bounding faces according to "from" and "to" sizes.
+  GeomShapePtr aBoundingFromShape = buildOffset(theFromShape, theFromSize, theDirection, *this);
+  GeomShapePtr aBoundingToShape   = buildOffset(theToShape, theToSize, theDirection, *this);
+
+  // Bounding box for shapes used in prism building.
+  Bnd_Box aBndBox;
+  BRepBndLib::Add(aBaseShape, aBndBox);
+  BRepBndLib::Add(aBoundingFromShape->impl<TopoDS_Shape>(), aBndBox);
+  BRepBndLib::Add(aBoundingToShape->impl<TopoDS_Shape>(), aBndBox);
+  double aPrismLength = 2.0 * aBndBox.CornerMin().Distance(aBndBox.CornerMax());
+
+  // Prism building.
+  gp_Trsf aTrsf;
+  aTrsf.SetTranslation(anExtVec * -aPrismLength);
+  BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf);
+  if (!aTransformBuilder || !aTransformBuilder->IsDone()) {
+    return;
+  }
+  this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
+      new GeomAlgoAPI_MakeShape(aTransformBuilder)));
+  TopoDS_Shape aMovedBase = aTransformBuilder->Shape();
+
+  // Making prism.
+  BRepPrimAPI_MakePrism* aPrismBuilder =
+      new BRepPrimAPI_MakePrism(aMovedBase, anExtVec * 2 * aPrismLength);
+  if (!aPrismBuilder || !aPrismBuilder->IsDone()) {
+    return;
+  }
+  this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
+      new GeomAlgoAPI_MakeShape(aPrismBuilder)));
+
+  GeomShapePtr aResult = toShape(aPrismBuilder->Shape());
+
+  // Prism generatrix
+  ListOfShape aPrismBaseFaces;
+  collectPrismBases(aMovedBase, *aPrismBuilder, aPrismBaseFaces, theTypeToExp);
+
+  // Build planar faces intersecting the prism fully.
+  BRepBndLib::Add(aResult->impl<TopoDS_Shape>(), aBndBox);
+  aBoundingFromShape = buildPlanarFace(aBoundingFromShape, aBndBox);
+  aBoundingToShape   = buildPlanarFace(aBoundingToShape, aBndBox);
+
+  // Perform partition.
+  ListOfShape anObjects, aTools;
+  anObjects.push_back(aResult);
+  aTools.push_back(aBoundingFromShape);
+  aTools.push_back(aBoundingToShape);
+
+  GeomMakeShapePtr aPartition(new GeomAlgoAPI_Partition(anObjects, aTools));
+  if (!aPartition->isDone())
+    return;
+
+  this->appendAlgo(aPartition);
+
+  // Collect pieces of boundary shapes, split by Partition.
+  if (theFromIsPlanar) {
+    ListOfShape anImagesFrom;
+    aPartition->modified(aBoundingFromShape, anImagesFrom);
+    for (ListOfShape::iterator anIt = anImagesFrom.begin(); anIt != anImagesFrom.end(); ++anIt)
+      addFromShape(*anIt);
+  }
+
+  if (theToIsPlanar) {
+    ListOfShape anImagesTo;
+    aPartition->modified(aBoundingToShape, anImagesTo);
+    for (ListOfShape::iterator anIt = anImagesTo.begin(); anIt != anImagesTo.end(); ++anIt)
+      addToShape(*anIt);
+  }
+
+  // Collect results which have both boundaries, selected for extrusion,
+  // but which do not contain top and bottom faces of the prism
+  // (these faces are treated as infinitely distant).
+  aResult = collectResults(aPartition, aTools, aPrismBaseFaces, theTypeToExp);
+  if (aResult && aResult->shapeType() == GeomAPI_Shape::COMPOUND) {
+    ListOfShape aResults;
+    aResult = GeomAlgoAPI_ShapeTools::combineShapes(aResult,
+        theTypeToExp == GeomAPI_Shape::EDGE ? GeomAPI_Shape::SHELL : GeomAPI_Shape::COMPSOLID,
+        aResults);
+
+    if (aResults.size() > 1 &&
+       (GeomAlgoAPI_ShapeTools::hasSharedTopology(aResults, GeomAPI_Shape::EDGE) ||
+        GeomAlgoAPI_ShapeTools::hasSharedTopology(aResults, GeomAPI_Shape::VERTEX))) {
+      // results shuold not have shared topology
+      aResult = GeomShapePtr();
+    }
+  }
+
+  if (aResult) {
+    this->setShape(aResult);
+    this->setDone(true);
+  }
+}
+
+
 // Auxilary functions:
+//==================================================================================================
+GeomShapePtr buildPlanarFace(const GeomShapePtr& theOriginalShape,
+                             const Bnd_Box& theBaseShapeBB)
+{
+  GeomPlanePtr aPlane = GeomAPI_Face(theOriginalShape).getPlane();
+  if (!aPlane)
+    return theOriginalShape;
+
+  gp_Pnt aCornerMin = theBaseShapeBB.CornerMin();
+  gp_Pnt aCornerMax = theBaseShapeBB.CornerMax();
+  double aSize = aCornerMin.SquareDistance(aCornerMax);
+
+  gp_Pnt aLocation = aPlane->location()->impl<gp_Pnt>();
+
+  gp_Pnt aCurPnt;
+  for (int x = 0; x < 2; ++x) {
+    aCurPnt.SetX(x == 0 ? aCornerMin.X() : aCornerMax.X());
+    for (int y = 0; y < 2; ++y) {
+      aCurPnt.SetY(y == 0 ? aCornerMin.Y() : aCornerMax.Y());
+      for (int z = 0; z < 2; ++z) {
+        aCurPnt.SetZ(z == 0 ? aCornerMin.Z() : aCornerMax.Z());
+        double aDist = aCurPnt.SquareDistance(aLocation);
+        if (aDist > aSize)
+          aSize = aDist;
+      }
+    }
+  }
+
+  aSize = Sqrt(aSize);
+  return GeomAlgoAPI_FaceBuilder::squareFace(aPlane, 2.0 * aSize);
+}
+
+//==================================================================================================
+GeomShapePtr buildOffset(const GeomShapePtr& theShape,
+                         const double theOffset,
+                         const GeomDirPtr theDirection,
+                         GeomAlgoAPI_MakeShapeList& theMakeShapeList)
+{
+  if (Abs(theOffset) < Precision::Confusion())
+    return theShape; // no need zero offset
+
+  GeomMakeShapePtr anAlgo(new GeomAlgoAPI_Offset(theShape, theOffset));
+  if (!anAlgo->isDone()) {
+    // offset not done, perform translation
+    std::shared_ptr<GeomAPI_Ax1> anAxis(new GeomAPI_Ax1());
+    anAxis->setDir(theDirection);
+    anAlgo.reset(new GeomAlgoAPI_Translation(theShape, anAxis, theOffset));
+  }
+
+  GeomShapePtr aResult = theShape;
+  if (anAlgo->isDone()) {
+    theMakeShapeList.appendAlgo(anAlgo);
+    aResult = anAlgo->shape();
+  }
+  return aResult;
+}
+
+//==================================================================================================
+void collectPrismBases(const TopoDS_Shape& theBaseShape,
+                       BRepPrimAPI_MakePrism& thePrismAlgo,
+                       ListOfShape& theBoundaries,
+                       const GeomAPI_Shape::ShapeType theTypeToExp)
+{
+  for (TopExp_Explorer anExp(theBaseShape, (TopAbs_ShapeEnum)theTypeToExp);
+       anExp.More(); anExp.Next()) {
+    theBoundaries.push_back(toShape(thePrismAlgo.FirstShape(anExp.Current())));
+    theBoundaries.push_back(toShape(thePrismAlgo.LastShape(anExp.Current())));
+  }
+}
+
+//==================================================================================================
+typedef std::set<GeomShapePtr, GeomAPI_Shape::Comparator> SetOfShape;
+
+bool isShapeApplicable(const GeomShapePtr& theSolid,
+                       const std::list<ListOfShape>& theShapesToExist,
+                       const SetOfShape& theShapesToExclude,
+                       const GeomAPI_Shape::ShapeType theTypeToExp)
+{
+  SetOfShape aFaces;
+  for (GeomAPI_ShapeExplorer aFExp(theSolid, theTypeToExp);
+       aFExp.more(); aFExp.next()) {
+    GeomShapePtr aCurrent = aFExp.current();
+    if (theShapesToExclude.find(aCurrent) != theShapesToExclude.end())
+      return false;
+    aFaces.insert(aCurrent);
+  }
+
+  // check all faces are in solid
+  bool isApplicable = true;
+  for (std::list<ListOfShape>::const_iterator it1 = theShapesToExist.begin();
+       it1 != theShapesToExist.end() && isApplicable; ++it1) {
+    ListOfShape::const_iterator it2 = it1->begin();
+    for (; it2 != it1->end(); ++it2)
+      if (aFaces.find(*it2) != aFaces.end())
+        break;
+    isApplicable = it2 != it1->end();
+  }
+  return isApplicable;
+}
+
+void collectModified(const GeomMakeShapePtr& theOperation,
+                     const ListOfShape& theShapes,
+                     std::list<ListOfShape>& theModified)
+{
+  for (ListOfShape::const_iterator anIt = theShapes.begin();
+       anIt != theShapes.end(); ++anIt) {
+    theModified.push_back(ListOfShape());
+    theOperation->modified(*anIt, theModified.back());
+    theOperation->generated(*anIt, theModified.back());
+    theModified.back().push_back(*anIt);
+  }
+}
+
+GeomShapePtr collectResults(const GeomMakeShapePtr& theOperation,
+                            const ListOfShape& theBoundaries,
+                            const ListOfShape& theShapesToExclude,
+                            const GeomAPI_Shape::ShapeType theTypeToExp)
+{
+  ListOfShape aResults;
+
+  // collect modified shapes
+  std::list<ListOfShape> aModifiedBoundaries;
+  collectModified(theOperation, theBoundaries, aModifiedBoundaries);
+
+  std::list<ListOfShape> aModifiedExclude;
+  collectModified(theOperation, theShapesToExclude, aModifiedExclude);
+  SetOfShape aTabooShapes;
+  for (std::list<ListOfShape>::iterator anIt = aModifiedExclude.begin();
+       anIt != aModifiedExclude.end(); ++anIt)
+    aTabooShapes.insert(anIt->begin(), anIt->end());
+
+  // type of sub-shapes to explode
+  GeomAPI_Shape::ShapeType aSubshapeType;
+  switch (theTypeToExp) {
+  case GeomAPI_Shape::VERTEX:
+    aSubshapeType = GeomAPI_Shape::EDGE;
+    break;
+  case GeomAPI_Shape::EDGE:
+    aSubshapeType = GeomAPI_Shape::FACE;
+    break;
+  case GeomAPI_Shape::FACE:
+    aSubshapeType = GeomAPI_Shape::SOLID;
+    break;
+  default:
+    aSubshapeType = GeomAPI_Shape::COMPOUND;
+  }
+
+  // search applicable solids
+  GeomShapePtr anOperationResult = theOperation->shape();
+  for (GeomAPI_ShapeExplorer anExp(anOperationResult, aSubshapeType);
+        anExp.more(); anExp.next()) {
+    if (isShapeApplicable(anExp.current(), aModifiedBoundaries, aTabooShapes, theTypeToExp))
+      aResults.push_back(anExp.current());
+  }
+
+  GeomShapePtr aResult;
+  if (aResults.size() == 1)
+    aResult = aResults.front();
+  else if (!aResults.empty())
+    aResult = GeomAlgoAPI_CompoundBuilder::compound(aResults);
+  return aResult;
+}
+
 //==================================================================================================
 void storeGenerationHistory(GeomAlgoAPI_Prism* thePrismAlgo,
                             const TopoDS_Shape& theBase,
index 7d2d2dbddb6eb6710c7ccee7c1da79d7e1936565..a38d45557d2b10316efd0886731725e452cf43db 100644 (file)
 #ifndef GeomAlgoAPI_Prism_H_
 #define GeomAlgoAPI_Prism_H_
 
-#include "GeomAlgoAPI.h"
-
 #include "GeomAlgoAPI_MakeSweep.h"
 
-#include <GeomAPI_Dir.h>
 #include <GeomAPI_Shape.h>
 
 #include <memory>
 
+class GeomAPI_Dir;
+class GeomAPI_Pln;
+
 /// \class GeomAlgoAPI_Prism
 /// \ingroup DataAlgo
 /// \brief Allows to create the prism based on a given face and bounding planes.
@@ -55,13 +55,32 @@ public:
                                        const double                       theFromSize);
 
 private:
-  /// Builds resulting shape.
-  void build(const GeomShapePtr&                theBaseShape,
-             const std::shared_ptr<GeomAPI_Dir> theDirection,
-             const GeomShapePtr&                theToShape,
-             const double                       theToSize,
-             const GeomShapePtr&                theFromShape,
-             const double                       theFromSize);
+  /// Build extrusion by distances from the base shape.
+  void buildBySizes(const GeomShapePtr                 theBaseShape,
+                    const std::shared_ptr<GeomAPI_Dir> theDirection,
+                    const double                       theToSize,
+                    const double                       theFromSize,
+                    const GeomAPI_Shape::ShapeType     theTypeToExp);
+
+  /// Build extrusion from plane to plane.
+  void buildByPlanes(const GeomShapePtr                 theBaseShape,
+                     const std::shared_ptr<GeomAPI_Dir> theDirection,
+                     const std::shared_ptr<GeomAPI_Pln> theToPlane,
+                     const double                       theToSize,
+                     const std::shared_ptr<GeomAPI_Pln> theFromPlane,
+                     const double                       theFromSize,
+                     const GeomAPI_Shape::ShapeType     theTypeToExp);
+
+  /// Build extrusion from face to face.
+  void buildByFaces(const GeomShapePtr                 theBaseShape,
+                    const std::shared_ptr<GeomAPI_Dir> theDirection,
+                    const GeomShapePtr                 theToShape,
+                    const double                       theToSize,
+                    const bool                         theToIsPlanar,
+                    const GeomShapePtr                 theFromShape,
+                    const double                       theFromSize,
+                    const bool                         theFromIsPlanar,
+                    const GeomAPI_Shape::ShapeType     theTypeToExp);
 };
 
 #endif
index 357f79216cd959866d0fee694d5753b04ffcdaa7..d1d3abe8b5317f5b03ee1e892e3e19c53f65b07f 100644 (file)
@@ -546,6 +546,24 @@ std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::groupSharedTopology(
   return aResult;
 }
 
+//==================================================================================================
+bool GeomAlgoAPI_ShapeTools::hasSharedTopology(const ListOfShape& theShapes,
+                                               const GeomAPI_Shape::ShapeType theShapeType)
+{
+  TopTools_IndexedMapOfShape aSubs;
+  for (ListOfShape::const_iterator anIt = theShapes.begin(); anIt != theShapes.end(); ++anIt) {
+    TopTools_IndexedMapOfShape aCurSubs;
+    TopExp::MapShapes((*anIt)->impl<TopoDS_Shape>(), (TopAbs_ShapeEnum)theShapeType, aCurSubs);
+    for (TopTools_IndexedMapOfShape::Iterator aSubIt(aCurSubs); aSubIt.More(); aSubIt.Next()) {
+      if (aSubs.Contains(aSubIt.Value()))
+        return true;
+      else
+        aSubs.Add(aSubIt.Value());
+    }
+  }
+  return false;
+}
+
 //==================================================================================================
 std::list<std::shared_ptr<GeomAPI_Pnt> >
   GeomAlgoAPI_ShapeTools::getBoundingBox(const ListOfShape& theShapes, const double theEnlarge)
index 4127ccf2cd7261b6acd0e892faac8f362ef7e0a1..da415d359c49cbfbe56e0b1e082e0016dceae297 100644 (file)
@@ -80,6 +80,13 @@ public:
   GEOMALGOAPI_EXPORT static std::shared_ptr<GeomAPI_Shape>
     groupSharedTopology(const std::shared_ptr<GeomAPI_Shape> theCompound);
 
+  /// \brief Check group of shapes has shared sub-shapes of the given type
+  /// \param[in] theShapes    list of shapes
+  /// \param[in] theShapeType type of sub-shapes to check
+  /// \return \c true if shared topology exists
+  GEOMALGOAPI_EXPORT static bool hasSharedTopology(const ListOfShape& theShapes,
+                                                   const GeomAPI_Shape::ShapeType theShapeType);
+
   /// \brief Calculates bounding box for theShapes
   /// \return list of eight points.
   /// \param[in] theShapes list of shapes.