Salome HOME
Make the SHAPERSTUDY python dump works on SHAPER objects stable, even after modificat...
authormpv <mpv@opencascade.com>
Wed, 12 Feb 2020 13:11:37 +0000 (16:11 +0300)
committermpv <mpv@opencascade.com>
Wed, 12 Feb 2020 13:11:37 +0000 (16:11 +0300)
src/ConnectorAPI/Test/TestShaperStudy1.py [new file with mode: 0644]
src/ConnectorAPI/Test/tests.set
src/ExchangePlugin/ExchangePlugin_Dump.cpp
src/ExchangePlugin/ExchangePlugin_Dump.h
src/ModelHighAPI/ModelHighAPI_Dumper.cpp
src/ModelHighAPI/ModelHighAPI_Dumper.h
src/PythonAPI/model/dump/DumpAssistant.py
src/PythonAPI/model/services/__init__.py
src/SHAPERGUI/SHAPERGUI_DataModel.cpp

diff --git a/src/ConnectorAPI/Test/TestShaperStudy1.py b/src/ConnectorAPI/Test/TestShaperStudy1.py
new file mode 100644 (file)
index 0000000..870278a
--- /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
+#
+
+import sys
+import salome
+
+salome.salome_init()
+
+###
+### SHAPER component
+###
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+model.addParameter(Part_1_doc, "r", "15")
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(25, 25, 15)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchCircle_1.center(), SketchAPI_Point(SketchPoint_1).coordinates(), 25)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchCircle_1.center(), SketchAPI_Point(SketchPoint_1).coordinates(), 25)
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], "r")
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2r")], model.selection(), 10, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Sketch_2 = model.addSketch(Part_2_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_2.addLine(-5.176380902051512, 19.31851652579896, 19.31851652579829, -5.176380902058602)
+SketchLine_2 = Sketch_2.addLine(19.31851652579829, -5.176380902058602, -14.14213562374638, -14.14213562374059)
+SketchConstraintCoincidence_1 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(-14.14213562374638, -14.14213562374059, -5.176380902051512, 19.31851652579896)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintEqual_2 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_2.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintDistance_1 = Sketch_2.setDistance(SketchLine_2.startPoint(), SketchAPI_Point(SketchPoint_2).coordinates(), 20, True)
+SketchConstraintDistance_2 = Sketch_2.setDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_2).coordinates(), 20, True)
+SketchConstraintDistance_3 = Sketch_2.setDistance(SketchLine_3.startPoint(), SketchAPI_Point(SketchPoint_2).coordinates(), 20, True)
+SketchProjection_3 = Sketch_2.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_4 = SketchProjection_3.createdFeature()
+SketchConstraintAngle_1 = Sketch_2.setAngle(SketchLine_3.result(), SketchLine_4.result(), 75)
+model.do()
+Extrusion_2 = model.addExtrusion(Part_2_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_3r-SketchLine_2r-SketchLine_1r")], model.selection(), 30, 0)
+Fillet_1 = model.addFillet(Part_2_doc, [model.selection("EDGE", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchLine_3][Extrusion_1_1/To_Face]")], 2)
+model.do()
+
+Part_3 = model.addPart(partSet)
+Part_3_doc = Part_3.document()
+Sketch_3 = model.addSketch(Part_3_doc, model.defaultPlane("XOZ"))
+SketchLine_5 = Sketch_3.addLine(52.5, 35, 22.5, 35)
+SketchLine_6 = Sketch_3.addLine(22.5, 35, 22.5, 15)
+SketchLine_7 = Sketch_3.addLine(22.5, 15, 52.5, 15)
+SketchLine_8 = Sketch_3.addLine(52.5, 15, 52.5, 35)
+SketchConstraintCoincidence_4 = Sketch_3.setCoincident(SketchLine_8.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_5 = Sketch_3.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintCoincidence_6 = Sketch_3.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+SketchConstraintCoincidence_7 = Sketch_3.setCoincident(SketchLine_7.endPoint(), SketchLine_8.startPoint())
+SketchConstraintHorizontal_1 = Sketch_3.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_1 = Sketch_3.setVertical(SketchLine_6.result())
+SketchConstraintHorizontal_2 = Sketch_3.setHorizontal(SketchLine_7.result())
+SketchConstraintVertical_2 = Sketch_3.setVertical(SketchLine_8.result())
+SketchLine_9 = Sketch_3.addLine(0, 0, 52.5, 35)
+SketchLine_9.setAuxiliary(True)
+SketchProjection_4 = Sketch_3.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_3 = SketchProjection_4.createdFeature()
+SketchConstraintCoincidence_8 = Sketch_3.setCoincident(SketchLine_9.startPoint(), SketchPoint_3.result())
+SketchConstraintCoincidence_9 = Sketch_3.setCoincident(SketchLine_5.startPoint(), SketchLine_9.endPoint())
+SketchConstraintCoincidence_10 = Sketch_3.setCoincident(SketchLine_6.endPoint(), SketchLine_9.result())
+SketchConstraintLength_1 = Sketch_3.setLength(SketchLine_8.result(), 20)
+SketchConstraintLength_2 = Sketch_3.setLength(SketchLine_5.result(), 30)
+SketchConstraintDistanceVertical_2 = Sketch_3.setVerticalDistance(SketchLine_7.endPoint(), SketchAPI_Point(SketchPoint_3).coordinates(), 15)
+model.do()
+Revolution_1 = model.addRevolution(Part_3_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f-SketchLine_4f")], model.selection("EDGE", "PartSet/OX"), 45, 0)
+model.end()
+
+###
+### SHAPERSTUDY component
+###
+
+if 'model' in globals():
+  model.publishToShaperStudy()
+import SHAPERSTUDY
+Extrusion_1_1, = SHAPERSTUDY.shape(model.featureStringId(Extrusion_1))
+Fillet_1_1, = SHAPERSTUDY.shape(model.featureStringId(Fillet_1))
+Revolution_1_1, = SHAPERSTUDY.shape(model.featureStringId(Revolution_1))
+###
+### SMESH component
+###
+
+import  SMESH, SALOMEDS
+from salome.smesh import smeshBuilder
+
+smesh = smeshBuilder.New()
+#smesh.SetEnablePublish( False ) # Set to False to avoid publish in study if not needed or in some particular situations:
+                                 # multiples meshes built in parallel, complex and numerous mesh edition (performance)
+
+Mesh_1 = smesh.Mesh(Fillet_1_1)
+Regular_1D = Mesh_1.Segment()
+Number_of_Segments_1 = Regular_1D.NumberOfSegments(7,None,[])
+MEFISTO_2D = Mesh_1.Triangle(algo=smeshBuilder.MEFISTO)
+Max_Element_Area_1 = MEFISTO_2D.MaxElementArea(20)
+isDone = Mesh_1.Compute()
+assert(isDone)
+Mesh_2 = smesh.Mesh(Extrusion_1_1)
+Cartesian_3D = Mesh_2.BodyFitted()
+Body_Fitting_Parameters_1 = Cartesian_3D.SetGrid([ [ '4.3589' ], [ 0, 1 ]],[ [ '4.3589' ], [ 0, 1 ]],[ [ '4.3589' ], [ 0, 1 ]],4,0)
+Body_Fitting_Parameters_1.SetFixedPoint( SMESH.PointStruct ( 0, 0, 0 ), 1 )
+Body_Fitting_Parameters_1.SetAxesDirs( SMESH.DirStruct( SMESH.PointStruct ( 1, 0, 0 )), SMESH.DirStruct( SMESH.PointStruct ( 0, 1, 0 )), SMESH.DirStruct( SMESH.PointStruct ( 0, 0, 1 )) )
+isDone = Mesh_2.Compute()
+assert(isDone)
+Mesh_3 = smesh.Mesh(Revolution_1_1)
+status = Mesh_3.AddHypothesis(Number_of_Segments_1)
+Regular_1D_1 = Mesh_3.Segment()
+isDone = Mesh_3.Compute()
+assert(isDone)
+
+## Set names of Mesh objects
+smesh.SetName(Regular_1D.GetAlgorithm(), 'Regular_1D')
+smesh.SetName(MEFISTO_2D.GetAlgorithm(), 'MEFISTO_2D')
+smesh.SetName(Cartesian_3D.GetAlgorithm(), 'Cartesian_3D')
+smesh.SetName(Mesh_1.GetMesh(), 'Mesh_1')
+smesh.SetName(Mesh_2.GetMesh(), 'Mesh_2')
+smesh.SetName(Mesh_3.GetMesh(), 'Mesh_3')
+smesh.SetName(Body_Fitting_Parameters_1, 'Body Fitting Parameters_1')
+smesh.SetName(Max_Element_Area_1, 'Max. Element Area_1')
+smesh.SetName(Number_of_Segments_1, 'Number of Segments_1')
+
+# check the SHAPER study objects generated names
+assert(Extrusion_1_1.GetName() == "Extrusion_1_1")
+assert(Fillet_1_1.GetName() == "Fillet_1_1")
+assert(Revolution_1_1.GetName() == "Revolution_1_1")
+# check the smesh mesh is computed correctly
+assert(Mesh_1.NbNodes() == 235)
+assert(Mesh_2.NbNodes() == 168)
+assert(Mesh_3.NbNodes() == 80)
index be23a5a85583f459f3a2b2cac302b9692448f6a5..4801850aed20ffbfd7232bb6b0eaf76e3293eef4 100644 (file)
@@ -25,4 +25,5 @@ SET(TEST_NAMES
   TestExportToGEOMWholeFeature
   Test2882
   Test17917
+  TestShaperStudy1.py
 )
index cf78b9b8c10a0ee53f1abd0eeaf80e8180b1e274..9ca46901b0afd9361f285cd821cd80a1615d06aa 100644 (file)
@@ -47,10 +47,13 @@ void ExchangePlugin_Dump::initAttributes()
   data()->addAttribute(GEOMETRIC_DUMP_ID(), ModelAPI_AttributeBoolean::typeId());
   data()->addAttribute(WEAK_NAMING_DUMP_ID(), ModelAPI_AttributeBoolean::typeId());
 
+  data()->addAttribute(EXPORT_VARIABLES_ID(), ModelAPI_AttributeBoolean::typeId());
+
   // default values
   boolean(TOPOLOGICAL_NAMING_DUMP_ID())->setValue(true);
   boolean(GEOMETRIC_DUMP_ID())->setValue(true);
   boolean(WEAK_NAMING_DUMP_ID())->setValue(false);
+  boolean(EXPORT_VARIABLES_ID())->setValue(false);
 }
 
 void ExchangePlugin_Dump::execute()
@@ -141,6 +144,14 @@ void ExchangePlugin_Dump::dump(const std::string& theFileName)
     aDumper->addCustomStorage(aWeakNamingStorage);
   }
 
-  if (!aDumper->process(aDoc, theFileName))
-    setError("An error occured while dumping to " + theFileName);
+  if (!aDumper->process(aDoc, theFileName)) {
+    setError("An error occurred while dumping to " + theFileName);
+  } else {
+    if (boolean(EXPORT_VARIABLES_ID())->value()) {
+      aDumper->exportVariables();
+    }
+  }
+  // clear cashed data after export variables was performed
+  aDumper->clearCustomStorage();
+
 }
index 5ee0f004b89e02e75912d3688a8ca3569b1f00f1..1d7127b0b5926c8ddf2e83447f131afd0d3bc419 100644 (file)
@@ -71,6 +71,13 @@ public:
     return MY_WEAK_NAMING_DUMP_ID;
   }
 
+  /// attribute name for boolean flag to export variable names correspondence to another module
+  inline static const std::string& EXPORT_VARIABLES_ID()
+  {
+    static const std::string MY_EXPORT_VARIABLES_ID("export_variables");
+    return MY_EXPORT_VARIABLES_ID;
+  }
+
   /// Default constructor
   EXCHANGEPLUGIN_EXPORT ExchangePlugin_Dump();
   /// Default destructor
index 9df987e6101f4b342e2a8d7c96f457d38f27448c..577f8b2db30f9203a75093423792f5a70f3cf6fc 100644 (file)
@@ -645,7 +645,6 @@ bool ModelHighAPI_Dumper::process(const std::shared_ptr<ModelAPI_Document>& theD
 
   // dump subfeatures and store result to file
   bool isOk = process(theDoc) && myDumpStorage->exportTo(theFileName, myModules);
-  clearCustomStorage();
   return isOk;
 }
 
@@ -1483,3 +1482,24 @@ ModelHighAPI_Dumper& operator<<(ModelHighAPI_Dumper& theDumper,
 
   return theDumper;
 }
+
+
+void ModelHighAPI_Dumper::exportVariables() const
+{
+  DocumentPtr aRoot = ModelAPI_Session::get()->moduleDocument();
+  EntityNameMap::const_iterator aNameIter = myNames.cbegin();
+  for(; aNameIter != myNames.end(); aNameIter++) {
+    FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aNameIter->first);
+    if (aFeature.get() && aFeature->document() != aRoot) {
+      FeaturePtr aPartFeat = ModelAPI_Tools::findPartFeature(aRoot, aFeature->document());
+      if (aPartFeat.get()) {
+        int aFeatureId = aFeature->data()->featureId();
+        int aPartId = aPartFeat->data()->featureId();
+        std::ostringstream anEntryStr;
+        anEntryStr<<aPartId<<":"<<aFeatureId;
+        std::string anEntry = anEntryStr.str();
+        exportVariable(anEntry, aNameIter->second.myCurrentName);
+      }
+    }
+  }
+}
index 2bbc294357441c7a74ef484ec8124b9ce3b68811..211ce075d9c72313e3e450abe444be3702be7580 100644 (file)
@@ -159,7 +159,6 @@ public:
   /// Clear custom storages list
   MODELHIGHAPI_EXPORT
   void clearCustomStorage();
