Salome HOME
[CEA] Simple API in Python 40642_SimpleAPI 46/head
authorEkaterina Sukhareva <ekaterina.sukhareva@opencascade.com>
Fri, 9 Feb 2024 18:21:42 +0000 (18:21 +0000)
committermbs <martin.bernhard@opencascade.com>
Mon, 13 May 2024 08:11:49 +0000 (09:11 +0100)
src/ModelAPI/CMakeLists.txt
src/ModelAPI/ModelAPI_Feature.cpp
src/ModelAPI/ModelAPI_Feature.h
src/ModelAPI/ModelAPI_Result.cpp
src/ModelAPI/ModelAPI_Result.h
src/ModelAPI/Test/Test40642_SimpleAPI.py [new file with mode: 0755]
src/ModelAPI/tests.set
src/ModelHighAPI/ModelHighAPI_Interface.cpp
src/ModelHighAPI/ModelHighAPI_Interface.h
test.models/coronavirus.py

index f2c9b64866e415e832e29e01b4ea007db72a9996..7882c7deef6f5c82bfadf557aea66cda96b73042 100644 (file)
@@ -133,6 +133,7 @@ INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/Config
                     ${PROJECT_SOURCE_DIR}/src/GeomAPI
                     ${PROJECT_SOURCE_DIR}/src/GeomAlgoAPI
                     ${PROJECT_SOURCE_DIR}/src/Locale
+                    ${SUIT_INCLUDE}
 )
 
 
index 8d8b7ffbc8e9129c4dbb8da354d2b69cd4787ae3..2041a9ac31f324f4647247dfb8389de513f87b03 100644 (file)
 #include <Config_Translator.h>
 #include <Config_PropManager.h>
 
+#include <Locale_Convert.h>
+
+#include <PyInterp_Interp.h>
+#include <Python.h>
+
 void ModelAPI_Feature::setError(const std::string& theError,
                                 bool isSend,
                                 bool isTranslate)
@@ -273,3 +278,75 @@ void ModelAPI_Feature::init()
   myIsDisabled = false;
   myIsStable = true;
 }
+
+void ModelAPI_Feature::showErrorMessage()
+{
+  PyLockWrapper lck;
+  std::string aResName{};
+  if(data().get())
+  {
+    aResName = Locale::Convert::toString(data()->name());
+  }
+  std::string aMessage = "WARNING! The "+ aResName +" feature does not have any results.";
+  PySys_WriteStdout("%s\n", aMessage.c_str());
+}
+
+ListOfShape ModelAPI_Feature::vertices(const bool theOnlyUnique)
+{
+  if(myResults.empty())
+  {
+    showErrorMessage();
+    return ListOfShape();
+  }
+  return lastResult()->vertices(theOnlyUnique);
+}
+
+ListOfShape ModelAPI_Feature::edges(const bool theOnlyUnique)
+{
+  if(myResults.empty())
+  {
+    showErrorMessage();
+    return ListOfShape();
+  }
+  return lastResult()->edges(theOnlyUnique);
+}
+
+ListOfShape ModelAPI_Feature::wires(const bool theOnlyUnique)
+{
+  if(myResults.empty())
+  {
+    showErrorMessage();
+    return ListOfShape();
+  }
+  return lastResult()->wires(theOnlyUnique);
+}
+
+ListOfShape ModelAPI_Feature::faces(const bool theOnlyUnique)
+{
+  if(myResults.empty())
+  {
+    showErrorMessage();
+    return ListOfShape();
+  }
+  return lastResult()->faces(theOnlyUnique);
+}
+
+ListOfShape ModelAPI_Feature::shells(const bool theOnlyUnique)
+{
+  if(myResults.empty())
+  {
+    showErrorMessage();
+    return ListOfShape();
+  }
+  return lastResult()->shells(theOnlyUnique);
+}
+
+ListOfShape ModelAPI_Feature::solids(const bool theOnlyUnique)
+{
+  if(myResults.empty())
+  {
+    showErrorMessage();
+    return ListOfShape();
+  }
+  return lastResult()->solids(theOnlyUnique);
+}
index 8c81aa3a52d0bd66c24acdfaf671e6522023406b..118cc1512b76f86c037955b86ba4c3573f49d4bf 100644 (file)
@@ -30,6 +30,8 @@
 #include <list>
 #include <string>
 
