Salome HOME
PAL20461 4.x Wrong mesh after creation of 3D mesh from 2D skin.
[modules/smesh.git] / src / SMESH / SMESH_subMesh.cxx
index 7c9cba60ff66d9ac8dee4bcae61db7eae66d316f..728e4bae6596667d0c44b5fcde82a7a74f4df583 100644 (file)
 #include <BRep_Builder.hxx>
 #include <BRep_Tool.hxx>
 #include <TopExp.hxx>
-#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
 #include <TopTools_IndexedMapOfShape.hxx>
 #include <TopTools_ListIteratorOfListOfShape.hxx>
-#include <TopTools_ListOfShape.hxx>
-#include <TopTools_MapOfShape.hxx>
 #include <TopoDS.hxx>
 #include <TopoDS_Compound.hxx>
 #include <gp_Pnt.hxx>
+#include <TopExp_Explorer.hxx>
+#include <TopoDS_Iterator.hxx>
 
-#include <Standard_Failure.hxx>
+#include <Standard_OutOfMemory.hxx>
 #include <Standard_ErrorHandler.hxx>
 
 using namespace std;
 
+//=============================================================================
+/*!
+ * \brief Allocate some memory at construction and release it at destruction.
+ * Is used to be able to continue working after mesh generation breaks due to
+ * lack of memory
+ */
+//=============================================================================
+
+struct MemoryReserve
+{
+  char* myBuf;
+  MemoryReserve(): myBuf( new char[1024*1024*2] ){}
+  ~MemoryReserve() { delete [] myBuf; }
+};
+
 //=============================================================================
 /*!
  *  default constructor:
@@ -172,6 +186,19 @@ void SMESH_subMesh::SetIsAlwaysComputed(bool isAlCo)
     ComputeStateEngine( CHECK_COMPUTE_STATE );
 }
 
+//=======================================================================
+/*!
+ * \brief Return true if no mesh entities is bound to the submesh
+ */
+//=======================================================================
+
+bool SMESH_subMesh::IsEmpty() const
+{
+  if (SMESHDS_SubMesh * subMeshDS = ((SMESH_subMesh*)this)->GetSubMeshDS())
+    return (!subMeshDS->GetNodes()->more() && !subMeshDS->GetElements()->more());
+  return true;
+}
+
 //=======================================================================
 //function : IsMeshComputed
 //purpose  : check if _subMeshDS contains mesh elements
@@ -397,10 +424,12 @@ const map < int, SMESH_subMesh * >& SMESH_subMesh::DependsOn()
   case TopAbs_SOLID:
     {
       //MESSAGE("solid");
-      for (TopExp_Explorer exp(_subShape, TopAbs_FACE); exp.More();
-           exp.Next())
-      {
-        InsertDependence(exp.Current());
+      if(_father->HasShapeToMesh()) {
+        for (TopExp_Explorer exp(_subShape, TopAbs_FACE); exp.More();
+             exp.Next())
+        {
+          InsertDependence(exp.Current());
+        }
       }
       break;
     }
@@ -482,10 +511,14 @@ bool SMESH_subMesh::CanAddHypothesis(const SMESH_Hypothesis* theHypothesis) cons
 {
   int aHypDim   = theHypothesis->GetDim();
   int aShapeDim = SMESH_Gen::GetShapeDim(_subShape);
+  if (aHypDim == 3 && aShapeDim == 3) {
+    // check case of open shell
+    //if (_subShape.ShapeType() == TopAbs_SHELL && !_subShape.Closed())
+    if (_subShape.ShapeType() == TopAbs_SHELL && !BRep_Tool::IsClosed(_subShape))
+      return false;
+  }
   if ( aHypDim <= aShapeDim )
     return true;
-//   if ( aHypDim < aShapeDim )
-//     return ( _father->IsMainShape( _subShape ));
 
   return false;
 }
@@ -559,13 +592,18 @@ SMESH_Hypothesis::Hypothesis_Status
         return SMESH_Hypothesis::HYP_OK;
     }
     // 0D hypothesis
