Salome HOME
Merge from V5_1_main 14/05/2010
[modules/smesh.git] / src / SMESH_I / SMESH_MeshEditor_i.cxx
index 000bc95e84c79b38ceecd757025d65c5e847562e..6887ed0a16129da83de75d2af9d6625d96e06266 100644 (file)
@@ -1,4 +1,4 @@
-//  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
+//  Copyright (C) 2007-2010  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_MeshEditor_i.cxx
 //  Author : Nicolas REJNERI
 //  Module : SMESH
-
+//
 #include "SMESH_MeshEditor_i.hxx"
 
 #include "SMDS_Mesh0DElement.hxx"
@@ -271,6 +272,27 @@ void SMESH_MeshEditor_i::initData(bool deleteSearchers)
   }
 }
 
+//=======================================================================
+//function : MakeIDSource
+//purpose  : Wrap a sequence of ids in a SMESH_IDSource
+//=======================================================================
+
+struct _IDSource : public POA_SMESH::SMESH_IDSource
+{
+  SMESH::long_array _ids;
+  SMESH::long_array* GetIDs()      { return new SMESH::long_array( _ids ); }
+  SMESH::long_array* GetMeshInfo() { return 0; }
+};
+
+SMESH::SMESH_IDSource_ptr SMESH_MeshEditor_i::MakeIDSource(const SMESH::long_array& ids)
+{
+  _IDSource* anIDSource = new _IDSource;
+  anIDSource->_ids = ids;
+  SMESH::SMESH_IDSource_var anIDSourceVar = anIDSource->_this();
+  
+  return anIDSourceVar._retn();
+}
+
 //=============================================================================
 /*!
  *
@@ -290,9 +312,10 @@ SMESH_MeshEditor_i::RemoveElements(const SMESH::long_array & IDsOfElements)
 
   // Update Python script
   TPythonDump() << "isDone = " << this << ".RemoveElements( " << IDsOfElements << " )";
-#ifdef _DEBUG_
-  TPythonDump() << "print 'RemoveElements: ', isDone";
-#endif
+
+  if ( IDsOfElements.length() )
+    myMesh->SetIsModified( true ); // issue 0020693
+
   // Remove Elements
   return anEditor.Remove( IdList, false );
 }
@@ -314,9 +337,9 @@ CORBA::Boolean SMESH_MeshEditor_i::RemoveNodes(const SMESH::long_array & IDsOfNo
 
   // Update Python script
   TPythonDump() << "isDone = " << this << ".RemoveNodes( " << IDsOfNodes << " )";
-#ifdef _DEBUG_
-  TPythonDump() << "print 'RemoveNodes: ', isDone";
-#endif
+
+  if ( IDsOfNodes.length() )
+    myMesh->SetIsModified( true ); // issue 0020693
 
   return anEditor.Remove( IdList, true );
 }
@@ -338,6 +361,8 @@ CORBA::Long SMESH_MeshEditor_i::AddNode(CORBA::Double x,
   TPythonDump() << "nodeID = " << this << ".AddNode( "
                 << x << ", " << y << ", " << z << " )";
 
+  myMesh->SetIsModified( true ); // issue 0020693
+
   return N->GetID();
 }
 
@@ -356,6 +381,8 @@ CORBA::Long SMESH_MeshEditor_i::Add0DElement(CORBA::Long IDOfNode)
   // Update Python script
   TPythonDump() << "elem0d = " << this << ".Add0DElement( " << IDOfNode <<" )";
 
+  myMesh->SetIsModified( true ); // issue 0020693
+
   if (elem)
     return elem->GetID();
 
@@ -397,7 +424,7 @@ CORBA::Long SMESH_MeshEditor_i::AddEdge(const SMESH::long_array & IDsOfNodes)
   }
 
   if(elem)
-    return elem->GetID();
+    return myMesh->SetIsModified( true ), elem->GetID();
 
   return 0;
 }
@@ -445,7 +472,7 @@ CORBA::Long SMESH_MeshEditor_i::AddFace(const SMESH::long_array & IDsOfNodes)
   TPythonDump() << "faceID = " << this << ".AddFace( " << IDsOfNodes << " )";
 
   if(elem)
-    return elem->GetID();
+    return myMesh->SetIsModified( true ), elem->GetID();
 
   return 0;
 }
@@ -468,14 +495,8 @@ CORBA::Long SMESH_MeshEditor_i::AddPolygonalFace (const SMESH::long_array & IDsO
 
   // Update Python script
   TPythonDump() <<"faceID = "<<this<<".AddPolygonalFace( "<<IDsOfNodes<<" )";
-#ifdef _DEBUG_
-  TPythonDump() << "print 'AddPolygonalFace: ', faceID";
-#endif
-
-  if(elem)
-    return elem->GetID();
 
-  return 0;
+  return elem ? ( myMesh->SetIsModified( true ), elem->GetID()) : 0;
 }
 
 //=============================================================================
@@ -517,12 +538,9 @@ CORBA::Long SMESH_MeshEditor_i::AddVolume(const SMESH::long_array & IDsOfNodes)
 
   // Update Python script
   TPythonDump() << "volID = " << this << ".AddVolume( " << IDsOfNodes << " )";
-#ifdef _DEBUG_
-  TPythonDump() << "print 'AddVolume: ', volID";
-#endif
 
   if(elem)
-    return elem->GetID();
+    return myMesh->SetIsModified( true ), elem->GetID();
 
   return 0;
 }
@@ -552,14 +570,8 @@ CORBA::Long SMESH_MeshEditor_i::AddPolyhedralVolume (const SMESH::long_array & I
   // Update Python script
   TPythonDump() << "volID = " << this << ".AddPolyhedralVolume( "
                 << IDsOfNodes << ", " << Quantities << " )";
-#ifdef _DEBUG_
-  TPythonDump() << "print 'AddPolyhedralVolume: ', volID";
-#endif
-
-  if(elem)
-    return elem->GetID();
 
-  return 0;
+  return elem ? ( myMesh->SetIsModified( true ), elem->GetID()) : 0;
 }
 
 //=============================================================================
@@ -590,14 +602,8 @@ CORBA::Long SMESH_MeshEditor_i::AddPolyhedralVolumeByFaces (const SMESH::long_ar
   // Update Python script
   TPythonDump() << "volID = " << this << ".AddPolyhedralVolumeByFaces( "
                 << IdsOfFaces << " )";
-#ifdef _DEBUG_
-  TPythonDump() << "print 'AddPolyhedralVolume: ', volID";
-#endif
-
-  if(elem)
-    return elem->GetID();
 
-  return 0;
+  return elem ? ( myMesh->SetIsModified( true ), elem->GetID()) : 0;
 }
 
 //=============================================================================
@@ -627,6 +633,8 @@ void SMESH_MeshEditor_i::SetNodeOnVertex(CORBA::Long NodeID, CORBA::Long VertexI
     THROW_SALOME_CORBA_EXCEPTION("Invalid VertexID", SALOME::BAD_PARAM);
 
   mesh->SetNodeOnVertex( node, VertexID );
+
+  myMesh->SetIsModified( true );
 }
 
 //=============================================================================
@@ -663,6 +671,8 @@ void SMESH_MeshEditor_i::SetNodeOnEdge(CORBA::Long NodeID, CORBA::Long EdgeID,
     THROW_SALOME_CORBA_EXCEPTION("Invalid paramOnEdge", SALOME::BAD_PARAM);
 
   mesh->SetNodeOnEdge( node, EdgeID, paramOnEdge );
+
+  myMesh->SetIsModified( true );
 }
 
 //=============================================================================
@@ -712,6 +722,8 @@ void SMESH_MeshEditor_i::SetNodeOnFace(CORBA::Long NodeID, CORBA::Long FaceID,
   }
 
   mesh->SetNodeOnFace( node, FaceID, u, v );
+
+  myMesh->SetIsModified( true );
 }
 
 //=============================================================================
@@ -742,6 +754,8 @@ void SMESH_MeshEditor_i::SetNodeInVolume(CORBA::Long NodeID, CORBA::Long SolidID
     THROW_SALOME_CORBA_EXCEPTION("Invalid SolidID", SALOME::BAD_PARAM);
 
   mesh->SetNodeInVolume( node, SolidID );
+
+  // myMesh->SetIsModified( true ); - SetNodeInVolume() can't prevent re-compute, I believe
 }
 
 //=============================================================================
@@ -775,6 +789,8 @@ void SMESH_MeshEditor_i::SetMeshElementOnShape(CORBA::Long ElementID,
     THROW_SALOME_CORBA_EXCEPTION("Invalid shape type", SALOME::BAD_PARAM);
 
   mesh->SetMeshElementOnShape( elem, ShapeID );
+
+  myMesh->SetIsModified( true );
 }
 
 //=============================================================================
@@ -797,6 +813,8 @@ CORBA::Boolean SMESH_MeshEditor_i::InverseDiag(CORBA::Long NodeID1,
   TPythonDump() << "isDone = " << this << ".InverseDiag( "
                 << NodeID1 << ", " << NodeID2 << " )";
 
+  myMesh->SetIsModified( true );
+
   ::SMESH_MeshEditor aMeshEditor( myMesh );
   return aMeshEditor.InverseDiag ( n1, n2 );
 }
@@ -825,6 +843,9 @@ CORBA::Boolean SMESH_MeshEditor_i::DeleteDiag(CORBA::Long NodeID1,
 
   bool stat = aMeshEditor.DeleteDiag ( n1, n2 );
 
+  if ( stat )
+    myMesh->SetIsModified( true ); // issue 0020693
+    
   storeResult(aMeshEditor);
 
   return stat;
@@ -851,6 +872,9 @@ CORBA::Boolean SMESH_MeshEditor_i::Reorient(const SMESH::long_array & IDsOfEleme
   // Update Python script
   TPythonDump() << "isDone = " << this << ".Reorient( " << IDsOfElements << " )";
 
+  if ( IDsOfElements.length() )
+    myMesh->SetIsModified( true ); // issue 0020693
+
   return true;
 }
 
@@ -865,15 +889,13 @@ CORBA::Boolean SMESH_MeshEditor_i::ReorientObject(SMESH::SMESH_IDSource_ptr theO
 {
   initData();
 
+  TPythonDump aTPythonDump; // suppress dump in Reorient()
+
   SMESH::long_array_var anElementsId = theObject->GetIDs();
   CORBA::Boolean isDone = Reorient(anElementsId);
 
-  // Clear python line, created by Reorient()
-  SMESH_Gen_i* aSMESHGen = SMESH_Gen_i::GetSMESHGen();
-  aSMESHGen->RemoveLastFromPythonScript(aSMESHGen->GetCurrentStudyID());
-
   // Update Python script
-  TPythonDump() << "isDone = " << this << ".ReorientObject( " << theObject << " )";
+  aTPythonDump << "isDone = " << this << ".ReorientObject( " << theObject << " )";
 
   return isDone;
 }
@@ -932,13 +954,12 @@ CORBA::Boolean SMESH_MeshEditor_i::TriToQuad (const SMESH::long_array &   IDsOfE
   // Update Python script
   TPythonDump() << "isDone = " << this << ".TriToQuad( "
                 << IDsOfElements << ", " << aNumericalFunctor << ", " << MaxAngle << " )";
-#ifdef _DEBUG_
-  TPythonDump() << "print 'TriToQuad: ', isDone";
-#endif
 
   ::SMESH_MeshEditor anEditor( myMesh );
 
   bool stat = anEditor.TriToQuad( faces, aCrit, MaxAngle );
+  if ( stat )
+    myMesh->SetIsModified( true ); // issue 0020693
 
   storeResult(anEditor);
 
@@ -957,25 +978,16 @@ CORBA::Boolean SMESH_MeshEditor_i::TriToQuadObject (SMESH::SMESH_IDSource_ptr
 {
   initData();
 
+  TPythonDump aTPythonDump;  // suppress dump in TriToQuad()
   SMESH::long_array_var anElementsId = theObject->GetIDs();
   CORBA::Boolean isDone = TriToQuad(anElementsId, Criterion, MaxAngle);
 
-  // Clear python line(s), created by TriToQuad()
-  SMESH_Gen_i* aSMESHGen = SMESH_Gen_i::GetSMESHGen();
-  aSMESHGen->RemoveLastFromPythonScript(aSMESHGen->GetCurrentStudyID());
-#ifdef _DEBUG_
-  aSMESHGen->RemoveLastFromPythonScript(aSMESHGen->GetCurrentStudyID());
-#endif
-
   SMESH::NumericalFunctor_i* aNumericalFunctor =
     SMESH::DownCast<SMESH::NumericalFunctor_i*>( Criterion );
 
   // Update Python script
-  TPythonDump() << "isDone = " << this << ".TriToQuadObject("
-                << theObject << ", " << aNumericalFunctor << ", " << MaxAngle << " )";
-#ifdef _DEBUG_
-  TPythonDump() << "print 'TriToQuadObject: ', isDone";
-#endif
+  aTPythonDump << "isDone = " << this << ".TriToQuadObject("
+               << theObject << ", " << aNumericalFunctor << ", " << MaxAngle << " )";
 
   return isDone;
 }
@@ -1006,12 +1018,11 @@ CORBA::Boolean SMESH_MeshEditor_i::QuadToTri (const SMESH::long_array &   IDsOfE
 
   // Update Python script
   TPythonDump() << "isDone = " << this << ".QuadToTri( " << IDsOfElements << ", " << aNumericalFunctor << " )";
-#ifdef _DEBUG_
-  TPythonDump() << "print 'QuadToTri: ', isDone";
-#endif
 
   ::SMESH_MeshEditor anEditor( myMesh );
   CORBA::Boolean stat = anEditor.QuadToTri( faces, aCrit );
+  if ( stat )
+    myMesh->SetIsModified( true ); // issue 0020693
 
   storeResult(anEditor);
 
@@ -1029,24 +1040,16 @@ CORBA::Boolean SMESH_MeshEditor_i::QuadToTriObject (SMESH::SMESH_IDSource_ptr
 {
   initData();
 
+  TPythonDump aTPythonDump;  // suppress dump in QuadToTri()
+
   SMESH::long_array_var anElementsId = theObject->GetIDs();
   CORBA::Boolean isDone = QuadToTri(anElementsId, Criterion);
 
-  // Clear python line(s), created by QuadToTri()
-  SMESH_Gen_i* aSMESHGen = SMESH_Gen_i::GetSMESHGen();
-  aSMESHGen->RemoveLastFromPythonScript(aSMESHGen->GetCurrentStudyID());
-#ifdef _DEBUG_
-  aSMESHGen->RemoveLastFromPythonScript(aSMESHGen->GetCurrentStudyID());
-#endif
-
   SMESH::NumericalFunctor_i* aNumericalFunctor =
     SMESH::DownCast<SMESH::NumericalFunctor_i*>( Criterion );
 
   // Update Python script
-  TPythonDump() << "isDone = " << this << ".QuadToTriObject( " << theObject << ", " << aNumericalFunctor << " )";
-#ifdef _DEBUG_
-  TPythonDump() << "print 'QuadToTriObject: ', isDone";
-#endif
+  aTPythonDump << "isDone = " << this << ".QuadToTriObject( " << theObject << ", " << aNumericalFunctor << " )";
 
   return isDone;
 }
@@ -1069,12 +1072,12 @@ CORBA::Boolean SMESH_MeshEditor_i::SplitQuad (const SMESH::long_array & IDsOfEle
   // Update Python script
   TPythonDump() << "isDone = " << this << ".SplitQuad( "
                 << IDsOfElements << ", " << Diag13 << " )";
-#ifdef _DEBUG_
-  TPythonDump() << "print 'SplitQuad: ', isDone";
-#endif
 
   ::SMESH_MeshEditor anEditor( myMesh );
   CORBA::Boolean stat = anEditor.QuadToTri( faces, Diag13 );
+  if ( stat )
+    myMesh->SetIsModified( true ); // issue 0020693
+
 
   storeResult(anEditor);
 
@@ -1092,22 +1095,14 @@ CORBA::Boolean SMESH_MeshEditor_i::SplitQuadObject (SMESH::SMESH_IDSource_ptr th
 {
   initData();
 
+  TPythonDump aTPythonDump;  // suppress dump in SplitQuad()
+
   SMESH::long_array_var anElementsId = theObject->GetIDs();
   CORBA::Boolean isDone = SplitQuad(anElementsId, Diag13);
 
-  // Clear python line(s), created by SplitQuad()
-  SMESH_Gen_i* aSMESHGen = SMESH_Gen_i::GetSMESHGen();
-  aSMESHGen->RemoveLastFromPythonScript(aSMESHGen->GetCurrentStudyID());
-#ifdef _DEBUG_
-  aSMESHGen->RemoveLastFromPythonScript(aSMESHGen->GetCurrentStudyID());
-#endif
-
   // Update Python script
-  TPythonDump() << "isDone = " << this << ".SplitQuadObject( "
-                << theObject << ", " << Diag13 << " )";
-#ifdef _DEBUG_
-  TPythonDump() << "print 'SplitQuadObject: ', isDone";
-#endif
+  aTPythonDump << "isDone = " << this << ".SplitQuadObject( "
+               << theObject << ", " << Diag13 << " )";
 
   return isDone;
 }
@@ -1138,6 +1133,33 @@ CORBA::Long SMESH_MeshEditor_i::BestSplit (CORBA::Long                 IDOfQuad,
   return -1;
 }
 
+//================================================================================
+/*!
+ * \brief Split volumic elements into tetrahedrons
+ */
+//================================================================================
+
+void SMESH_MeshEditor_i::SplitVolumesIntoTetra (SMESH::SMESH_IDSource_ptr elems,
+                                                CORBA::Short              methodFlags)
+  throw (SALOME::SALOME_Exception)
+{
+  Unexpect aCatch(SALOME_SalomeException);
+
+  SMESH::long_array_var anElementsId = elems->GetIDs();
+  TIDSortedElemSet elemSet;
+  arrayToSet( anElementsId, GetMeshDS(), elemSet, SMDSAbs_Volume );
+  
+  ::SMESH_MeshEditor anEditor (myMesh);
+  anEditor.SplitVolumesIntoTetra( elemSet, int( methodFlags ));
+
+  storeResult(anEditor);
+
+//   if ( myLastCreatedElems.length() ) - it does not influence Compute()
+//     myMesh->SetIsModified( true ); // issue 0020693
+
+  TPythonDump() << this << ".SplitVolumesIntoTetra( "
+                << elems << ", " << methodFlags << " )";
+}
 
 //=======================================================================
 //function : Smooth
