Salome HOME
0020028: EDF 842 SMESH : Can't export to med a mesh with same names
[modules/smesh.git] / src / SMESH / SMESH_Mesh.cxx
index 0b361a52ba302c4eb2285dee267a39119f3fe326..d39700ed360a2600e4a38aedbf9f059f0d65b4b4 100644 (file)
@@ -1,31 +1,29 @@
-//  SMESH SMESH : implementaion of SMESH idl descriptions
+//  Copyright (C) 2007-2008  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
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2.1 of the License.
 //
-//  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
-//  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
-// 
-//  This library is free software; you can redistribute it and/or 
-//  modify it under the terms of the GNU Lesser General Public 
-//  License as published by the Free Software Foundation; either 
-//  version 2.1 of the License. 
-// 
-//  This library is distributed in the hope that it will be useful, 
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of 
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
-//  Lesser General Public License for more details. 
-// 
-//  You should have received a copy of the GNU Lesser General Public 
-//  License along with this library; if not, write to the Free Software 
-//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA 
-// 
-// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
 //
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 //
+//  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
+//  SMESH SMESH : implementaion of SMESH idl descriptions
 //  File   : SMESH_Mesh.cxx
 //  Author : Paul RASCLE, EDF
 //  Module : SMESH
-//  $Header$
-
+//
 #include "SMESH_Mesh.hxx"
 #include "SMESH_subMesh.hxx"
 #include "SMESH_Gen.hxx"
 #include "DriverUNV_R_SMDS_Mesh.h"
 #include "DriverSTL_R_SMDS_Mesh.h"
 
+#undef _Precision_HeaderFile
+#include <BRepBndLib.hxx>
 #include <BRepPrimAPI_MakeBox.hxx>
+#include <Bnd_Box.hxx>
 #include <TopExp.hxx>
 #include <TopExp_Explorer.hxx>
 #include <TopTools_ListIteratorOfListOfShape.hxx>
@@ -60,6 +61,8 @@
 
 #include "Utils_ExceptHandlers.hxx"
 
+using namespace std;
+
 // maximum stored group name length in MED file
 #define MAX_MED_GROUP_NAME_LENGTH 80
 