+typedef std::list<std::shared_ptr<GeomAPI_Shape> > ListOfShape;
+
 /**\class ModelAPI_Feature
  * \ingroup DataModel
  * \brief Feature function that represents the particular functionality
@@ -163,6 +165,30 @@ class ModelAPI_Feature : public ModelAPI_Object
   /// \return a boolean value about it is performed
   MODELAPI_EXPORT virtual bool customAction(const std::string& theActionId);
 
+  /// Returns all the vertices produced by this feature
+  MODELAPI_EXPORT virtual ListOfShape
+                  vertices(const bool theOnlyUnique = false);
+
+  /// Returns all the edges produced by this feature
+  MODELAPI_EXPORT virtual ListOfShape
+                  edges(const bool theOnlyUnique = false);
+
+  /// Returns all the wires produced by this feature
+  MODELAPI_EXPORT virtual ListOfShape
+                  wires(const bool theOnlyUnique = false);
+
+  /// Returns all the faces produced by this feature
+  MODELAPI_EXPORT virtual ListOfShape
+                  faces(const bool theOnlyUnique = false);
+
+  /// Returns all the shells produced by this feature
+  MODELAPI_EXPORT virtual ListOfShape
+                  shells(const bool theOnlyUnique = false);
+
+  /// Returns all the solids produced by this feature
+  MODELAPI_EXPORT virtual ListOfShape
+                  solids(const bool theOnlyUnique = false);
+
  //
  // Helper methods, aliases for data()->method()
  // -----------------------------------------------------------------------------------------------
@@ -246,7 +272,12 @@ class ModelAPI_Feature : public ModelAPI_Object
   {
     return data()->attribute(theID);
   }
-  protected:
+
+ private:
+  /// Print warning message to python console
+  void showErrorMessage();
+
+ protected:
   /// This method is called just after creation of the object: it must initialize
   /// all fields, normally initialized in the constructor
   MODELAPI_EXPORT virtual void init();
index ec88a61afa35f31c1994aa23770004d85228c479..2c3bdc9f9acaebbc921fc95b367c14249921db77 100644 (file)
 #include <ModelAPI_AttributeDouble.h>
 #include <ModelAPI_AttributeBoolean.h>
 
+#include <GeomAPI_Shape.h>
+
 #include <Events_Loop.h>
+#include <Events_InfoMessage.h>
+
+#include <Locale_Convert.h>
+
+#include <PyInterp_Interp.h>
+#include <Python.h>
 
 ModelAPI_Result::~ModelAPI_Result()
 {
@@ -101,12 +109,83 @@ void ModelAPI_Result::setIsConcealed(const bool theValue, const bool /*theForced
   }
 }
 
-
 std::shared_ptr<GeomAPI_Shape> ModelAPI_Result::shape()
 {
   return std::shared_ptr<GeomAPI_Shape>();
 }
 
+void ModelAPI_Result::showErrorMessage()
+{
+  PyLockWrapper lck;
+  std::string aResName{};
+  if(data().get())
+  {
+    aResName = Locale::Convert::toString(data()->name());
+  }
+  std::string aMessage = "WARNING! The "+ aResName +" result is not valid.";
+  PySys_WriteStdout("%s\n", aMessage.c_str());
+}
+
+ListOfShape ModelAPI_Result::vertices(const bool theOnlyUnique)
+{
+  if(!shape().get() || isDisabled())
+  {
+    showErrorMessage();
+    return ListOfShape();
+  }
+  return shape()->subShapes(GeomAPI_Shape::VERTEX, theOnlyUnique);
+}
+
+ListOfShape ModelAPI_Result::edges(const bool theOnlyUnique)
+{
+  if(!shape().get() || isDisabled())
+  {
+    showErrorMessage();
+    return ListOfShape();
+  }
+  return shape()->subShapes(GeomAPI_Shape::EDGE, theOnlyUnique);
+}
+
+ListOfShape ModelAPI_Result::wires(const bool theOnlyUnique)
+{
+  if(!shape().get() || isDisabled())
+  {
+    showErrorMessage();
+    return ListOfShape();
+  }
+  return shape()->subShapes(GeomAPI_Shape::WIRE, theOnlyUnique);
+}
+
+ListOfShape ModelAPI_Result::faces(const bool theOnlyUnique)
+{
+  if(!shape().get() || isDisabled())
+  {
+    showErrorMessage();
+    return ListOfShape();
+  }
+  return shape()->subShapes(GeomAPI_Shape::FACE, theOnlyUnique);
+}
+
+ListOfShape ModelAPI_Result::shells(const bool theOnlyUnique)
+{
+  if(!shape().get() || isDisabled())
+  {
+    showErrorMessage();
+    return ListOfShape();
+  }
+  return shape()->subShapes(GeomAPI_Shape::SHELL, theOnlyUnique);
+}
+
+ListOfShape ModelAPI_Result::solids(const bool theOnlyUnique)
+{
+  if(!shape().get() || isDisabled())
+  {
+    showErrorMessage();
+    return ListOfShape();
+  }
+  return shape()->subShapes(GeomAPI_Shape::SOLID, theOnlyUnique);
+}
+
 void ModelAPI_Result::attributeChanged(const std::string& theID)
 {
   static Events_Loop* aLoop = Events_Loop::loop();
index 8573eff3c70b11cac427e139163f02a672e26ecd..e82ea2f355d123eb0f36f26dd450ecac3567a876 100644 (file)
@@ -25,6 +25,8 @@
 class GeomAPI_Shape;
 class ModelAPI_Feature;
 
+typedef std::list<std::shared_ptr<GeomAPI_Shape> > ListOfShape;
+
 /**\class ModelAPI_Result
  * \ingroup DataModel
  * \brief The result of a feature.
@@ -120,12 +122,40 @@ class ModelAPI_Result : public ModelAPI_Object
   MODELAPI_EXPORT virtual ~ModelAPI_Result();
 
   /// Returns the shape-result produced by this feature (or null if no shapes)
-  MODELAPI_EXPORT virtual std::shared_ptr<GeomAPI_Shape> shape();
+  MODELAPI_EXPORT virtual std::shared_ptr<GeomAPI_Shape> shape(); 
+
+  /// Returns all the vertices of this result
+  MODELAPI_EXPORT virtual ListOfShape
+                  vertices(const bool theOnlyUnique = false);
+
+  /// Returns all the edges of this result
+  MODELAPI_EXPORT virtual ListOfShape
+                  edges(const bool theOnlyUnique = false);
+
+  /// Returns all the wires of this result
+  MODELAPI_EXPORT virtual ListOfShape
+                  wires(const bool theOnlyUnique = false);
+
+  /// Returns all the faces of this result
+  MODELAPI_EXPORT virtual ListOfShape
+                  faces(const bool theOnlyUnique = false);
+
+  /// Returns all the shells of this result
+  MODELAPI_EXPORT virtual ListOfShape
+                  shells(const bool theOnlyUnique = false);
+
+  /// Returns all the solids of this result
+  MODELAPI_EXPORT virtual ListOfShape
+                  solids(const bool theOnlyUnique = false);
 
   /// On change of attribute of the result update presentation of this result:
   /// for the current moment there are only presentation attributes assigned to results
   MODELAPI_EXPORT virtual void attributeChanged(const std::string& theID);
 
+private:
+  /// Print warning message to python console
+  void showErrorMessage();
+
 protected:
   /// This method is called just after creation of the object: it must initialize
   /// all fields, normally initialized in the constructor
diff --git a/src/ModelAPI/Test/Test40642_SimpleAPI.py b/src/ModelAPI/Test/Test40642_SimpleAPI.py
new file mode 100755 (executable)
index 0000000..039320c
--- /dev/null
@@ -0,0 +1,155 @@
+#!/usr/bin/env python
+
+###
+### This file is generated automatically by SALOME v9.12.0 with dump python functionality
+###
+
+import sys
+import salome
+
+salome.salome_init()
+
+###
+### SHAPER component
+###
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+
+### Create Part
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+
+### Create Box
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+model.do()
+
+#########################################################
+assert (len(Box_1.vertices()) == 48)
+assert (len(Box_1.defaultResult().vertices()) == 48)
+assert (len(Box_1.feature().vertices()) == 48)
+
+# Count only unique vertices
+assert (len(Box_1.vertices(True) ) == 8)
+assert (len(Box_1.defaultResult().vertices(True)) == 8)
+assert (len(Box_1.feature().vertices(True)) == 8)
+
+#########################################################
+assert (len(Box_1.edges()) == 24)
+assert (len(Box_1.defaultResult().edges()) == 24)
+assert (len(Box_1.feature().edges()) == 24)
+
+# Count only unique edges
+assert (len(Box_1.edges(True)) == 12)
+assert (len(Box_1.defaultResult().edges(True)) == 12)
+assert (len(Box_1.feature().edges(True)) == 12)
+
+#########################################################
+assert (len(Box_1.wires()) == 6)
+assert (len(Box_1.defaultResult().wires()) == 6)
+assert (len(Box_1.feature().wires()) == 6)
+
+#########################################################
+assert (len(Box_1.faces()) == 6)
+assert (len(Box_1.defaultResult().faces()) == 6)
+assert (len(Box_1.feature().faces()) == 6)
+
+#########################################################
+assert (len(Box_1.shells()) == 1)
+assert (len(Box_1.defaultResult().shells()) == 1)
+assert (len(Box_1.feature().shells()) == 1)
+
+#########################################################
+assert (len(Box_1.solids()) == 1)
+assert (len(Box_1.defaultResult().solids()) == 1)
+assert (len(Box_1.feature().solids()) == 1)
+
+
+### Create Box
+Box_2 = model.addBox(Part_1_doc, 40, 40, 5, 5, 5, 5)
+
+### Create Box
+Box_3 = model.addBox(Part_1_doc, 40, 40, 15, 5, 5, 5)
+
+### Create Box
+Box_4 = model.addBox(Part_1_doc, 40, 40, 25, 5, 5, 5)
+
+### Create CompSolid
+CompSolid_1_objects = [model.selection("SOLID", "Box_2_1"),
+                       model.selection("SOLID", "Box_3_1"),
+                       model.selection("SOLID", "Box_4_1")]
+CompSolid_1 = model.addCompSolid(Part_1_doc, CompSolid_1_objects)
+model.do()
+
+#########################################################
+assert (len(CompSolid_1.vertices()) == 144)
+assert (len(CompSolid_1.defaultResult().vertices()) == 144)
+assert (len(CompSolid_1.feature().vertices()) == 144)
+
+# Count only unique vertices
+assert (len(CompSolid_1.vertices(True) ) == 16)
+assert (len(CompSolid_1.defaultResult().vertices(True)) == 16)
+assert (len(CompSolid_1.feature().vertices(True)) == 16)
+
+#########################################################
+assert (len(CompSolid_1.edges()) == 72)
+assert (len(CompSolid_1.defaultResult().edges()) == 72)
+assert (len(CompSolid_1.feature().edges()) == 72)
+
+# Count only unique edges
+assert (len(CompSolid_1.edges(True)) == 28)
+assert (len(CompSolid_1.defaultResult().edges(True)) == 28)
+assert (len(CompSolid_1.feature().edges(True)) == 28)
+
+#########################################################
+assert (len(CompSolid_1.wires()) == 18)
+assert (len(CompSolid_1.defaultResult().wires()) == 18)
+assert (len(CompSolid_1.feature().wires()) == 18)
+
+#########################################################
+assert (len(CompSolid_1.faces()) == 18)
+assert (len(CompSolid_1.defaultResult().faces()) == 18)
+assert (len(CompSolid_1.feature().faces()) == 18)
+
+#########################################################
+assert (len(CompSolid_1.shells()) == 3)
+assert (len(CompSolid_1.defaultResult().shells()) == 3)
+assert (len(CompSolid_1.feature().shells()) == 3)
+
+#########################################################
+assert (len(CompSolid_1.solids()) == 3)
+assert (len(CompSolid_1.defaultResult().solids()) == 3)
+assert (len(CompSolid_1.feature().solids()) == 3)
+
+#########################################################
+### Create Sketch
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+
+### Create SketchCircle
+SketchCircle_1 = Sketch_1.addCircle(20, 20, 5)
+model.do()
+### Create Face
+Face_1 = model.addFace(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchCircle_1_2")])
+model.do()
+
+#########################################################
+### Result is a single face (no shell or solid)
+assert (len(Face_1.faces()) == 1)
+assert (len(Face_1.shells()) == 0)
+assert (len(Face_1.solids()) == 0)
+
+#########################################################
+### Create Common
+Common_1 = model.addCommon(Part_1_doc, [model.selection("SOLID", "Box_1_1"), model.selection("COMPSOLID", "CompSolid_1_1")], keepSubResults = True)
+model.do()
+
+#########################################################
+### There is no result created by the Common_1 feature
+assert (Common_1.defaultResult() == None) # use this check to identify a non-existent result (feature can still ba valid!!)
+assert (len(Common_1.faces()) == 0)
+assert (len(Common_1.solids()) == 0)
+assert (len(Common_1.feature().solids()) == 0)
+
+model.end()
index daf11288093b35892ece7ed5555aee558b7a682f..304575aebe89e5589aebc13a3d1f112a1dbe0835 100644 (file)
@@ -124,4 +124,5 @@ SET(TEST_NAMES
                Test26745.py
                TestMovePart1.py
                TestMovePart2.py
+               Test40642_SimpleAPI.py
 )
index 9873ab7a5f1f41d1aa14e0c6912098843e5c05c6..99983df1675c685e1da5af28c862c821f98535de 100644 (file)
@@ -141,3 +141,39 @@ const std::string& ModelHighAPI_Interface::attributeGetter(const std::string& th
 {
   return myAttrGetter[theAttrName];
 }
+
+ListOfShape ModelHighAPI_Interface::vertices(const bool theOnlyUnique)
+{
+  const_cast<ModelHighAPI_Interface*>(this)->execute();
+  return feature()->vertices(theOnlyUnique);
+}
+
+ListOfShape ModelHighAPI_Interface::edges(const bool theOnlyUnique)
+{
+  const_cast<ModelHighAPI_Interface*>(this)->execute();
+  return feature()->edges(theOnlyUnique);
+}
+
+ListOfShape ModelHighAPI_Interface::wires(const bool theOnlyUnique)
+{
+  const_cast<ModelHighAPI_Interface*>(this)->execute();
+  return feature()->wires(theOnlyUnique);
+}
+
+ListOfShape ModelHighAPI_Interface::faces(const bool theOnlyUnique)
+{
+  const_cast<ModelHighAPI_Interface*>(this)->execute();
+  return feature()->faces(theOnlyUnique);
+}
+
+ListOfShape ModelHighAPI_Interface::shells(const bool theOnlyUnique)
+{
+  const_cast<ModelHighAPI_Interface*>(this)->execute();
+  return feature()->shells(theOnlyUnique);
+}
+
+ListOfShape ModelHighAPI_Interface::solids(const bool theOnlyUnique)
+{
+  const_cast<ModelHighAPI_Interface*>(this)->execute();
+  return feature()->solids(theOnlyUnique);
+}
index b96d8776f7b9485c9ff6d184543444465b0d0c27..995ac7151e90fe6e3d150ce0c206631122a20b56 100644 (file)
@@ -33,6 +33,10 @@ class ModelAPI_Feature;
 class ModelAPI_Result;
 class ModelHighAPI_Selection;
 class ModelHighAPI_Dumper;
+
+class GeomAPI_Shape;
+
+typedef std::list<std::shared_ptr<GeomAPI_Shape> > ListOfShape;
 //--------------------------------------------------------------------------------------
 /**\class ModelHighAPI_Interface
  * \ingroup CPPHighAPI
@@ -98,6 +102,30 @@ public:
   MODELHIGHAPI_EXPORT
   virtual void dump(ModelHighAPI_Dumper& /*theDumper*/) const {}
 
