]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
bos #26448 Construction elements: create extra planes
authorAlexey Kondratyev <alexey.kondratyev@opencascade.com>
Fri, 8 Oct 2021 13:54:33 +0000 (16:54 +0300)
committervsr <vsr@opencascade.com>
Fri, 5 Nov 2021 11:24:10 +0000 (14:24 +0300)
Add attribute "number of copies" for creating plane by rotating and by distance from other plane.

Added a corresponding field in the creation window.

Change documentation to reference about copies when creating a planes.

Change "dump to script" to set number of copies(or without it).

Add Python test.

Add translate to French.

13 files changed:
src/ConstructionAPI/ConstructionAPI_Plane.cpp
src/ConstructionAPI/ConstructionAPI_Plane.h
src/ConstructionPlugin/ConstructionPlugin_Plane.cpp
src/ConstructionPlugin/ConstructionPlugin_Plane.h
src/ConstructionPlugin/ConstructionPlugin_msg_en.ts
src/ConstructionPlugin/ConstructionPlugin_msg_fr.ts
src/ConstructionPlugin/Test/TestPlane_Copies.py [new file with mode: 0644]
src/ConstructionPlugin/doc/images/Plane3.png
src/ConstructionPlugin/doc/planeFeature.rst
src/ConstructionPlugin/plane_widget.xml
src/ConstructionPlugin/tests.set
src/Model/Model_Objects.cpp
src/Model/Model_Update.cpp

index cd0bbb42471fd43a5bbbdb68a7944f69a144f492..3933b16230288c625690c37df6dc91d67bf7aba2 100644 (file)
@@ -33,11 +33,12 @@ ConstructionAPI_Plane::ConstructionAPI_Plane(const std::shared_ptr<ModelAPI_Feat
 ConstructionAPI_Plane::ConstructionAPI_Plane(const std::shared_ptr<ModelAPI_Feature>& theFeature,
                                              const ModelHighAPI_Selection& theFace,
                                              const ModelHighAPI_Double& theDistance,
-                                             const bool theIsReverse)
+                                             const bool theIsReverse,
+                                             const ModelHighAPI_Integer& theNbCopy)
 : ModelHighAPI_Interface(theFeature)
 {
   if(initialize()) {
-    setByFaceAndDistance(theFace, theDistance, theIsReverse);
+    setByFaceAndDistance(theFace, theDistance, theIsReverse, theNbCopy);
   }
 }
 
@@ -99,11 +100,12 @@ ConstructionAPI_Plane::ConstructionAPI_Plane(const std::shared_ptr<ModelAPI_Feat
 ConstructionAPI_Plane::ConstructionAPI_Plane(const std::shared_ptr<ModelAPI_Feature>& theFeature,
                                              const ModelHighAPI_Selection& thePlane,
                                              const ModelHighAPI_Selection& theAxis,
-                                             const ModelHighAPI_Double& theAngle)
+                                             const ModelHighAPI_Double& theAngle,
+                                             const ModelHighAPI_Integer& theNbCopy)
 : ModelHighAPI_Interface(theFeature)
 {
   if(initialize()) {
-    setByRotation(thePlane, theAxis, theAngle);
+    setByRotation(thePlane, theAxis, theAngle, theNbCopy);
   }
 }
 
@@ -115,7 +117,8 @@ ConstructionAPI_Plane::~ConstructionAPI_Plane()
 //==================================================================================================
 void ConstructionAPI_Plane::setByFaceAndDistance(const ModelHighAPI_Selection& theFace,
                                                  const ModelHighAPI_Double& theDistance,
-                                                 const bool theIsReverse)
+                                                 const bool theIsReverse,
+                                                 const ModelHighAPI_Integer& theNbCopy)
 {
   fillAttribute(ConstructionPlugin_Plane::CREATION_METHOD_BY_OTHER_PLANE(), mycreationMethod);
   fillAttribute(theFace, myplane);
@@ -123,6 +126,7 @@ void ConstructionAPI_Plane::setByFaceAndDistance(const ModelHighAPI_Selection& t
                 mycreationMethodByOtherPlane);
   fillAttribute(theDistance, mydistance);
   fillAttribute(theIsReverse, myreverse);
+  fillAttribute(theNbCopy, mynbcopy);
 
   execute();
 }