-    else if ( _algoState == HYP_OK ) { // update default _algoState
-      _algoState = NO_ALGO;
-      algo = gen->GetAlgo(*_father, _subShape);
-      if ( algo ) {
-        _algoState = MISSING_HYP;
-        if ( algo->CheckHypothesis(*_father,_subShape, aux_ret))
-          _algoState = HYP_OK;
+    else if ( _algoState == HYP_OK ) {
+      // update default _algoState
+      if ( event != REMOVE_FATHER_ALGO )
+      {
+        _algoState = NO_ALGO;
+        algo = gen->GetAlgo(*_father, _subShape);
+        if ( algo ) {
+          _algoState = MISSING_HYP;
+          if ( event == REMOVE_FATHER_HYP ||
+               algo->CheckHypothesis(*_father,_subShape, aux_ret))
+            _algoState = HYP_OK;
+        }
       }
     }
   }
@@ -582,7 +620,7 @@ SMESH_Hypothesis::Hypothesis_Status
     // -------------------------------------------
     algo = static_cast< SMESH_Algo* >( anHyp );
     if ( !_father->HasShapeToMesh() && algo->NeedShape() )
-      return SMESH_Hypothesis::HYP_BAD_GEOMETRY;
+      return SMESH_Hypothesis::HYP_NEED_SHAPE;
     // ----------------------
     // check mesh conformity
     // ----------------------
@@ -603,49 +641,6 @@ SMESH_Hypothesis::Hypothesis_Status
 
     if ( !meshDS->AddHypothesis(_subShape, anHyp))
       return SMESH_Hypothesis::HYP_ALREADY_EXIST;
-
-    // Serve Propagation of 1D hypothesis
-    // NOTE: it is possible to re-implement Propagation using EventListener
-    if (event == ADD_HYP) {
-      bool isPropagationOk = true;
-      bool isPropagationHyp = ( strcmp( "Propagation", anHyp->GetName() ) == 0 );
-
-      if ( isPropagationHyp ) {
-        TopExp_Explorer exp (_subShape, TopAbs_EDGE);
-        TopTools_MapOfShape aMap;
-        for (; exp.More(); exp.Next()) {
-          if (aMap.Add(exp.Current())) {
-            if (!_father->BuildPropagationChain(exp.Current())) {
-              isPropagationOk = false;
-            }
-          }
-        }
-      }
-      else if (anHyp->GetDim() == 1) { // Only 1D hypothesis can be propagated
-        TopExp_Explorer exp (_subShape, TopAbs_EDGE);
-        TopTools_MapOfShape aMap;
-        for (; exp.More(); exp.Next()) {
-          if (aMap.Add(exp.Current())) {
-            TopoDS_Shape aMainEdge;
-            if (_father->IsPropagatedHypothesis(exp.Current(), aMainEdge)) {
-              isPropagationOk = _father->RebuildPropagationChains();
-            } else if (_father->IsPropagationHypothesis(exp.Current())) {
-              isPropagationOk = _father->BuildPropagationChain(exp.Current());
-            } else {
-            }
-          }
-        }
-      } else {
-      }
-
-      if ( isPropagationOk ) {
-        if ( isPropagationHyp )
-          return ret; // nothing more to do for "Propagation" hypothesis
-      }
-      else if ( ret < SMESH_Hypothesis::HYP_CONCURENT) {
-        ret = SMESH_Hypothesis::HYP_CONCURENT;
-      }
-    } // Serve Propagation of 1D hypothesis
   }
 
   // --------------------------
@@ -656,45 +651,7 @@ SMESH_Hypothesis::Hypothesis_Status
     if (!meshDS->RemoveHypothesis(_subShape, anHyp))
       return SMESH_Hypothesis::HYP_OK; // nothing changes
 
