From a57578dc1eab7deb82c57c47f79bb698b4bf3864 Mon Sep 17 00:00:00 2001 From: Ekaterina Sukhareva Date: Fri, 9 Feb 2024 18:21:42 +0000 Subject: [PATCH] [CEA] Simple API in Python --- src/ModelAPI/CMakeLists.txt | 1 + src/ModelAPI/ModelAPI_Feature.cpp | 77 ++++++++++ src/ModelAPI/ModelAPI_Feature.h | 33 ++++- src/ModelAPI/ModelAPI_Result.cpp | 81 +++++++++- src/ModelAPI/ModelAPI_Result.h | 32 +++- src/ModelAPI/Test/Test40642_SimpleAPI.py | 155 ++++++++++++++++++++ src/ModelAPI/tests.set | 1 + src/ModelHighAPI/ModelHighAPI_Interface.cpp | 36 +++++ src/ModelHighAPI/ModelHighAPI_Interface.h | 28 ++++ test.models/coronavirus.py | 27 ++-- 10 files changed, 452 insertions(+), 19 deletions(-) create mode 100755 src/ModelAPI/Test/Test40642_SimpleAPI.py diff --git a/src/ModelAPI/CMakeLists.txt b/src/ModelAPI/CMakeLists.txt index f2c9b6486..7882c7dee 100644 --- a/src/ModelAPI/CMakeLists.txt +++ b/src/ModelAPI/CMakeLists.txt @@ -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} ) diff --git a/src/ModelAPI/ModelAPI_Feature.cpp b/src/ModelAPI/ModelAPI_Feature.cpp index 8d8b7ffbc..2041a9ac3 100644 --- a/src/ModelAPI/ModelAPI_Feature.cpp +++ b/src/ModelAPI/ModelAPI_Feature.cpp @@ -29,6 +29,11 @@ #include #include +#include + +#include +#include + 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); +} diff --git a/src/ModelAPI/ModelAPI_Feature.h b/src/ModelAPI/ModelAPI_Feature.h index 8c81aa3a5..118cc1512 100644 --- a/src/ModelAPI/ModelAPI_Feature.h +++ b/src/ModelAPI/ModelAPI_Feature.h @@ -30,6 +30,8 @@ #include #include +typedef std::list > 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(); diff --git a/src/ModelAPI/ModelAPI_Result.cpp b/src/ModelAPI/ModelAPI_Result.cpp index ec88a61af..2c3bdc9f9 100644 --- a/src/ModelAPI/ModelAPI_Result.cpp +++ b/src/ModelAPI/ModelAPI_Result.cpp @@ -25,7 +25,15 @@ #include #include +#include + #include +#include + +#include + +#include +#include ModelAPI_Result::~ModelAPI_Result() { @@ -101,12 +109,83 @@ void ModelAPI_Result::setIsConcealed(const bool theValue, const bool /*theForced } } - std::shared_ptr ModelAPI_Result::shape() { return std::shared_ptr(); } +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(); diff --git a/src/ModelAPI/ModelAPI_Result.h b/src/ModelAPI/ModelAPI_Result.h index 8573eff3c..e82ea2f35 100644 --- a/src/ModelAPI/ModelAPI_Result.h +++ b/src/ModelAPI/ModelAPI_Result.h @@ -25,6 +25,8 @@ class GeomAPI_Shape; class ModelAPI_Feature; +typedef std::list > 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 shape(); + MODELAPI_EXPORT virtual std::shared_ptr 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 index 000000000..039320c39 --- /dev/null +++ b/src/ModelAPI/Test/Test40642_SimpleAPI.py @@ -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() diff --git a/src/ModelAPI/tests.set b/src/ModelAPI/tests.set index daf112880..304575aeb 100644 --- a/src/ModelAPI/tests.set +++ b/src/ModelAPI/tests.set @@ -124,4 +124,5 @@ SET(TEST_NAMES Test26745.py TestMovePart1.py TestMovePart2.py + Test40642_SimpleAPI.py ) diff --git a/src/ModelHighAPI/ModelHighAPI_Interface.cpp b/src/ModelHighAPI/ModelHighAPI_Interface.cpp index 9873ab7a5..99983df16 100644 --- a/src/ModelHighAPI/ModelHighAPI_Interface.cpp +++ b/src/ModelHighAPI/ModelHighAPI_Interface.cpp @@ -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(this)->execute(); + return feature()->vertices(theOnlyUnique); +} + +ListOfShape ModelHighAPI_Interface::edges(const bool theOnlyUnique) +{ + const_cast(this)->execute(); + return feature()->edges(theOnlyUnique); +} + +ListOfShape ModelHighAPI_Interface::wires(const bool theOnlyUnique) +{ + const_cast(this)->execute(); + return feature()->wires(theOnlyUnique); +} + +ListOfShape ModelHighAPI_Interface::faces(const bool theOnlyUnique) +{ + const_cast(this)->execute(); + return feature()->faces(theOnlyUnique); +} + +ListOfShape ModelHighAPI_Interface::shells(const bool theOnlyUnique) +{ + const_cast(this)->execute(); + return feature()->shells(theOnlyUnique); +} + +ListOfShape ModelHighAPI_Interface::solids(const bool theOnlyUnique) +{ + const_cast(this)->execute(); + return feature()->solids(theOnlyUnique); +} diff --git a/src/ModelHighAPI/ModelHighAPI_Interface.h b/src/ModelHighAPI/ModelHighAPI_Interface.h index b96d8776f..995ac7151 100644 --- a/src/ModelHighAPI/ModelHighAPI_Interface.h +++ b/src/ModelHighAPI/ModelHighAPI_Interface.h @@ -33,6 +33,10 @@ class ModelAPI_Feature; class ModelAPI_Result; class ModelHighAPI_Selection; class ModelHighAPI_Dumper; + +class GeomAPI_Shape; + +typedef std::list > 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 myFeature; ///< feature of this interface diff --git a/test.models/coronavirus.py b/test.models/coronavirus.py index 211d412b0..3d94f8000 100644 --- a/test.models/coronavirus.py +++ b/test.models/coronavirus.py @@ -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") -- 2.39.2