@@ -196,7 +200,8 @@ void ConstructionAPI_Plane::setByCoincidentToPoint(const ModelHighAPI_Selection&
 //==================================================================================================
 void ConstructionAPI_Plane::setByRotation(const ModelHighAPI_Selection& thePlane,
                                           const ModelHighAPI_Selection& theAxis,
-                                          const ModelHighAPI_Double& theAngle)
+                                          const ModelHighAPI_Double& theAngle,
+                                          const ModelHighAPI_Integer& theNbCopy)
 {
   fillAttribute(ConstructionPlugin_Plane::CREATION_METHOD_BY_OTHER_PLANE(), mycreationMethod);
   fillAttribute(thePlane, myplane);
@@ -204,6 +209,7 @@ void ConstructionAPI_Plane::setByRotation(const ModelHighAPI_Selection& thePlane
                 mycreationMethodByOtherPlane);
   fillAttribute(theAxis, myaxis);
   fillAttribute(theAngle, myangle);
+  fillAttribute(theNbCopy, mynbcopy);
 
   execute();
 }
@@ -248,8 +254,11 @@ void ConstructionAPI_Plane::dump(ModelHighAPI_Dumper& theDumper) const
        ConstructionPlugin_Plane::CREATION_METHOD_BY_DISTANCE_FROM_OTHER()) {
       AttributeDoublePtr anAttrDistance = aBase->real(ConstructionPlugin_Plane::DISTANCE());
       AttributeBooleanPtr anAttrReverse = aBase->boolean(ConstructionPlugin_Plane::REVERSE());
+      AttributeIntegerPtr anAttrNbCopy = aBase->integer(ConstructionPlugin_Plane::NB_COPIES());
 
       theDumper << ", " << anAttrPlane << ", " << anAttrDistance << ", " << anAttrReverse;
+      if(anAttrNbCopy.get() && anAttrNbCopy->value() > 1)
+        theDumper << ", " << anAttrNbCopy;
     } else if(aCreationMethodOption ==
               ConstructionPlugin_Plane::CREATION_METHOD_BY_COINCIDENT_TO_POINT()) {
       AttributeSelectionPtr anAttrPoint =
@@ -259,8 +268,11 @@ void ConstructionAPI_Plane::dump(ModelHighAPI_Dumper& theDumper) const
     } else if(aCreationMethodOption == ConstructionPlugin_Plane::CREATION_METHOD_BY_ROTATION()) {
       AttributeSelectionPtr anAttrAxis = aBase->selection(ConstructionPlugin_Plane::AXIS());
       AttributeDoublePtr anAttrAngle = aBase->real(ConstructionPlugin_Plane::ANGLE());
+      AttributeIntegerPtr anAttrNbCopy = aBase->integer(ConstructionPlugin_Plane::NB_COPIES());
 
       theDumper << ", " << anAttrPlane << ", " << anAttrAxis << ", " << anAttrAngle;
+      if (anAttrNbCopy.get() && anAttrNbCopy->value() > 1)
+         theDumper << ", " << anAttrNbCopy;
     }
   } else if(aCreationMethod ==
             ConstructionPlugin_Plane::CREATION_METHOD_BY_TWO_PARALLEL_PLANES()) {
@@ -277,11 +289,12 @@ void ConstructionAPI_Plane::dump(ModelHighAPI_Dumper& theDumper) const
 PlanePtr addPlane(const std::shared_ptr<ModelAPI_Document>& thePart,
                   const ModelHighAPI_Selection& theFace,
                   const ModelHighAPI_Double& theDistance,
-                  const bool theIsReverse)
+                  const bool theIsReverse,
+                  const ModelHighAPI_Integer& theNbCopies)
 {
   // TODO(spo): check that thePart is not empty
   std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(ConstructionAPI_Plane::ID());
-  return PlanePtr(new ConstructionAPI_Plane(aFeature, theFace, theDistance, theIsReverse));
+  return PlanePtr(new ConstructionAPI_Plane(aFeature, theFace, theDistance, theIsReverse, theNbCopies));
 }
 
 //==================================================================================================