-    // Serve Propagation of 1D hypothesis
-    // NOTE: it is possible to re-implement Propagation using EventListener
-    if (event == REMOVE_HYP)
-    {
-      bool isPropagationOk = true;
-      SMESH_HypoFilter propagFilter( SMESH_HypoFilter::HasName( "Propagation" ));
-      bool isPropagationHyp = propagFilter.IsOk( anHyp, _subShape );
-
-      if ( isPropagationHyp )
-      {
-        TopExp_Explorer exp (_subShape, TopAbs_EDGE);
-        TopTools_MapOfShape aMap;
-        for (; exp.More(); exp.Next()) {
-          if (aMap.Add(exp.Current()) &&
-              !_father->GetHypothesis( exp.Current(), propagFilter, true )) {
-            // no more Propagation on the current edge
-            if (!_father->RemovePropagationChain(exp.Current())) {
-              return SMESH_Hypothesis::HYP_UNKNOWN_FATAL;
-            }
-          }
-        }
-        // rebuild propagation chains, because removing one
-        // chain can resolve concurention, existing before
-        isPropagationOk = _father->RebuildPropagationChains();
-      }
-      else if (anHyp->GetDim() == 1) // Only 1D hypothesis can be propagated
-      {
-        isPropagationOk = _father->RebuildPropagationChains();
-      }
-
-      if ( isPropagationOk ) {
-        if ( isPropagationHyp )
-          return ret; // nothing more to do for "Propagation" hypothesis
-      }
-      else if ( ret < SMESH_Hypothesis::HYP_CONCURENT) {
-        ret = SMESH_Hypothesis::HYP_CONCURENT;
-      }
-    } // Serve Propagation of 1D hypothesis
-    else // event == REMOVE_ALGO
+    if (event == REMOVE_ALGO)
     {
       algo = dynamic_cast<SMESH_Algo*> (anHyp);
       if (!algo->NeedDescretBoundary())
@@ -705,6 +662,7 @@ SMESH_Hypothesis::Hypothesis_Status
         CleanDependants();
        ComputeStateEngine( CLEAN );
         CleanDependsOn();
+        ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE );
       }
     }
   }
@@ -1024,11 +982,13 @@ SMESH_Hypothesis::Hypothesis_Status
     TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
     for ( ; ( ret == SMESH_Hypothesis::HYP_OK && it.More()); it.Next() ) {
       if ( SMESH_Algo* upperAlgo = gen->GetAlgo( *_father, it.Value() ))
-        if ( !upperAlgo->NeedDescretBoundary() )
+        if ( !upperAlgo->NeedDescretBoundary() && !upperAlgo->SupportSubmeshes())
           ret = SMESH_Hypothesis::HYP_HIDDEN_ALGO;
     }
     // is algo hiding?