-
   /// Dump given document into the file
   /// \return \c true, if succeed
   MODELHIGHAPI_EXPORT
@@ -335,6 +334,13 @@ public:
   MODELHIGHAPI_EXPORT
   bool isDumped(const std::shared_ptr<ModelAPI_AttributeRefList>& theRefList) const;
 
+  /// Export variables names to another module (calls exportVariable implemented in python)
+  MODELHIGHAPI_EXPORT virtual void exportVariables() const;
+
+  /// Export one variable name to another module (implemented in python)
+  MODELHIGHAPI_EXPORT virtual void exportVariable(
+    const std::string& theEntry, const std::string& theVarName) const {}
+
 protected:
   /// Dump "setName" command if last entity had user-defined name
   MODELHIGHAPI_EXPORT void dumpEntitySetName();
index 0b3eeb16745ef1f9f940a79467f389833bae1ce7..3170cc8570794ee6d7be7beeb43b2d38fb071a4e 100644 (file)
@@ -44,6 +44,7 @@ class DumpAssistant(ModelHighAPI.ModelHighAPI_Dumper):
         ModelHighAPI.ModelHighAPI_Dumper.__init__(self)
         ModelHighAPI.ModelHighAPI_Dumper.setInstance(self)
         self.collectFeatures()
+        self.myEngine = None
 
     ## Collect feature wrappers, which allow dumping (have method dump)
     def collectFeatures(self):
