Salome HOME
PAL12157. Make Dump() show info on quadratic elements
[modules/smesh.git] / src / SMESH / SMESH_Mesh.cxx
index ef500ac8eab896f3570e468c9a8502e9a97735c4..42500393dd9692e05559425dd52eee4663b9d590 100644 (file)
@@ -17,7 +17,7 @@
 //  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.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 //
 //
 #include "SMESH_Gen.hxx"
 #include "SMESH_Hypothesis.hxx"
 #include "SMESH_Group.hxx"
+#include "SMESH_HypoFilter.hxx"
 #include "SMESHDS_Group.hxx"
 #include "SMESHDS_Script.hxx"
+#include "SMESHDS_GroupOnGeom.hxx"
 #include "SMDS_MeshVolume.hxx"
 
 #include "utilities.h"
 #include <TopTools_ListOfShape.hxx>
 #include <TopTools_Array1OfShape.hxx>
 #include <TopTools_ListIteratorOfListOfShape.hxx>
+#include <TopTools_MapOfShape.hxx>
 
 #include <memory>
 
 #include "Utils_ExceptHandlers.hxx"
 
+// maximum stored group name length in MED file
+#define MAX_MED_GROUP_NAME_LENGTH 80
+
 #ifdef _DEBUG_
 static int MYDEBUG = 0;
 #else
@@ -73,17 +79,21 @@ static int MYDEBUG = 0;
  */
 //=============================================================================
 
-SMESH_Mesh::SMESH_Mesh(int localId, int studyId, SMESH_Gen * gen, SMESHDS_Document * myDocument)
-: _groupId( 0 )
+SMESH_Mesh::SMESH_Mesh(int theLocalId, 
+                      int theStudyId, 
+                      SMESH_Gen* theGen,
+                      bool theIsEmbeddedMode,
+                      SMESHDS_Document* theDocument):
+  _groupId( 0 )
 {
   INFOS("SMESH_Mesh::SMESH_Mesh(int localId)");
-       _id = localId;
-       _studyId = studyId;
-       _gen = gen;
-       _myDocument = myDocument;
-       _idDoc = _myDocument->NewMesh();
-       _myMeshDS = _myDocument->GetMesh(_idDoc);
-       _isShapeToMesh = false;
+  _id = theLocalId;
+  _studyId = theStudyId;
+  _gen = theGen;
+  _myDocument = theDocument;
+  _idDoc = theDocument->NewMesh(theIsEmbeddedMode);
+  _myMeshDS = theDocument->GetMesh(_idDoc);
+  _isShapeToMesh = false;
 }
 
 //=============================================================================
@@ -110,15 +120,49 @@ SMESH_Mesh::~SMESH_Mesh()
  */
 //=============================================================================
 
-void SMESH_Mesh::ShapeToMesh(const TopoDS_Shape & aShape){
+void SMESH_Mesh::ShapeToMesh(const TopoDS_Shape & aShape)
+{
   if(MYDEBUG) MESSAGE("SMESH_Mesh::ShapeToMesh");
-  if (_isShapeToMesh)
-    throw
-      SALOME_Exception(LOCALIZED
-                      ("a shape to mesh as already been defined"));
+
+  if ( !_myMeshDS->ShapeToMesh().IsNull() && aShape.IsNull() )
+  {
+    // removal of a shape to mesh, delete objects referring to sub-shapes:
+    // - sub-meshes
+    map <int, SMESH_subMesh *>::iterator i_sm = _mapSubMesh.begin();
+    for ( ; i_sm != _mapSubMesh.end(); ++i_sm )
+      delete i_sm->second;
+    _mapSubMesh.clear();
+    //  - groups on geometry
+    map <int, SMESH_Group *>::iterator i_gr = _mapGroup.begin();
+    while ( i_gr != _mapGroup.end() ) {
+      if ( dynamic_cast<SMESHDS_GroupOnGeom*>( i_gr->second->GetGroupDS() )) {
+        _myMeshDS->RemoveGroup( i_gr->second->GetGroupDS() );
+        delete i_gr->second;
+        _mapGroup.erase( i_gr++ );
+      }
+      else
+        i_gr++;
+    }
+    _mapPropagationChains.Clear();
+  }
+  else
+  {
+    if (_isShapeToMesh)
+      throw SALOME_Exception(LOCALIZED ("a shape to mesh has already been defined"));
+  }
   _isShapeToMesh = true;
   _myMeshDS->ShapeToMesh(aShape);
-  
+
+  // fill _mapAncestors
+  _mapAncestors.Clear();
+  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 );
+
   // NRI : 24/02/03
   //EAP: 1/9/04 TopExp::MapShapes(aShape, _subShapes); USE the same map of _myMeshDS
 }
@@ -132,7 +176,7 @@ int SMESH_Mesh::UNVToMesh(const char* theFileName)
 {
   if(MYDEBUG) MESSAGE("UNVToMesh - theFileName = "<<theFileName);
   if(_isShapeToMesh)
-    throw SALOME_Exception(LOCALIZED("a shape to mesh as already been defined"));
+    throw SALOME_Exception(LOCALIZED("a shape to mesh has already been defined"));
   _isShapeToMesh = true;
   DriverUNV_R_SMDS_Mesh myReader;
   myReader.SetMesh(_myMeshDS);
@@ -140,10 +184,40 @@ int SMESH_Mesh::UNVToMesh(const char* theFileName)
   myReader.SetMeshId(-1);
   myReader.Perform();
   if(MYDEBUG){
-    MESSAGE("MEDToMesh - _myMeshDS->NbNodes() = "<<_myMeshDS->NbNodes());
-    MESSAGE("MEDToMesh - _myMeshDS->NbEdges() = "<<_myMeshDS->NbEdges());
-    MESSAGE("MEDToMesh - _myMeshDS->NbFaces() = "<<_myMeshDS->NbFaces());
-    MESSAGE("MEDToMesh - _myMeshDS->NbVolumes() = "<<_myMeshDS->NbVolumes());
+    MESSAGE("UNVToMesh - _myMeshDS->NbNodes() = "<<_myMeshDS->NbNodes());
+    MESSAGE("UNVToMesh - _myMeshDS->NbEdges() = "<<_myMeshDS->NbEdges());
+    MESSAGE("UNVToMesh - _myMeshDS->NbFaces() = "<<_myMeshDS->NbFaces());
+    MESSAGE("UNVToMesh - _myMeshDS->NbVolumes() = "<<_myMeshDS->NbVolumes());
+  }
+  SMDS_MeshGroup* aGroup = (SMDS_MeshGroup*) myReader.GetGroup();
+  if (aGroup != 0) {
+    TGroupNamesMap aGroupNames = myReader.GetGroupNamesMap();
+    //const TGroupIdMap& aGroupId = myReader.GetGroupIdMap();
+    aGroup->InitSubGroupsIterator();
+    while (aGroup->MoreSubGroups()) {
+      SMDS_MeshGroup* aSubGroup = (SMDS_MeshGroup*) aGroup->NextSubGroup();
+      std::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());
+       }
+      }
+    }
   }
   return 1;
 }