+    /// Returns all the vertices produced by this feature
+  MODELHIGHAPI_EXPORT virtual ListOfShape
+               vertices(const bool theOnlyUnique = false);
+
+  /// Returns all the edges produced by this feature
+  MODELHIGHAPI_EXPORT virtual ListOfShape 
+               edges(const bool theOnlyUnique = false);
+
+  /// Returns all the wires produced by this feature
+  MODELHIGHAPI_EXPORT virtual ListOfShape
+               wires(const bool theOnlyUnique = false);
+
+  /// Returns all the faces produced by this feature
+  MODELHIGHAPI_EXPORT virtual ListOfShape
+               faces(const bool theOnlyUnique = false);
+
+  /// Returns all the shells produced by this feature
+  MODELHIGHAPI_EXPORT virtual ListOfShape 
+               shells(const bool theOnlyUnique = false);
+
+      /// Returns all the solids produced by this feature
+  MODELHIGHAPI_EXPORT virtual ListOfShape
+               solids(const bool theOnlyUnique = false);
+
 protected:
   std::shared_ptr<ModelAPI_Feature> myFeature; ///< feature of this interface
 
index 211d412b0ce4ece81ecf17ea9560ffcd5f01bf6b..3d94f8000260d4711e095c39d2a3ddf7d60bcb95 100644 (file)
@@ -131,13 +131,11 @@ Solid_tube_ext = model.addSolid(Part_1_doc, liste_tube_ext)
 
 # Recherche de la face du tube sur laquelle faire un congé de raccordement (fillet) :
 face = Filling_4.defaultResult().shape().face()