@@ -332,9 +345,10 @@ PlanePtr addPlane(const std::shared_ptr<ModelAPI_Document>& thePart,
 PlanePtr addPlane(const std::shared_ptr<ModelAPI_Document>& thePart,
                   const ModelHighAPI_Selection& thePlane,
                   const ModelHighAPI_Selection& theAxis,
-                  const ModelHighAPI_Double& theAngle)
+                  const ModelHighAPI_Double& theAngle,
+                  const ModelHighAPI_Integer& theNbCopies)
 {
   // TODO(spo): check that thePart is not empty
   std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(ConstructionAPI_Plane::ID());
-  return PlanePtr(new ConstructionAPI_Plane(aFeature, thePlane, theAxis, theAngle));
+  return PlanePtr(new ConstructionAPI_Plane(aFeature, thePlane, theAxis, theAngle, theNbCopies));
 }
index b8b28d3f4ef44a73785a50e650135f8a5282487b..b99940b090035d30047cc31737c9b63bc5a3ae22 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <ModelHighAPI_Interface.h>
 #include <ModelHighAPI_Macro.h>
+#include <ModelHighAPI_Integer.h>
 
 class ModelHighAPI_Double;
 class ModelHighAPI_Selection;
@@ -45,7 +46,8 @@ public:
   ConstructionAPI_Plane(const std::shared_ptr<ModelAPI_Feature>& theFeature,
                         const ModelHighAPI_Selection& theFace,
                         const ModelHighAPI_Double& theDistance,
-                        const bool theIsReverse);
+                        const bool theIsReverse,
+                        const ModelHighAPI_Integer& theNbCopy = ModelHighAPI_Integer(1));
 
   /// Constructor with values
   CONSTRUCTIONAPI_EXPORT
@@ -80,13 +82,14 @@ public:
   ConstructionAPI_Plane(const std::shared_ptr<ModelAPI_Feature>& theFeature,
                         const ModelHighAPI_Selection& thePlane,
                         const ModelHighAPI_Selection& theAxis,
-                        const ModelHighAPI_Double& theAngle);
+                        const ModelHighAPI_Double& theAngle,
+                        const ModelHighAPI_Integer& theNbCopy = ModelHighAPI_Integer(1));
 
   /// Destructor
   CONSTRUCTIONAPI_EXPORT
   virtual ~ConstructionAPI_Plane();
 
-  INTERFACE_20(ConstructionPlugin_Plane::ID(),
+  INTERFACE_21(ConstructionPlugin_Plane::ID(),
                creationMethod, ConstructionPlugin_Plane::CREATION_METHOD(),
                ModelAPI_AttributeString, /** Creation method */,
                A, ConstructionPlugin_Plane::A(),
@@ -127,13 +130,16 @@ public:
                plane1, ConstructionPlugin_Plane::PLANE1(),
                ModelAPI_AttributeSelection, /** Plane 1 */,
                plane2, ConstructionPlugin_Plane::PLANE2(),
-               ModelAPI_AttributeSelection, /** Plane 2 */)
+               ModelAPI_AttributeSelection, /** Plane 2 */,
+               nbcopy, ConstructionPlugin_Plane::NB_COPIES(),
+               ModelAPI_AttributeInteger, /** Number of copies */)
 
   /// Set face and distance
   CONSTRUCTIONAPI_EXPORT
   void setByFaceAndDistance(const ModelHighAPI_Selection& theFace,
                             const ModelHighAPI_Double& theDistance,
-                            const bool theIsReverse);
+                            const bool theIsReverse,
+                            const ModelHighAPI_Integer& theNbCopy = ModelHighAPI_Integer(1));
 
   /// Set GeneralEquation parameters of the feature
   CONSTRUCTIONAPI_EXPORT
@@ -168,7 +174,8 @@ public:
   CONSTRUCTIONAPI_EXPORT
   void setByRotation(const ModelHighAPI_Selection& thePlane,
                      const ModelHighAPI_Selection& theAxis,
-                     const ModelHighAPI_Double& theAngle);
+                     const ModelHighAPI_Double& theAngle,
+                     const ModelHighAPI_Integer& theNbCopy = ModelHighAPI_Integer(1));
 
   /// Dump wrapped feature
   CONSTRUCTIONAPI_EXPORT