@@ -80,11 +83,11 @@ typedef SMESH_HypoFilter THypType;
 //=============================================================================
 
 SMESH_Mesh::SMESH_Mesh(int               theLocalId, 
-                      int               theStudyId, 
-                      SMESH_Gen*        theGen,
-                      bool              theIsEmbeddedMode,
-                      SMESHDS_Document* theDocument):
-  _groupId( 0 )
+                       int               theStudyId, 
+                       SMESH_Gen*        theGen,
+                       bool              theIsEmbeddedMode,
+                       SMESHDS_Document* theDocument):
+  _groupId( 0 ), _nbSubShapes( 0 )
 {
   MESSAGE("SMESH_Mesh::SMESH_Mesh(int localId)");
   _id            = theLocalId;
@@ -95,6 +98,7 @@ SMESH_Mesh::SMESH_Mesh(int               theLocalId,
   _myMeshDS      = theDocument->GetMesh(_idDoc);
   _isShapeToMesh = false;
   _isAutoColor   = false;
+  _shapeDiagonal = 0.0;
   _myMeshDS->ShapeToMesh( PseudoShape() );
 }
 
@@ -108,12 +112,18 @@ SMESH_Mesh::~SMESH_Mesh()
 {
   INFOS("SMESH_Mesh::~SMESH_Mesh");
 
+  // issue 0020340: EDF 1022 SMESH : Crash with FindNodeClosestTo in a second new study
+  //   Notify event listeners at least that something happens
+  if ( SMESH_subMesh * sm = GetSubMeshContaining(1))
+    sm->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
+
   // delete groups
   map < int, SMESH_Group * >::iterator itg;
   for (itg = _mapGroup.begin(); itg != _mapGroup.end(); itg++) {
     SMESH_Group *aGroup = (*itg).second;
     delete aGroup;
   }
+  _mapGroup.clear();
 }
 
 //=============================================================================
@@ -126,9 +136,11 @@ void SMESH_Mesh::ShapeToMesh(const TopoDS_Shape & aShape)
 {
   if(MYDEBUG) MESSAGE("SMESH_Mesh::ShapeToMesh");
 
-  if ( !aShape.IsNull() && _isShapeToMesh )
-    throw SALOME_Exception(LOCALIZED ("a shape to mesh has already been defined"));
-
+  if ( !aShape.IsNull() && _isShapeToMesh ) {
+    if ( aShape.ShapeType() != TopAbs_COMPOUND && // group contents is allowed to change
+         _myMeshDS->ShapeToMesh().ShapeType() != TopAbs_COMPOUND )
+      throw SALOME_Exception(LOCALIZED ("a shape to mesh has already been defined"));
+  }
   // clear current data
   if ( !_myMeshDS->ShapeToMesh().IsNull() )
   {
@@ -154,6 +166,8 @@ void SMESH_Mesh::ShapeToMesh(const TopoDS_Shape & aShape)
     // clear SMESHDS
     TopoDS_Shape aNullShape;
     _myMeshDS->ShapeToMesh( aNullShape );
+
+    _shapeDiagonal = 0.0;
   }
 
   // set a new geometry
@@ -161,15 +175,16 @@ void SMESH_Mesh::ShapeToMesh(const TopoDS_Shape & aShape)
   {
     _myMeshDS->ShapeToMesh(aShape);
     _isShapeToMesh = true;
+    _nbSubShapes = _myMeshDS->MaxShapeIndex();
 
-    // fill _mapAncestors
-    int desType, ancType;
-    for ( desType = TopAbs_VERTEX; desType > TopAbs_COMPOUND; desType-- )
-      for ( ancType = desType - 1; ancType >= TopAbs_COMPOUND; ancType-- )
-        TopExp::MapShapesAndAncestors ( aShape,
-                                        (TopAbs_ShapeEnum) desType,
-                                        (TopAbs_ShapeEnum) ancType,
-                                        _mapAncestors );
+    // fill map of ancestors
+    fillAncestorsMap(aShape);
+  }
+  else
+  {
+    _isShapeToMesh = false;
+    _shapeDiagonal = 0.0;
+    _myMeshDS->ShapeToMesh( PseudoShape() );
   }
 }
 
@@ -201,6 +216,125 @@ const TopoDS_Solid& SMESH_Mesh::PseudoShape()
   return aSolid;
 }
 