-    if ( ret == SMESH_Hypothesis::HYP_OK && !algo->NeedDescretBoundary() ) {
+    if ( ret == SMESH_Hypothesis::HYP_OK &&
+         !algo->NeedDescretBoundary()    &&
+         !algo->SupportSubmeshes()) {
       map<int, SMESH_subMesh*>::reverse_iterator i_sm = _mapDepend.rbegin();
       for ( ; ( ret == SMESH_Hypothesis::HYP_OK && i_sm != _mapDepend.rend()) ; ++i_sm )
         if ( gen->GetAlgo( *_father, i_sm->second->_subShape ))
@@ -1045,6 +1005,7 @@ SMESH_Hypothesis::Hypothesis_Status
 
   if ( stateChange && oldAlgoState == HYP_OK ) { // hyp becomes KO
     DeleteOwnListeners();
+    SetIsAlwaysComputed( false );
     if (_subShape.ShapeType() == TopAbs_VERTEX ) {
       // restore default states
       _algoState = HYP_OK;
@@ -1134,7 +1095,7 @@ SMESH_Hypothesis::Hypothesis_Status
   SMESH_Hypothesis::Hypothesis_Status ret = SMESH_Hypothesis::HYP_OK;
   //EAP: a wire (dim==1) should notify edges (dim==1)
   //EAP: int dim = SMESH_Gen::GetShapeDim(_subShape);
-  if (_subShape.ShapeType() < TopAbs_EDGE ) // wire,face etc
+  //if (_subShape.ShapeType() < TopAbs_EDGE ) // wire,face etc
   {
     SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
     while ( smIt->more() ) {
@@ -1236,7 +1197,7 @@ static void cleanSubMesh( SMESH_subMesh * subMesh )
       while (itn->more()) {
         const SMDS_MeshNode * node = itn->next();
         //MESSAGE( " RM node: "<<node->GetID());
-        if ( node->NbInverseNodes() == 0 )
+        if ( node->NbInverseElements() == 0 )
           meshDS->RemoveFreeNode(node, subMeshDS);
         else // for StdMeshers_CompositeSegment_1D: node in one submesh, edge in another
           meshDS->RemoveNode(node);
@@ -1264,7 +1225,12 @@ bool SMESH_subMesh::ComputeStateEngine(int event)
     _computeState = READY_TO_COMPUTE;
     SMESHDS_SubMesh* smDS = GetSubMeshDS();
     if ( smDS && smDS->NbNodes() ) {
-      _computeState = COMPUTE_OK;
+      if ( event == CLEAN ) {
+        CleanDependants();
+        cleanSubMesh( this );
+      }
+      else
+        _computeState = COMPUTE_OK;
     }
     else if ( event == COMPUTE && !_alwaysComputed ) {
       const TopoDS_Vertex & V = TopoDS::Vertex( _subShape );
@@ -1350,22 +1316,29 @@ bool SMESH_subMesh::ComputeStateEngine(int event)
           SetAlgoState(MISSING_HYP);
           break;
         }
+        TopoDS_Shape shape = _subShape;
         // check submeshes needed
         if (_father->HasShapeToMesh() ) {
-          bool subComputed = SubMeshesComputed();
+          bool subComputed = false;
+          if (!algo->OnlyUnaryInput())
+            shape = GetCollection( gen, algo, subComputed );
+          else
+            subComputed = SubMeshesComputed();
           ret = ( algo->NeedDescretBoundary() ? subComputed :
+                  algo->SupportSubmeshes() ? true :
                   ( !subComputed || _father->IsNotConformAllowed() ));
           if (!ret) {
             _computeState = FAILED_TO_COMPUTE;
             if ( !algo->NeedDescretBoundary() )
               _computeError =
-                SMESH_ComputeError::New(COMPERR_BAD_INPUT_MESH,"Unexpected submesh",algo);
+                SMESH_ComputeError::New(COMPERR_BAD_INPUT_MESH,
+                                        "Unexpected computed submesh",algo);
             break;
           }
         }
         // compute
-        CleanDependants();
-        RemoveSubMeshElementsAndNodes();
+//         CleanDependants(); for "UseExisting_*D" algos
+//         RemoveSubMeshElementsAndNodes();
         ret = false;
         _computeState = FAILED_TO_COMPUTE;
         _computeError = SMESH_ComputeError::New(COMPERR_OK,"",algo);
@@ -1374,43 +1347,54 @@ bool SMESH_subMesh::ComputeStateEngine(int event)
           OCC_CATCH_SIGNALS;
 #endif
           algo->InitComputeError();
+          MemoryReserve aMemoryReserve;
+          SMDS_Mesh::CheckMemory();
           if ( !_father->HasShapeToMesh() ) // no shape
           {
             SMESH_MesherHelper helper( *_father );
-            helper.SetSubShape( _subShape );
+            helper.SetSubShape( shape );
             helper.SetElementsOnShape( true );
             ret = algo->Compute(*_father, &helper );
           }
           else
           {
-            if (!algo->NeedDescretBoundary() && !algo->OnlyUnaryInput()) {
-              ret = ApplyToCollection( algo, GetCollection( gen, algo ) );
-              break;
-            }
-            else {
-              ret = algo->Compute((*_father), _subShape);
-            }
+            ret = algo->Compute((*_father), shape);
           }
-          if ( !ret )
+          if ( !ret && _computeError->IsOK() ) // algo can set _computeError of submesh
             _computeError = algo->GetComputeError();
         }
-        catch (Standard_Failure& exc) {
+        catch ( std::bad_alloc& exc ) {
+          MESSAGE("std::bad_alloc thrown inside algo->Compute()");
+          if ( _computeError ) {
+            _computeError->myName = COMPERR_MEMORY_PB;
+            //_computeError->myComment = exc.what();
+          }
+          cleanSubMesh( this );
+          throw exc;
+        }
+        catch ( Standard_OutOfMemory& exc ) {
+          MESSAGE("Standard_OutOfMemory thrown inside algo->Compute()");
+          if ( _computeError ) {
+            _computeError->myName = COMPERR_MEMORY_PB;
+            //_computeError->myComment = exc.what();
+          }
+          cleanSubMesh( this );
+          throw std::bad_alloc();
+        }
+        catch (Standard_Failure& ex) {
           if ( !_computeError ) _computeError = SMESH_ComputeError::New();
           _computeError->myName    = COMPERR_OCC_EXCEPTION;
-          _computeError->myComment = exc.GetMessageString();
+          _computeError->myComment += ex.DynamicType()->Name();
+          if ( ex.GetMessageString() && strlen( ex.GetMessageString() )) {
+            _computeError->myComment += ": ";
+            _computeError->myComment += ex.GetMessageString();
+          }
         }
         catch ( SALOME_Exception& S_ex ) {
           if ( !_computeError ) _computeError = SMESH_ComputeError::New();
           _computeError->myName    = COMPERR_SLM_EXCEPTION;
           _computeError->myComment = S_ex.what();
         }
-        catch ( std::bad_alloc& exc ) {
-          if ( _computeError ) {
-            _computeError->myName    = COMPERR_MEMORY_PB;
-            _computeError->myComment = exc.what();
-          }
-          throw exc;
-        }
         catch ( std::exception& exc ) {
           if ( !_computeError ) _computeError = SMESH_ComputeError::New();
           _computeError->myName    = COMPERR_STD_EXCEPTION;
@@ -1422,28 +1406,24 @@ bool SMESH_subMesh::ComputeStateEngine(int event)
           else
             ret = false;
         }
-        if ( ret && _computeError && !_computeError->IsOK() ) {
-          ret = false;
-        }
-        if (ret) { // check if anything was built
+        if (ret && !_alwaysComputed && shape == _subShape) { // check if anything was built
           ret = ( GetSubMeshDS() && ( GetSubMeshDS()->NbElements() || GetSubMeshDS()->NbNodes() ));
         }
-        if (!ret)
+        bool isComputeErrorSet = !CheckComputeError( algo, shape );
+        if (!ret && !isComputeErrorSet)
         {
           // Set _computeError
           if ( !_computeError )
             _computeError = SMESH_ComputeError::New();
           if ( _computeError->IsOK() )
             _computeError->myName = COMPERR_ALGO_FAILED;
+          _computeState = FAILED_TO_COMPUTE;
         }
-        else
+        if (ret)
         {
           _computeError.reset();
-          UpdateDependantsState( SUBMESH_COMPUTED ); // send event SUBMESH_COMPUTED
         }
-        if ( !algo->NeedDescretBoundary() )
-          UpdateSubMeshState( ret ? COMPUTE_OK : FAILED_TO_COMPUTE );
-        CheckComputeError( algo );
+        UpdateDependantsState( SUBMESH_COMPUTED ); // send event SUBMESH_COMPUTED
       }
       break;
     case CLEAN:
@@ -1534,6 +1514,9 @@ bool SMESH_subMesh::ComputeStateEngine(int event)
     switch (event)
     {
     case MODIF_ALGO_STATE:
+      algo = gen->GetAlgo((*_father), _subShape);
+      if (algo && !algo->NeedDescretBoundary())
+        CleanDependsOn(); // clean sub-meshes with event CLEAN
       if (_algoState == HYP_OK)
         _computeState = READY_TO_COMPUTE;
       else
@@ -1584,53 +1567,80 @@ bool SMESH_subMesh::ComputeStateEngine(int event)
 
 //=======================================================================
 /*!
- * \brief Update compute_state by _computeError
+ * \brief Update compute_state by _computeError and send proper events to
+ * dependent submeshes
+  * \retval bool - true if _computeError is NOT set
  */
 //=======================================================================
 
-bool SMESH_subMesh::CheckComputeError(SMESH_Algo* theAlgo)
+bool SMESH_subMesh::CheckComputeError(SMESH_Algo* theAlgo, const TopoDS_Shape& theShape)
 {
-  bool noErrors = ( !_computeError || _computeError->IsOK() );
-  if ( !noErrors )
+  bool noErrors = true;
+
+  if ( !theShape.IsNull() )
   {
-    if ( !_computeError->myAlgo )
-      _computeError->myAlgo = theAlgo;
-
-    // Show error
-    SMESH_Comment text;
-    text << theAlgo->GetName() << " failed on subshape " << _Id << " with error ";
-    if (_computeError->IsCommon() )
-      text << _computeError->CommonName();
+    // Check state of submeshes
+    if ( !theAlgo->NeedDescretBoundary())
+    {
+      SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
+      while ( smIt->more() )
+        if ( !smIt->next()->CheckComputeError( theAlgo ))
+          noErrors = false;
+    }
+
+    // Check state of neighbours
+    if ( !theAlgo->OnlyUnaryInput() &&
+         theShape.ShapeType() == TopAbs_COMPOUND &&
+         !theShape.IsSame( _subShape ))
+    {
+      for (TopoDS_Iterator subIt( theShape ); subIt.More(); subIt.Next()) {
+        SMESH_subMesh* sm = _father->GetSubMesh( subIt.Value() );
+        if ( sm != this ) {
+          if ( !sm->CheckComputeError( theAlgo, sm->GetSubShape() ))
+            noErrors = false;
+          UpdateDependantsState( SUBMESH_COMPUTED ); // send event SUBMESH_COMPUTED
+        }
+      }
+    }
+  }
+  {
+    // Check my state
+    if ( !_computeError || _computeError->IsOK() )
+    {
+      _computeState = COMPUTE_OK;
+    }
     else
-      text << _computeError->myName;
-    if ( _computeError->myComment.size() > 0 )
-      text << " \"" << _computeError->myComment << "\"";
+    {
+      if ( !_computeError->myAlgo )
+        _computeError->myAlgo = theAlgo;
+
+      // Show error
+      SMESH_Comment text;
+      text << theAlgo->GetName() << " failed on subshape #" << _Id << " with error ";
+      if (_computeError->IsCommon() )
+        text << _computeError->CommonName();
+      else
+        text << _computeError->myName;
+      if ( _computeError->myComment.size() > 0 )
+        text << " \"" << _computeError->myComment << "\"";
 
 #ifdef _DEBUG_
-    cout << text << endl;
-    // Show vertices location of a failed shape
-    cout << "Subshape vertices (first 10):" << endl;
-    TopTools_IndexedMapOfShape vMap;
-    TopExp::MapShapes( _subShape, TopAbs_VERTEX, vMap );
-    for ( int iv = 1; iv <= vMap.Extent() && iv < 11; ++iv ) {
-      gp_Pnt P( BRep_Tool::Pnt( TopoDS::Vertex( vMap( iv ) )));
-      cout << P.X() << " " << P.Y() << " " << P.Z() << " " << endl;
-    }
+      MESSAGE_BEGIN ( text );
+      // Show vertices location of a failed shape
+      TopTools_IndexedMapOfShape vMap;
+      TopExp::MapShapes( _subShape, TopAbs_VERTEX, vMap );
+      MESSAGE_ADD ( "Subshape vertices " << ( vMap.Extent()>10 ? "(first 10):" : ":") );
+      for ( int iv = 1; iv <= vMap.Extent() && iv < 11; ++iv ) {
+        gp_Pnt P( BRep_Tool::Pnt( TopoDS::Vertex( vMap( iv ) )));
+        MESSAGE_ADD ( "#" << _father->GetMeshDS()->ShapeToIndex( vMap( iv )) << " "
+                   << P.X() << " " << P.Y() << " " << P.Z() << " " );
+      }
 #else
-    INFOS( text );
+      INFOS( text );
 #endif
-    _computeState = FAILED_TO_COMPUTE;
-  }
-  else
-  {
-    _computeState = COMPUTE_OK;
-  }
-  // Check state of submeshes
-  if ( !theAlgo->NeedDescretBoundary() /*&& theAlgo->OnlyUnaryInput()*/ ) {
-    SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(false,false);
-    while ( smIt->more() )
-      if ( !smIt->next()->CheckComputeError( theAlgo ))
-        noErrors = false;
+      _computeState = FAILED_TO_COMPUTE;
+      noErrors = false;
+    }
   }
   return noErrors;
 }
@@ -1779,10 +1789,13 @@ void SMESH_subMesh::RemoveSubMeshElementsAndNodes()
 //           meshed at once along with _subShape
 //=======================================================================
 
-TopoDS_Shape SMESH_subMesh::GetCollection(SMESH_Gen * theGen, SMESH_Algo* theAlgo)
+TopoDS_Shape SMESH_subMesh::GetCollection(SMESH_Gen * theGen,
+                                          SMESH_Algo* theAlgo,
+                                          bool &      theSubComputed)
 {
   MESSAGE("SMESH_subMesh::GetCollection");
-  ASSERT (!theAlgo->NeedDescretBoundary());
+
+  theSubComputed = SubMeshesComputed();
 
   TopoDS_Shape mainShape = _father->GetMeshDS()->ShapeToMesh();
 
@@ -1812,9 +1825,11 @@ TopoDS_Shape SMESH_subMesh::GetCollection(SMESH_Gen * theGen, SMESH_Algo* theAlg
     else if ( subMesh->GetComputeState() == READY_TO_COMPUTE )
     {
       SMESH_Algo* anAlgo = theGen->GetAlgo( *_father, S );
-      if (anAlgo == theAlgo &&
-          anAlgo->GetUsedHypothesis( *_father, S, ignoreAuxiliaryHyps ) == aUsedHyp)
+      if (strcmp( anAlgo->GetName(), theAlgo->GetName()) == 0 && // same algo
+          anAlgo->GetUsedHypothesis( *_father, S, ignoreAuxiliaryHyps ) == aUsedHyp) // same hyps
         aBuilder.Add( aCompound, S );
+      if ( !subMesh->SubMeshesComputed() )
+        theSubComputed = false;
     }
   }
 
@@ -1929,8 +1944,9 @@ void SMESH_subMesh::SetEventListener(EventListener* listener, EventListenerData*
   map< EventListener*, EventListenerData* >::iterator l_d =
     myEventListeners.find( listener );
   if ( l_d != myEventListeners.end() ) {
-    if ( l_d->second && l_d->second->IsDeletable() )
-      delete l_d->second;
+    EventListenerData* curData = l_d->second;
+    if ( curData && curData != data && curData->IsDeletable() )
+      delete curData;
     l_d->second = data;
   }
   else 
@@ -2031,13 +2047,17 @@ void SMESH_subMeshEventListener::ProcessEvent(const int          event,
        eventType == SMESH_subMesh::COMPUTE_EVENT)
   {
     ASSERT( data->mySubMeshes.front() != subMesh );
+    list<SMESH_subMesh*>::iterator smIt = data->mySubMeshes.begin();
+    list<SMESH_subMesh*>::iterator smEnd = data->mySubMeshes.end();
     switch ( event ) {
     case SMESH_subMesh::CLEAN:
-      data->mySubMeshes.front()->ComputeStateEngine( event );
+      for ( ; smIt != smEnd; ++ smIt)
+        (*smIt)->ComputeStateEngine( event );
       break;
     case SMESH_subMesh::COMPUTE:
       if ( subMesh->GetComputeState() == SMESH_subMesh::COMPUTE_OK )
-        data->mySubMeshes.front()->ComputeStateEngine( SMESH_subMesh::SUBMESH_COMPUTED );
+        for ( ; smIt != smEnd; ++ smIt)
+          (*smIt)->ComputeStateEngine( SMESH_subMesh::SUBMESH_COMPUTED );
       break;
     default:;
     }
@@ -2058,7 +2078,8 @@ namespace {
               SMESH_subMesh*                 prepend,
               SMESH_subMesh*                 append): myIt(subIt),myAppend(append)
     {
-      myCur = prepend ? prepend : myIt->more() ? myIt->next() : 0;
+      myCur = prepend ? prepend : myIt->more() ? myIt->next() : append;
+      if ( myCur == append ) append = 0;
     }
     /// Return true if and only if there are other object in this iterator
     virtual bool more()