@@ -157,7 +231,7 @@ int SMESH_Mesh::MEDToMesh(const char* theFileName, const char* theMeshName)
 {
   if(MYDEBUG) MESSAGE("MEDToMesh - theFileName = "<<theFileName<<", mesh name = "<<theMeshName);
   if(_isShapeToMesh)
-    throw SALOME_Exception(LOCALIZED("a shape to mesh as already been defined"));
+    throw SALOME_Exception(LOCALIZED("a shape to mesh has already been defined"));
   _isShapeToMesh = true;
   DriverMED_R_SMESHDS_Mesh myReader;
   myReader.SetMesh(_myMeshDS);
@@ -173,16 +247,17 @@ int SMESH_Mesh::MEDToMesh(const char* theFileName, const char* theMeshName)
   }
 
   // Reading groups (sub-meshes are out of scope of MED import functionality)
-  list<string> aGroupNames = myReader.GetGroupNames();
+  list<TNameAndType> aGroupNames = myReader.GetGroupNamesAndTypes();
   if(MYDEBUG) MESSAGE("MEDToMesh - Nb groups = "<<aGroupNames.size()); 
   int anId;
-  for ( list<string>::iterator it = aGroupNames.begin(); it != aGroupNames.end(); it++ ) {
-    SMESH_Group* aGroup = AddGroup( SMDSAbs_All, it->c_str(), anId );
+  list<TNameAndType>::iterator name_type = aGroupNames.begin();
+  for ( ; name_type != aGroupNames.end(); name_type++ ) {
+    SMESH_Group* aGroup = AddGroup( name_type->second, name_type->first.c_str(), anId );
     if ( aGroup ) {
-      if(MYDEBUG) MESSAGE("MEDToMesh - group added: "<<it->c_str());      
+      if(MYDEBUG) MESSAGE("MEDToMesh - group added: "<<name_type->first.c_str());      
       SMESHDS_Group* aGroupDS = dynamic_cast<SMESHDS_Group*>( aGroup->GetGroupDS() );
       if ( aGroupDS ) {
-        aGroupDS->SetStoreName( it->c_str() );
+        aGroupDS->SetStoreName( name_type->first.c_str() );
         myReader.GetGroup( aGroupDS );
       }
     }
@@ -197,9 +272,9 @@ int SMESH_Mesh::MEDToMesh(const char* theFileName, const char* theMeshName)
 
 int SMESH_Mesh::STLToMesh(const char* theFileName)
 {
-  if(MYDEBUG) MESSAGE("UNVToMesh - theFileName = "<<theFileName);
+  if(MYDEBUG) MESSAGE("STLToMesh - theFileName = "<<theFileName);
   if(_isShapeToMesh)
-    throw SALOME_Exception(LOCALIZED("a shape to mesh as already been defined"));
+    throw SALOME_Exception(LOCALIZED("a shape to mesh has already been defined"));
   _isShapeToMesh = true;
   DriverSTL_R_SMDS_Mesh myReader;
   myReader.SetMesh(_myMeshDS);
@@ -207,10 +282,10 @@ int SMESH_Mesh::STLToMesh(const char* theFileName)
   myReader.SetMeshId(-1);
   myReader.Perform();
   if(MYDEBUG){
-    MESSAGE("MEDToMesh - _myMeshDS->NbNodes() = "<<_myMeshDS->NbNodes());
-    MESSAGE("MEDToMesh - _myMeshDS->NbEdges() = "<<_myMeshDS->NbEdges());
-    MESSAGE("MEDToMesh - _myMeshDS->NbFaces() = "<<_myMeshDS->NbFaces());
-    MESSAGE("MEDToMesh - _myMeshDS->NbVolumes() = "<<_myMeshDS->NbVolumes());
+    MESSAGE("STLToMesh - _myMeshDS->NbNodes() = "<<_myMeshDS->NbNodes());
+    MESSAGE("STLToMesh - _myMeshDS->NbEdges() = "<<_myMeshDS->NbEdges());
+    MESSAGE("STLToMesh - _myMeshDS->NbFaces() = "<<_myMeshDS->NbFaces());
+    MESSAGE("STLToMesh - _myMeshDS->NbVolumes() = "<<_myMeshDS->NbVolumes());
   }
   return 1;
 }
@@ -229,15 +304,21 @@ SMESH_Hypothesis::Hypothesis_Status
   if(MYDEBUG) MESSAGE("SMESH_Mesh::AddHypothesis");
 
   SMESH_subMesh *subMesh = GetSubMesh(aSubShape);
+  if ( !subMesh || !subMesh->GetId())
+    return SMESH_Hypothesis::HYP_BAD_SUBSHAPE;
+
   SMESHDS_SubMesh *subMeshDS = subMesh->GetSubMeshDS();
-  if ( subMeshDS && subMeshDS->IsComplexSubmesh() )
+  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;
@@ -343,6 +424,8 @@ SMESH_Hypothesis::Hypothesis_Status
     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;
@@ -437,6 +520,104 @@ SMESH_Mesh::GetHypothesisList(const TopoDS_Shape & aSubShape) const
   return _myMeshDS->GetHypothesis(aSubShape);
 }
 
+//=======================================================================
+//function : GetHypothesis
+//purpose  : 
+//=======================================================================
+
+const SMESH_Hypothesis * SMESH_Mesh::GetHypothesis(const TopoDS_Shape &    aSubShape,
+                                                   const SMESH_HypoFilter& aFilter,
+                                                   const bool              andAncestors) 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 = static_cast<const SMESH_Hypothesis*>( *hyp );
+      if ( aFilter.IsOk( h, aSubShape))
+        return h;
+    }
+  }
+  if ( andAncestors )
+  {
+    TopTools_ListIteratorOfListOfShape it( GetAncestors( aSubShape ));
+    for (; it.More(); it.Next() )
+    {
+      const list<const SMESHDS_Hypothesis*>& hypList = _myMeshDS->GetHypothesis(it.Value());
+      list<const SMESHDS_Hypothesis*>::const_iterator hyp = hypList.begin();
+      for ( ; hyp != hypList.end(); hyp++ ) {
+        const SMESH_Hypothesis * h = static_cast<const SMESH_Hypothesis*>( *hyp );
+        if (aFilter.IsOk( h, it.Value() ))
+          return h;
+      }
+    }
+  }
+  return 0;
+}
+
+//=======================================================================
+//function : GetHypotheses
+//purpose  : 
+//=======================================================================
+
+//================================================================================
+/*!
+ * \brief Return hypothesis assigned to the shape
+  * \param aSubShape - the shape to check
+  * \param aFilter - the hypothesis filter
+  * \param aHypList - the list of the found hypotheses
+  * \param andAncestors - flag to check hypos assigned to ancestors of the shape
+  * \retval int - number of unique hypos in aHypList
+ */
+//================================================================================
+
+int SMESH_Mesh::GetHypotheses(const TopoDS_Shape &                aSubShape,
+                              const SMESH_HypoFilter&             aFilter,
+                              list <const SMESHDS_Hypothesis * >& aHypList,
+                              const bool                          andAncestors) const
+{
+  set<string> hypTypes; // to exclude same type hypos from the result list
+  int nbHyps = 0;
+
+  // fill in hypTypes
+  list<const SMESHDS_Hypothesis*>::const_iterator hyp;
+  for ( hyp = aHypList.begin(); hyp != aHypList.end(); hyp++ )
+    if ( hypTypes.insert( (*hyp)->GetName() ).second )
+      nbHyps++;
+
+  // get hypos from aSubShape
+  {
+    const list<const SMESHDS_Hypothesis*>& hypList = _myMeshDS->GetHypothesis(aSubShape);
+    for ( hyp = hypList.begin(); hyp != hypList.end(); hyp++ )
+      if ( aFilter.IsOk (static_cast<const SMESH_Hypothesis*>( *hyp ), aSubShape) &&
+           hypTypes.insert( (*hyp)->GetName() ).second )
+      {
+        aHypList.push_back( *hyp );
+        nbHyps++;
+      }
+  }
+
+  // get hypos from ancestors of aSubShape
+  if ( andAncestors )
+  {
+    TopTools_MapOfShape map;
+    TopTools_ListIteratorOfListOfShape it( GetAncestors( aSubShape ));
+    for (; it.More(); it.Next() )
+    {
+     if ( !map.Add( it.Value() ))
+        continue;
+      const list<const SMESHDS_Hypothesis*>& hypList = _myMeshDS->GetHypothesis(it.Value());
+      for ( hyp = hypList.begin(); hyp != hypList.end(); hyp++ )
+        if (aFilter.IsOk( static_cast<const SMESH_Hypothesis*>( *hyp ), it.Value() ) &&
+            hypTypes.insert( (*hyp)->GetName() ).second ) {
+          aHypList.push_back( *hyp );
+          nbHyps++;
+        }
+    }
+  }
+  return nbHyps;
+}
+
 //=============================================================================
 /*!
  * 
@@ -492,28 +673,31 @@ SMESH_Gen *SMESH_Mesh::GetGen()
 //=============================================================================
 
 SMESH_subMesh *SMESH_Mesh::GetSubMesh(const TopoDS_Shape & aSubShape)
-throw(SALOME_Exception)
+  throw(SALOME_Exception)
 {
   Unexpect aCatch(SalomeException);
   SMESH_subMesh *aSubMesh;
   int index = _myMeshDS->ShapeToIndex(aSubShape);
-  
+
   // for submeshes on GEOM Group
   if ( !index && aSubShape.ShapeType() == TopAbs_COMPOUND ) {
     TopoDS_Iterator it( aSubShape );
     if ( it.More() )
       index = _myMeshDS->AddCompoundSubmesh( aSubShape, it.Value().ShapeType() );
   }
+//   if ( !index )
+//     return NULL; // neither sub-shape nor a group
 
-  if (_mapSubMesh.find(index) != _mapSubMesh.end())
-    {
-      aSubMesh = _mapSubMesh[index];
-    }
+  map <int, SMESH_subMesh *>::iterator i_sm = _mapSubMesh.find(index);
+  if ( i_sm != _mapSubMesh.end())
+  {
+    aSubMesh = i_sm->second;
+  }
   else
-    {
-      aSubMesh = new SMESH_subMesh(index, this, _myMeshDS, aSubShape);
-      _mapSubMesh[index] = aSubMesh;
-    }
+  {
+    aSubMesh = new SMESH_subMesh(index, this, _myMeshDS, aSubShape);
+    _mapSubMesh[index] = aSubMesh;
+  }
   return aSubMesh;
 }
 
@@ -525,38 +709,55 @@ throw(SALOME_Exception)
 //=============================================================================
 
 SMESH_subMesh *SMESH_Mesh::GetSubMeshContaining(const TopoDS_Shape & aSubShape)
-throw(SALOME_Exception)
+  throw(SALOME_Exception)
 {
   Unexpect aCatch(SalomeException);
-  bool isFound = false;
   SMESH_subMesh *aSubMesh = NULL;
   
   int index = _myMeshDS->ShapeToIndex(aSubShape);
-  if (_mapSubMesh.find(index) != _mapSubMesh.end())
-    {
-      aSubMesh = _mapSubMesh[index];
-      isFound = true;
-    }
-  if (!isFound)
-    aSubMesh = NULL;
+
+  map <int, SMESH_subMesh *>::iterator i_sm = _mapSubMesh.find(index);
+  if ( i_sm != _mapSubMesh.end())
+    aSubMesh = i_sm->second;
+
   return aSubMesh;
 }
 
+//=============================================================================
+/*!
+ * Get the SMESH_subMesh object implementation. Dont create it, return null
+ * if it does not exist.
+ */
+//=============================================================================
+
+SMESH_subMesh *SMESH_Mesh::GetSubMeshContaining(const int aShapeID)
+throw(SALOME_Exception)
+{
+  Unexpect aCatch(SalomeException);
+  
+  map <int, SMESH_subMesh *>::iterator i_sm = _mapSubMesh.find(aShapeID);
+  if (i_sm == _mapSubMesh.end())
+    return NULL;
+  return i_sm->second;
+}
+
 //=======================================================================
 //function : IsUsedHypothesis
 //purpose  : Return True if anHyp is used to mesh aSubShape
 //=======================================================================
 
 bool SMESH_Mesh::IsUsedHypothesis(SMESHDS_Hypothesis * anHyp,
-                                  const TopoDS_Shape & aSubShape)
+                                  const SMESH_subMesh* aSubMesh)
 {
-  // check if anHyp is applicable to aSubShape
-  SMESH_subMesh * subMesh = GetSubMeshContaining( aSubShape );
-  if (!subMesh ||
-      !subMesh->IsApplicableHypotesis(static_cast<SMESH_Hypothesis*>(anHyp)))
+  SMESH_Hypothesis* hyp = static_cast<SMESH_Hypothesis*>(anHyp);
+
+  // check if anHyp can be used to mesh aSubMesh
+  if ( !aSubMesh || !aSubMesh->IsApplicableHypotesis( hyp ))
     return false;
 
-  SMESH_Algo *algo = _gen->GetAlgo(*this, aSubShape);
+  const TopoDS_Shape & aSubShape = const_cast<SMESH_subMesh*>( aSubMesh )->GetSubShape();
+
+  SMESH_Algo *algo = _gen->GetAlgo(*this, aSubShape );
 
   // algorithm
   if (anHyp->GetType() > SMESHDS_Hypothesis::PARAM_ALGO)
@@ -566,41 +767,18 @@ bool SMESH_Mesh::IsUsedHypothesis(SMESHDS_Hypothesis * anHyp,
   if (algo)
   {
     // look trough hypotheses used by algo
-    const list <const SMESHDS_Hypothesis * >&usedHyps =
-      algo->GetUsedHypothesis(*this, aSubShape);
-    list <const SMESHDS_Hypothesis * >::const_iterator itl;
-    for (itl = usedHyps.begin(); itl != usedHyps.end(); itl++)
-      if (anHyp == (*itl))
-        return true;
-  }
-  else
-  {
-    // look through all assigned hypotheses
-    {
-      const list <const SMESHDS_Hypothesis * >&usedHyps =
-        _myMeshDS->GetHypothesis( aSubShape );
-      list <const SMESHDS_Hypothesis * >::const_iterator itl;
-      for (itl = usedHyps.begin(); itl != usedHyps.end(); itl++)
-        if (anHyp == (*itl))
-          return true;
-    }
-
-    // on ancestors
-    TopTools_ListIteratorOfListOfShape it( GetAncestors( aSubShape ));
-    for (; it.More(); it.Next())
-    {
-      const list <const SMESHDS_Hypothesis * >&usedHyps =
-        _myMeshDS->GetHypothesis( aSubShape );
-      list <const SMESHDS_Hypothesis * >::const_iterator itl;
-      for (itl = usedHyps.begin(); itl != usedHyps.end(); itl++)
-        if (anHyp == (*itl))
-          return true;
+    SMESH_HypoFilter hypoKind;
+    if ( algo->InitCompatibleHypoFilter( hypoKind, !hyp->IsAuxiliary() )) {
+      list <const SMESHDS_Hypothesis * > usedHyps;
+      if ( GetHypotheses( aSubShape, hypoKind, usedHyps, true ))
+        return ( find( usedHyps.begin(), usedHyps.end(), anHyp ) != usedHyps.end() );
     }
   }
-    
-  return false;
-}
 
+  // look through all assigned hypotheses
+  //SMESH_HypoFilter filter( SMESH_HypoFilter::Is( hyp ));
+  return false; //GetHypothesis( aSubShape, filter, true );
+}
 
 //=============================================================================
 /*!
@@ -609,28 +787,100 @@ bool SMESH_Mesh::IsUsedHypothesis(SMESHDS_Hypothesis * anHyp,
 //=============================================================================
 
 const list < SMESH_subMesh * >&
-       SMESH_Mesh::GetSubMeshUsingHypothesis(SMESHDS_Hypothesis * anHyp)
-throw(SALOME_Exception)
+SMESH_Mesh::GetSubMeshUsingHypothesis(SMESHDS_Hypothesis * anHyp)
+  throw(SALOME_Exception)
 {
   Unexpect aCatch(SalomeException);
-       if(MYDEBUG) MESSAGE("SMESH_Mesh::GetSubMeshUsingHypothesis");
-       map < int, SMESH_subMesh * >::iterator itsm;
-       _subMeshesUsingHypothesisList.clear();
-       for (itsm = _mapSubMesh.begin(); itsm != _mapSubMesh.end(); itsm++)
-       {
-               SMESH_subMesh *aSubMesh = (*itsm).second;
-               if ( IsUsedHypothesis ( anHyp, aSubMesh->GetSubShape() ))
-                       _subMeshesUsingHypothesisList.push_back(aSubMesh);
-       }
-       return _subMeshesUsingHypothesisList;
+  if(MYDEBUG) MESSAGE("SMESH_Mesh::GetSubMeshUsingHypothesis");
+  map < int, SMESH_subMesh * >::iterator itsm;
+  _subMeshesUsingHypothesisList.clear();
+  for (itsm = _mapSubMesh.begin(); itsm != _mapSubMesh.end(); itsm++)
+  {
+    SMESH_subMesh *aSubMesh = (*itsm).second;
+    if ( IsUsedHypothesis ( anHyp, aSubMesh ))
+      _subMeshesUsingHypothesisList.push_back(aSubMesh);
+  }
+  return _subMeshesUsingHypothesisList;
+}
+
+//=======================================================================
+//function : NotifySubMeshesHypothesisModification
+//purpose  : Say all submeshes using theChangedHyp that it has been modified
+//=======================================================================
+
+void SMESH_Mesh::NotifySubMeshesHypothesisModification(const SMESH_Hypothesis* theChangedHyp)
+{
+  Unexpect aCatch(SalomeException);
+
+  const SMESH_Hypothesis* hyp = static_cast<const SMESH_Hypothesis*>(theChangedHyp);
+
+  const SMESH_Algo *foundAlgo = 0;
+  SMESH_HypoFilter algoKind( SMESH_HypoFilter::IsAlgo() );
+  SMESH_HypoFilter compatibleHypoKind;
+  list <const SMESHDS_Hypothesis * > usedHyps;
+
+
+  map < int, SMESH_subMesh * >::iterator itsm;
+  for (itsm = _mapSubMesh.begin(); itsm != _mapSubMesh.end(); itsm++)
+  {
+    SMESH_subMesh *aSubMesh = (*itsm).second;
+    if ( aSubMesh->IsApplicableHypotesis( hyp ))
+    {
+      const TopoDS_Shape & aSubShape = aSubMesh->GetSubShape();
+
+      if ( !foundAlgo ) // init filter for algo search
+        algoKind.And( algoKind.IsApplicableTo( aSubShape ));
+      
+      const SMESH_Algo *algo = static_cast<const SMESH_Algo*>
+        ( GetHypothesis( aSubShape, algoKind, true ));
+
+      if ( algo )
+      {
+        bool sameAlgo = ( algo == foundAlgo );
+        if ( !sameAlgo && foundAlgo )
+          sameAlgo = ( strcmp( algo->GetName(), foundAlgo->GetName() ) == 0);
+
+        if ( !sameAlgo ) { // init filter for used hypos search
+          if ( !algo->InitCompatibleHypoFilter( compatibleHypoKind, !hyp->IsAuxiliary() ))
+            continue; // algo does not use any hypothesis
+          foundAlgo = algo;
+        }
+
+        // check if hyp is used by algo
+        usedHyps.clear();
+        if ( GetHypotheses( aSubShape, compatibleHypoKind, usedHyps, true ) &&
+             find( usedHyps.begin(), usedHyps.end(), hyp ) != usedHyps.end() )
+        {
+          aSubMesh->ComputeStateEngine(SMESH_subMesh::MODIF_HYP);
+
+          if ( algo->GetDim() == 1 && IsPropagationHypothesis( aSubShape ))
+            CleanMeshOnPropagationChain( aSubShape );
+        }
+      }
+    }
+  }
 }
 
 //=============================================================================
-/*!
- *
+/*! Export* methods.
+ *  To store mesh contents on disk in different formats.
  */
 //=============================================================================
 
+bool SMESH_Mesh::HasDuplicatedGroupNamesMED()
+{
+  set<string> aGroupNames;
+  for ( map<int, SMESH_Group*>::iterator it = _mapGroup.begin(); it != _mapGroup.end(); it++ ) {
+    SMESH_Group* aGroup = it->second;
+    string aGroupName = aGroup->GetName();
+    aGroupName.resize(MAX_MED_GROUP_NAME_LENGTH);
+    if (!aGroupNames.insert(aGroupName).second)
+      return true;
+  }
+
+  return false;
+}
+
 void SMESH_Mesh::ExportMED(const char *file, 
                           const char* theMeshName, 
                           bool theAutoGroups,
@@ -638,6 +888,7 @@ void SMESH_Mesh::ExportMED(const char *file,
   throw(SALOME_Exception)
 {
   Unexpect aCatch(SalomeException);
+
   DriverMED_W_SMESHDS_Mesh myWriter;
   myWriter.SetFile    ( file, MED::EVersion(theVersion) );
   myWriter.SetMesh    ( _myMeshDS   );
@@ -655,15 +906,28 @@ void SMESH_Mesh::ExportMED(const char *file,
     myWriter.AddGroupOfVolumes();
   }
 
+  // Pass groups to writer. Provide unique group names.
+  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 ) {
-      aGroupDS->SetStoreName( aGroup->GetName() );
+      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++) {
+        sprintf(&aString[0], "GR_%d_%s", i, aGroupName0.c_str());
+        aGroupName = aString;
+        aGroupName.resize(MAX_MED_GROUP_NAME_LENGTH);
+      }
+      aGroupDS->SetStoreName( aGroupName.c_str() );
       myWriter.AddGroup( aGroupDS );
     }
   }
 
+  // Perform export
   myWriter.Perform();
 }
 