+//=======================================================================
+/*!
+ * \brief Return diagonal size of bounding box of a shape
+ */
+//=======================================================================
+
+double SMESH_Mesh::GetShapeDiagonalSize(const TopoDS_Shape & aShape)
+{
+  if ( !aShape.IsNull() ) {
+    Bnd_Box Box;
+    BRepBndLib::Add(aShape, Box);
+    return sqrt( Box.SquareExtent() );
+  }
+  return 0;
+}
+
+//=======================================================================
+/*!
+ * \brief Return diagonal size of bounding box of shape to mesh
+ */
+//=======================================================================
+
+double SMESH_Mesh::GetShapeDiagonalSize() const
+{
+  if ( _shapeDiagonal == 0. && _isShapeToMesh )
+    const_cast<SMESH_Mesh*>(this)->_shapeDiagonal = GetShapeDiagonalSize( GetShapeToMesh() );
+
+  return _shapeDiagonal;
+}
+
+//=======================================================================
+/*!
+ * \brief Remove all nodes and elements
+ */
+//=======================================================================
+
+void SMESH_Mesh::Clear()
+{
+  // clear mesh data
+  _myMeshDS->ClearMesh();
+
+  // update compute state of submeshes
+  if ( SMESH_subMesh *sm = GetSubMeshContaining( GetShapeToMesh() ) ) {
+    SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(/*includeSelf=*/true,
+                                                             /*complexShapeFirst=*/false);
+    while ( smIt->more() ) {
+      sm = smIt->next();
+      sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
+    }
+  }
+
+//   // clear sub-meshes; get ready to re-compute as a side-effect 
+
+//   if ( SMESH_subMesh *sm = GetSubMeshContaining( GetShapeToMesh() ) )
+//   {
+//     SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(/*includeSelf=*/true,
+//                                                              /*complexShapeFirst=*/false);
+//     while ( smIt->more() )
+//     {
+//       sm = smIt->next();
+//       TopAbs_ShapeEnum shapeType = sm->GetSubShape().ShapeType();      
+//       if ( shapeType == TopAbs_VERTEX || shapeType < TopAbs_SOLID )
+//         // all other shapes depends on vertices so they are already cleaned
+//         sm->ComputeStateEngine( SMESH_subMesh::CLEAN );
+//       // to recompute even if failed
+//       sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
+//     }
+//   }
+
+//   // clear entities not on sub-meshes
+
+//   SMDS_VolumeIteratorPtr vIt = _myMeshDS->volumesIterator();
+//   while ( vIt->more() )
+//     _myMeshDS->RemoveFreeElement( vIt->next(), 0 );
+
+//   SMDS_FaceIteratorPtr fIt = _myMeshDS->facesIterator();
+//   while ( fIt->more() )
+//     _myMeshDS->RemoveFreeElement( fIt->next(), 0 );
+
+//   SMDS_EdgeIteratorPtr eIt = _myMeshDS->edgesIterator();
+//   while ( eIt->more() )
+//     _myMeshDS->RemoveFreeElement( eIt->next(), 0 );
+
+//   SMDS_NodeIteratorPtr nIt = _myMeshDS->nodesIterator();
+//   while ( nIt->more() ) {
+//     const SMDS_MeshNode * node = nIt->next();
+//     if ( node->NbInverseElements() == 0 )
+//       _myMeshDS->RemoveFreeNode( node, 0 );
+//     else
+//       _myMeshDS->RemoveNode(node);
+//   }
+}
+
+//=======================================================================
+/*!
+ * \brief Remove all nodes and elements of indicated shape
+ */
+//=======================================================================
+
+void SMESH_Mesh::ClearSubMesh(const int theShapeId)
+{
+  // clear sub-meshes; get ready to re-compute as a side-effect 
+  if ( SMESH_subMesh *sm = GetSubMeshContaining( theShapeId ) )
+  {
+    SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(/*includeSelf=*/true,
+                                                             /*complexShapeFirst=*/false);
+    while ( smIt->more() )
+    {
+      sm = smIt->next();
+      TopAbs_ShapeEnum shapeType = sm->GetSubShape().ShapeType();      
+      if ( shapeType == TopAbs_VERTEX || shapeType < TopAbs_SOLID )
+        // all other shapes depends on vertices so they are already cleaned
+        sm->ComputeStateEngine( SMESH_subMesh::CLEAN );
+      // to recompute even if failed
+      sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
+    }
+  }
+}
+
 //=======================================================================
 //function : UNVToMesh
 //purpose  : 
@@ -230,26 +364,26 @@ int SMESH_Mesh::UNVToMesh(const char* theFileName)
     aGroup->InitSubGroupsIterator();
     while (aGroup->MoreSubGroups()) {
       SMDS_MeshGroup* aSubGroup = (SMDS_MeshGroup*) aGroup->NextSubGroup();
-      std::string aName = aGroupNames[aSubGroup];
+      string aName = aGroupNames[aSubGroup];
       int aId;
 
       SMESH_Group* aSMESHGroup = AddGroup( aSubGroup->GetType(), aName.c_str(), aId );
       if ( aSMESHGroup ) {
-       if(MYDEBUG) MESSAGE("UNVToMesh - group added: "<<aName);      
-       SMESHDS_Group* aGroupDS = dynamic_cast<SMESHDS_Group*>( aSMESHGroup->GetGroupDS() );
-       if ( aGroupDS ) {
-         aGroupDS->SetStoreName(aName.c_str());
-         aSubGroup->InitIterator();
-         const SMDS_MeshElement* aElement = 0;
-         while (aSubGroup->More()) {
-           aElement = aSubGroup->Next();
-           if (aElement) {
-             aGroupDS->SMDSGroup().Add(aElement);
-           }
-         }
-         if (aElement)
-           aGroupDS->SetType(aElement->GetType());
-       }
+        if(MYDEBUG) MESSAGE("UNVToMesh - group added: "<<aName);      
+        SMESHDS_Group* aGroupDS = dynamic_cast<SMESHDS_Group*>( aSMESHGroup->GetGroupDS() );
+        if ( aGroupDS ) {
+          aGroupDS->SetStoreName(aName.c_str());
+          aSubGroup->InitIterator();
+          const SMDS_MeshElement* aElement = 0;
+          while (aSubGroup->More()) {
+            aElement = aSubGroup->Next();
+            if (aElement) {
+              aGroupDS->SMDSGroup().Add(aElement);
+            }
+          }
+          if (aElement)
+            aGroupDS->SetType(aElement->GetType());
+        }
       }
     }
   }