-exp = GeomAPI_ShapeExplorer(Solid_tube_ext.defaultResult().shape(), GeomAPI_Shape.FACE)
-while exp.more():
-   cur = exp.current().face()
-   if face.isEqual(cur) : # and face.isSameGeometry(cur):
-      res = cur
+faces = Solid_tube_ext.faces()
+for ff in faces:
+   if face.isEqual(ff) : # and face.isSameGeometry(cur):
+      res = ff.face()
       break
-   exp.next()
 #print(type(res))
 Fillet_1 = model.addFillet(Part_1_doc, [model.selection(Solid_tube_ext.defaultResult(), res)], "fillet_radius_top", keepSubResults = False)
 Solid_tube_ext = Fillet_1
@@ -198,13 +196,11 @@ for i in range(Intersection_1.result().numberOfSubs()):
                maxRad = rad
 #print(Intersection_1.result().subResult(imax).name())
 edge = GeomAPI_Edge(Intersection_1.result().subResult(imax).resultSubShapePair()[1])
-exp = GeomAPI_ShapeExplorer(Fuse_1.defaultResult().shape(), GeomAPI_Shape.EDGE)
-while exp.more():
-   cur = exp.current().edge()
-   if edge.isEqual(cur) : # and edge.isSameGeometry(cur):
-      resEdge = cur
+edges = Fuse_1.edges()
+for ee in edges:
+   if edge.isEqual(ee) : # and edge.isSameGeometry(cur):
+      resEdge = ee.edge()
       break