@@ -184,7 +191,8 @@ CONSTRUCTIONAPI_EXPORT
 PlanePtr addPlane(const std::shared_ptr<ModelAPI_Document>& thePart,
                   const ModelHighAPI_Selection& theFace,
                   const ModelHighAPI_Double& theDistance,
-                  const bool theIsReverse);
+                  const bool theIsReverse,
+                  const ModelHighAPI_Integer& theNbCopy = ModelHighAPI_Integer(1));
 
 /// \ingroup CPPHighAPI
 /// \brief Create Plane feature
@@ -224,6 +232,7 @@ CONSTRUCTIONAPI_EXPORT
 PlanePtr addPlane(const std::shared_ptr<ModelAPI_Document>& thePart,
                   const ModelHighAPI_Selection& thePlane,
                   const ModelHighAPI_Selection& theAxis,
-                  const ModelHighAPI_Double& theAngle);
+                  const ModelHighAPI_Double& theAngle,
+                  const ModelHighAPI_Integer& theNbCopy = ModelHighAPI_Integer(1));
 
 #endif /* SRC_CONSTRUCTIONAPI_CONSTRUCTIONAPI_PLANE_H_ */
index c4c384ba5d61f8092812038f4c8c37f9f48db1e3..6a6d7fc6b33e0008481f804ea0d43ff10737c810 100644 (file)
@@ -42,6 +42,7 @@
 #include <ModelAPI_AttributeSelection.h>
 #include <ModelAPI_AttributeString.h>
 #include <ModelAPI_AttributeBoolean.h>
+#include <ModelAPI_AttributeInteger.h>
 #include <ModelAPI_ResultConstruction.h>
 #include <ModelAPI_Session.h>
 #include <ModelAPI_Validator.h>
@@ -99,46 +100,63 @@ void ConstructionPlugin_Plane::initAttributes()
   // By two parallel planes.
   data()->addAttribute(PLANE1(), ModelAPI_AttributeSelection::typeId());
   data()->addAttribute(PLANE2(), ModelAPI_AttributeSelection::typeId());
+
+  // By other plane.
+  AttributeIntegerPtr aNbCopies = std::dynamic_pointer_cast<ModelAPI_AttributeInteger>(
+    data()->addAttribute(NB_COPIES(), ModelAPI_AttributeInteger::typeId()));
+
+  if (!aNbCopies->isInitialized())
+    aNbCopies->setValue(1);
 }
 
 //==================================================================================================
 void ConstructionPlugin_Plane::execute()
 {
-  GeomShapePtr aShape;
+  ListOfShape aShapes;
 
   std::string aCreationMethod = string(CREATION_METHOD())->value();
   if(aCreationMethod == CREATION_METHOD_BY_GENERAL_EQUATION() ||
       aCreationMethod == "PlaneByGeneralEquation") {
-    aShape = createByGeneralEquation();
+    aShapes.push_back(createByGeneralEquation());
   } else if(aCreationMethod == CREATION_METHOD_BY_THREE_POINTS()) {
-    aShape = createByThreePoints();
+    aShapes.push_back(createByThreePoints());
   } else if(aCreationMethod == CREATION_METHOD_BY_LINE_AND_POINT()) {
-    aShape = createByLineAndPoint();
+    aShapes.push_back(createByLineAndPoint());
   } else if(aCreationMethod == CREATION_METHOD_BY_OTHER_PLANE()) {
     std::string aCreationMethodOption = string(CREATION_METHOD_BY_OTHER_PLANE_OPTION())->value();
     if(aCreationMethodOption == CREATION_METHOD_BY_DISTANCE_FROM_OTHER()) {
-      aShape = createByDistanceFromOther();
+      createByDistanceFromOther(aShapes);
     } else if(aCreationMethodOption == CREATION_METHOD_BY_COINCIDENT_TO_POINT()) {
-      aShape = createByCoincidentPoint();
+      aShapes.push_back(createByCoincidentPoint());
     } else if(aCreationMethodOption == CREATION_METHOD_BY_ROTATION()) {
-      aShape = createByRotation();
+      createByRotation(aShapes);
     }
   } else if(aCreationMethod == CREATION_METHOD_BY_TWO_PARALLEL_PLANES()) {
-    aShape = createByTwoParallelPlanes();
+    aShapes.push_back(createByTwoParallelPlanes());
   } else {
     setError("Error: Plane creation method \"" + aCreationMethod + "\" not supported.");
     return;
   }
 
-  if(!aShape.get()) {
+  if(aShapes.size() == 0) {
     setError("Error: Could not create a plane.");
     return;
   }
 
-  ResultConstructionPtr aConstr = document()->createConstruction(data());
-  aConstr->setInfinite(true);
-  aConstr->setShape(aShape);
-  setResult(aConstr);
+  int anIndex = 0;
+  for (auto aShapeIter = aShapes.begin(); aShapeIter != aShapes.end(); ++aShapeIter, ++anIndex)
+  {
+    if (!aShapeIter->get())
+    {
+      setError("Error: Could not create a plane.");
+      continue;
+    }
+    ResultConstructionPtr aConstr = document()->createConstruction(data(), anIndex);
+    aConstr->setInfinite(true);
+    aConstr->setShape(*aShapeIter);
+    setResult(aConstr, anIndex);
+  }
+  removeResults(anIndex);
 }
 
 //==================================================================================================
@@ -191,7 +209,6 @@ std::shared_ptr<GeomAPI_Shape> ConstructionPlugin_Plane::createByGeneralEquation
   }
   return aPlaneFace;
 }