@@ -684,6 +948,17 @@ void SMESH_Mesh::ExportUNV(const char *file) throw(SALOME_Exception)
   myWriter.SetFile(string(file));
   myWriter.SetMesh(_myMeshDS);
   myWriter.SetMeshId(_idDoc);
+  //  myWriter.SetGroups(_mapGroup);
+
+  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 ) {
+      string aGroupName = aGroup->GetName();
+      aGroupDS->SetStoreName( aGroupName.c_str() );
+      myWriter.AddGroup( aGroupDS );
+    }
+  }
   myWriter.Perform();
 }
 
@@ -714,10 +989,21 @@ int SMESH_Mesh::NbNodes() throw(SALOME_Exception)
  *  
  */
 //=============================================================================
-int SMESH_Mesh::NbEdges() throw(SALOME_Exception)
+int SMESH_Mesh::NbEdges(ElementOrder order) throw(SALOME_Exception)
 {
   Unexpect aCatch(SalomeException);
-  return _myMeshDS->NbEdges();
+  if (order == ORDER_ANY)
+    return _myMeshDS->NbEdges();
+
+  int Nb = 0;
+  SMDS_EdgeIteratorPtr it = _myMeshDS->edgesIterator();
+  while (it->more()) {
+    const SMDS_MeshEdge* cur = it->next();
+    if ( order == ORDER_LINEAR && !cur->IsQuadratic() ||
+         order == ORDER_QUADRATIC && cur->IsQuadratic() )
+      Nb++;
+  }
+  return Nb;
 }
 
 //=============================================================================