@@ -341,33 +475,6 @@ SMESH_Hypothesis::Hypothesis_Status
   if ( !subMesh || !subMesh->GetId())
     return SMESH_Hypothesis::HYP_BAD_SUBSHAPE;
 
-  SMESHDS_SubMesh *subMeshDS = subMesh->GetSubMeshDS();
-  if ( subMeshDS && subMeshDS->IsComplexSubmesh() ) // group of sub-shapes and maybe of not sub-
-  {
-    MESSAGE("AddHypothesis() to complex submesh");
-    // return the worst but not fatal state of all group memebers
-    SMESH_Hypothesis::Hypothesis_Status aBestRet, aWorstNotFatal, ret;
-    aBestRet = SMESH_Hypothesis::HYP_BAD_DIM;
-    aWorstNotFatal = SMESH_Hypothesis::HYP_OK;
-    for ( TopoDS_Iterator itS ( aSubShape ); itS.More(); itS.Next())
-    {
-      if ( !GetMeshDS()->ShapeToIndex( itS.Value() ))
-        continue; // not sub-shape
-      ret = AddHypothesis( itS.Value(), anHypId );
-      if ( !SMESH_Hypothesis::IsStatusFatal( ret ) && ret > aWorstNotFatal )
-        aWorstNotFatal = ret;
-      if ( ret < aBestRet )
-        aBestRet = ret;
-    }
-    // bind hypotheses to a group just to know
-    SMESH_Hypothesis *anHyp = _gen->GetStudyContext(_studyId)->mapHypothesis[anHypId];
-    GetMeshDS()->AddHypothesis( aSubShape, anHyp );
-
-    if ( SMESH_Hypothesis::IsStatusFatal( aBestRet ))
-      return aBestRet;
-    return aWorstNotFatal;
-  }
-
   StudyContextStruct *sc = _gen->GetStudyContext(_studyId);
   if (sc->mapHypothesis.find(anHypId) == sc->mapHypothesis.end())
   {
@@ -448,32 +555,6 @@ SMESH_Hypothesis::Hypothesis_Status
   Unexpect aCatch(SalomeException);
   if(MYDEBUG) MESSAGE("SMESH_Mesh::RemoveHypothesis");
   
-  SMESH_subMesh *subMesh = GetSubMesh(aSubShape);
-  SMESHDS_SubMesh *subMeshDS = subMesh->GetSubMeshDS();
-  if ( subMeshDS && subMeshDS->IsComplexSubmesh() )
-  {
-    // return the worst but not fatal state of all group memebers
-    SMESH_Hypothesis::Hypothesis_Status aBestRet, aWorstNotFatal, ret;
-    aBestRet = SMESH_Hypothesis::HYP_BAD_DIM;
-    aWorstNotFatal = SMESH_Hypothesis::HYP_OK;
-    for ( TopoDS_Iterator itS ( aSubShape ); itS.More(); itS.Next())
-    {
-      if ( !GetMeshDS()->ShapeToIndex( itS.Value() ))
-        continue; // not sub-shape
-      ret = RemoveHypothesis( itS.Value(), anHypId );
-      if ( !SMESH_Hypothesis::IsStatusFatal( ret ) && ret > aWorstNotFatal )
-        aWorstNotFatal = ret;
-      if ( ret < aBestRet )
-        aBestRet = ret;
-    }
-    SMESH_Hypothesis *anHyp = _gen->GetStudyContext(_studyId)->mapHypothesis[anHypId];
-    GetMeshDS()->RemoveHypothesis( aSubShape, anHyp );
-
-    if ( SMESH_Hypothesis::IsStatusFatal( aBestRet ))
-      return aBestRet;
-    return aWorstNotFatal;
-  }
-
   StudyContextStruct *sc = _gen->GetStudyContext(_studyId);
   if (sc->mapHypothesis.find(anHypId) == sc->mapHypothesis.end())
     throw SALOME_Exception(LOCALIZED("hypothesis does not exist"));
@@ -487,6 +568,8 @@ SMESH_Hypothesis::Hypothesis_Status
   bool isAlgo = ( !anHyp->GetType() == SMESHDS_Hypothesis::PARAM_ALGO );
   int event = isAlgo ? SMESH_subMesh::REMOVE_ALGO : SMESH_subMesh::REMOVE_HYP;
 
+  SMESH_subMesh *subMesh = GetSubMesh(aSubShape);
+
   SMESH_Hypothesis::Hypothesis_Status ret = subMesh->AlgoStateEngine(event, anHyp);
 
   // there may appear concurrent hyps that were covered by the removed hyp
@@ -545,37 +628,46 @@ SMESH_Mesh::GetHypothesisList(const TopoDS_Shape & aSubShape) const
 //=======================================================================
 /*!
  * \brief Return the hypothesis assigned to the shape
-  * \param aSubShape - the shape to check
-  * \param aFilter - the hypothesis filter
-  * \param andAncestors - flag to check hypos assigned to ancestors of the shape
-  * \retval SMESH_Hypothesis* - the first hypo passed through aFilter
+ *  \param aSubShape    - the shape to check
+ *  \param aFilter      - the hypothesis filter
+ *  \param andAncestors - flag to check hypos assigned to ancestors of the shape
+ *  \param assignedTo   - to return the shape the found hypo is assigned to
+ *  \retval SMESH_Hypothesis* - the first hypo passed through aFilter
  */
 //=======================================================================
 
 const SMESH_Hypothesis * SMESH_Mesh::GetHypothesis(const TopoDS_Shape &    aSubShape,
                                                    const SMESH_HypoFilter& aFilter,
-                                                   const bool              andAncestors) const
+                                                   const bool              andAncestors,
+                                                   TopoDS_Shape*           assignedTo) const
 {
   {
     const list<const SMESHDS_Hypothesis*>& hypList = _myMeshDS->GetHypothesis(aSubShape);
     list<const SMESHDS_Hypothesis*>::const_iterator hyp = hypList.begin();
     for ( ; hyp != hypList.end(); hyp++ ) {
       const SMESH_Hypothesis * h = cSMESH_Hyp( *hyp );
-      if ( aFilter.IsOk( h, aSubShape))
+      if ( aFilter.IsOk( h, aSubShape)) {
+        if ( assignedTo ) *assignedTo = aSubShape;
         return h;
+      }
     }
   }
   if ( andAncestors )
   {
-    TopTools_ListIteratorOfListOfShape it( GetAncestors( aSubShape ));
-    for (; it.More(); it.Next() )
+    // user sorted submeshes of ancestors, according to stored submesh priority
+    const list<SMESH_subMesh*> smList = getAncestorsSubMeshes( aSubShape );
+    list<SMESH_subMesh*>::const_iterator smIt = smList.begin(); 
+    for ( ; smIt != smList.end(); smIt++ )
     {
-      const list<const SMESHDS_Hypothesis*>& hypList = _myMeshDS->GetHypothesis(it.Value());
+      const TopoDS_Shape& curSh = (*smIt)->GetSubShape();
+      const list<const SMESHDS_Hypothesis*>& hypList = _myMeshDS->GetHypothesis(curSh);
       list<const SMESHDS_Hypothesis*>::const_iterator hyp = hypList.begin();
       for ( ; hyp != hypList.end(); hyp++ ) {
         const SMESH_Hypothesis * h = cSMESH_Hyp( *hyp );
-        if (aFilter.IsOk( h, it.Value() ))
+        if (aFilter.IsOk( h, curSh )) {
+          if ( assignedTo ) *assignedTo = curSh;
           return h;
+        }
       }
     }
   }
@@ -632,14 +724,18 @@ int SMESH_Mesh::GetHypotheses(const TopoDS_Shape &                aSubShape,
   if ( andAncestors )
   {
     TopTools_MapOfShape map;
-    TopTools_ListIteratorOfListOfShape it( GetAncestors( aSubShape ));
-    for (; it.More(); it.Next() )
+
+    // user sorted submeshes of ancestors, according to stored submesh priority
+    const list<SMESH_subMesh*> smList = getAncestorsSubMeshes( aSubShape );
+    list<SMESH_subMesh*>::const_iterator smIt = smList.begin(); 
+    for ( ; smIt != smList.end(); smIt++ )
     {
-     if ( !map.Add( it.Value() ))
+      const TopoDS_Shape& curSh = (*smIt)->GetSubShape();
+     if ( !map.Add( curSh ))
         continue;
-      const list<const SMESHDS_Hypothesis*>& hypList = _myMeshDS->GetHypothesis(it.Value());
+      const list<const SMESHDS_Hypothesis*>& hypList = _myMeshDS->GetHypothesis(curSh);
       for ( hyp = hypList.begin(); hyp != hypList.end(); hyp++ )
-        if (aFilter.IsOk( cSMESH_Hyp( *hyp ), it.Value() ) &&
+        if (aFilter.IsOk( cSMESH_Hyp( *hyp ), curSh ) &&
             ( cSMESH_Hyp(*hyp)->IsAuxiliary() || !mainHypFound ) &&
             hypTypes.insert( (*hyp)->GetName() ).second )
         {
@@ -692,10 +788,16 @@ SMESH_subMesh *SMESH_Mesh::GetSubMesh(const TopoDS_Shape & aSubShape)
   int index = _myMeshDS->ShapeToIndex(aSubShape);
 
   // for submeshes on GEOM Group
-  if ( !index && aSubShape.ShapeType() == TopAbs_COMPOUND ) {
+  if (( !index || index > _nbSubShapes ) && aSubShape.ShapeType() == TopAbs_COMPOUND ) {
     TopoDS_Iterator it( aSubShape );
     if ( it.More() )
+    {
       index = _myMeshDS->AddCompoundSubmesh( aSubShape, it.Value().ShapeType() );
+      if ( index > _nbSubShapes ) _nbSubShapes = index; // not to create sm for this group again
+
+      // fill map of Ancestors
+      fillAncestorsMap(aSubShape);
+    }
   }
 //   if ( !index )
 //     return NULL; // neither sub-shape nor a group
@@ -709,6 +811,7 @@ SMESH_subMesh *SMESH_Mesh::GetSubMesh(const TopoDS_Shape & aSubShape)
   {
     aSubMesh = new SMESH_subMesh(index, this, _myMeshDS, aSubShape);
     _mapSubMesh[index] = aSubMesh;
+    ClearMeshOrder();
   }
   return aSubMesh;
 }
@@ -926,12 +1029,15 @@ bool SMESH_Mesh::GetAutoColor() throw(SALOME_Exception)
 
 bool SMESH_Mesh::HasDuplicatedGroupNamesMED()
 {
-  set<string> aGroupNames;
-  for ( map<int, SMESH_Group*>::iterator it = _mapGroup.begin(); it != _mapGroup.end(); it++ ) {
+  //set<string> aGroupNames; // Corrected for Mantis issue 0020028
+  map< SMDSAbs_ElementType, set<string> > aGroupNames;
+  for ( map<int, SMESH_Group*>::iterator it = _mapGroup.begin(); it != _mapGroup.end(); it++ )
+  {
     SMESH_Group* aGroup = it->second;
+    SMDSAbs_ElementType aType = aGroup->GetGroupDS()->GetType();
     string aGroupName = aGroup->GetName();
     aGroupName.resize(MAX_MED_GROUP_NAME_LENGTH);
-    if (!aGroupNames.insert(aGroupName).second)
+    if (!aGroupNames[aType].insert(aGroupName).second)
       return true;
   }
 
@@ -939,9 +1045,9 @@ bool SMESH_Mesh::HasDuplicatedGroupNamesMED()
 }
 
 void SMESH_Mesh::ExportMED(const char *file, 
-                          const char* theMeshName, 
-                          bool theAutoGroups,
-                          int theVersion) 
+                           const char* theMeshName, 
+                           bool theAutoGroups,
+                           int theVersion) 
   throw(SALOME_Exception)
 {
   Unexpect aCatch(SalomeException);
@@ -964,17 +1070,19 @@ void SMESH_Mesh::ExportMED(const char *file,
   }
 
   // Pass groups to writer. Provide unique group names.
-  set<string> aGroupNames;
+  //set<string> aGroupNames; // Corrected for Mantis issue 0020028
+  map< SMDSAbs_ElementType, set<string> > aGroupNames;
   char aString [256];
   int maxNbIter = 10000; // to guarantee cycle finish
   for ( map<int, SMESH_Group*>::iterator it = _mapGroup.begin(); it != _mapGroup.end(); it++ ) {
     SMESH_Group*       aGroup   = it->second;
     SMESHDS_GroupBase* aGroupDS = aGroup->GetGroupDS();
     if ( aGroupDS ) {
+      SMDSAbs_ElementType aType = aGroupDS->GetType();
       string aGroupName0 = aGroup->GetName();
       aGroupName0.resize(MAX_MED_GROUP_NAME_LENGTH);
       string aGroupName = aGroupName0;
-      for (int i = 1; !aGroupNames.insert(aGroupName).second && i < maxNbIter; i++) {
+      for (int i = 1; !aGroupNames[aType].insert(aGroupName).second && i < maxNbIter; i++) {
         sprintf(&aString[0], "GR_%d_%s", i, aGroupName0.c_str());
         aGroupName = aString;
         aGroupName.resize(MAX_MED_GROUP_NAME_LENGTH);
@@ -1048,6 +1156,18 @@ int SMESH_Mesh::NbNodes() throw(SALOME_Exception)
  */
 //================================================================================
 
+int SMESH_Mesh::Nb0DElements() throw(SALOME_Exception)
+{
+  Unexpect aCatch(SalomeException);
+  return _myMeshDS->GetMeshInfo().Nb0DElements();
+}
+
+//================================================================================
+/*!
+ * \brief  Return number of edges of given order in the mesh
+ */
+//================================================================================
+
 int SMESH_Mesh::NbEdges(SMDSAbs_ElementOrder order) throw(SALOME_Exception)
 {
   Unexpect aCatch(SalomeException);
@@ -1217,7 +1337,7 @@ bool SMESH_Mesh::IsMainShape(const TopoDS_Shape& theShape) const
 
 SMESH_Group* SMESH_Mesh::AddGroup (const SMDSAbs_ElementType theType,
                                    const char*               theName,
-                                  int&                      theId,
+                                   int&                      theId,
                                    const TopoDS_Shape&       theShape)
 {
   if (_mapGroup.find(_groupId) != _mapGroup.end())
@@ -1383,3 +1503,163 @@ SMDSAbs_ElementType SMESH_Mesh::GetElementType( const int id, const bool iselem
 {
   return _myMeshDS->GetElementType( id, iselem );
 }
+
+//=============================================================================
+/*!
+ *  \brief Convert group on geometry into standalone group
+ */
+//=============================================================================
+
+SMESH_Group* SMESH_Mesh::ConvertToStandalone ( int theGroupID )
+{
+  SMESH_Group* aGroup = 0;
+  map < int, SMESH_Group * >::iterator itg = _mapGroup.find( theGroupID );
+  if ( itg == _mapGroup.end() )
+    return aGroup;
+
+  SMESH_Group* anOldGrp = (*itg).second;
+  SMESHDS_GroupBase* anOldGrpDS = anOldGrp->GetGroupDS();
+  if ( !anOldGrp || !anOldGrpDS )
+    return aGroup;
+
+  // create new standalone group
+  aGroup = new SMESH_Group (theGroupID, this, anOldGrpDS->GetType(), anOldGrp->GetName() );
+  _mapGroup[theGroupID] = aGroup;
+
+  SMESHDS_Group* aNewGrpDS = dynamic_cast<SMESHDS_Group*>( aGroup->GetGroupDS() );
+  GetMeshDS()->RemoveGroup( anOldGrpDS );
+  GetMeshDS()->AddGroup( aNewGrpDS );
+
+  // add elements (or nodes) into new created group
+  SMDS_ElemIteratorPtr anItr = anOldGrpDS->GetElements();
+  while ( anItr->more() )
+    aNewGrpDS->Add( (anItr->next())->GetID() );
+
+  // remove old group
+  delete anOldGrp;
+
+  return aGroup;
+}
+
+//=============================================================================
+/*!
+ *  \brief remove submesh order  from Mesh
+ */
+//=============================================================================
+
+void SMESH_Mesh::ClearMeshOrder()
+{
+  _mySubMeshOrder.clear();
+}
+
+//=============================================================================
+/*!
+ *  \brief remove submesh order  from Mesh
+ */
+//=============================================================================
+
+void SMESH_Mesh::SetMeshOrder(const TListOfListOfInt& theOrder )
+{
+  _mySubMeshOrder = theOrder;
+}
+
+//=============================================================================
+/*!
+ *  \brief return submesh order if any
+ */
+//=============================================================================
+
+const TListOfListOfInt& SMESH_Mesh::GetMeshOrder() const
+{
+  return _mySubMeshOrder;
+}
+
+//=============================================================================
+/*!
+ *  \brief fillAncestorsMap
+ */
+//=============================================================================
+
+void SMESH_Mesh::fillAncestorsMap(const TopoDS_Shape& theShape)
+{
+  // fill _mapAncestors
+  int desType, ancType;
+  for ( desType = TopAbs_VERTEX; desType > TopAbs_COMPOUND; desType-- )
+    for ( ancType = desType - 1; ancType >= TopAbs_COMPOUND; ancType-- )
+      TopExp::MapShapesAndAncestors ( theShape,
+                                      (TopAbs_ShapeEnum) desType,
+                                      (TopAbs_ShapeEnum) ancType,
+                                      _mapAncestors );
+}
+
+//=============================================================================
+/*!
+ * \brief sort submeshes according to stored mesh order
+ * \param theListToSort in out list to be sorted
+ * \return FALSE if nothing sorted
+ */
+//=============================================================================
+
+bool SMESH_Mesh::SortByMeshOrder(list<SMESH_subMesh*>& theListToSort) const
+{
+  if ( !_mySubMeshOrder.size() || theListToSort.size() < 2)
+    return true;
+  
+  bool res = false;
+  list<SMESH_subMesh*> onlyOrderedList;
+  // collect all ordered submeshes in one list as pointers
+  // and get their positions within theListToSort
+  typedef list<SMESH_subMesh*>::iterator TPosInList;
+  map< int, TPosInList > sortedPos;
+  TPosInList smBeg = theListToSort.begin(), smEnd = theListToSort.end();
+  TListOfListOfInt::const_iterator listIddIt = _mySubMeshOrder.begin();
+  for( ; listIddIt != _mySubMeshOrder.end(); listIddIt++) {
+    const TListOfInt& listOfId = *listIddIt;
+    TListOfInt::const_iterator idIt = listOfId.begin();
+    for ( ; idIt != listOfId.end(); idIt++ ) {
+      if ( SMESH_subMesh * sm = GetSubMeshContaining( *idIt )) {
+        TPosInList smPos = find( smBeg, smEnd, sm );
+        if ( smPos != smEnd ) {
+          onlyOrderedList.push_back( sm );
+          sortedPos[ distance( smBeg, smPos )] = smPos;
+        }
+      }
+    }
+  }
+  if (onlyOrderedList.size() < 2)
+    return res;
+  res = true;
+
+  list<SMESH_subMesh*>::iterator onlyBIt = onlyOrderedList.begin();
+  list<SMESH_subMesh*>::iterator onlyEIt = onlyOrderedList.end();
+
+  // iterates on ordered submeshes and insert them in detected positions
+  map< int, TPosInList >::iterator i_pos = sortedPos.begin();
+  for ( ; onlyBIt != onlyEIt; ++onlyBIt, ++i_pos )
+    *(i_pos->second) = *onlyBIt;
+
+  return res;
+}
+
+//=============================================================================
+/*!
+ * \brief sort submeshes according to stored mesh order
+ * \param theListToSort in out list to be sorted
+ * \return FALSE if nothing sorted
+ */
+//=============================================================================
+
+list<SMESH_subMesh*> SMESH_Mesh::getAncestorsSubMeshes
+  (const TopoDS_Shape& theSubShape) const
+{
+  list<SMESH_subMesh*> listOfSubMesh;
+  TopTools_ListIteratorOfListOfShape it( GetAncestors( theSubShape ));
+  for (; it.More(); it.Next() )
+    if ( SMESH_subMesh* sm = GetSubMeshContaining( it.Value() ))
+      listOfSubMesh.push_back(sm);
+
+  // sort submeshes according to stored mesh order
+  SortByMeshOrder( listOfSubMesh );
+
+  return listOfSubMesh;
+}