-
 //==================================================================================================
 std::shared_ptr<GeomAPI_Shape> ConstructionPlugin_Plane::createByThreePoints()
 {
@@ -275,17 +292,18 @@ std::shared_ptr<GeomAPI_Shape> ConstructionPlugin_Plane::createByLineAndPoint()
 }
 
 //==================================================================================================
-std::shared_ptr<GeomAPI_Shape> ConstructionPlugin_Plane::createByDistanceFromOther()
+void ConstructionPlugin_Plane::createByDistanceFromOther(ListOfShape& theShapes)
 {
   AttributeSelectionPtr aFaceAttr = data()->selection(ConstructionPlugin_Plane::PLANE());
   AttributeDoublePtr aDistAttr = data()->real(ConstructionPlugin_Plane::DISTANCE());
-  std::shared_ptr<GeomAPI_Shape> aPlane;
+  AttributeIntegerPtr aNbCopyAttr = data()->integer(ConstructionPlugin_Plane::NB_COPIES());
   if ((aFaceAttr.get() != NULL) &&
-      (aDistAttr.get() != NULL) &&
+      (aDistAttr.get() != NULL) && (aNbCopyAttr.get() != NULL) &&
       aFaceAttr->isInitialized() && aDistAttr->isInitialized()) {
 
     double aDist = aDistAttr->value();
     bool anIsReverse = boolean(REVERSE())->value();
+    int aNumOfCopies = aNbCopyAttr->value();
     if(anIsReverse) aDist = -aDist;
     GeomShapePtr aShape = aFaceAttr->value();
     if (!aShape.get() && aFaceAttr->context()) {
@@ -293,7 +311,7 @@ std::shared_ptr<GeomAPI_Shape> ConstructionPlugin_Plane::createByDistanceFromOth
     }
 
     if(!aShape.get()) {
-      return aPlane;
+      return;
     }
 
     std::shared_ptr<GeomAPI_Face> aFace;
@@ -305,18 +323,22 @@ std::shared_ptr<GeomAPI_Shape> ConstructionPlugin_Plane::createByDistanceFromOth
       aFace = anIt.current()->face();
     }
     if (!aFace)
-      return GeomShapePtr();
+      return;
 
     std::shared_ptr<GeomAPI_Pln> aPln = aFace->getPlane();
     std::shared_ptr<GeomAPI_Pnt> aOrig = aPln->location();
     std::shared_ptr<GeomAPI_Dir> aDir = aPln->direction();
 
-    aOrig->translate(aDir, aDist);
-    std::shared_ptr<GeomAPI_Pln> aNewPln(new GeomAPI_Pln(aOrig, aDir));
+    for (int aNbCopy = 0; aNbCopy < aNumOfCopies; ++aNbCopy)
+    {
+      std::shared_ptr<GeomAPI_Shape> aPlane;
+      aOrig->translate(aDir, aDist);
+      std::shared_ptr<GeomAPI_Pln> aNewPln(new GeomAPI_Pln(aOrig, aDir));
 
-    aPlane = makeRectangularFace(aFace, aNewPln);
+      aPlane = makeRectangularFace(aFace, aNewPln);
+      theShapes.push_back(aPlane);
+    }
   }