@@ -97,5 +98,18 @@ class DumpAssistant(ModelHighAPI.ModelHighAPI_Dumper):
             return self.myWrapperNames[aFeatureKind]
         return std_string()
 
+    ## Exports the dumped variables names to the SHAPERSTUDY
+    def exportVariable(self, theEntry, theVarName):
+        try:
+          if self.myEngine == None:
+            import SHAPERSTUDY_utils
+            aComponent = SHAPERSTUDY_utils.findOrCreateComponent()
+            self.myEngine = SHAPERSTUDY_utils.getEngine()
+          if self.myEngine != 1:
+            self.myEngine.StoreVariableName(theEntry, theVarName)
+        except:
+          self.myEngine = 1 # invalid access
+        pass
+
 # Instance of dumper
 dumper = DumpAssistant
index e5bc144781375b027324426e6c45959e8e40e104..5e10f000eb8c7a0ff319231eac368ac3c0d54d4f 100644 (file)
@@ -29,9 +29,19 @@ from ModelHighAPI import reset
 from ModelHighAPI import addFolder, removeFolder
 from ModelHighAPI import ModelHighAPI_Selection as selection
 from ModelHighAPI import checkPythonDump as checkPythonDump
+from ModelAPI import findPartFeature
 
 # a method used for the python dump of the SHAPER STUDY
 def publishToShaperStudy():
   begin()
   activeDocument().addFeature("PublishToStudy")
   end()
