Salome HOME
PR: synchro V7_main tag mergefrom_V6_main_06Mar13
[modules/smesh.git] / src / SMESH_I / SMESH_2smeshpy.cxx
index 48144a9962bd0ab920d27c7e1bb70b5af467209a..5b10f99146c7cc79f79a2cc5e9ee063eb9fc5381 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2011  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
 //
 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 
-//  SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses
 // File      : SMESH_2smeshpy.cxx
 // Created   : Fri Nov 18 13:20:10 2005
 // Author    : Edward AGAPOV (eap)
 //
 #include "SMESH_2smeshpy.hxx"
 
-#include "utilities.h"
 #include "SMESH_PythonDump.hxx"
 #include "SMESH_NoteBook.hxx"
 #include "SMESH_Filter_i.hxx"
 
+#include <SALOMEDS_wrap.hxx>
+#include <utilities.h>
+
 #include <Resource_DataMapOfAsciiStringAsciiString.hxx>
 #include <Resource_DataMapIteratorOfDataMapOfAsciiStringAsciiString.hxx>
 
@@ -125,6 +126,31 @@ namespace {
     }
   };
 
+  //================================================================================
+  /*!
+   * \brief Map of TCollection_AsciiString initialized by C array of C strings.
+   *        Odd items of the C array are map keys, and even items are values
+   */
+  //================================================================================
+
+  struct TStringMap: public map<TCollection_AsciiString,TCollection_AsciiString>
+  {
+    /*!
+     * \brief Filling. The last string must be ""
+     */
+    void Insert(const char* names_values[]) {
+      for ( int i = 0; names_values[i][0] ; i += 2 )
+        insert( make_pair( (char*) names_values[i], names_values[i+1] ));
+    }
+    /*!
+     * \brief Check if a string is in
+     */
+    TCollection_AsciiString Value(const TCollection_AsciiString& name ) {
+      map< _AString, _AString >::iterator it = find( name );
+      return it == end() ? "" : it->second;
+    }
+  };
+
   //================================================================================
   /*!
    * \brief Returns a mesh by object
@@ -228,6 +254,13 @@ namespace {
     //   - FT_EqualEdges            = 15
     //   - FT_EqualFaces            = 16
     //   - FT_EqualVolumes          = 17
+    // v 6.6.0: FT_Undefined == 44, new items:
+    //   - FT_BallDiameter          = 37
+    // v 6.7.1: FT_Undefined == 45, new items:
+    //   - FT_EntityType            = 36
+    //
+    // It's necessary to continue recording this history and to fill
+    // undef2newItems (see below) accordingly.
 
     typedef map< int, vector< int > > TUndef2newItems;
     static TUndef2newItems undef2newItems;
@@ -242,6 +275,10 @@ namespace {
         undef2newItems[ 39 ].assign( items, items+6 ); }
       { int items[] = { 14, 15, 16, 17 };
         undef2newItems[ 43 ].assign( items, items+4 ); }
+      { int items[] = { 37 };
+        undef2newItems[ 44 ].assign( items, items+1 ); }
+      { int items[] = { 36 };
+        undef2newItems[ 45 ].assign( items, items+1 ); }
     }
 
     int iType     = Type.IntegerValue();
@@ -400,7 +437,7 @@ _pyGen::_pyGen(Resource_DataMapOfAsciiStringAsciiString& theEntry2AccessorMethod
   {
     // find a GEOM entry
     _pyID geomID;
-    SALOMEDS::SComponent_var geomComp = theStudy->FindComponent("GEOM");
+    SALOMEDS::SComponent_wrap geomComp = theStudy->FindComponent("GEOM");
     if ( geomComp->_is_nil() ) return;
     CORBA::String_var entry = geomComp->GetID();
     geomID = entry.in();
@@ -456,6 +493,13 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
   if ( objID.IsEmpty() )
     return aCommand;
 
+  // Prevent moving a command creating a sub-mesh to the end of the script
+  // if the sub-mesh is used in theCommand as argument
+  if ( _pySubMesh::CanBeArgOfMethod( aCommand->GetMethod() ))
+  {
+    PlaceSubmeshAfterItsCreation( aCommand );
+  }
+
   // Find an object to process theCommand
 
   // SMESH_Gen method?
@@ -511,16 +555,23 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
          method == "DoubleNodeGroupNew"     ||
          method == "DoubleNodeGroupsNew"    ||
          method == "DoubleNodeElemGroupNew" ||
-         method == "DoubleNodeElemGroupsNew" )
+         method == "DoubleNodeElemGroupsNew"||
+         method == "DoubleNodeElemGroup2New"||
+         method == "DoubleNodeElemGroups2New"
+         )
       groups = aCommand->GetResultValue();
     else if ( method == "MakeBoundaryMesh" )
       groups = aCommand->GetResultValue(2);
     else if ( method == "MakeBoundaryElements")
       groups = aCommand->GetResultValue(3);
+    else if ( method == "Create0DElementsOnAllNodes" &&
+              aCommand->GetArg(2).Length() > 2 ) // group name != ''
+      groups = aCommand->GetResultValue();
 
     id_editor->second->Process( aCommand );
     id_editor->second->AddProcessedCmd( aCommand );
 
+    // create meshes
     if ( !meshID.IsEmpty() &&
          !myMeshes.count( meshID ) &&
          aCommand->IsStudyEntry( meshID ))
@@ -531,6 +582,7 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
       aCommand->Clear();
       aCommand->GetString() = processedCommand; // discard changes made by _pyMesh
     }
+    // create groups
     if ( !groups.IsEmpty() )
     {
       if ( !aCommand->IsStudyEntry( meshID ))
@@ -612,7 +664,7 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
     // 1    2       3         4            5           6       7        8         9             10
     // in order to avoid the problem of type mismatch of long and FunctorType
     const TCollection_AsciiString
-      SMESH("SMESH."), dfltFunctor = "SMESH.FT_Undefined", dftlTol = "1e-07", dftlPreci = "-1";
+      SMESH("SMESH."), dfltFunctor("SMESH.FT_Undefined"), dftlTol("1e-07"), dftlPreci("-1");
     TCollection_AsciiString
       Type          = aCommand->GetArg(1),  // long
       Compare       = aCommand->GetArg(2),  // long
@@ -638,17 +690,34 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
     aCommand->SetArg( 2, Type );
     aCommand->SetArg( 3, Compare );
 
-    if ( Type == "SMESH.FT_ElemGeomType" && Threshold.IsIntegerValue() )
+    if ( Threshold.IsIntegerValue() )
     {
-      // set SMESH.GeometryType instead of a numerical Threshold
-      const char* types[SMESH::Geom_POLYHEDRA+1] = {
-        "Geom_POINT", "Geom_EDGE", "Geom_TRIANGLE", "Geom_QUADRANGLE", "Geom_POLYGON",
-        "Geom_TETRA", "Geom_PYRAMID", "Geom_HEXA", "Geom_PENTA", "Geom_HEXAGONAL_PRISM",
-        "Geom_POLYHEDRA"
-      };
       int iGeom = Threshold.IntegerValue();
-      if ( -1 < iGeom && iGeom < SMESH::Geom_POLYHEDRA+1 )
-        Threshold = SMESH + types[ iGeom ];
+      if ( Type == "SMESH.FT_ElemGeomType" )
+      {
+        // set SMESH.GeometryType instead of a numerical Threshold
+        const char* types[SMESH::Geom_BALL+1] = {
+          "Geom_POINT", "Geom_EDGE", "Geom_TRIANGLE", "Geom_QUADRANGLE", "Geom_POLYGON",
+          "Geom_TETRA", "Geom_PYRAMID", "Geom_HEXA", "Geom_PENTA", "Geom_HEXAGONAL_PRISM",
+          "Geom_POLYHEDRA", "Geom_BALL" };
+        if ( -1 < iGeom && iGeom < SMESH::Geom_POLYHEDRA+1 )
+          Threshold = SMESH + types[ iGeom ];
+      }
+      if (Type == "SMESH.FT_EntityType")
+      {
+        // set SMESH.EntityType instead of a numerical Threshold
+        const char* types[SMESH::Entity_Ball+1] = {
+          "Entity_Node", "Entity_0D", "Entity_Edge", "Entity_Quad_Edge",
+          "Entity_Triangle", "Entity_Quad_Triangle",
+          "Entity_Quadrangle", "Entity_Quad_Quadrangle", "Entity_BiQuad_Quadrangle",
+          "Entity_Polygon", "Entity_Quad_Polygon", "Entity_Tetra", "Entity_Quad_Tetra",
+          "Entity_Pyramid", "Entity_Quad_Pyramid",
+          "Entity_Hexa", "Entity_Quad_Hexa", "Entity_TriQuad_Hexa",
+          "Entity_Penta", "Entity_Quad_Penta", "Entity_Hexagonal_Prism",
+          "Entity_Polyhedra", "Entity_Quad_Polyhedra", "Entity_Ball" };
+        if ( -1 < iGeom && iGeom < SMESH::Entity_Quad_Polyhedra+1 )
+          Threshold = SMESH + types[ iGeom ];
+      }
     }
     if ( ThresholdID.Length() != 2 && ThresholdStr.Length() != 2) // not '' or ""
       aCommand->SetArg( 4, ThresholdID.SubString( 2, ThresholdID.Length()-1 )); // shape entry
@@ -714,15 +783,25 @@ void _pyGen::Process( const Handle(_pyCommand)& theCommand )
     myMeshes.insert( make_pair( mesh->GetID(), mesh ));
     return;
   }
-  if( method == "CreateMeshesFromMED" || method == "CreateMeshesFromSAUV")
+  if( method == "CreateMeshesFromMED" ||
+      method == "CreateMeshesFromSAUV"||
+      method == "CreateMeshesFromGMF" )
   {
     for(int ind = 0;ind<theCommand->GetNbResultValues();ind++)
     {
-      const _pyID& meshID = theCommand->GetResultValue(ind+1);
+      _pyID meshID = theCommand->GetResultValue(ind+1);
       if ( !theCommand->IsStudyEntry( meshID ) ) continue;
       Handle(_pyMesh) mesh = new _pyMesh( theCommand, theCommand->GetResultValue(ind+1));
       myMeshes.insert( make_pair( mesh->GetID(), mesh ));
     }
+    if ( method == "CreateMeshesFromGMF" )
+    {
+      // CreateMeshesFromGMF( theFileName, theMakeRequiredGroups ) ->
+      // CreateMeshesFromGMF( theFileName )
+      _AString file = theCommand->GetArg(1);
+      theCommand->RemoveArgs();
+      theCommand->SetArg( 1, file );
+    }
   }
 
   // CreateHypothesis()
@@ -770,7 +849,7 @@ void _pyGen::Process( const Handle(_pyCommand)& theCommand )
     }
   }
 
-  // objects erasing creation command if no more it's commands invoked:
+  // objects erasing creation command if no more its commands invoked:
   // SMESH_Pattern, FilterManager
   if ( method == "GetPattern" ||
        method == "CreateFilterManager" ||
@@ -881,6 +960,34 @@ void _pyGen::Flush()
   myCommands.push_back( myLastCommand );
 }
 
+//================================================================================
+/*!
+ * \brief Prevent moving a command creating a sub-mesh to the end of the script
+ *        if the sub-mesh is used in theCmdUsingSubmesh as argument
+ */
+//================================================================================
+
+void _pyGen::PlaceSubmeshAfterItsCreation( Handle(_pyCommand) theCmdUsingSubmesh ) const
+{
+  map< _pyID, Handle(_pyObject) >::const_iterator id_obj = myObjects.begin();
+  for ( ; id_obj != myObjects.end(); ++id_obj )
+  {
+    if ( !id_obj->second->IsKind( STANDARD_TYPE( _pySubMesh ))) continue;
+    for ( int iArg = theCmdUsingSubmesh->GetNbArgs(); iArg; --iArg )
+    {
+      const _pyID& arg = theCmdUsingSubmesh->GetArg( iArg );
+      if ( arg.IsEmpty() || arg.Value( 1 ) == '"' || arg.Value( 1 ) == '\'' )
+        continue;
+      list< _pyID > idList = theCmdUsingSubmesh->GetStudyEntries( arg );
+      list< _pyID >::iterator id = idList.begin();
+      for ( ; id != idList.end(); ++id )
+        if ( id_obj->first == *id )
+          // _pySubMesh::Process() does what we need
+          Handle(_pySubMesh)::DownCast( id_obj->second )->Process( theCmdUsingSubmesh );
+    }
+  }
+}
+
 //================================================================================
 /*!
  * \brief Clean commmands of removed objects depending on myIsPublished flag
@@ -1231,7 +1338,8 @@ bool _pyGen::IsGeomObject(const _pyID& theObjID) const
   if ( myGeomIDNb )
   {
     return ( myGeomIDIndex <= theObjID.Length() &&
-             int( theObjID.Value( myGeomIDIndex )) == myGeomIDNb);
+             int( theObjID.Value( myGeomIDIndex )) == myGeomIDNb &&
+             _pyCommand::IsStudyEntry( theObjID ));
   }
   return false;
 }
@@ -1252,7 +1360,7 @@ bool _pyGen::IsNotPublished(const _pyID& theObjID) const
   // either the SMESH object is not in study or it is a GEOM object
   if ( IsGeomObject( theObjID ))
   {
-    SALOMEDS::SObject_var so = myStudy->FindObjectID( theObjID.ToCString() );
+    SALOMEDS::SObject_wrap so = myStudy->FindObjectID( theObjID.ToCString() );
     if ( so->_is_nil() ) return true;
     CORBA::Object_var obj = so->GetObject();
     return CORBA::is_nil( obj );
@@ -1437,12 +1545,6 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand )
       mySubmeshes.push_back( subMesh );
     }
   }
-  else if ( method == "RemoveSubMesh" ) { // move submesh creation before its removal
-    Handle(_pySubMesh) subMesh = theGen->FindSubMesh( theCommand->GetArg(1) );
-    if ( !subMesh.IsNull() )
-      subMesh->Process( theCommand );
-    AddMeshAccess( theCommand );
-  }
   // ----------------------------------------------------------------------
   else if ( method == "AddHypothesis" ) { // mesh.AddHypothesis(geom, HYPO )
     myAddHypCmds.push_back( theCommand );
@@ -1464,6 +1566,33 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand )
     myGroups.push_back( group );
     theGen->AddObject( group );
   }
+  // update list of groups
+  else if ( method == "GetGroups" )
+  {
+    TCollection_AsciiString grIDs = theCommand->GetResultValue();
+    list< _pyID > idList = theCommand->GetStudyEntries( grIDs );
+    list< _pyID >::iterator grID = idList.begin();
+    for ( ; grID != idList.end(); ++grID )
+    {
+      Handle(_pyObject) obj = theGen->FindObject( *grID );
+      if ( obj.IsNull() )
+      {
+        Handle(_pyGroup) group = new _pyGroup( theCommand, *grID );
+        theGen->AddObject( group );
+        myGroups.push_back( group );
+      }
+    }
+  }
+  // notify a group about full removal
+  else if ( method == "RemoveGroupWithContents" )
+  {
+    if ( !theGen->IsToKeepAllCommands() ) { // snapshot mode
+      const _pyID groupID = theCommand->GetArg( 1 );
+      Handle(_pyGroup) grp = Handle(_pyGroup)::DownCast( theGen->FindObject( groupID ));
+      if ( !grp.IsNull() )
+        grp->RemovedWithContents();
+    }
+  }
   // ----------------------------------------------------------------------
   else if ( theCommand->MethodStartsFrom( "Export" ))
   {
@@ -1479,6 +1608,14 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand )
         theCommand->SetArg( i-1, theCommand->GetArg( i ));
       theCommand->SetArg( nbArgs, partID );
     }
+    else if ( method == "ExportGMF" )
+    { // ExportGMF(part,file,bool) -> ExportCGNS(file, part)
+      _pyID partID  = theCommand->GetArg( 1 );
+      _AString file = theCommand->GetArg( 2 );
+      theCommand->RemoveArgs();
+      theCommand->SetArg( 1, file );
+      theCommand->SetArg( 2, partID );
+    }
     else if ( theCommand->MethodStartsFrom( "ExportPartTo" ))
     { // ExportPartTo*(part, ...) -> Export*(..., part)
       //
@@ -1500,26 +1637,44 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand )
   // ----------------------------------------------------------------------
   else if ( method == "RemoveHypothesis" ) // (geom, hyp)
   {
-    _pyID hypID = theCommand->GetArg( 2 );
+    _pyID hypID  = theCommand->GetArg( 2 );
+    _pyID geomID = theCommand->GetArg( 1 );
+    bool isLocal = ( geomID != GetGeom() );
 
     // check if this mesh still has corresponding addition command
-    bool hasAddCmd = false;
-    list< Handle(_pyCommand) >::iterator cmd = myAddHypCmds.begin();
-    while ( cmd != myAddHypCmds.end() )
+    Handle(_pyCommand) addCmd;
+    list< Handle(_pyCommand) >::iterator cmd;
+    list< Handle(_pyCommand) >* addCmds[2] = { &myAddHypCmds, &myNotConvertedAddHypCmds };
+    for ( int i = 0; i < 2; ++i )
     {
-      // AddHypothesis(geom, hyp)
-      if ( hypID == (*cmd)->GetArg( 2 )) { // erase both (add and remove) commands
-        theCommand->Clear();
-        (*cmd)->Clear();
-        cmd = myAddHypCmds.erase( cmd );
-        hasAddCmd = true;
-      }
-      else {
-        ++cmd;
+      list< Handle(_pyCommand )> & addHypCmds = *(addCmds[i]);
+      for ( cmd = addHypCmds.begin(); cmd != addHypCmds.end(); )
+      {
+        bool sameHyp = true;
+        if ( hypID != (*cmd)->GetArg( 1 ) && hypID != (*cmd)->GetArg( 2 ))
+          sameHyp = false; // other hyp
+        if ( (*cmd)->GetNbArgs() == 2 &&
+             geomID != (*cmd)->GetArg( 1 ) && geomID != (*cmd)->GetArg( 2 ))
+          sameHyp = false; // other geom
+        if ( (*cmd)->GetNbArgs() == 1 && isLocal )
+          sameHyp = false; // other geom
+        if ( sameHyp )
+        {
+          addCmd = *cmd;
+          cmd    = addHypCmds.erase( cmd );
+          if ( !theGen->IsToKeepAllCommands() ) {
+            addCmd->Clear();
+            theCommand->Clear();
+          }
+        }
+        else
+        {
+          ++cmd;
+        }
       }
     }
     Handle(_pyHypothesis) hyp = theGen->FindHyp( hypID );
-    if ( ! hasAddCmd && hypID.Length() != 0 ) { // hypo addition already wrapped
+    if ( !theCommand->IsEmpty() && !hypID.IsEmpty() ) {
       // RemoveHypothesis(geom, hyp) --> RemoveHypothesis( hyp, geom=0 )
       _pyID geom = theCommand->GetArg( 1 );
       theCommand->RemoveArgs();
@@ -1547,23 +1702,6 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand )
         subMesh->Process( theCommand ); // it moves GetSubMesh() before theCommand
     }
   }
-  // update list of groups
-  else if ( method == "GetGroups" )
-  {
-    TCollection_AsciiString grIDs = theCommand->GetResultValue();
-    list< _pyID > idList = theCommand->GetStudyEntries( grIDs );
-    list< _pyID >::iterator grID = idList.begin();
-    for ( ; grID != idList.end(); ++grID )
-    {
-      Handle(_pyObject) obj = theGen->FindObject( *grID );
-      if ( obj.IsNull() )
-      {
-        Handle(_pyGroup) group = new _pyGroup( theCommand, *grID );
-        theGen->AddObject( group );
-        myGroups.push_back( group );
-      }
-    }
-  }
   // add accessor method if necessary
   else
   {
@@ -1701,6 +1839,7 @@ void _pyMesh::Flush()
       addCmd->SetArg( 1, algoID );
       if ( isLocalAlgo )
         addCmd->SetArg( 2, geom );
+      myNotConvertedAddHypCmds.push_back( addCmd );
     }
   }
 
@@ -1721,6 +1860,7 @@ void _pyMesh::Flush()
       addCmd->SetArg( 1, hypID );
       if ( geom != GetGeom() )
         addCmd->SetArg( 2, geom );
+      myNotConvertedAddHypCmds.push_back( addCmd );
     }
   }
 
@@ -1870,14 +2010,15 @@ _pyMeshEditor::_pyMeshEditor(const Handle(_pyCommand)& theCreationCmd):
 
 void _pyMeshEditor::Process( const Handle(_pyCommand)& theCommand)
 {
-  // names of SMESH_MeshEditor methods fully equal to methods of python class Mesh, so
-  // commands calling this methods are converted to calls of methods of Mesh
+  // names of SMESH_MeshEditor methods fully equal to methods of the python class Mesh, so
+  // commands calling this methods are converted to calls of Mesh methods
   static TStringSet sameMethods;
   if ( sameMethods.empty() ) {
     const char * names[] = {
-      "RemoveElements","RemoveNodes","RemoveOrphanNodes","AddNode","Add0DElement","AddEdge","AddFace","AddPolygonalFace",
+      "RemoveElements","RemoveNodes","RemoveOrphanNodes","AddNode","Add0DElement","AddEdge","AddFace","AddPolygonalFace","AddBall",
       "AddVolume","AddPolyhedralVolume","AddPolyhedralVolumeByFaces","MoveNode", "MoveClosestNodeToPoint",
-      "InverseDiag","DeleteDiag","Reorient","ReorientObject","TriToQuad","SplitQuad","SplitQuadObject",
+      "InverseDiag","DeleteDiag","Reorient","ReorientObject",
+      "TriToQuad","TriToQuadObject", "SplitQuad","SplitQuadObject",
       "BestSplit","Smooth","SmoothObject","SmoothParametric","SmoothParametricObject",
       "ConvertToQuadratic","ConvertFromQuadratic","RenumberNodes","RenumberElements",
       "RotationSweep","RotationSweepObject","RotationSweepObject1D","RotationSweepObject2D",
@@ -1891,12 +2032,26 @@ void _pyMeshEditor::Process( const Handle(_pyCommand)& theCommand)
       "GetLastCreatedElems",
       "MirrorMakeMesh","MirrorObjectMakeMesh","TranslateMakeMesh",
       "TranslateObjectMakeMesh","RotateMakeMesh","RotateObjectMakeMesh","MakeBoundaryMesh",
-      "MakeBoundaryElements"
+      "MakeBoundaryElements", "SplitVolumesIntoTetra"
       ,"" }; // <- mark of the end
     sameMethods.Insert( names );
   }
 
-  // names of SMESH_MeshEditor methods which differ from methods of class Mesh
+  // names of SMESH_MeshEditor commands in which only a method name must be replaced
+  TStringMap diffMethods;
+  if ( diffMethods.empty() ) {
+    const char * orig2newName[] = {
+      // original name --------------> new name
+      "ExtrusionAlongPathObjX"      , "ExtrusionAlongPathX",
+      "FindCoincidentNodesOnPartBut", "FindCoincidentNodesOnPart",
+      "ConvertToQuadraticObject"    , "ConvertToQuadratic",
+      "ConvertFromQuadraticObject"  , "ConvertFromQuadratic",
+      "Create0DElementsOnAllNodes"  , "Add0DElementsToAllNodes",
+      ""};// <- mark of the end
+    diffMethods.Insert( orig2newName );
+  }
+
+  // names of SMESH_MeshEditor methods which differ from methods of Mesh class
   // only by last two arguments
   static TStringSet diffLastTwoArgsMethods;
   if (diffLastTwoArgsMethods.empty() ) {
@@ -1908,13 +2063,28 @@ void _pyMeshEditor::Process( const Handle(_pyCommand)& theCommand)
     diffLastTwoArgsMethods.Insert( names );
   }
 
+  // only a method name is to change?
   const TCollection_AsciiString & method = theCommand->GetMethod();
   bool isPyMeshMethod = sameMethods.Contains( method );
   if ( !isPyMeshMethod )
   {
-    //Replace SMESH_MeshEditor "MakeGroups" functions by the Mesh
-    //functions with the flag "theMakeGroups = True" like:
-    //SMESH_MeshEditor.CmdMakeGroups => Mesh.Cmd(...,True)
+    TCollection_AsciiString newMethod = diffMethods.Value( method );
+    if (( isPyMeshMethod = ( newMethod.Length() > 0 )))
+      theCommand->SetMethod( newMethod );
+  }
+  // ConvertToBiQuadratic(...) -> ConvertToQuadratic(...,True)
+  if ( !isPyMeshMethod && (method == "ConvertToBiQuadratic" || method == "ConvertToBiQuadraticObject") )
+  {
+    isPyMeshMethod = true;
+    theCommand->SetMethod( method.SubString( 1, 9) + method.SubString( 12, method.Length()));
+    theCommand->SetArg( theCommand->GetNbArgs() + 1, "True" );
+  }
+
+  if ( !isPyMeshMethod )
+  {
+    // Replace SMESH_MeshEditor "*MakeGroups" functions by the Mesh
+    // functions with the flag "theMakeGroups = True" like:
+    // SMESH_MeshEditor.CmdMakeGroups => Mesh.Cmd(...,True)
     int pos = method.Search("MakeGroups");
     if( pos != -1)
     {
@@ -1939,60 +2109,46 @@ void _pyMeshEditor::Process( const Handle(_pyCommand)& theCommand)
     }
   }
 
-  // ExtrusionSweep0D() -> ExtrusionSweep()
+  // ExtrusionSweep0D()       -> ExtrusionSweep()
   // ExtrusionSweepObject0D() -> ExtrusionSweepObject()
   if ( !isPyMeshMethod && ( method == "ExtrusionSweep0D"  ||
                             method == "ExtrusionSweepObject0D" ))
   {
-    isPyMeshMethod=true;
+    isPyMeshMethod = true;
     theCommand->SetMethod( method.SubString( 1, method.Length()-2));
     theCommand->SetArg(theCommand->GetNbArgs()+1,"False");  //sets flag "MakeGroups = False"
     theCommand->SetArg(theCommand->GetNbArgs()+1,"True");  //sets flag "IsNode = True"
   }
-  // set "ExtrusionAlongPathX()" instead of "ExtrusionAlongPathObjX()"
-  if ( !isPyMeshMethod && method == "ExtrusionAlongPathObjX")
-  {
-    isPyMeshMethod=true;
-    theCommand->SetMethod("ExtrusionAlongPathX");
-  }
 
-  // set "FindCoincidentNodesOnPart()" instead of "FindCoincidentNodesOnPartBut()"
-  if ( !isPyMeshMethod && method == "FindCoincidentNodesOnPartBut")
-  {
-    isPyMeshMethod=true;
-    theCommand->SetMethod("FindCoincidentNodesOnPart");
-  }
-  // DoubleNodeElemGroupNew() -> DoubleNodeElemGroup()
-  // DoubleNodeGroupNew() -> DoubleNodeGroup()
-  // DoubleNodeGroupsNew() -> DoubleNodeGroups()
-  // DoubleNodeElemGroupsNew() -> DoubleNodeElemGroups()
+  // DoubleNode...New(...) -> DoubleNode...(...,True)
   if ( !isPyMeshMethod && ( method == "DoubleNodeElemGroupNew"  ||
                             method == "DoubleNodeElemGroupsNew" ||
                             method == "DoubleNodeGroupNew"      ||
-                            method == "DoubleNodeGroupsNew"))
-  {
-    isPyMeshMethod=true;
-    theCommand->SetMethod( method.SubString( 1, method.Length()-3));
-    theCommand->SetArg(theCommand->GetNbArgs()+1,"True");
-  }
-  // ConvertToQuadraticObject(bool,obj) -> ConvertToQuadratic(bool,obj)
-  // ConvertFromQuadraticObject(obj) -> ConvertFromQuadratic(obj)
-  if ( !isPyMeshMethod && ( method == "ConvertToQuadraticObject" ||
-                            method == "ConvertFromQuadraticObject" ))
+                            method == "DoubleNodeGroupsNew"     ||
+                            method == "DoubleNodeElemGroup2New" ||
+                            method == "DoubleNodeElemGroups2New"))
   {
-    isPyMeshMethod=true;
-    theCommand->SetMethod( method.SubString( 1, method.Length()-6));
-    // prevent moving creation of the converted sub-mesh to the end of the script
-    bool isFromQua = ( method.Value( 8 ) == 'F' );
-    Handle(_pySubMesh) sm = theGen->FindSubMesh( theCommand->GetArg( isFromQua ? 1 : 2 ));
-    if ( !sm.IsNull() )
-      sm->Process( theCommand );
+    isPyMeshMethod = true;
+    const int excessLen = 3 + int( method.Value( method.Length()-3 ) == '2' );
+    theCommand->SetMethod( method.SubString( 1, method.Length()-excessLen));
+    if ( excessLen == 3 )
+    {
+      theCommand->SetArg(theCommand->GetNbArgs()+1,"True");
+    }
+    else if ( theCommand->GetArg(4) == "0" ||
+              theCommand->GetArg(5) == "0" )
+    {
+      // [ nothing, Group ] = DoubleNodeGroup2New(,,,False, True) ->
+      // Group = DoubleNodeGroup2New(,,,False, True)
+      _pyID groupID = theCommand->GetResultValue( 1 + int( theCommand->GetArg(4) == "0"));
+      theCommand->SetResultValue( groupID );
+    }
   }
   // FindAmongElementsByPoint(meshPart, x, y, z, elementType) ->
   // FindElementsByPoint(x, y, z, elementType, meshPart)
   if ( !isPyMeshMethod && method == "FindAmongElementsByPoint" )
   {
-    isPyMeshMethod=true;
+    isPyMeshMethod = true;
     theCommand->SetMethod( "FindElementsByPoint" );
     // make the 1st arg be the last one
     _pyID partID = theCommand->GetArg( 1 );
@@ -2001,11 +2157,32 @@ void _pyMeshEditor::Process( const Handle(_pyCommand)& theCommand)
       theCommand->SetArg( i-1, theCommand->GetArg( i ));
     theCommand->SetArg( nbArgs, partID );
   }
+  // Reorient2D( mesh, dir, face, point ) -> Reorient2D( mesh, dir, faceORpoint )
+  if ( !isPyMeshMethod && method == "Reorient2D" )
+  {
+    isPyMeshMethod = true;
+    _AString mesh  = theCommand->GetArg( 1 );
+    _AString dir   = theCommand->GetArg( 2 );
+    _AString face  = theCommand->GetArg( 3 );
+    _AString point = theCommand->GetArg( 4 );
+    theCommand->RemoveArgs();
+    theCommand->SetArg( 1, mesh );
+    theCommand->SetArg( 2, dir );
+    if ( face.Value(1) == '-' || face.Value(1) == '0' ) // invalid: face <= 0
+      theCommand->SetArg( 3, point );
+    else
+      theCommand->SetArg( 3, face );
+  }
+
+  if ( method == "QuadToTri" || method == "QuadToTriObject" )
+  {
+    isPyMeshMethod = true;
+    int crit_arg = theCommand->GetNbArgs();
+    const _AString& crit = theCommand->GetArg(crit_arg);
+    if (crit.Search("MaxElementLength2D") != -1)
+      theCommand->SetArg(crit_arg, "");
+  }
 
-  // meshes made by *MakeMesh() methods are not wrapped by _pyMesh,
-  // so let _pyMesh care of it (TMP?)
-  //     if ( theCommand->GetMethod().Search("MakeMesh") != -1 )
-  //       _pyMesh( new _pyCommand( theCommand->GetString(), 0 )); // for theGen->SetAccessorMethod()
   if ( isPyMeshMethod )
   {
     theCommand->SetObject( myMesh );
@@ -2013,7 +2190,7 @@ void _pyMeshEditor::Process( const Handle(_pyCommand)& theCommand)
   else
   {
     // editor creation command is needed only if any editor function is called
-    theGen->AddMeshAccessorMethod( theCommand ); // for *Object()
+    theGen->AddMeshAccessorMethod( theCommand ); // for *Object() methods
     if ( !myCreationCmdStr.IsEmpty() ) {
       GetCreationCmd()->GetString() = myCreationCmdStr;
       myCreationCmdStr.Clear();
@@ -2295,7 +2472,7 @@ void _pyHypothesis::Assign( const Handle(_pyHypothesis)& theOther,
   myGeom                    = theOther->myGeom;
   myMesh                    = theMesh;
   myAlgoType2CreationMethod = theOther->myAlgoType2CreationMethod;
-  //myArgCommands             = theOther->myArgCommands;
+  myAccumulativeMethods     = theOther->myAccumulativeMethods;
   //myUnusedCommands          = theOther->myUnusedCommands;
   // init myCurCrMethod
   GetCreationMethod( theOther->GetAlgoType() );
@@ -2424,7 +2601,9 @@ bool _pyHypothesis::GetReferredMeshesAndGeom( list< Handle(_pyMesh) >& meshes )
 void _pyHypothesis::rememberCmdOfParameter( const Handle(_pyCommand) & theCommand )
 {
   // parameters are discriminated by method name
-  TCollection_AsciiString method = theCommand->GetMethod();
+  _AString method = theCommand->GetMethod();
+  if ( myAccumulativeMethods.count( method ))
+    return; // this method adds values and not override the previus value
 
   // discriminate commands setting different parameters via one method
   // by passing parameter names like e.g. SetOption("size", "0.2")
@@ -2442,7 +2621,7 @@ void _pyHypothesis::rememberCmdOfParameter( const Handle(_pyCommand) & theComman
     }
   }
   // parameters are discriminated by method name
-  list< Handle(_pyCommand)>& cmds = myMeth2Commands[ theCommand->GetMethod() ];
+  list< Handle(_pyCommand)>& cmds = myMeth2Commands[ method /*theCommand->GetMethod()*/ ];
   if ( !cmds.empty() && !isCmdUsedForCompute( cmds.back() ))
   {
     cmds.back()->Clear(); // previous parameter value has not been used
@@ -3027,22 +3206,25 @@ const int _pyCommand::GetNbResultValues()
 //================================================================================
 /*!
  * \brief Return substring of python command looking like
- *  ResultValue1 , ResultValue1,... = Obj.Meth() with res index
+ *  ResultValue1 , ResultValue2,... = Obj.Meth() with res index
  * \retval const TCollection_AsciiString & - ResultValue with res index substring
  */
 //================================================================================
-const TCollection_AsciiString & _pyCommand::GetResultValue(int res)
+TCollection_AsciiString _pyCommand::GetResultValue(int res)
 {
   int begPos = 1;
-  int Nb=0;
+  if ( SkipSpaces( myString, begPos ) && myString.Value( begPos ) == '[' )
+    ++begPos; // skip [, else the whole list is returned
   int endPos = myString.Location( "=", 1, Length() );
+  int Nb=0;
   while ( begPos < endPos) {
-    myRes = GetWord( myString, begPos, true );
-    begPos = begPos + myRes.Length();
+    _AString result = GetWord( myString, begPos, true );
+    begPos = begPos + result.Length();
     Nb++;
-    if(res == Nb){
-      myRes.RemoveAll('[');myRes.RemoveAll(']');
-      return myRes;
+    if(res == Nb) {
+      result.RemoveAll('[');
+      result.RemoveAll(']');
+      return result;
     }
     if(Nb>res)
       break;
@@ -3240,10 +3422,10 @@ static inline bool isWord(const char c, const bool dotIsWord)
  */
 //================================================================================
 
-TCollection_AsciiString _pyCommand::GetWord( const TCollection_AsciiString & theString,
-                                            int &      theStartPos,
-                                            const bool theForward,
-                                            const bool dotIsWord )
+TCollection_AsciiString _pyCommand::GetWord( const _AString & theString,
+                                             int &            theStartPos,
+                                             const bool       theForward,
+                                             const bool       dotIsWord )
 {
   int beg = theStartPos, end = theStartPos;
   theStartPos = EMPTY;
@@ -3350,8 +3532,6 @@ std::list< _pyID > _pyCommand::GetStudyEntries( const TCollection_AsciiString& s
   * \param theString - The string
   * \param thePos - The position to search from and which returns result
   * \retval bool - false if there are only space after thePos in theString
- *
- *
  */
 //================================================================================
 
@@ -3457,7 +3637,7 @@ void _pyCommand::SetArg( int index, const TCollection_AsciiString& theArg)
 
 void _pyCommand::RemoveArgs()
 {
-  if ( int pos = myString.Location( '(', 1, Length() ))
+  if ( int pos = myString.Location( '(', Max( 1, GetBegPos( METHOD_IND )), Length() ))
     myString.Trunc( pos );
   myString += ")";
   myArgs.Clear();
@@ -3646,6 +3826,49 @@ _pySubMesh::_pySubMesh(const Handle(_pyCommand)& theCreationCmd):
   myMesh = ObjectToMesh( theGen->FindObject( theCreationCmd->GetObject() ));
 }
 
+//================================================================================
+/*!
+ * \brief Return true if a sub-mesh can be used as argument of the given method
+ */
+//================================================================================
+
+bool _pySubMesh::CanBeArgOfMethod(const _AString& theMethodName)
+{
+  // names of all methods where a sub-mesh can be used as argument
+  static TStringSet methods;
+  if ( methods.empty() ) {
+    const char * names[] = {
+      // methods of SMESH_Gen
+      "CopyMesh",
+      // methods of SMESH_Group
+      "AddFrom",
+      // methods of SMESH_Measurements
+      "MinDistance",
+      // methods of SMESH_Mesh
+      "ExportPartToMED","ExportCGNS","ExportPartToDAT","ExportPartToUNV","ExportPartToSTL",
+      "RemoveSubMesh",
+      // methods of SMESH_MeshEditor
+      "ReorientObject","Reorient2D","TriToQuadObject","QuadToTriObject","SplitQuadObject",
+      "SplitVolumesIntoTetra","SmoothObject","SmoothParametricObject","ConvertFromQuadraticObject",
+      "RotationSweepObject","RotationSweepObjectMakeGroups","RotationSweepObject1D",
+      "RotationSweepObject1DMakeGroups","RotationSweepObject2D","RotationSweepObject2DMakeGroups",
+      "ExtrusionSweepObject","ExtrusionSweepObjectMakeGroups","ExtrusionSweepObject0D",
+      "ExtrusionSweepObject0DMakeGroups","ExtrusionSweepObject1D","ExtrusionSweepObject2D",
+      "ExtrusionSweepObject1DMakeGroups","ExtrusionSweepObject2DMakeGroups",
+      "ExtrusionAlongPathObjX","ExtrusionAlongPathObject","ExtrusionAlongPathObjectMakeGroups",
+      "ExtrusionAlongPathObject1D","ExtrusionAlongPathObject1DMakeGroups",
+      "ExtrusionAlongPathObject2D","ExtrusionAlongPathObject2DMakeGroups","MirrorObject",
+      "MirrorObjectMakeGroups","MirrorObjectMakeMesh","TranslateObject","Scale",
+      "TranslateObjectMakeGroups","TranslateObjectMakeMesh","ScaleMakeGroups","ScaleMakeMesh",
+      "RotateObject","RotateObjectMakeGroups","RotateObjectMakeMesh","FindCoincidentNodesOnPart",
+      "FindCoincidentNodesOnPartBut","FindEqualElements","FindAmongElementsByPoint",
+      "MakeBoundaryMesh","Create0DElementsOnAllNodes",
+      "" }; // <- mark of end
+    methods.Insert( names );
+  }
+  return methods.Contains( theMethodName );
+}
+
 //================================================================================
 /*!
  * \brief count invoked commands
@@ -3685,6 +3908,8 @@ _pyGroup::_pyGroup(const Handle(_pyCommand)& theCreationCmd, const _pyID & id)
   if ( !id.IsEmpty() )
     setID( id );
 
+  myCanClearCreationCmd = true;
+
   const _AString& method = theCreationCmd->GetMethod();
   if ( method == "CreateGroup" ) // CreateGroup() --> CreateEmptyGroup()
   {
@@ -3727,6 +3952,27 @@ _pyGroup::_pyGroup(const Handle(_pyCommand)& theCreationCmd, const _pyID & id)
     }
     myFilter = filter;
   }
+  else
+  {
+    // theCreationCmd does something else apart from creation of this group
+    // and thus it can't be cleared if this group is removed
+    myCanClearCreationCmd = false;
+  }
+}
+
+//================================================================================
+/*!
+ * \brief set myCanClearCreationCmd = true if the main action of the creation
+ *        command is discarded
+ */
+//================================================================================
+
+void _pyGroup::RemovedWithContents()
+{
+  // this code would be appropriate if Add0DElementsToAllNodes() returned only new nodes
+  // via a created group
+  //if ( GetCreationCmd()->GetMethod() == "Add0DElementsToAllNodes")
+  // myCanClearCreationCmd = true;
 }
 
 //================================================================================
@@ -3803,6 +4049,21 @@ void _pyGroup::Process( const Handle(_pyCommand)& theCommand)
   theGen->AddMeshAccessorMethod( theCommand );
 }
 
+//================================================================================
+/*!
+ * \brief Prevent clearing "DoubleNode...() command if a group created by it is removed
+ */
+//================================================================================
+
+void _pyGroup::Flush()
+{
+  if ( !theGen->IsToKeepAllCommands() &&
+       myCreationCmd && !myCanClearCreationCmd )
+  {
+    myCreationCmd.Nullify(); // this way myCreationCmd won't be cleared
+  }
+}
+
 //================================================================================
 /*!
  * \brief Constructor of _pyFilter
@@ -3893,73 +4154,8 @@ bool _pyFilter::CanClear()
 
 _pyHypothesisReader::_pyHypothesisReader()
 {
-  // Get paths to xml files of plugins
-  vector< string > xmlPaths;
-  string sep;
-  if ( const char* meshersList = getenv("SMESH_MeshersList") )
-  {
-    string meshers = meshersList, plugin;
-    string::size_type from = 0, pos;
-    while ( from < meshers.size() )
-    {
-      // cut off plugin name
-      pos = meshers.find( ':', from );
-      if ( pos != string::npos )
-        plugin = meshers.substr( from, pos-from );
-      else
-        plugin = meshers.substr( from ), pos = meshers.size();
-      from = pos + 1;
-
-      // get PLUGIN_ROOT_DIR path
-      string rootDirVar, pluginSubDir = plugin;
-      if ( plugin == "StdMeshers" )
-        rootDirVar = "SMESH", pluginSubDir = "smesh";
-      else
-        for ( pos = 0; pos < plugin.size(); ++pos )
-          rootDirVar += toupper( plugin[pos] );
-      rootDirVar += "_ROOT_DIR";
-
-      const char* rootDir = getenv( rootDirVar.c_str() );
-      if ( !rootDir || strlen(rootDir) == 0 )
-      {
-        rootDirVar = plugin + "_ROOT_DIR"; // HexoticPLUGIN_ROOT_DIR
-        rootDir = getenv( rootDirVar.c_str() );
-        if ( !rootDir || strlen(rootDir) == 0 ) continue;
-      }
-
-      // get a separator from rootDir
-      for ( pos = strlen( rootDir )-1; pos >= 0 && sep.empty(); --pos )
-        if ( rootDir[pos] == '/' || rootDir[pos] == '\\' )
-        {
-          sep = rootDir[pos];
-          break;
-        }
-#ifdef WNT
-      if (sep.empty() ) sep = "\\";
-#else
-      if (sep.empty() ) sep = "/";
-#endif
-
-      // get a path to resource file
-      string xmlPath = rootDir;
-      if ( xmlPath[ xmlPath.size()-1 ] != sep[0] )
-        xmlPath += sep;
-      xmlPath += "share" + sep + "salome" + sep + "resources" + sep;
-      for ( pos = 0; pos < pluginSubDir.size(); ++pos )
-        xmlPath += tolower( pluginSubDir[pos] );
-      xmlPath += sep + plugin + ".xml";
-      bool fileOK;
-#ifdef WNT
-      fileOK = (GetFileAttributes(xmlPath.c_str()) != INVALID_FILE_ATTRIBUTES);
-#else
-      fileOK = (access(xmlPath.c_str(), F_OK) == 0);
-#endif
-      if ( fileOK )
-        xmlPaths.push_back( xmlPath );
-    }
-  }
-
   // Read xml files
+  vector< string > xmlPaths = SMESH_Gen::GetPluginXMLPaths();
   LDOMParser xmlParser;
   for ( size_t i = 0; i < xmlPaths.size(); ++i )
   {
@@ -3981,7 +4177,7 @@ _pyHypothesisReader::_pyHypothesisReader()
     LDOM_NodeList algoNodeList = xmlDoc.getElementsByTagName( "algorithm" );
     for ( int i = 0; i < algoNodeList.getLength(); ++i )
     {
-      LDOM_Node algoNode = algoNodeList.item( i );
+      LDOM_Node     algoNode = algoNodeList.item( i );
       LDOM_Element& algoElem = (LDOM_Element&) algoNode;
       LDOM_NodeList pyAlgoNodeList = algoElem.getElementsByTagName( "algo" );
       if ( pyAlgoNodeList.getLength() < 1 ) continue;
@@ -4043,7 +4239,43 @@ _pyHypothesisReader::_pyHypothesisReader()
         }
       }
     }
-  }
+    // <hypothesis type="BLSURF_Parameters"
+    //          ...
+    //          dim="2">
+    //   <python-wrap>
+    //     <accumulative-methods> 
+    //       SetEnforcedVertex,
+    //       SetEnforcedVertexNamed
+    //     </accumulative-methods>
+    //   </python-wrap>
+    // </hypothesis>
+    //
+    LDOM_NodeList hypNodeList = xmlDoc.getElementsByTagName( "hypothesis" );
+    for ( int i = 0; i < hypNodeList.getLength(); ++i )
+    {
+      LDOM_Node     hypNode      = hypNodeList.item( i );
+      LDOM_Element& hypElem      = (LDOM_Element&) hypNode;
+      _AString      hypType      = hypElem.getAttribute("type");
+      LDOM_NodeList methNodeList = hypElem.getElementsByTagName( "accumulative-methods" );
+      if ( methNodeList.getLength() != 1 || hypType.IsEmpty() ) continue;
+
+      map<_AString, Handle(_pyHypothesis)>::const_iterator type2hyp = myType2Hyp.find( hypType );
+      if ( type2hyp == myType2Hyp.end() ) continue;
+
+      LDOM_Node methNode = methNodeList.item( 0 );
+      LDOM_Node textNode = methNode.getFirstChild();
+      _AString      text = textNode.getNodeValue();
+      _AString method;
+      int pos = 1;
+      do {
+        method = _pyCommand::GetWord( text, pos, /*forward= */true );
+        pos += method.Length();
+        type2hyp->second->AddAccumulativeMethod( method );
+      }
+      while ( !method.IsEmpty() );
+    }
+
+  } // loop on xmlPaths
 }
 
 //================================================================================