-  return aPlane;
 }
 
 //==================================================================================================
@@ -357,7 +379,7 @@ std::shared_ptr<GeomAPI_Shape> ConstructionPlugin_Plane::createByCoincidentPoint
 }
 
 //==================================================================================================
-std::shared_ptr<GeomAPI_Shape> ConstructionPlugin_Plane::createByRotation()
+void ConstructionPlugin_Plane::createByRotation(ListOfShape& theShapes)
 {
   // Get face.
   AttributeSelectionPtr aFaceSelection = selection(PLANE());
@@ -374,7 +396,7 @@ std::shared_ptr<GeomAPI_Shape> ConstructionPlugin_Plane::createByRotation()
     aFace = anIt.current()->face();
   }
   if (!aFace)
-    return GeomShapePtr();
+    return;
   aFace = makeRectangularFace(aFace, aFace->getPlane());
 
   // Get axis.
@@ -392,7 +414,14 @@ std::shared_ptr<GeomAPI_Shape> ConstructionPlugin_Plane::createByRotation()
     anEdge = anIt.current()->edge();
   }
   if (!anEdge)
-    return GeomShapePtr();
+    return;
+
+  AttributeIntegerPtr aNbCopyAttr = data()->integer(ConstructionPlugin_Plane::NB_COPIES());
+  int aNBCopy;
+  if (!aNbCopyAttr.get())
+    return;
+
+  aNBCopy = aNbCopyAttr->value();
 
   std::shared_ptr<GeomAPI_Ax1> anAxis =
     std::shared_ptr<GeomAPI_Ax1>(new GeomAPI_Ax1(anEdge->line()->location(),
@@ -401,17 +430,20 @@ std::shared_ptr<GeomAPI_Shape> ConstructionPlugin_Plane::createByRotation()
   // Getting angle.
   double anAngle = real(ANGLE())->value();
 
-  std::shared_ptr<GeomAlgoAPI_Rotation> aRotationAlgo(
-      new GeomAlgoAPI_Rotation(aFace, anAxis, anAngle));
-  // Checking that the algorithm worked properly.
-  std::string anError;
-  if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aRotationAlgo, getKind(), anError)) {
-    setError("Error: Failed to rotate plane");
-    return GeomShapePtr();
-  }
+  for (int anIndex = 1; anIndex <= aNBCopy; ++anIndex)
+  {
+    std::shared_ptr<GeomAlgoAPI_Rotation> aRotationAlgo(
+      new GeomAlgoAPI_Rotation(aFace, anAxis, anAngle * anIndex));
+    // Checking that the algorithm worked properly.
+    std::string anError;
+    if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aRotationAlgo, getKind(), anError)) {
+      setError("Error: Failed to rotate plane");
+      return;
+    }
 
-  std::shared_ptr<GeomAPI_Face> aRes(new GeomAPI_Face(aRotationAlgo->shape()));
-  return aRes;
+    std::shared_ptr<GeomAPI_Face> aRes(new GeomAPI_Face(aRotationAlgo->shape()));
+    theShapes.push_back(aRes);
+  }
 }
 
 //==================================================================================================
index 214f4e6dbe7a36dadff5d180f83eb94dfa9472a5..ff6b14adf9e0ea22e0050b0fadc973a243f4c2de 100644 (file)
@@ -25,6 +25,7 @@
 #include <ModelAPI_Feature.h>
 #include <ModelAPI_Result.h>
 #include <GeomAPI_ICustomPrs.h>
+#include <GeomAPI_Shape.h>
 
 /// \class ConstructionPlugin_Plane
 /// \ingroup Plugins
@@ -226,6 +227,11 @@ public:
     return ATTR_ID;
   }
 
+  inline static const std::string& NB_COPIES()
+  {
+    static const std::string ATTR_ID("nb_copies");
+    return ATTR_ID;
+  }
 
   /// Attribute name for a parameter for the general equation of a plane (ax+by+cz+d=0)
   inline static const std::string& A()
@@ -270,11 +276,11 @@ protected:
   std::shared_ptr<GeomAPI_Shape> createByThreePoints();
   std::shared_ptr<GeomAPI_Shape> createByLineAndPoint();
   std::shared_ptr<GeomAPI_Shape> createByCoincidentPoint();