-   exp.next()
 #print(type(res))
 Sphere_ext = model.addFillet(Part_1_doc, [model.selection(Fuse_1.defaultResult(), resEdge)], "fillet_radius_bottom", keepSubResults = False)
 #Sphere_ext = Fillet_2
@@ -281,15 +277,14 @@ model.do()
 # Détermination des arêtes du bas des tubes sur lesquelles mettre des "fillets" :
 #print("Edge n°",jmax,"avec le plus grand rayon :",Intersection_1.result().subResult(jmax).name(),"-- rayon=",maxRad)
 FilletEdges = []
-exp = GeomAPI_ShapeExplorer(Fuse_2.defaultResult().shape(), GeomAPI_Shape.EDGE)
-while exp.more():
-       cur = exp.current().edge()
+edges = Fuse_2.edges()
+for ee in edges:
+       cur = ee.edge()
        for edge in EdgesForFillet:
                if edge.isEqual(cur) : # and edge.isSameGeometry(cur):
                        FilletEdges.append(model.selection(Fuse_2.defaultResult(), cur))
                        EdgesForFillet.remove(edge)
                        break
-       exp.next()
 #print(type(res))
 Fillet_2 = model.addFillet(Part_1_doc, FilletEdges, "fillet_radius_bottom", keepSubResults = False)
 Fillet_2.setName("Fillets_bottom_tubes")