@@ -1243,6 +1265,8 @@ SMESH_MeshEditor_i::smooth(const SMESH::long_array &              IDsOfElements,
   anEditor.Smooth(elements, fixedNodes, method,
                   MaxNbOfIterations, MaxAspectRatio, IsParametric );
 
+  myMesh->SetIsModified( true ); // issue 0020693
+
   storeResult(anEditor);
 
   // Update Python script
@@ -1253,9 +1277,6 @@ SMESH_MeshEditor_i::smooth(const SMESH::long_array &              IDsOfElements,
                 << "SMESH.SMESH_MeshEditor."
                 << ( Method == SMESH::SMESH_MeshEditor::CENTROIDAL_SMOOTH ?
                      "CENTROIDAL_SMOOTH )" : "LAPLACIAN_SMOOTH )");
-#ifdef _DEBUG_
-  TPythonDump() << "print 'Smooth: ', isDone";
-#endif
 
   return true;
 }
@@ -1277,28 +1298,20 @@ SMESH_MeshEditor_i::smoothObject(SMESH::SMESH_IDSource_ptr              theObjec
 {
   initData();
 
+  TPythonDump aTPythonDump;  // suppress dump in smooth()
+
   SMESH::long_array_var anElementsId = theObject->GetIDs();
   CORBA::Boolean isDone = smooth (anElementsId, IDsOfFixedNodes, MaxNbOfIterations,
                                   MaxAspectRatio, Method, IsParametric);
 
-  // Clear python line(s), created by Smooth()
-  SMESH_Gen_i* aSMESHGen = SMESH_Gen_i::GetSMESHGen();
-  aSMESHGen->RemoveLastFromPythonScript(aSMESHGen->GetCurrentStudyID());
-#ifdef _DEBUG_
-  aSMESHGen->RemoveLastFromPythonScript(aSMESHGen->GetCurrentStudyID());
-#endif
-
   // Update Python script
-  TPythonDump() << "isDone = " << this << "."
-                << (IsParametric ? "SmoothParametricObject( " : "SmoothObject( ")
-                << theObject << ", " << IDsOfFixedNodes << ", "
-                << MaxNbOfIterations << ", " << MaxAspectRatio << ", "
-                << "SMESH.SMESH_MeshEditor."
-                << ( Method == SMESH::SMESH_MeshEditor::CENTROIDAL_SMOOTH ?
-                     "CENTROIDAL_SMOOTH )" : "LAPLACIAN_SMOOTH )");
-#ifdef _DEBUG_
-  TPythonDump() << "print 'SmoothObject: ', isDone";
-#endif
+  aTPythonDump << "isDone = " << this << "."
+               << (IsParametric ? "SmoothParametricObject( " : "SmoothObject( ")
+               << theObject << ", " << IDsOfFixedNodes << ", "
+               << MaxNbOfIterations << ", " << MaxAspectRatio << ", "
+               << "SMESH.SMESH_MeshEditor."
+               << ( Method == SMESH::SMESH_MeshEditor::CENTROIDAL_SMOOTH ?
+                    "CENTROIDAL_SMOOTH )" : "LAPLACIAN_SMOOTH )");
 
   return isDone;
 }
@@ -1392,6 +1405,8 @@ SMESH_MeshEditor_i::rotationSweep(const SMESH::long_array & theIDsOfElements,
                               theNbOfSteps, theTolerance, theMakeGroups, makeWalls);
   storeResult(anEditor);
 
+  //  myMesh->SetIsModified( true ); -- it does not influence Compute()
+
   return theMakeGroups ? getGroups(groupIds.get()) : 0;
 }
 
@@ -2742,9 +2757,11 @@ SMESH_MeshEditor_i::mirror(const SMESH::long_array &           theIDsOfElements,
   ::SMESH_MeshEditor::PGroupIDs groupIds =
       anEditor.Transform (elements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
 
-  if(theCopy) {
+  if(theCopy)
     storeResult(anEditor);
-  }
+  else
+    myMesh->SetIsModified( true );
+
   return theMakeGroups ? getGroups(groupIds.get()) : 0;
 }
 
@@ -2951,6 +2968,8 @@ SMESH_MeshEditor_i::translate(const SMESH::long_array & theIDsOfElements,
 
   if(theCopy)
     storeResult(anEditor);
+  else
+    myMesh->SetIsModified( true );
 
   return theMakeGroups ? getGroups(groupIds.get()) : 0;
 }
@@ -3155,9 +3174,11 @@ SMESH_MeshEditor_i::rotate(const SMESH::long_array & theIDsOfElements,
   ::SMESH_MeshEditor::PGroupIDs groupIds =
       anEditor.Transform (elements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
 
-  if(theCopy) {
+  if(theCopy) 
     storeResult(anEditor);
-  }
+  else
+    myMesh->SetIsModified( true );
+
   return theMakeGroups ? getGroups(groupIds.get()) : 0;
 }
 
@@ -3346,6 +3367,142 @@ SMESH_MeshEditor_i::RotateObjectMakeMesh(SMESH::SMESH_IDSource_ptr theObject,
   return mesh._retn();
 }
 
+
+//=======================================================================
+//function : scale
+//purpose  : 
+//=======================================================================
+
+SMESH::ListOfGroups*
+SMESH_MeshEditor_i::scale(const SMESH::long_array &  theIDsOfElements,
+                          const SMESH::PointStruct&  thePoint,
+                          const SMESH::double_array& theScaleFact,
+                          CORBA::Boolean             theCopy,
+                          const bool                 theMakeGroups,
+                          ::SMESH_Mesh*              theTargetMesh)
+{
+  initData();
+
+  TIDSortedElemSet elements;
+  arrayToSet(theIDsOfElements, GetMeshDS(), elements);
+
+  gp_Pnt aPnt( thePoint.x, thePoint.y, thePoint.z );
+  list<double> aScaleFact;
+  for (int i = 0; i < theScaleFact.length(); i++) {
+    aScaleFact.push_back( theScaleFact[i] );
+  }
+
+  ::SMESH_MeshEditor anEditor( myMesh );
+  ::SMESH_MeshEditor::PGroupIDs groupIds =
+      anEditor.Scale (elements, aPnt, aScaleFact, theCopy,
+                      theMakeGroups, theTargetMesh);
+
+  if(theCopy)
+    storeResult(anEditor);
+  else
+    myMesh->SetIsModified( true );
+
+  return theMakeGroups ? getGroups(groupIds.get()) : 0;
+}
+
+
+//=======================================================================
+//function : Scale
+//purpose  :
+//=======================================================================
+
+void SMESH_MeshEditor_i::Scale(SMESH::SMESH_IDSource_ptr  theObject,
+                               const SMESH::PointStruct&  thePoint,
+                               const SMESH::double_array& theScaleFact,
+                               CORBA::Boolean             theCopy)
+{
+  if ( !myPreviewMode ) {
+    TPythonDump() << this << ".Scale( "
+                  << theObject << ", "
+                  << "SMESH.PointStruct( "  << thePoint.x << ", "
+                  << thePoint.y << ", " << thePoint.z << " ) ,"
+                  << theScaleFact << ", "
+                  << theCopy << " )";
+  }
+  SMESH::long_array_var anElementsId = theObject->GetIDs();
+  scale(anElementsId, thePoint, theScaleFact, theCopy, false);
+}
+
+
+//=======================================================================
+//function : ScaleMakeGroups
+//purpose  : 
+//=======================================================================
+
+SMESH::ListOfGroups*
+SMESH_MeshEditor_i::ScaleMakeGroups(SMESH::SMESH_IDSource_ptr  theObject,
+                                    const SMESH::PointStruct&  thePoint,
+                                    const SMESH::double_array& theScaleFact)
+{
+  SMESH::long_array_var anElementsId = theObject->GetIDs();
+  SMESH::ListOfGroups * aGroups = 
+    scale(anElementsId, thePoint, theScaleFact, true, true);
+
+  if ( !myPreviewMode ) {
+
+    TPythonDump aPythonDump;
+    DumpGroupsList(aPythonDump,aGroups);
+    aPythonDump << this << ".Scale("
+                << theObject << ","
+                << "SMESH.PointStruct(" <<thePoint.x << ","
+                << thePoint.y << "," << thePoint.z << "),"
+                << theScaleFact << ",True,True)";
+  }
+  return aGroups;
+}
+
+
+//=======================================================================
+//function : ScaleMakeMesh
+//purpose  : 
+//=======================================================================
+
+SMESH::SMESH_Mesh_ptr
+SMESH_MeshEditor_i::ScaleMakeMesh(SMESH::SMESH_IDSource_ptr  theObject,
+                                  const SMESH::PointStruct&  thePoint,
+                                  const SMESH::double_array& theScaleFact,
+                                  CORBA::Boolean             theCopyGroups,
+                                  const char*                theMeshName)
+{
+  SMESH_Mesh_i* mesh_i;
+  SMESH::SMESH_Mesh_var mesh;
+  { // open new scope to dump "MakeMesh" command
+    // and then "GetGroups" using SMESH_Mesh::GetGroups()
+
+    TPythonDump pydump; // to prevent dump at mesh creation
+    mesh = makeMesh( theMeshName );
+    mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
+
+    if ( mesh_i ) {
+      SMESH::long_array_var anElementsId = theObject->GetIDs();
+      scale(anElementsId, thePoint, theScaleFact,
+            false, theCopyGroups, & mesh_i->GetImpl());
+      mesh_i->CreateGroupServants();
+    }
+    if ( !myPreviewMode ) {
+      pydump << mesh << " = " << this << ".ScaleMakeMesh( "
+             << theObject << ", "
+             << "SMESH.PointStruct( "  << thePoint.x << ", "
+             << thePoint.y << ", " << thePoint.z << " ) ,"
+             << theScaleFact << ", "
+             << theCopyGroups << ", '"
+             << theMeshName << "' )";
+    }
+  }
+
+  //dump "GetGroups"
+  if(!myPreviewMode && mesh_i)
+    mesh_i->GetGroups();
+
+  return mesh._retn();
+}
+
+
 //=======================================================================
 //function : FindCoincidentNodes
 //purpose  :
@@ -3390,8 +3547,9 @@ void SMESH_MeshEditor_i::FindCoincidentNodesOnPart(SMESH::SMESH_IDSource_ptr
   SMESHDS_Mesh* aMesh = GetMeshDS();
   set<const SMDS_MeshNode*> nodes;
 
-  if ( !CORBA::is_nil(SMESH::SMESH_GroupBase::_narrow(theObject)) &&
-       SMESH::SMESH_GroupBase::_narrow(theObject)->GetType() == SMESH::NODE) {
+  SMESH::SMESH_GroupBase_var group = SMESH::SMESH_GroupBase::_narrow(theObject);
+  if ( !group->_is_nil() && group->GetType() == SMESH::NODE)
+  {
     for(int i = 0; i < aElementsId->length(); i++) {
       CORBA::Long ind = aElementsId[i];
       const SMDS_MeshNode * elem = aMesh->FindNode(ind);
@@ -3469,6 +3627,8 @@ void SMESH_MeshEditor_i::MergeNodes (const SMESH::array_of_long_array& GroupsOfN
   anEditor.MergeNodes( aListOfListOfNodes );
 
   aTPythonDump <<  "])";
+
+  myMesh->SetIsModified( true );
 }
 
 //=======================================================================
@@ -3479,8 +3639,10 @@ void SMESH_MeshEditor_i::FindEqualElements(SMESH::SMESH_IDSource_ptr      theObj
                                            SMESH::array_of_long_array_out GroupsOfElementsID)
 {
   initData();
-  if ( !(!CORBA::is_nil(SMESH::SMESH_GroupBase::_narrow(theObject)) &&
-         SMESH::SMESH_GroupBase::_narrow(theObject)->GetType() == SMESH::NODE) ) {
+
+  SMESH::SMESH_GroupBase_var group = SMESH::SMESH_GroupBase::_narrow(theObject);
+  if ( !(!group->_is_nil() && group->GetType() == SMESH::NODE) )
+  {
     typedef list<int> TListOfIDs;
     set<const SMDS_MeshElement*> elems;
     SMESH::long_array_var aElementsId = theObject->GetIDs();
@@ -3548,6 +3710,8 @@ void SMESH_MeshEditor_i::MergeElements(const SMESH::array_of_long_array& GroupsO
   ::SMESH_MeshEditor anEditor( myMesh );
   anEditor.MergeElements(aListOfListOfElementsID);
 
+  myMesh->SetIsModified( true );
+
   aTPythonDump << "] )";
 }
 
@@ -3595,6 +3759,8 @@ CORBA::Boolean SMESH_MeshEditor_i::MoveNode(CORBA::Long   NodeID,
   TPythonDump() << "isDone = " << this << ".MoveNode( "
                 << NodeID << ", " << x << ", " << y << ", " << z << " )";
 
+  myMesh->SetIsModified( true );
+
   return true;
 }
 
@@ -3684,10 +3850,13 @@ CORBA::Long SMESH_MeshEditor_i::MoveClosestNodeToPoint(CORBA::Double x,
     }
   }
 
-  if ( !myPreviewMode ) {
+  if ( !myPreviewMode )
+  {
     TPythonDump() << "nodeID = " << this
                   << ".MoveClosestNodeToPoint( "<< x << ", " << y << ", " << z
                   << ", " << nodeID << " )";
+
+    myMesh->SetIsModified( true );
   }
 
   return nodeID;
@@ -3731,6 +3900,24 @@ SMESH::long_array* SMESH_MeshEditor_i::FindElementsByPoint(CORBA::Double      x,
   return res._retn();
 }
 
+//=======================================================================
+//function : GetPointState
+//purpose  : Return point state in a closed 2D mesh in terms of TopAbs_State enumeration.
+//           TopAbs_UNKNOWN state means that either mesh is wrong or the analysis fails.
+//=======================================================================
+
+CORBA::Short SMESH_MeshEditor_i::GetPointState(CORBA::Double x,
+                                               CORBA::Double y,
+                                               CORBA::Double z)
+{
+  theSearchersDeleter.Set( myMesh );
+  if ( !theElementSearcher ) {
+    ::SMESH_MeshEditor anEditor( myMesh );
+    theElementSearcher = anEditor.GetElementSearcher();
+  }
+  return CORBA::Short( theElementSearcher->GetPointState( gp_Pnt( x,y,z )));
+}
+
 //=======================================================================
 //function : convError
 //purpose  :
@@ -3814,6 +4001,8 @@ SMESH_MeshEditor_i::SewFreeBorders(CORBA::Long FirstNodeID1,
 
   storeResult(anEditor);
 
+  myMesh->SetIsModified( true );
+
   return error;
 }
 
@@ -3869,6 +4058,8 @@ SMESH_MeshEditor_i::SewConformFreeBorders(CORBA::Long FirstNodeID1,
 
   storeResult(anEditor);
 
+  myMesh->SetIsModified( true );
+
   return error;
 }
 
@@ -3929,6 +4120,8 @@ SMESH_MeshEditor_i::SewBorderToSide(CORBA::Long FirstNodeIDOnFreeBorder,
 
   storeResult(anEditor);
 
+  myMesh->SetIsModified( true );
+
   return error;
 }
 
@@ -3984,6 +4177,8 @@ SMESH_MeshEditor_i::SewSideElements(const SMESH::long_array& IDsOfSide1Elements,
 
   storeResult(anEditor);
 
+  myMesh->SetIsModified( true );
+
   return error;
 }
 
@@ -4017,11 +4212,13 @@ CORBA::Boolean SMESH_MeshEditor_i::ChangeElemNodes(CORBA::Long ide,
   }
   TPythonDump() << "isDone = " << this << ".ChangeElemNodes( "
                 << ide << ", " << newIDs << " )";
-#ifdef _DEBUG_
-  TPythonDump() << "print 'ChangeElemNodes: ', isDone";
-#endif
 
-  return GetMeshDS()->ChangeElementNodes( elem, & aNodes[0], nbn1+1 );
+  bool res = GetMeshDS()->ChangeElementNodes( elem, & aNodes[0], nbn1+1 );
+
+  if ( res )
+    myMesh->SetIsModified( true );
+
+  return res;
 }
 
 //================================================================================
@@ -4169,6 +4366,7 @@ void SMESH_MeshEditor_i::ConvertToQuadratic(CORBA::Boolean theForce3d)
   ::SMESH_MeshEditor anEditor( myMesh );
   anEditor.ConvertToQuadratic(theForce3d);
   TPythonDump() << this << ".ConvertToQuadratic( " << theForce3d << " )";
+  myMesh->SetIsModified( true );
 }
 
 //=======================================================================
@@ -4181,6 +4379,8 @@ CORBA::Boolean SMESH_MeshEditor_i::ConvertFromQuadratic()
   ::SMESH_MeshEditor anEditor( myMesh );
   CORBA::Boolean isDone = anEditor.ConvertFromQuadratic();
   TPythonDump() << this << ".ConvertFromQuadratic()";
+  if ( isDone )
+    myMesh->SetIsModified( true );
   return isDone;
 }
 
@@ -4244,6 +4444,8 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodes( const SMESH::long_array& theNode
   bool aResult = aMeshEditor.DoubleNodes( aListOfNodes, aListOfElems );
 
   storeResult( aMeshEditor) ;
+  if ( aResult )
+    myMesh->SetIsModified( true );
 
   return aResult;
 }
@@ -4265,7 +4467,10 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNode( CORBA::Long              theNodeI
   SMESH::long_array_var aNodes = new SMESH::long_array;
   aNodes->length( 1 );
   aNodes[ 0 ] = theNodeId;
-  return DoubleNodes( aNodes, theModifiedElems );
+  bool done = DoubleNodes( aNodes, theModifiedElems );
+  if ( done )
+    myMesh->SetIsModified( true );
+  return done;
 }
 
 //================================================================================
@@ -4296,7 +4501,12 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroup(
     aModifiedElems->length( 0 );
   }
 
-  return DoubleNodes( aNodes, aModifiedElems );
+  bool done = DoubleNodes( aNodes, aModifiedElems );
+
+  if ( done )
+    myMesh->SetIsModified( true );
+
+  return done;
 }
 
 //================================================================================
@@ -4347,6 +4557,9 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroups(
 
   storeResult( aMeshEditor) ;
 
+  if ( aResult )
+    myMesh->SetIsModified( true );
+
   return aResult;
 }
 
@@ -4382,6 +4595,9 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElem( const SMESH::long_array& theE
 
   storeResult( aMeshEditor) ;
 
+  if ( aResult )
+    myMesh->SetIsModified( true );
+
   // Update Python script
   TPythonDump() << "isDone = " << this << ".DoubleNodes( " << theElems << ", "
     << theNodesNot << ", " << theAffectedElems << " )";
@@ -4422,6 +4638,9 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemInRegion
 
   storeResult( aMeshEditor) ;
 
+  if ( aResult )
+    myMesh->SetIsModified( true );
+
   // Update Python script
   TPythonDump() << "isDone = " << this << ".DoubleNodesInRegion( " << theElems << ", "
     << theNodesNot << ", " << theShape << " )";
@@ -4452,11 +4671,9 @@ static void groupToSet(SMESH::SMESH_GroupBase_ptr theGrp,
   arrayToSet( anIDs, theMeshDS, theElemSet, theType);
 }
 
-CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroup( 
-                                                       SMESH::SMESH_GroupBase_ptr theElems,
+CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroup(SMESH::SMESH_GroupBase_ptr theElems,
                                                        SMESH::SMESH_GroupBase_ptr theNodesNot,
-                                                       SMESH::SMESH_GroupBase_ptr theAffectedElems )
-
+                                                       SMESH::SMESH_GroupBase_ptr theAffectedElems)
 {
   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
     return false;
@@ -4475,6 +4692,9 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroup(
 
   storeResult( aMeshEditor) ;
 
+  if ( aResult )
+    myMesh->SetIsModified( true );
+
   // Update Python script
   TPythonDump() << "isDone = " << this << ".DoubleNodeGroup( " << theElems << ", "
     << theNodesNot << ", " << theAffectedElems << " )";
@@ -4517,6 +4737,9 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroupInRegion(
 
   storeResult( aMeshEditor) ;
 
+  if ( aResult )
+    myMesh->SetIsModified( true );
+
   // Update Python script
   TPythonDump() << "isDone = " << this << ".DoubleNodeGroupInRegion( " << theElems << ", "
     << theNodesNot << ", " << theShape << " )";
@@ -4553,10 +4776,9 @@ static void listOfGroupToSet(const SMESH::ListOfGroups& theGrpList,
   }
 }
 
-CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroups( 
-                                                        const SMESH::ListOfGroups& theElems,
+CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroups(const SMESH::ListOfGroups& theElems,
                                                         const SMESH::ListOfGroups& theNodesNot,
-                                                        const SMESH::ListOfGroups& theAffectedElems )
+                                                        const SMESH::ListOfGroups& theAffectedElems)
 {
   initData();
 
@@ -4572,8 +4794,11 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroups(
 
   storeResult( aMeshEditor) ;
 
+  if ( aResult )
+    myMesh->SetIsModified( true );
+
   // Update Python script
-  TPythonDump() << "isDone = " << this << ".DoubleNodeGroups( " << &theElems << ", "
+  TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroups( " << &theElems << ", "
     << &theNodesNot << ", " << &theAffectedElems << " )";
   return aResult;
 }
@@ -4592,10 +4817,10 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroups(
 */
 //================================================================================
 
-CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroupsInRegion( 
-                                                                const SMESH::ListOfGroups& theElems,
-                                                                const SMESH::ListOfGroups& theNodesNot,
-                                                                GEOM::GEOM_Object_ptr      theShape )
+CORBA::Boolean
+SMESH_MeshEditor_i::DoubleNodeElemGroupsInRegion(const SMESH::ListOfGroups& theElems,
+                                                 const SMESH::ListOfGroups& theNodesNot,
+                                                 GEOM::GEOM_Object_ptr      theShape )
 {
   initData();
 
@@ -4611,6 +4836,9 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroupsInRegion(
 
   storeResult( aMeshEditor) ;
 
+  if ( aResult )
+    myMesh->SetIsModified( true );
+
   // Update Python script
   TPythonDump() << "isDone = " << this << ".DoubleNodeGroupsInRegion( " << &theElems << ", "
     << &theNodesNot << ", " << theShape << " )";