-  std::shared_ptr<GeomAPI_Shape> createByRotation();
+  void createByRotation(ListOfShape& theShapes);
   std::shared_ptr<GeomAPI_Shape> createByTwoParallelPlanes();
   /// Creates a new plane by copy of face plane with translation along the normal
   /// to the specified distance.
-  std::shared_ptr<GeomAPI_Shape> createByDistanceFromOther();
+  void createByDistanceFromOther(ListOfShape& theShapes);
 };
 
 #endif
index ecb0de35dc81dba5384c511d2779133363163414..2de6c5fea3b1eb232f0809fed798e771fa5d274a 100644 (file)
       <translation>Select the third point.</translation>
     </message>
   </context>
+  <context>
+    <name>Plane:nb_copies</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Select the number of copies.</translation>
+    </message>
+  </context>
 
   <context>
     <name>Point:edge</name>
index 21fa8315f62378e141438c94bcfdcb8f70c212cf..240f138ed7f6535ef0503bb11e4efafbd6bde1f0 100644 (file)
       <translation>Sens inverse</translation>
     </message>
   </context>
-
+  <context>
+    <name>Plane:nb_copies</name>
+    <message>
+      <source>Nb copies</source>
+      <translation>Nb d'exemplaires</translation>
+    </message>
+    <message>
+      <source>Number of copies of the plane</source>
+      <translation>Nombre de plans</translation>
+    </message>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez le nombre d'exemplaires.</translation>
+    </message>
+  </context>
   <context>
     <name>Point</name>
     <message>