@@ -725,35 +1011,75 @@ int SMESH_Mesh::NbEdges() throw(SALOME_Exception)
  *  
  */
 //=============================================================================
-int SMESH_Mesh::NbFaces() throw(SALOME_Exception)
+int SMESH_Mesh::NbFaces(ElementOrder order) throw(SALOME_Exception)
 {
   Unexpect aCatch(SalomeException);
-  return _myMeshDS->NbFaces();
+  if (order == ORDER_ANY)
+    return _myMeshDS->NbFaces();
+
+  int Nb = 0;
+  SMDS_FaceIteratorPtr it = _myMeshDS->facesIterator();
+  while (it->more()) {
+    const SMDS_MeshFace* cur = it->next();
+    if ( order == ORDER_LINEAR && !cur->IsQuadratic() ||
+         order == ORDER_QUADRATIC && cur->IsQuadratic() )
+      Nb++;
+  }
+  return Nb;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 /// Return the number of 3 nodes faces in the mesh. This method run in O(n)
 ///////////////////////////////////////////////////////////////////////////////
-int SMESH_Mesh::NbTriangles() throw(SALOME_Exception)
+int SMESH_Mesh::NbTriangles(ElementOrder order) throw(SALOME_Exception)
 {
   Unexpect aCatch(SalomeException);
   int Nb = 0;
   
   SMDS_FaceIteratorPtr itFaces=_myMeshDS->facesIterator();
-  while(itFaces->more()) if(itFaces->next()->NbNodes()==3) Nb++;
+  while (itFaces->more()) {
+    const SMDS_MeshFace* curFace = itFaces->next();
+    int nbnod = curFace->NbNodes();
+    if ( !curFace->IsPoly() && 
+        ( order == ORDER_ANY && (nbnod==3 || nbnod==6) ||
+           order == ORDER_LINEAR && nbnod==3 ||
+           order == ORDER_QUADRATIC && nbnod==6 ) )
+      Nb++;
+  }
   return Nb;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 /// Return the number of 4 nodes faces in the mesh. This method run in O(n)
 ///////////////////////////////////////////////////////////////////////////////
-int SMESH_Mesh::NbQuadrangles() throw(SALOME_Exception)
+int SMESH_Mesh::NbQuadrangles(ElementOrder order) throw(SALOME_Exception)
 {
   Unexpect aCatch(SalomeException);
   int Nb = 0;
   
   SMDS_FaceIteratorPtr itFaces=_myMeshDS->facesIterator();
-  while(itFaces->more()) if(itFaces->next()->NbNodes()==4) Nb++;
+  while (itFaces->more()) {
+    const SMDS_MeshFace* curFace = itFaces->next();
+    int nbnod = curFace->NbNodes();
+    if ( !curFace->IsPoly() && 
+        ( order == ORDER_ANY && (nbnod==4 || nbnod==8) ||
+           order == ORDER_LINEAR && nbnod==4 ||
+           order == ORDER_QUADRATIC && nbnod==8 ) )
+      Nb++;
+  }
+  return Nb;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Return the number of polygonal faces in the mesh. This method run in O(n)
+///////////////////////////////////////////////////////////////////////////////
+int SMESH_Mesh::NbPolygons() throw(SALOME_Exception)
+{
+  Unexpect aCatch(SalomeException);
+  int Nb = 0;
+  SMDS_FaceIteratorPtr itFaces = _myMeshDS->facesIterator();
+  while (itFaces->more())
+    if (itFaces->next()->IsPoly()) Nb++;
   return Nb;
 }
 
@@ -762,45 +1088,98 @@ int SMESH_Mesh::NbQuadrangles() throw(SALOME_Exception)
  *  
  */
 //=============================================================================
-int SMESH_Mesh::NbVolumes() throw(SALOME_Exception)
+int SMESH_Mesh::NbVolumes(ElementOrder order) throw(SALOME_Exception)
 {
   Unexpect aCatch(SalomeException);
-  return _myMeshDS->NbVolumes();
+  if (order == ORDER_ANY)
+    return _myMeshDS->NbVolumes();
+
+  int Nb = 0;
+  SMDS_VolumeIteratorPtr it = _myMeshDS->volumesIterator();
+  while (it->more()) {
+    const SMDS_MeshVolume* cur = it->next();
+    if ( order == ORDER_LINEAR && !cur->IsQuadratic() ||
+         order == ORDER_QUADRATIC && cur->IsQuadratic() )
+      Nb++;
+  }
+  return Nb;
 }
 
-int SMESH_Mesh::NbTetras() throw(SALOME_Exception)
+int SMESH_Mesh::NbTetras(ElementOrder order) throw(SALOME_Exception)
 {
   Unexpect aCatch(SalomeException);
   int Nb = 0;
   SMDS_VolumeIteratorPtr itVolumes=_myMeshDS->volumesIterator();
-  while(itVolumes->more()) if(itVolumes->next()->NbNodes()==4) Nb++;
+  while (itVolumes->more()) {
+    const SMDS_MeshVolume* curVolume = itVolumes->next();
+    int nbnod = curVolume->NbNodes();
+    if ( !curVolume->IsPoly() && 
+        ( order == ORDER_ANY && (nbnod==4 || nbnod==10) ||
+           order == ORDER_LINEAR && nbnod==4 ||
+           order == ORDER_QUADRATIC && nbnod==10 ) )
+      Nb++;
+  }
   return Nb;
 }
 
-int SMESH_Mesh::NbHexas() throw(SALOME_Exception)
+int SMESH_Mesh::NbHexas(ElementOrder order) throw(SALOME_Exception)
 {
   Unexpect aCatch(SalomeException);
   int Nb = 0;
   SMDS_VolumeIteratorPtr itVolumes=_myMeshDS->volumesIterator();
-  while(itVolumes->more()) if(itVolumes->next()->NbNodes()==8) Nb++;
+  while (itVolumes->more()) {
+    const SMDS_MeshVolume* curVolume = itVolumes->next();
+    int nbnod = curVolume->NbNodes();
+    if ( !curVolume->IsPoly() && 
+        ( order == ORDER_ANY && (nbnod==8 || nbnod==20) ||
+           order == ORDER_LINEAR && nbnod==8 ||
+           order == ORDER_QUADRATIC && nbnod==20 ) )
+      Nb++;
+  }
   return Nb;
 }
 
-int SMESH_Mesh::NbPyramids() throw(SALOME_Exception)
+int SMESH_Mesh::NbPyramids(ElementOrder order) throw(SALOME_Exception)
 {
   Unexpect aCatch(SalomeException);
   int Nb = 0;
   SMDS_VolumeIteratorPtr itVolumes=_myMeshDS->volumesIterator();
-  while(itVolumes->more()) if(itVolumes->next()->NbNodes()==5) Nb++;
+  while (itVolumes->more()) {
+    const SMDS_MeshVolume* curVolume = itVolumes->next();
+    int nbnod = curVolume->NbNodes();
+    if ( !curVolume->IsPoly() && 
+        ( order == ORDER_ANY && (nbnod==5 || nbnod==13) ||
+           order == ORDER_LINEAR && nbnod==5 ||
+           order == ORDER_QUADRATIC && nbnod==13 ) )
+      Nb++;
+  }
   return Nb;
 }
 
-int SMESH_Mesh::NbPrisms() throw(SALOME_Exception)
+int SMESH_Mesh::NbPrisms(ElementOrder order) throw(SALOME_Exception)
 {
   Unexpect aCatch(SalomeException);
   int Nb = 0;
   SMDS_VolumeIteratorPtr itVolumes=_myMeshDS->volumesIterator();
-  while(itVolumes->more()) if(itVolumes->next()->NbNodes()==6) Nb++;
+  while (itVolumes->more()) {
+    const SMDS_MeshVolume* curVolume = itVolumes->next();
+    int nbnod = curVolume->NbNodes();
+    if ( !curVolume->IsPoly() && 
+        ( order == ORDER_ANY && (nbnod==6 || nbnod==15) ||
+           order == ORDER_LINEAR && nbnod==6 ||
+           order == ORDER_QUADRATIC && nbnod==15 ) )
+      Nb++;
+  }
+  return Nb;
+}
+
+int SMESH_Mesh::NbPolyhedrons() throw(SALOME_Exception)
+{
+  Unexpect aCatch(SalomeException);
+  int Nb = 0;
+  SMDS_VolumeIteratorPtr itVolumes = _myMeshDS->volumesIterator();
+  while (itVolumes->more())
+    if (itVolumes->next()->IsPoly()) Nb++;
   return Nb;
 }
 
@@ -824,18 +1203,8 @@ bool SMESH_Mesh::IsNotConformAllowed() const
 {
   if(MYDEBUG) MESSAGE("SMESH_Mesh::IsNotConformAllowed");
 
-  const list<const SMESHDS_Hypothesis*>& listHyp =
-    _myMeshDS->GetHypothesis( _myMeshDS->ShapeToMesh() );
-  list<const SMESHDS_Hypothesis*>::const_iterator it=listHyp.begin();
-  while (it!=listHyp.end())
-  {
-    const SMESHDS_Hypothesis *aHyp = *it;
-    string hypName = aHyp->GetName();
-    if ( hypName == "NotConformAllowed" )
-      return true;
-    it++;
-  }
-  return false;
+  SMESH_HypoFilter filter( SMESH_HypoFilter::HasName( "NotConformAllowed" ));
+  return GetHypothesis( _myMeshDS->ShapeToMesh(), filter, false );
 }
 
 //=======================================================================
@@ -909,30 +1278,22 @@ void SMESH_Mesh::RemoveGroup (const int theGroupID)
   if (_mapGroup.find(theGroupID) == _mapGroup.end())
     return;
   GetMeshDS()->RemoveGroup( _mapGroup[theGroupID]->GetGroupDS() );
-  _mapGroup.erase (theGroupID);
   delete _mapGroup[theGroupID];
+  _mapGroup.erase (theGroupID);
 }
 
 //=============================================================================
 /*!
  *  IsLocal1DHypothesis
- *  Check, if there is 1D hypothesis assigned directly on <theEdge>
+ *  Returns a local 1D hypothesis used for theEdge
  */
 //=============================================================================
-bool SMESH_Mesh::IsLocal1DHypothesis (const TopoDS_Shape& theEdge)
+const SMESH_Hypothesis* SMESH_Mesh::IsLocal1DHypothesis (const TopoDS_Shape& theEdge)
 {
-  const SMESHDS_Mesh* meshDS = GetMeshDS();
-  const list<const SMESHDS_Hypothesis*>& listHyp = meshDS->GetHypothesis(theEdge);
-  list<const SMESHDS_Hypothesis*>::const_iterator it = listHyp.begin();
-
-  for (; it != listHyp.end(); it++) {
-    const SMESH_Hypothesis * aHyp = static_cast<const SMESH_Hypothesis*>(*it);
-    if (aHyp->GetType() == SMESHDS_Hypothesis::PARAM_ALGO &&
-        aHyp->GetDim() == 1) { // 1D Hypothesis found
-      return true;
-    }
-  }
-  return false;
+  SMESH_HypoFilter hypo ( SMESH_HypoFilter::HasDim( 1 ));
+  hypo.AndNot( hypo.IsAlgo() ).AndNot( hypo.IsAssignedTo( GetMeshDS()->ShapeToMesh() ));
+
+  return GetHypothesis( theEdge, hypo, true );
 }
 
 //=============================================================================
@@ -955,7 +1316,8 @@ bool SMESH_Mesh::IsPropagatedHypothesis (const TopoDS_Shape& theEdge,
 {
   int nbChains = _mapPropagationChains.Extent();
   for (int i = 1; i <= nbChains; i++) {
-    const TopTools_IndexedMapOfShape& aChain = _mapPropagationChains.FindFromIndex(i);
+    //const TopTools_IndexedMapOfShape& aChain = _mapPropagationChains.FindFromIndex(i);
+    const SMESH_IndexedMapOfShape& aChain = _mapPropagationChains.FindFromIndex(i);
     if (aChain.Contains(theEdge)) {
       theMainEdge = _mapPropagationChains.FindKey(i);
       return true;
@@ -976,7 +1338,7 @@ bool SMESH_Mesh::IsReversedInChain (const TopoDS_Shape& theEdge,
   if ( !theMainEdge.IsNull() && !theEdge.IsNull() &&
       _mapPropagationChains.Contains( theMainEdge ))
   {
-    const TopTools_IndexedMapOfShape& aChain =
+    const SMESH_IndexedMapOfShape& aChain =
       _mapPropagationChains.FindFromKey( theMainEdge );
     int index = aChain.FindIndex( theEdge );
     if ( index )
@@ -992,14 +1354,14 @@ bool SMESH_Mesh::IsReversedInChain (const TopoDS_Shape& theEdge,
 //=============================================================================
 void SMESH_Mesh::CleanMeshOnPropagationChain (const TopoDS_Shape& theMainEdge)
 {
-  const TopTools_IndexedMapOfShape& aChain = _mapPropagationChains.FindFromKey(theMainEdge);
+  const SMESH_IndexedMapOfShape& aChain = _mapPropagationChains.FindFromKey(theMainEdge);
   int i, nbEdges = aChain.Extent();
   for (i = 1; i <= nbEdges; i++) {
     TopoDS_Shape anEdge = aChain.FindKey(i);
     SMESH_subMesh *subMesh = GetSubMesh(anEdge);
     SMESHDS_SubMesh *subMeshDS = subMesh->GetSubMeshDS();
     if (subMeshDS && subMeshDS->NbElements() > 0) {
-      subMesh->ComputeStateEngine(SMESH_subMesh::CLEANDEP);
+      subMesh->ComputeStateEngine(SMESH_subMesh::CLEAN);
     }
   }
 }
@@ -1053,11 +1415,15 @@ bool SMESH_Mesh::RemovePropagationChain (const TopoDS_Shape& theMainEdge)
 
   // Remove the chain from the map
   int i = _mapPropagationChains.FindIndex(theMainEdge);
-  TopoDS_Vertex anEmptyShape;
-  BRep_Builder BB;
-  BB.MakeVertex(anEmptyShape, gp_Pnt(0,0,0), 0.1);
-  TopTools_IndexedMapOfShape anEmptyMap;
-  _mapPropagationChains.Substitute(i, anEmptyShape, anEmptyMap);
+  if ( i == _mapPropagationChains.Extent() )
+    _mapPropagationChains.RemoveLast();
+  else {
+    TopoDS_Vertex anEmptyShape;
+    BRep_Builder BB;
+    BB.MakeVertex(anEmptyShape, gp_Pnt(0,0,0), 0.1);
+    SMESH_IndexedMapOfShape anEmptyMap;
+    _mapPropagationChains.Substitute(i, anEmptyShape, anEmptyMap);
+  }
 
   return true;
 }
@@ -1073,18 +1439,19 @@ bool SMESH_Mesh::BuildPropagationChain (const TopoDS_Shape& theMainEdge)
 
   // Add new chain, if there is no
   if (!_mapPropagationChains.Contains(theMainEdge)) {
-    TopTools_IndexedMapOfShape aNewChain;
+    SMESH_IndexedMapOfShape aNewChain;
     _mapPropagationChains.Add(theMainEdge, aNewChain);
   }
 
   // Check presence of 1D hypothesis to be propagated
-  if (!IsLocal1DHypothesis(theMainEdge)) {
+  const SMESH_Hypothesis* aMainHyp = IsLocal1DHypothesis(theMainEdge);
+  if (!aMainHyp) {
     MESSAGE("Warning: There is no 1D hypothesis to propagate. Please, assign.");
     return true;
   }
 
   // Edges, on which the 1D hypothesis will be propagated from <theMainEdge>
-  TopTools_IndexedMapOfShape& aChain = _mapPropagationChains.ChangeFromKey(theMainEdge);
+  SMESH_IndexedMapOfShape& aChain = _mapPropagationChains.ChangeFromKey(theMainEdge);
   if (aChain.Extent() > 0) {
     CleanMeshOnPropagationChain(theMainEdge);
     aChain.Clear();
@@ -1152,18 +1519,14 @@ bool SMESH_Mesh::BuildPropagationChain (const TopoDS_Shape& theMainEdge)
             if (opp > 4) opp -= 4;
             anOppE = anEdges(opp);
 
-            if (!aChain.Contains(anOppE)) {
-              if (!IsLocal1DHypothesis(anOppE)) {
-                TopoDS_Shape aMainEdgeForOppEdge;
-                if (IsPropagatedHypothesis(anOppE, aMainEdgeForOppEdge)) {
-                  // Collision!
-                  MESSAGE("Error: Collision between propagated hypotheses");
-                  CleanMeshOnPropagationChain(theMainEdge);
-                  aChain.Clear();
-                  return false;
-                } else {
+            // add anOppE to aChain if ...
+            if (!aChain.Contains(anOppE)) { // ... anOppE is not in aChain
+              if (!IsLocal1DHypothesis(anOppE)) { // ... no other 1d hyp on anOppE
+                TopoDS_Shape aMainEdgeForOppEdge; // ... no other hyp is propagated to anOppE
+                if (!IsPropagatedHypothesis(anOppE, aMainEdgeForOppEdge))
+                {
                   // Add found edge to the chain oriented so that to
-                  // have it in aChain co-directed with theMainEdge
+                  // have it co-directed with a forward MainEdge
                   TopAbs_Orientation ori = anE.Orientation();
                   if ( anEdges(opp).Orientation() == anEdges(found).Orientation() )
                     ori = TopAbs::Reverse( ori );
@@ -1171,6 +1534,13 @@ bool SMESH_Mesh::BuildPropagationChain (const TopoDS_Shape& theMainEdge)
                   aChain.Add(anOppE);
                   listCurEdges.Append(anOppE);
                 }
+                else {
+                  // Collision!
+                  MESSAGE("Error: Collision between propagated hypotheses");
+                  CleanMeshOnPropagationChain(theMainEdge);
+                  aChain.Clear();
+                  return ( aMainHyp == IsLocal1DHypothesis(aMainEdgeForOppEdge) );
+                }
               }
             }
           } // if (nb == 5 && found > 0)
@@ -1191,20 +1561,8 @@ bool SMESH_Mesh::BuildPropagationChain (const TopoDS_Shape& theMainEdge)
 //           that lower dimention shapes come first.
 //=======================================================================
 
-const TopTools_ListOfShape& SMESH_Mesh::GetAncestors(const TopoDS_Shape& theS)
+const TopTools_ListOfShape& SMESH_Mesh::GetAncestors(const TopoDS_Shape& theS) const
 {
-  if ( _mapAncestors.IsEmpty() )
-  {
-    // fill _mapAncestors
-    int desType, ancType;
-    for ( desType = TopAbs_EDGE; desType > TopAbs_COMPOUND; desType-- )
-      for ( ancType = desType - 1; ancType >= TopAbs_COMPOUND; ancType-- )
-        TopExp::MapShapesAndAncestors (_myMeshDS->ShapeToMesh(),
-                                       (TopAbs_ShapeEnum) desType,
-                                       (TopAbs_ShapeEnum) ancType,
-                                       _mapAncestors );
-  }
-
   if ( _mapAncestors.Contains( theS ) )
     return _mapAncestors.FindFromKey( theS );
 
@@ -1218,55 +1576,72 @@ const TopTools_ListOfShape& SMESH_Mesh::GetAncestors(const TopoDS_Shape& theS)
 //=======================================================================
 ostream& SMESH_Mesh::Dump(ostream& save)
 {
-  save << "========================== Dump contents of mesh ==========================" << endl;
-  save << "1) Total number of nodes:     " << NbNodes() << endl;
-  save << "2) Total number of edges:     " << NbEdges() << endl;
-  save << "3) Total number of faces:     " << NbFaces() << endl;
-  if ( NbFaces() > 0 ) {
-    int nb3 = NbTriangles();
-    int nb4 = NbQuadrangles();
-    save << "3.1.) Number of triangles:    " << nb3 << endl;
-    save << "3.2.) Number of quadrangles:  " << nb4 << endl;
-    if ( nb3 + nb4 !=  NbFaces() ) {
-      map<int,int> myFaceMap;
-      SMDS_FaceIteratorPtr itFaces=_myMeshDS->facesIterator();
-      while( itFaces->more( ) ) {
-       int nbNodes = itFaces->next()->NbNodes();
-       if ( myFaceMap.find( nbNodes ) == myFaceMap.end() )
-         myFaceMap[ nbNodes ] = 0;
-       myFaceMap[ nbNodes ] = myFaceMap[ nbNodes ] + 1;
+  int clause = 0;
+  save << "========================== Dump contents of mesh ==========================" << endl << endl;
+  save << ++clause << ") Total number of        nodes:     " << NbNodes() << endl << endl;
+  for ( int isQuadratic = 0; isQuadratic < 2; ++isQuadratic )
+  {
+    string orderStr = isQuadratic ? "quadratic" : "linear";
+    ElementOrder order  = isQuadratic ? ORDER_QUADRATIC : ORDER_LINEAR;
+
+    save << ++clause << ") Total number of " << orderStr << " edges:     " << NbEdges(order) << endl;
+    save << ++clause << ") Total number of " << orderStr << " faces:     " << NbFaces(order) << endl;
+    if ( NbFaces(order) > 0 ) {
+      int nb3 = NbTriangles(order);
+      int nb4 = NbQuadrangles(order);
+      save << clause << ".1.) Number of " << orderStr << " triangles:    " << nb3 << endl;
+      save << clause << ".2.) Number of " << orderStr << " quadrangles:  " << nb4 << endl;
+      if ( nb3 + nb4 !=  NbFaces(order) ) {
+        map<int,int> myFaceMap;
+        SMDS_FaceIteratorPtr itFaces=_myMeshDS->facesIterator();
+        while( itFaces->more( ) ) {
+          int nbNodes = itFaces->next()->NbNodes();
+          if ( myFaceMap.find( nbNodes ) == myFaceMap.end() )
+            myFaceMap[ nbNodes ] = 0;
+          myFaceMap[ nbNodes ] = myFaceMap[ nbNodes ] + 1;
+        }
+        save << clause << ".3.) Faces in detail: " << endl;
+        map <int,int>::iterator itF;
+        for (itF = myFaceMap.begin(); itF != myFaceMap.end(); itF++)
+          save << "--> nb nodes: " << itF->first << " - nb elemens: " << itF->second << endl;
       }
-      save << "3.3.) Faces in detail: " << endl;
-      map <int,int>::iterator itF;
-      for (itF = myFaceMap.begin(); itF != myFaceMap.end(); itF++)
-       save << "--> nb nodes: " << itF->first << " - nb elemens: " << itF->second << endl;
     }
-  }
-  save << "4) Total number of volumes:   " << NbVolumes() << endl;
-  if ( NbVolumes() > 0 ) {
-    int nb8 = NbHexas();
-    int nb4 = NbTetras();
-    int nb5 = NbPyramids();
-    int nb6 = NbPrisms();
-    save << "4.1.) Number of hexahedrons:  " << nb8 << endl;
-    save << "4.2.) Number of tetrahedrons: " << nb4 << endl;
-    save << "4.3.) Number of prisms:       " << nb6 << endl;
-    save << "4.4.) Number of pyramides:    " << nb5 << endl;
-    if ( nb8 + nb4 + nb5 + nb6 != NbVolumes() ) {
-      map<int,int> myVolumesMap;
-      SMDS_VolumeIteratorPtr itVolumes=_myMeshDS->volumesIterator();
-      while( itVolumes->more( ) ) {
-       int nbNodes = itVolumes->next()->NbNodes();
-       if ( myVolumesMap.find( nbNodes ) == myVolumesMap.end() )
-         myVolumesMap[ nbNodes ] = 0;
-       myVolumesMap[ nbNodes ] = myVolumesMap[ nbNodes ] + 1;
+    save << ++clause << ") Total number of " << orderStr << " volumes:   " << NbVolumes(order) << endl;
+    if ( NbVolumes(order) > 0 ) {
+      int nb8 = NbHexas(order);
+      int nb4 = NbTetras(order);
+      int nb5 = NbPyramids(order);
+      int nb6 = NbPrisms(order);
+      save << clause << ".1.) Number of " << orderStr << " hexahedrons:  " << nb8 << endl;
+      save << clause << ".2.) Number of " << orderStr << " tetrahedrons: " << nb4 << endl;
+      save << clause << ".3.) Number of " << orderStr << " prisms:       " << nb6 << endl;
+      save << clause << ".4.) Number of " << orderStr << " pyramides:    " << nb5 << endl;
+      if ( nb8 + nb4 + nb5 + nb6 != NbVolumes(order) ) {
+        map<int,int> myVolumesMap;
+        SMDS_VolumeIteratorPtr itVolumes=_myMeshDS->volumesIterator();
+        while( itVolumes->more( ) ) {
+          int nbNodes = itVolumes->next()->NbNodes();
+          if ( myVolumesMap.find( nbNodes ) == myVolumesMap.end() )
+            myVolumesMap[ nbNodes ] = 0;
+          myVolumesMap[ nbNodes ] = myVolumesMap[ nbNodes ] + 1;
+        }
+        save << clause << ".5.) Volumes in detail: " << endl;
+        map <int,int>::iterator itV;
+        for (itV = myVolumesMap.begin(); itV != myVolumesMap.end(); itV++)
+          save << "--> nb nodes: " << itV->first << " - nb elemens: " << itV->second << endl;
       }
-      save << "4.5.) Volumes in detail: " << endl;
-      map <int,int>::iterator itV;
-      for (itV = myVolumesMap.begin(); itV != myVolumesMap.end(); itV++)
-       save << "--> nb nodes: " << itV->first << " - nb elemens: " << itV->second << endl;
     }
+    save << endl;
   }
   save << "===========================================================================" << endl;
   return save;
 }
+
+//=======================================================================
+//function : GetElementType
+//purpose  : Returns type of mesh element with certain id
+//=======================================================================
+SMDSAbs_ElementType SMESH_Mesh::GetElementType( const int id, const bool iselem )
+{
+  return _myMeshDS->GetElementType( id, iselem );
+}