+
+# returns unique identifier of the feature : id of part it belongs to + ":" + id of feature
+def featureStringId(theFeature):
+  aRoot = moduleDocument()
+  aCurrent = theFeature.feature().document()
+  if aRoot and aCurrent:
+    print(str(dir()))
+    return str(findPartFeature(aRoot, aCurrent).data().featureId()) + ":" + str(theFeature.feature().data().featureId())
+  return ""
index a84de59dfca76318575047d820a3e9538cf3177f..5a2effdc7fa16695843f6e1806feadc4aac9dffe 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <ModelAPI_Session.h>
 #include <ModelAPI_AttributeString.h>
+#include <ModelAPI_AttributeBoolean.h>
 #include <ExchangePlugin_Dump.h>
 
 #include <LightApp_Study.h>
@@ -199,6 +200,10 @@ bool SHAPERGUI_DataModel::dumpPython(const QString& thePath, CAM_Study* theStudy
     if (aAttr.get())
       aAttr->setValue(".py");
 
+#ifdef HAVE_SALOME
+    aFeature->boolean(ExchangePlugin_Dump::EXPORT_VARIABLES_ID())->setValue(true);
+#endif
+
     ModelAPI_Session::get()->finishOperation();
 
     if (QFile::exists(aFileName.c_str())) {
@@ -237,4 +242,3 @@ bool SHAPERGUI_DataModel::dumpPython(const QString& thePath, CAM_Study* theStudy
   }
   return false;
 }
-