diff --git a/src/ConstructionPlugin/Test/TestPlane_Copies.py b/src/ConstructionPlugin/Test/TestPlane_Copies.py
new file mode 100644 (file)
index 0000000..ddc4621
--- /dev/null
@@ -0,0 +1,65 @@
+# Copyright (C) 2014-2021  CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+"""
+Test case for Construction Plane feature. Written on High API.
+"""
+from ModelAPI import *
+from GeomAPI import *
+
+from salome.shaper import model
+
+# Get session
+aSession = ModelAPI_Session.get()
+
+# Create a part
+aDocument = aSession.activeDocument()
+aSession.startOperation()
+model.addPart(aDocument)
+aDocument = aSession.activeDocument()
+aSession.finishOperation()
+
+# Test a plane by general equation
+aSession.startOperation()
+aPlane = model.addPlane(aDocument, 1, 1, 1, 0)
+aSession.finishOperation()
+assert (len(aPlane.results()) > 0)
+
+# Create an axis
+aSession.startOperation()
+anAxis = model.addAxis(aDocument, 100, 0, 0)
+aSession.finishOperation()
+
+# Test a plane by rotation
+aSession.startOperation()
+aRotatedPlane = model.addPlane(aDocument, aPlane.result(), anAxis.result(), 45)
+aRotatedPlanes = model.addPlane(aDocument, aPlane.result(), anAxis.result(), 45, 5)
+aSession.finishOperation()
+assert (len(aRotatedPlane.results()) > 0)
+assert (len(aRotatedPlanes.results()) == 5)
+
+# Test a plane by distance from other
+aSession.startOperation()
+anOnlyPlane = model.addPlane(aDocument, aPlane.result(), 50, False)
+assert (len(anOnlyPlane.results()) > 0)
+aPlane = model.addPlane(aDocument, aPlane.result(), 50, False, 10)
+aSession.finishOperation()
+assert (len(aPlane.results()) == 10)
+
+assert(model.checkPythonDump())
index be4eddd0dad1d363bb9482b52c3b489003c06e91..a0512dd0a3c6d630bc4a2dbe42d587d81743ea5e 100644 (file)
Binary files a/src/ConstructionPlugin/doc/images/Plane3.png and b/src/ConstructionPlugin/doc/images/Plane3.png differ
index 90c7134e08b617abd455f5463434a432c3c912e5..a0b2d71fbc23a0990cad5b0322373700c23ee051 100644 (file)
@@ -28,7 +28,7 @@ There are 4 algorithms for creation of a Plane:
    :align: left
    :height: 24px
 
-**By other plane** creates a plane parallel to another plane.
+**By other plane** creates a plane or planes(if the number of copies is more than one) parallel to another plane.
 
 .. figure:: images/plane_by_two_parallel_planes_32x32.png
    :align: left
@@ -134,18 +134,19 @@ By rotation around an edge by a specified angle.
 
 **TUI Commands**:
 
-.. py:function:: model.addPlane(Part_doc, model.selection("FACE", "Box_1_1/Front"), 10, False)
+.. py:function:: model.addPlane(Part_doc, model.selection("FACE", "Box_1_1/Front"), 10, False, 1)
 
     :param part: The current part object.
     :param object: A plane.
     :param real: An offset.
     :param boolean: Is reverse.
+    :param integer: Number of copies
     :return: Result object.
 
 Result
 """"""
 
-The Result of the operation will be a plane parallel to already existing one:
+The Result of the operation will be a plane (or planes at equal distance from each other, if the number of copies is more than one) parallel to already existing one:
 
 .. figure:: images/CreatedPlane3.png
    :align: center
index b9e777555003b0ea4e5115d31c43f50a028aeff6..0c487b5ac7b3af3f229ffa5d5866c8977f518820 100644 (file)
                        min="0"
                        default="10">
           </doublevalue>
+          <integervalue id="nb_copies"
+                        label="Nb copies"
+                        tooltip="Number of copies of the plane"
+                        min="1"
+                        default="1">
+          </integervalue>
           <boolvalue id="reverse"
                      label="Reverse"
                      tooltip="Checked means on the other side of the selected plane."
                        default="45">
             <validator id="GeomValidators_Positive"/>
           </doublevalue>
+          <integervalue id="nb_copies"
+                        label="Nb copies"
+                        tooltip="Number of copies of the plane "
+                        min="1"
+                        default="1">
+          </integervalue>
         </box>
       </toolbox>
     </box>
index 09e2211bc8e2a119e92a91bacdbe38655203633a..1bfdfa7fd9f145daa26e690570db27f90a871b9c 100644 (file)
@@ -37,6 +37,7 @@ SET(TEST_NAMES
     TestPlane.py
     TestPlane_ErrorMsg.py
     TestPlane_FaceValidator.py
+    TestPlane_Copies.py
     Test19207.py
     Test19471.py
 )
index ebb3d6be922a088ca19edd6d98ab5f1186577d0d..1265360d602afe2cc0e7c96e0951fe7aeeeeb0eb 100644 (file)
@@ -1905,10 +1905,12 @@ void Model_Objects::updateResults(FeaturePtr theFeature, std::set<FeaturePtr>& t
           }
         } else if (aGroup->Get() == ModelAPI_ResultConstruction::group().c_str()) {
           ResultConstructionPtr aConstr = createConstruction(theFeature->data(), aResIndex);
-          if (!aConstr->updateShape())
-            theFeature->execute(); // not stored shape in the data structure, execute to have it
-          else
-            theFeature->setResult(aConstr, aResIndex); // result is ready without execution
+          if (!aConstr->data()->isDeleted()) {
+            if (!aConstr->updateShape())
+              theFeature->execute(); // not stored shape in the data structure, execute to have it
+            else
+              theFeature->setResult(aConstr, aResIndex); // result is ready without execution
+          }
         } else if (aGroup->Get() == ModelAPI_ResultGroup::group().c_str()) {
           aNewBody = createGroup(theFeature->data(), aResIndex);
         } else if (aGroup->Get() == ModelAPI_ResultField::group().c_str()) {
index 25c0cd9783f1f1393325751fb1ebd2b4c3681551..dc5da8ad12b144ac2687a052dccea7ab32e71e56 100644 (file)
@@ -905,8 +905,7 @@ void Model_Update::updateArguments(FeaturePtr theFeature) {
       bool isObligatory = aFactory->isCase(theFeature, theFeature->data()->id(aSel));
       if (isObligatory)
         aState = ModelAPI_StateInvalidArgument;
-    } else if (theFeature->getKind() == "Sketch" && aSel->id() == "External" &&
-               aSel->isInitialized()) {
+    } else if (aSel->isInitialized()) {
       // #19703 : if sketch plane was selected, but after context disappears, it must become invalid
       aSel->update();
       if (aSel->isInvalid()) {