Salome HOME
NPAL16168 (geometrical group edition from a submesh don't modifiy mesh computation)
[modules/smesh.git] / src / SMESH_I / SMESH_Gen_i.cxx
index 2492eb127b28ce6dcb4bc457666ab3a7c1d3a2e4..493abb9081ec5b599d70a419d04d13e8343a8580 100644 (file)
@@ -76,6 +76,7 @@
 #include "SMDS_FacePosition.hxx"
 #include "SMDS_VertexPosition.hxx"
 #include "SMDS_SpacePosition.hxx"
+#include "SMDS_PolyhedralVolumeOfNodes.hxx"
 
 #include CORBA_SERVER_HEADER(SMESH_Group)
 #include CORBA_SERVER_HEADER(SMESH_Filter)
@@ -108,6 +109,7 @@ static int MYDEBUG = 0;
 #endif
 
 // Static variables definition
+GEOM::GEOM_Gen_var      SMESH_Gen_i::myGeomGen = GEOM::GEOM_Gen::_nil();
 CORBA::ORB_var          SMESH_Gen_i::myOrb;
 PortableServer::POA_var SMESH_Gen_i::myPoa;
 SALOME_NamingService*   SMESH_Gen_i::myNS  = NULL;
@@ -205,9 +207,15 @@ SALOME_LifeCycleCORBA*  SMESH_Gen_i::GetLCC() {
  */
 //=============================================================================     
 GEOM::GEOM_Gen_ptr SMESH_Gen_i::GetGeomEngine() {
-  GEOM::GEOM_Gen_var aGeomEngine =
-    GEOM::GEOM_Gen::_narrow( GetLCC()->FindOrLoad_Component("FactoryServer","GEOM") );
-  return aGeomEngine._retn();
+  //CCRT GEOM::GEOM_Gen_var aGeomEngine =
+  //CCRT   GEOM::GEOM_Gen::_narrow( GetLCC()->FindOrLoad_Component("FactoryServer","GEOM") );
+  //CCRT return aGeomEngine._retn();
+  if(CORBA::is_nil(myGeomGen))
+  {
+    Engines::Component_ptr temp=GetLCC()->FindOrLoad_Component("FactoryServer","GEOM");
+    myGeomGen=GEOM::GEOM_Gen::_narrow(temp);
+  }
+  return myGeomGen;
 }
 
 //=============================================================================
@@ -413,6 +421,20 @@ GEOM_Client* SMESH_Gen_i::GetShapeReader()
   return myShapeReader;
 }
 
+//=============================================================================
+/*!
+ *  SMESH_Gen_i::SetGeomEngine
+ *
+ *  Set GEOM::GEOM_Gen reference
+ */
+//=============================================================================
+GEOM::GEOM_Gen_ptr SMESH_Gen_i::SetGeomEngine( const char* containerLoc )
+{
+  Engines::Component_ptr temp=GetLCC()->FindOrLoad_Component(containerLoc,"GEOM");
+  myGeomGen=GEOM::GEOM_Gen::_narrow(temp);
+  return myGeomGen;
+}
+
 //=============================================================================
 /*!
  *  SMESH_Gen_i::SetEmbeddedMode
@@ -891,6 +913,105 @@ CORBA::Boolean SMESH_Gen_i::IsReadyToCompute( SMESH::SMESH_Mesh_ptr theMesh,
   return false;
 }
 
+//================================================================================
+/*!
+ * \brief  Find SObject for an algo
+ */
+//================================================================================
+
+SALOMEDS::SObject_ptr SMESH_Gen_i::GetAlgoSO(const ::SMESH_Algo* algo)
+{
+  if ( algo ) {
+    if ( !myCurrentStudy->_is_nil() ) {
+      // find algo in the study
+      SALOMEDS::SComponent_var father = SALOMEDS::SComponent::_narrow
+        ( myCurrentStudy->FindComponent( ComponentDataType() ) );
+      if ( !father->_is_nil() ) {
+        SALOMEDS::ChildIterator_var itBig = myCurrentStudy->NewChildIterator( father );
+        for ( ; itBig->More(); itBig->Next() ) {
+          SALOMEDS::SObject_var gotBranch = itBig->Value();
+          if ( gotBranch->Tag() == GetAlgorithmsRootTag() ) {
+            SALOMEDS::ChildIterator_var algoIt = myCurrentStudy->NewChildIterator( gotBranch );
+            for ( ; algoIt->More(); algoIt->Next() ) {
+              SALOMEDS::SObject_var algoSO = algoIt->Value();
+              CORBA::Object_var     algoIOR = SObjectToObject( algoSO );
+              if ( !CORBA::is_nil( algoIOR )) {
+                SMESH_Hypothesis_i* impl = SMESH::DownCast<SMESH_Hypothesis_i*>( algoIOR );
+                if ( impl && impl->GetImpl() == algo )
+                  return algoSO._retn();
+              }
+            } // loop on algo SO's
+            break;
+          } // if algo tag
+        } // SMESH component iterator
+      }
+    }
+  }
+  return SALOMEDS::SObject::_nil();
+}
+
+//================================================================================
+/*!
+ * \brief Return errors of mesh computation
+ */
+//================================================================================
+
+SMESH::compute_error_array* SMESH_Gen_i::GetComputeErrors( SMESH::SMESH_Mesh_ptr theMesh, 
+                                                           GEOM::GEOM_Object_ptr theSubObject )
+  throw ( SALOME::SALOME_Exception )
+{
+  Unexpect aCatch(SALOME_SalomeException);
+  if(MYDEBUG) MESSAGE( "SMESH_Gen_i::GetComputeErrors()" );
+
+  if ( CORBA::is_nil( theSubObject ) )
+    THROW_SALOME_CORBA_EXCEPTION( "bad shape object reference", SALOME::BAD_PARAM );
+
+  if ( CORBA::is_nil( theMesh ) )
+    THROW_SALOME_CORBA_EXCEPTION( "bad Mesh reference",SALOME::BAD_PARAM );
+
+  SMESH::compute_error_array_var error_array = new SMESH::compute_error_array;
+  try {
+    if ( SMESH_Mesh_i* meshServant = SMESH::DownCast<SMESH_Mesh_i*>( theMesh ))
+    {
+      TopoDS_Shape shape = GeomObjectToShape( theSubObject );
+      ::SMESH_Mesh& mesh = meshServant->GetImpl();
+
+      error_array->length( mesh.GetMeshDS()->MaxShapeIndex() );
+      int nbErr = 0;
+
+      SMESH_subMesh *sm = mesh.GetSubMesh(shape);
+      const bool includeSelf = true, complexShapeFirst = true;
+      SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(includeSelf,
+                                                               complexShapeFirst);
+      while ( smIt->more() )
+      {
+        sm = smIt->next();
+        if ( sm->GetSubShape().ShapeType() == TopAbs_VERTEX )
+          break;
+        SMESH_ComputeErrorPtr error = sm->GetComputeError();
+        if ( error && !error->IsOK() && error->myAlgo )
+        {
+          SMESH::ComputeError & errStruct = error_array[ nbErr++ ];
+          errStruct.code       = -( error->myName < 0 ? error->myName + 1: error->myName ); // -1 -> 0
+          errStruct.comment    = error->myComment.c_str();
+          errStruct.subShapeID = sm->GetId();
+          SALOMEDS::SObject_var algoSO = GetAlgoSO( error->myAlgo );
+          if ( !algoSO->_is_nil() )
+            errStruct.algoName   = algoSO->GetName();
+          else
+            errStruct.algoName   = error->myAlgo->GetName();
+        }
+      }
+      error_array->length( nbErr );
+    }
+  }
+  catch ( SALOME_Exception& S_ex ) {
+    INFOS( "catch exception "<< S_ex.what() );
+  }
+
+  return error_array._retn();
+}
+
 //================================================================================
 /*!
  * \brief Returns errors of hypotheses definintion
@@ -928,55 +1049,15 @@ SMESH::algo_error_array* SMESH_Gen_i::GetAlgoState( SMESH::SMESH_Mesh_ptr theMes
       int i = 0;
       for ( error = error_list.begin(); error != error_list.end(); ++error )
       {
-        // error name
-        SMESH::AlgoStateErrorName errName;
-        switch ( error->_name ) {
-        case ::SMESH_Gen::MISSING_ALGO:     errName = SMESH::MISSING_ALGO; break;
-        case ::SMESH_Gen::MISSING_HYPO:     errName = SMESH::MISSING_HYPO; break;
-        case ::SMESH_Gen::NOT_CONFORM_MESH: errName = SMESH::NOT_CONFORM_MESH; break;
-        case ::SMESH_Gen::BAD_PARAM_VALUE:  errName = SMESH::BAD_PARAM_VALUE; break;
-        default:
-          THROW_SALOME_CORBA_EXCEPTION( "bad error name",SALOME::BAD_PARAM );
-        }
-        // algo name
-        CORBA::String_var algoName = "";
-        if ( error->_algo ) {
-          if ( !myCurrentStudy->_is_nil() ) {
-            // find algo in the study
-            SALOMEDS::SComponent_var father = SALOMEDS::SComponent::_narrow
-              ( myCurrentStudy->FindComponent( ComponentDataType() ) );
-            if ( !father->_is_nil() ) {
-              SALOMEDS::ChildIterator_var itBig = myCurrentStudy->NewChildIterator( father );
-              for ( ; itBig->More(); itBig->Next() ) {
-                SALOMEDS::SObject_var gotBranch = itBig->Value();
-                if ( gotBranch->Tag() == GetAlgorithmsRootTag() ) {
-                  SALOMEDS::ChildIterator_var algoIt = myCurrentStudy->NewChildIterator( gotBranch );
-                  for ( ; algoIt->More(); algoIt->Next() ) {
-                    SALOMEDS::SObject_var algoSO = algoIt->Value();
-                    CORBA::Object_var    algoIOR = SObjectToObject( algoSO );
-                    if ( !CORBA::is_nil( algoIOR )) {
-                      SMESH_Hypothesis_i* myImpl = SMESH::DownCast<SMESH_Hypothesis_i*>( algoIOR );
-                      if ( myImpl && myImpl->GetImpl() == error->_algo ) {
-                        algoName = algoSO->GetName();
-                        break;
-                      }
-                    }
-                  } // loop on algo SO's
-                  break;
-                } // if algo tag
-              } // SMESH component iterator
-            }
-          }
-          if ( algoName.in() == 0 )
-            // use algo type name
-            algoName = error->_algo->GetName();
-        }
         // fill AlgoStateError structure
         SMESH::AlgoStateError & errStruct = error_array[ i++ ];
-        errStruct.name         = errName;
-        errStruct.algoName     = algoName;
+        errStruct.state        = SMESH_Mesh_i::ConvertHypothesisStatus( error->_name );
         errStruct.algoDim      = error->_algoDim;
         errStruct.isGlobalAlgo = error->_isGlobalAlgo;
+        errStruct.algoName     = "";
+        SALOMEDS::SObject_var algoSO = GetAlgoSO( error->_algo );
+        if ( !algoSO->_is_nil() )
+          errStruct.algoName   = algoSO->GetName();
       }
     }
   }
@@ -1094,6 +1175,8 @@ CORBA::Boolean SMESH_Gen_i::Compute( SMESH::SMESH_Mesh_ptr theMesh,
     SMESH_Mesh_i* meshServant = dynamic_cast<SMESH_Mesh_i*>( GetServant( theMesh ).in() );
     ASSERT( meshServant );
     if ( meshServant ) {
+      // NPAL16168: "geometrical group edition from a submesh don't modifiy mesh computation"
+      meshServant->CheckGeomGroupModif();
       // get local TopoDS_Shape
       TopoDS_Shape myLocShape = GeomObjectToShape( theShapeObject );
       // call implementation compute
@@ -1101,9 +1184,8 @@ CORBA::Boolean SMESH_Gen_i::Compute( SMESH::SMESH_Mesh_ptr theMesh,
       return myGen.Compute( myLocMesh, myLocShape);
     }
   }
-  catch ( std::bad_alloc& exc ) {
-    THROW_SALOME_CORBA_EXCEPTION( "Memory allocation problem",
-                                  SALOME::INTERNAL_ERROR );
+  catch ( std::bad_alloc ) {
+    INFOS( "Compute(): lack of memory" );
   }
   catch ( SALOME_Exception& S_ex ) {
     INFOS( "Compute(): catch exception "<< S_ex.what() );
@@ -1135,14 +1217,37 @@ SMESH_Gen_i::GetGeometryByMeshElement( SMESH::SMESH_Mesh_ptr  theMesh,
   GEOM::GEOM_Object_var geom = FindGeometryByMeshElement(theMesh, theElementID);
   if ( !geom->_is_nil() ) {
     GEOM::GEOM_Object_var mainShape = theMesh->GetShapeToMesh();
-    GEOM::GEOM_Gen_var    geomGen   = GetGeomEngine();
+    GEOM::GEOM_Gen_ptr    geomGen   = GetGeomEngine();
 
     // try to find the corresponding SObject
-    GeomObjectToShape( geom ); // geom client remembers the found shape
     SALOMEDS::SObject_var SObj = ObjectToSObject( myCurrentStudy, geom.in() );
-    if ( SObj->_is_nil() )
-      // publish a new subshape
+    if ( SObj->_is_nil() ) // submesh can be not found even if published
+    {
+      // try to find published submesh
+      GEOM::ListOfLong_var list = geom->GetSubShapeIndices();
+      if ( !geom->IsMainShape() && list->length() == 1 ) {
+        SALOMEDS::SObject_var mainSO = ObjectToSObject( myCurrentStudy, mainShape );
+        SALOMEDS::ChildIterator_var it;
+        if ( !mainSO->_is_nil() )
+          it = myCurrentStudy->NewChildIterator( mainSO );
+        if ( !it->_is_nil() ) {
+          for ( it->InitEx(true); SObj->_is_nil() && it->More(); it->Next() ) {
+            GEOM::GEOM_Object_var subGeom =
+              GEOM::GEOM_Object::_narrow( SObjectToObject( it->Value() ));
+            if ( !subGeom->_is_nil() ) {
+              GEOM::ListOfLong_var subList = subGeom->GetSubShapeIndices();
+              if ( subList->length() == 1 && list[0] == subList[0] ) {
+                SObj = it->Value();
+                geom = subGeom;
+              }
+            }
+          }
+        }
+      }
+    }
+    if ( SObj->_is_nil() ) // publish a new subshape
       SObj = geomGen->AddInStudy( myCurrentStudy, geom, theGeomName, mainShape );
+
     // return only published geometry
     if ( !SObj->_is_nil() )
       return geom._retn();
@@ -1150,7 +1255,6 @@ SMESH_Gen_i::GetGeometryByMeshElement( SMESH::SMESH_Mesh_ptr  theMesh,
   return GEOM::GEOM_Object::_nil();
 }
 
-
 //================================================================================
 /*!
  * \brief Return geometrical object the given element is built on.
@@ -1162,7 +1266,7 @@ SMESH_Gen_i::GetGeometryByMeshElement( SMESH::SMESH_Mesh_ptr  theMesh,
 
 GEOM::GEOM_Object_ptr
 SMESH_Gen_i::FindGeometryByMeshElement( SMESH::SMESH_Mesh_ptr  theMesh,
-                                   CORBA::Long            theElementID)
+                                        CORBA::Long            theElementID)
   throw ( SALOME::SALOME_Exception )
 {
   Unexpect aCatch(SALOME_SalomeException);
@@ -1170,7 +1274,7 @@ SMESH_Gen_i::FindGeometryByMeshElement( SMESH::SMESH_Mesh_ptr  theMesh,
     THROW_SALOME_CORBA_EXCEPTION( "bad Mesh reference", SALOME::BAD_PARAM );
 
   GEOM::GEOM_Object_var mainShape = theMesh->GetShapeToMesh();
-  GEOM::GEOM_Gen_var    geomGen   = GetGeomEngine();
+  GEOM::GEOM_Gen_ptr    geomGen   = GetGeomEngine();
 
   // get a core mesh DS
   SMESH_Mesh_i* meshServant = SMESH::DownCast<SMESH_Mesh_i*>( theMesh );
@@ -1190,13 +1294,203 @@ SMESH_Gen_i::FindGeometryByMeshElement( SMESH::SMESH_Mesh_ptr  theMesh,
           if ( !op->_is_nil() )
             geom = op->GetSubShape( mainShape, shapeID );
         }
-        if ( !geom->_is_nil() )
+        if ( !geom->_is_nil() ) {
+          GeomObjectToShape( geom ); // let geom client remember the found shape
          return geom._retn();
+        }
       }
   }
   return GEOM::GEOM_Object::_nil();
 }
 
+//================================================================================
+/*!
+ *  SMESH_Gen_i::Concatenate
+ *
+ *  Concatenate the given meshes into one mesh
+ */
+//================================================================================
+
+SMESH::SMESH_Mesh_ptr SMESH_Gen_i::Concatenate(const SMESH::mesh_array& theMeshesArray,
+                                              CORBA::Boolean           theUniteIdenticalGroups, 
+                                              CORBA::Boolean           theMergeNodesAndElements, 
+                                              CORBA::Double            theMergeTolerance)
+  throw ( SALOME::SALOME_Exception )
+{
+  typedef map<int, int> TIDsMap;
+  typedef list<SMESH::SMESH_Group_var> TListOfNewGroups;
+  typedef map< pair<string, SMESH::ElementType>, TListOfNewGroups > TGroupsMap;
+  typedef std::set<SMESHDS_GroupBase*> TGroups;
+
+  TPythonDump aPythonDump; // prevent dump of called methods
+
+  // create mesh
+  SMESH::SMESH_Mesh_var aNewMesh = CreateEmptyMesh();
+  
+  if ( !aNewMesh->_is_nil() ) {
+    SMESH_Mesh_i* aNewImpl = dynamic_cast<SMESH_Mesh_i*>( GetServant( aNewMesh ).in() );
+    if ( aNewImpl ) {
+      ::SMESH_Mesh& aLocMesh = aNewImpl->GetImpl();
+      SMESHDS_Mesh* aNewMeshDS = aLocMesh.GetMeshDS();
+
+      TGroupsMap aGroupsMap;
+      TListOfNewGroups aListOfNewGroups;
+      SMESH_MeshEditor aNewEditor = ::SMESH_MeshEditor(&aLocMesh);
+      SMESH::ListOfGroups_var aListOfGroups = new SMESH::ListOfGroups();
+
+      // loop on meshes
+      for ( int i = 0; i < theMeshesArray.length(); i++) {
+       SMESH::SMESH_Mesh_var anInitMesh = theMeshesArray[i];
+       if ( !anInitMesh->_is_nil() ) {
+         SMESH_Mesh_i* anInitImpl = dynamic_cast<SMESH_Mesh_i*>( GetServant( anInitMesh ).in() );
+         if ( anInitImpl ) {
+           ::SMESH_Mesh& aInitLocMesh = anInitImpl->GetImpl();
+           SMESHDS_Mesh* anInitMeshDS = aInitLocMesh.GetMeshDS();
+
+           TIDsMap nodesMap;
+           TIDsMap elemsMap;
+
+           // loop on elements of mesh
+           SMDS_ElemIteratorPtr itElems = anInitMeshDS->elementsIterator();
+           const SMDS_MeshElement* anElem = 0;
+           const SMDS_MeshElement* aNewElem = 0;
+           int anElemNbNodes = 0;
+
+           for ( int j = 0; itElems->more(); j++) {
+             anElem = itElems->next();
+             SMDSAbs_ElementType anElemType = anElem->GetType();
+             anElemNbNodes = anElem->NbNodes();
+             std::vector<const SMDS_MeshNode*> aNodesArray (anElemNbNodes);
+
+             // loop on nodes of element
+             const SMDS_MeshNode* aNode = 0;
+             const SMDS_MeshNode* aNewNode = 0;
+             SMDS_ElemIteratorPtr itNodes = anElem->nodesIterator();
+
+             for ( int k = 0; itNodes->more(); k++) {
+               aNode = static_cast<const SMDS_MeshNode*>(itNodes->next());
+               if ( nodesMap.find(aNode->GetID()) == nodesMap.end() ) {
+                 aNewNode = aNewMeshDS->AddNode(aNode->X(), aNode->Y(), aNode->Z());
+                 nodesMap.insert( make_pair(aNode->GetID(), aNewNode->GetID()) );
+               }
+               else
+                 aNewNode = aNewMeshDS->FindNode( nodesMap.find(aNode->GetID())->second );
+               aNodesArray[k] = aNewNode;
+             }//nodes loop
+
+             // creates a corresponding element on existent nodes in new mesh
+             if ( anElem->IsPoly() && anElemType == SMDSAbs_Volume )
+               {
+                 const SMDS_PolyhedralVolumeOfNodes* aVolume =
+                   dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*> (anElem);
+                 if ( aVolume ) {
+                   aNewElem = aNewMeshDS->AddPolyhedralVolume(aNodesArray, 
+                                                              aVolume->GetQuanities());
+                   elemsMap.insert(make_pair(anElem->GetID(), aNewElem->GetID()));
+                 }
+               }
+             else {
+               
+               aNewElem = aNewEditor.AddElement(aNodesArray,
+                                                anElemType,
+                                                anElem->IsPoly());
+               elemsMap.insert(make_pair(anElem->GetID(), aNewElem->GetID()));
+             } 
+           }//elems loop
+           
+           aListOfGroups = anInitImpl->GetGroups();
+           SMESH::SMESH_GroupBase_ptr aGroup;
+
+           // loop on groups of mesh
+           SMESH::long_array_var anInitIDs = new SMESH::long_array();
+           SMESH::long_array_var anNewIDs = new SMESH::long_array();
+           SMESH::SMESH_Group_var aNewGroup;
+           for (int i = 0; i < aListOfGroups->length(); i++) {
+             aGroup = aListOfGroups[i];
+             aListOfNewGroups.clear();
+             SMESH::ElementType aGroupType = aGroup->GetType();
+             CORBA::String_var aGroupName = aGroup->GetName();
+             
+             TGroupsMap::iterator anIter = aGroupsMap.find(make_pair(aGroupName, aGroupType));
+
+             // convert a list of IDs
+             anInitIDs = aGroup->GetListOfID();
+             anNewIDs->length(anInitIDs->length());
+             if ( aGroupType == SMESH::NODE )
+               for (int j = 0; j < anInitIDs->length(); j++) {
+                 anNewIDs[j] = nodesMap.find(anInitIDs[j])->second;
+               }
+             else
+               for (int j = 0; j < anInitIDs->length(); j++) {
+                 anNewIDs[j] = elemsMap.find(anInitIDs[j])->second;
+               }
+             
+             // check that current group name and type don't have identical ones in union mesh
+             if ( anIter == aGroupsMap.end() ) {
+               // add a new group in the mesh
+               aNewGroup = aNewImpl->CreateGroup(aGroupType, aGroupName);
+               // add elements into new group
+               aNewGroup->Add( anNewIDs );
+               
+               aListOfNewGroups.push_back(aNewGroup);
+               aGroupsMap.insert(make_pair( make_pair(aGroupName, aGroupType), aListOfNewGroups ));
+             }
+
+             else if ( theUniteIdenticalGroups ) {
+               // unite identical groups
+               TListOfNewGroups& aNewGroups = anIter->second;
+               aNewGroups.front()->Add( anNewIDs );
+             }
+
+             else {
+               // rename identical groups
+               aNewGroup = aNewImpl->CreateGroup(aGroupType, aGroupName);
+               aNewGroup->Add( anNewIDs );
+               
+               TListOfNewGroups& aNewGroups = anIter->second;
+               string aNewGroupName;
+               if (aNewGroups.size() == 1) {
+                 aNewGroupName = string(aGroupName) + "_1";
+                 aNewGroups.front()->SetName(aNewGroupName.c_str());
+               }
+               char aGroupNum[128];
+               sprintf(aGroupNum, "%u", aNewGroups.size()+1);
+               aNewGroupName = string(aGroupName) + "_" + string(aGroupNum);
+               aNewGroup->SetName(aNewGroupName.c_str());
+               aNewGroups.push_back(aNewGroup);
+             }
+           }//groups loop
+         }
+       }
+      }//meshes loop
+
+      if (theMergeNodesAndElements) {
+       // merge nodes
+       set<const SMDS_MeshNode*> aMeshNodes; // no input nodes
+       SMESH_MeshEditor::TListOfListOfNodes aGroupsOfNodes;
+       aNewEditor.FindCoincidentNodes( aMeshNodes, theMergeTolerance, aGroupsOfNodes );
+       aNewEditor.MergeNodes( aGroupsOfNodes );
+       // merge elements
+       aNewEditor.MergeEqualElements();
+      }
+    }
+  }
+  
+  // Update Python script
+  aPythonDump << aNewMesh << " = " << this << ".Concatenate(";
+  aPythonDump << "[";
+  for ( int i = 0; i < theMeshesArray.length(); i++) {
+    if (i > 0) aPythonDump << ", ";
+    aPythonDump << theMeshesArray[i];
+  }
+  aPythonDump << "], ";
+  aPythonDump << theUniteIdenticalGroups << ", "
+              << theMergeNodesAndElements << ", "
+              << theMergeTolerance << ")";
+
+  return aNewMesh._retn();
+}
+
 //=============================================================================
 /*!
  *  SMESH_Gen_i::Save
@@ -1221,10 +1515,10 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent,
   SavePython(myCurrentStudy);
 
   StudyContext* myStudyContext = GetCurrentStudyContext();
-  
+
   // Declare a byte stream
   SALOMEDS::TMPFile_var aStreamFile;
-  
+
   // Obtain a temporary dir
   TCollection_AsciiString tmpDir =
     ( isMultiFile ) ? TCollection_AsciiString( ( char* )theURL ) : ( char* )SALOMEDS_Tool::GetTmpDir().c_str();