Salome HOME
NPAL16168 (geometrical group edition from a submesh don't modifiy mesh computation)
[modules/smesh.git] / src / SMESH / SMESH_Mesh.cxx
1 //  SMESH SMESH : implementaion of SMESH idl descriptions
2 //
3 //  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
5 // 
6 //  This library is free software; you can redistribute it and/or 
7 //  modify it under the terms of the GNU Lesser General Public 
8 //  License as published by the Free Software Foundation; either 
9 //  version 2.1 of the License. 
10 // 
11 //  This library is distributed in the hope that it will be useful, 
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of 
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
14 //  Lesser General Public License for more details. 
15 // 
16 //  You should have received a copy of the GNU Lesser General Public 
17 //  License along with this library; if not, write to the Free Software 
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA 
19 // 
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //
23 //
24 //  File   : SMESH_Mesh.cxx
25 //  Author : Paul RASCLE, EDF
26 //  Module : SMESH
27 //  $Header$
28
29 #include "SMESH_Mesh.hxx"
30 #include "SMESH_subMesh.hxx"
31 #include "SMESH_Gen.hxx"
32 #include "SMESH_Hypothesis.hxx"
33 #include "SMESH_Group.hxx"
34 #include "SMESH_HypoFilter.hxx"
35 #include "SMESHDS_Group.hxx"
36 #include "SMESHDS_Script.hxx"
37 #include "SMESHDS_GroupOnGeom.hxx"
38 #include "SMDS_MeshVolume.hxx"
39
40 #include "utilities.h"
41
42 #include "DriverMED_W_SMESHDS_Mesh.h"
43 #include "DriverDAT_W_SMDS_Mesh.h"
44 #include "DriverUNV_W_SMDS_Mesh.h"
45 #include "DriverSTL_W_SMDS_Mesh.h"
46
47 #include "DriverMED_R_SMESHDS_Mesh.h"
48 #include "DriverUNV_R_SMDS_Mesh.h"
49 #include "DriverSTL_R_SMDS_Mesh.h"
50
51 #include <BRepTools_WireExplorer.hxx>
52 #include <BRepPrimAPI_MakeBox.hxx>
53 #include <BRep_Builder.hxx>
54 #include <gp_Pnt.hxx>
55
56 #include <TCollection_AsciiString.hxx>
57 #include <TopExp.hxx>
58 #include <TopTools_ListOfShape.hxx>
59 #include <TopTools_Array1OfShape.hxx>
60 #include <TopTools_ListIteratorOfListOfShape.hxx>
61 #include <TopTools_MapOfShape.hxx>
62
63 #include <memory>
64
65 #include "Utils_ExceptHandlers.hxx"
66
67 // maximum stored group name length in MED file
68 #define MAX_MED_GROUP_NAME_LENGTH 80
69
70 #ifdef _DEBUG_
71 static int MYDEBUG = 0;
72 #else
73 static int MYDEBUG = 0;
74 #endif
75
76 #define cSMESH_Hyp(h) static_cast<const SMESH_Hypothesis*>(h)
77
78 typedef SMESH_HypoFilter THypType;
79
80 //=============================================================================
81 /*!
82  * 
83  */
84 //=============================================================================
85
86 SMESH_Mesh::SMESH_Mesh(int               theLocalId, 
87                        int               theStudyId, 
88                        SMESH_Gen*        theGen,
89                        bool              theIsEmbeddedMode,
90                        SMESHDS_Document* theDocument):
91   _groupId( 0 )
92 {
93   MESSAGE("SMESH_Mesh::SMESH_Mesh(int localId)");
94   _id            = theLocalId;
95   _studyId       = theStudyId;
96   _gen           = theGen;
97   _myDocument    = theDocument;
98   _idDoc         = theDocument->NewMesh(theIsEmbeddedMode);
99   _myMeshDS      = theDocument->GetMesh(_idDoc);
100   _isShapeToMesh = false;
101   _myMeshDS->ShapeToMesh( PseudoShape() );
102 }
103
104 //=============================================================================
105 /*!
106  * 
107  */
108 //=============================================================================
109
110 SMESH_Mesh::~SMESH_Mesh()
111 {
112   INFOS("SMESH_Mesh::~SMESH_Mesh");
113
114   // delete groups
115   map < int, SMESH_Group * >::iterator itg;
116   for (itg = _mapGroup.begin(); itg != _mapGroup.end(); itg++) {
117     SMESH_Group *aGroup = (*itg).second;
118     delete aGroup;
119   }
120 }
121
122 //=============================================================================
123 /*!
124  * \brief Set geometry to be meshed
125  */
126 //=============================================================================
127
128 void SMESH_Mesh::ShapeToMesh(const TopoDS_Shape & aShape)
129 {
130   if(MYDEBUG) MESSAGE("SMESH_Mesh::ShapeToMesh");
131
132   if ( !aShape.IsNull() && _isShapeToMesh )
133     throw SALOME_Exception(LOCALIZED ("a shape to mesh has already been defined"));
134
135   // clear current data
136   if ( !_myMeshDS->ShapeToMesh().IsNull() )
137   {
138     // removal of a shape to mesh, delete objects referring to sub-shapes:
139     // - sub-meshes
140     map <int, SMESH_subMesh *>::iterator i_sm = _mapSubMesh.begin();
141     for ( ; i_sm != _mapSubMesh.end(); ++i_sm )
142       delete i_sm->second;
143     _mapSubMesh.clear();
144     //  - groups on geometry
145     map <int, SMESH_Group *>::iterator i_gr = _mapGroup.begin();
146     while ( i_gr != _mapGroup.end() ) {
147       if ( dynamic_cast<SMESHDS_GroupOnGeom*>( i_gr->second->GetGroupDS() )) {
148         _myMeshDS->RemoveGroup( i_gr->second->GetGroupDS() );
149         delete i_gr->second;
150         _mapGroup.erase( i_gr++ );
151       }
152       else
153         i_gr++;
154     }
155     _mapAncestors.Clear();
156     _mapPropagationChains.Clear();
157
158     // clear SMESHDS
159     TopoDS_Shape aNullShape;
160     _myMeshDS->ShapeToMesh( aNullShape );
161   }
162
163   // set a new geometry
164   if ( !aShape.IsNull() )
165   {
166     _myMeshDS->ShapeToMesh(aShape);
167     _isShapeToMesh = true;
168
169     // fill _mapAncestors
170     int desType, ancType;
171     for ( desType = TopAbs_VERTEX; desType > TopAbs_COMPOUND; desType-- )
172       for ( ancType = desType - 1; ancType >= TopAbs_COMPOUND; ancType-- )
173         TopExp::MapShapesAndAncestors ( aShape,
174                                         (TopAbs_ShapeEnum) desType,
175                                         (TopAbs_ShapeEnum) ancType,
176                                         _mapAncestors );
177   }
178 }
179
180 //=======================================================================
181 /*!
182  * \brief Return geometry to be meshed. (It may be a PseudoShape()!)
183  */
184 //=======================================================================
185
186 TopoDS_Shape SMESH_Mesh::GetShapeToMesh() const
187 {
188   return _myMeshDS->ShapeToMesh();
189 }
190
191 //=======================================================================
192 /*!
193  * \brief Return a solid which is returned by GetShapeToMesh() if
194  *        a real geometry to be meshed was not set
195  */
196 //=======================================================================
197
198 const TopoDS_Solid& SMESH_Mesh::PseudoShape()
199 {
200   static TopoDS_Solid aSolid;
201   if ( aSolid.IsNull() )
202   {
203     aSolid = BRepPrimAPI_MakeBox(1,1,1);
204   }
205   return aSolid;
206 }
207
208 //=======================================================================
209 //function : UNVToMesh
210 //purpose  : 
211 //=======================================================================
212
213 int SMESH_Mesh::UNVToMesh(const char* theFileName)
214 {
215   if(MYDEBUG) MESSAGE("UNVToMesh - theFileName = "<<theFileName);
216   if(_isShapeToMesh)
217     throw SALOME_Exception(LOCALIZED("a shape to mesh has already been defined"));
218   _isShapeToMesh = true;
219   DriverUNV_R_SMDS_Mesh myReader;
220   myReader.SetMesh(_myMeshDS);
221   myReader.SetFile(theFileName);
222   myReader.SetMeshId(-1);
223   myReader.Perform();
224   if(MYDEBUG){
225     MESSAGE("UNVToMesh - _myMeshDS->NbNodes() = "<<_myMeshDS->NbNodes());
226     MESSAGE("UNVToMesh - _myMeshDS->NbEdges() = "<<_myMeshDS->NbEdges());
227     MESSAGE("UNVToMesh - _myMeshDS->NbFaces() = "<<_myMeshDS->NbFaces());
228     MESSAGE("UNVToMesh - _myMeshDS->NbVolumes() = "<<_myMeshDS->NbVolumes());
229   }
230   SMDS_MeshGroup* aGroup = (SMDS_MeshGroup*) myReader.GetGroup();
231   if (aGroup != 0) {
232     TGroupNamesMap aGroupNames = myReader.GetGroupNamesMap();
233     //const TGroupIdMap& aGroupId = myReader.GetGroupIdMap();
234     aGroup->InitSubGroupsIterator();
235     while (aGroup->MoreSubGroups()) {
236       SMDS_MeshGroup* aSubGroup = (SMDS_MeshGroup*) aGroup->NextSubGroup();
237       std::string aName = aGroupNames[aSubGroup];
238       int aId;
239
240       SMESH_Group* aSMESHGroup = AddGroup( aSubGroup->GetType(), aName.c_str(), aId );
241       if ( aSMESHGroup ) {
242         if(MYDEBUG) MESSAGE("UNVToMesh - group added: "<<aName);      
243         SMESHDS_Group* aGroupDS = dynamic_cast<SMESHDS_Group*>( aSMESHGroup->GetGroupDS() );
244         if ( aGroupDS ) {
245           aGroupDS->SetStoreName(aName.c_str());
246           aSubGroup->InitIterator();
247           const SMDS_MeshElement* aElement = 0;
248           while (aSubGroup->More()) {
249             aElement = aSubGroup->Next();
250             if (aElement) {
251               aGroupDS->SMDSGroup().Add(aElement);
252             }
253           }
254           if (aElement)
255             aGroupDS->SetType(aElement->GetType());
256         }
257       }
258     }
259   }
260   return 1;
261 }
262
263 //=======================================================================
264 //function : MEDToMesh
265 //purpose  : 
266 //=======================================================================
267
268 int SMESH_Mesh::MEDToMesh(const char* theFileName, const char* theMeshName)
269 {
270   if(MYDEBUG) MESSAGE("MEDToMesh - theFileName = "<<theFileName<<", mesh name = "<<theMeshName);
271   if(_isShapeToMesh)
272     throw SALOME_Exception(LOCALIZED("a shape to mesh has already been defined"));
273   _isShapeToMesh = true;
274   DriverMED_R_SMESHDS_Mesh myReader;
275   myReader.SetMesh(_myMeshDS);
276   myReader.SetMeshId(-1);
277   myReader.SetFile(theFileName);
278   myReader.SetMeshName(theMeshName);
279   Driver_Mesh::Status status = myReader.Perform();
280   if(MYDEBUG){
281     MESSAGE("MEDToMesh - _myMeshDS->NbNodes() = "<<_myMeshDS->NbNodes());
282     MESSAGE("MEDToMesh - _myMeshDS->NbEdges() = "<<_myMeshDS->NbEdges());
283     MESSAGE("MEDToMesh - _myMeshDS->NbFaces() = "<<_myMeshDS->NbFaces());
284     MESSAGE("MEDToMesh - _myMeshDS->NbVolumes() = "<<_myMeshDS->NbVolumes());
285   }
286
287   // Reading groups (sub-meshes are out of scope of MED import functionality)
288   list<TNameAndType> aGroupNames = myReader.GetGroupNamesAndTypes();
289   if(MYDEBUG) MESSAGE("MEDToMesh - Nb groups = "<<aGroupNames.size()); 
290   int anId;
291   list<TNameAndType>::iterator name_type = aGroupNames.begin();
292   for ( ; name_type != aGroupNames.end(); name_type++ ) {
293     SMESH_Group* aGroup = AddGroup( name_type->second, name_type->first.c_str(), anId );
294     if ( aGroup ) {
295       if(MYDEBUG) MESSAGE("MEDToMesh - group added: "<<name_type->first.c_str());      
296       SMESHDS_Group* aGroupDS = dynamic_cast<SMESHDS_Group*>( aGroup->GetGroupDS() );
297       if ( aGroupDS ) {
298         aGroupDS->SetStoreName( name_type->first.c_str() );
299         myReader.GetGroup( aGroupDS );
300       }
301     }
302   }
303   return (int) status;
304 }
305
306 //=======================================================================
307 //function : STLToMesh
308 //purpose  : 
309 //=======================================================================
310
311 int SMESH_Mesh::STLToMesh(const char* theFileName)
312 {
313   if(MYDEBUG) MESSAGE("STLToMesh - theFileName = "<<theFileName);
314   if(_isShapeToMesh)
315     throw SALOME_Exception(LOCALIZED("a shape to mesh has already been defined"));
316   _isShapeToMesh = true;
317   DriverSTL_R_SMDS_Mesh myReader;
318   myReader.SetMesh(_myMeshDS);
319   myReader.SetFile(theFileName);
320   myReader.SetMeshId(-1);
321   myReader.Perform();
322   if(MYDEBUG){
323     MESSAGE("STLToMesh - _myMeshDS->NbNodes() = "<<_myMeshDS->NbNodes());
324     MESSAGE("STLToMesh - _myMeshDS->NbEdges() = "<<_myMeshDS->NbEdges());
325     MESSAGE("STLToMesh - _myMeshDS->NbFaces() = "<<_myMeshDS->NbFaces());
326     MESSAGE("STLToMesh - _myMeshDS->NbVolumes() = "<<_myMeshDS->NbVolumes());
327   }
328   return 1;
329 }
330
331 //=============================================================================
332 /*!
333  * 
334  */
335 //=============================================================================
336
337 SMESH_Hypothesis::Hypothesis_Status
338   SMESH_Mesh::AddHypothesis(const TopoDS_Shape & aSubShape,
339                             int                  anHypId  ) throw(SALOME_Exception)
340 {
341   Unexpect aCatch(SalomeException);
342   if(MYDEBUG) MESSAGE("SMESH_Mesh::AddHypothesis");
343
344   SMESH_subMesh *subMesh = GetSubMesh(aSubShape);
345   if ( !subMesh || !subMesh->GetId())
346     return SMESH_Hypothesis::HYP_BAD_SUBSHAPE;
347
348   SMESHDS_SubMesh *subMeshDS = subMesh->GetSubMeshDS();
349   if ( subMeshDS && subMeshDS->IsComplexSubmesh() ) // group of sub-shapes and maybe of not sub-
350   {
351     MESSAGE("AddHypothesis() to complex submesh");
352     // return the worst but not fatal state of all group memebers
353     SMESH_Hypothesis::Hypothesis_Status aBestRet, aWorstNotFatal, ret;
354     aBestRet = SMESH_Hypothesis::HYP_BAD_DIM;
355     aWorstNotFatal = SMESH_Hypothesis::HYP_OK;
356     for ( TopoDS_Iterator itS ( aSubShape ); itS.More(); itS.Next())
357     {
358       if ( !GetMeshDS()->ShapeToIndex( itS.Value() ))
359         continue; // not sub-shape
360       ret = AddHypothesis( itS.Value(), anHypId );
361       if ( !SMESH_Hypothesis::IsStatusFatal( ret ) && ret > aWorstNotFatal )
362         aWorstNotFatal = ret;
363       if ( ret < aBestRet )
364         aBestRet = ret;
365     }
366     // bind hypotheses to a group just to know
367     SMESH_Hypothesis *anHyp = _gen->GetStudyContext(_studyId)->mapHypothesis[anHypId];
368     GetMeshDS()->AddHypothesis( aSubShape, anHyp );
369
370     if ( SMESH_Hypothesis::IsStatusFatal( aBestRet ))
371       return aBestRet;
372     return aWorstNotFatal;
373   }
374
375   StudyContextStruct *sc = _gen->GetStudyContext(_studyId);
376   if (sc->mapHypothesis.find(anHypId) == sc->mapHypothesis.end())
377   {
378     if(MYDEBUG) MESSAGE("Hypothesis ID does not give an hypothesis");
379     if(MYDEBUG) {
380       SCRUTE(_studyId);
381       SCRUTE(anHypId);
382     }
383     throw SALOME_Exception(LOCALIZED("hypothesis does not exist"));
384   }
385
386   SMESH_Hypothesis *anHyp = sc->mapHypothesis[anHypId];
387   MESSAGE( "SMESH_Mesh::AddHypothesis " << anHyp->GetName() );
388
389   bool isGlobalHyp = IsMainShape( aSubShape );
390
391   // NotConformAllowed can be only global
392   if ( !isGlobalHyp )
393   {
394     string hypName = anHyp->GetName();
395     if ( hypName == "NotConformAllowed" )
396     {
397       if(MYDEBUG) MESSAGE( "Hypotesis <NotConformAllowed> can be only global" );
398       return SMESH_Hypothesis::HYP_INCOMPATIBLE;
399     }
400   }
401
402   // shape 
403
404   bool isAlgo = ( !anHyp->GetType() == SMESHDS_Hypothesis::PARAM_ALGO );
405   int event = isAlgo ? SMESH_subMesh::ADD_ALGO : SMESH_subMesh::ADD_HYP;
406
407   SMESH_Hypothesis::Hypothesis_Status ret = subMesh->AlgoStateEngine(event, anHyp);
408
409   // subShapes
410   if (!SMESH_Hypothesis::IsStatusFatal(ret) &&
411       anHyp->GetDim() <= SMESH_Gen::GetShapeDim(aSubShape)) // is added on father
412   {
413     event = isAlgo ? SMESH_subMesh::ADD_FATHER_ALGO : SMESH_subMesh::ADD_FATHER_HYP;
414
415     SMESH_Hypothesis::Hypothesis_Status ret2 =
416       subMesh->SubMeshesAlgoStateEngine(event, anHyp);
417     if (ret2 > ret)
418       ret = ret2;
419
420     // check concurent hypotheses on ansestors
421     if (ret < SMESH_Hypothesis::HYP_CONCURENT && !isGlobalHyp )
422     {
423       SMESH_subMeshIteratorPtr smIt = subMesh->getDependsOnIterator(false,false);
424       while ( smIt->more() ) {
425         SMESH_subMesh* sm = smIt->next();
426         if ( sm->IsApplicableHypotesis( anHyp )) {
427           ret2 = sm->CheckConcurentHypothesis( anHyp->GetType() );
428           if (ret2 > ret) {
429             ret = ret2;
430             break;
431           }
432         }
433       }
434     }
435   }
436
437   if(MYDEBUG) subMesh->DumpAlgoState(true);
438   SCRUTE(ret);
439   return ret;
440 }
441
442 //=============================================================================
443 /*!
444  * 
445  */
446 //=============================================================================
447
448 SMESH_Hypothesis::Hypothesis_Status
449   SMESH_Mesh::RemoveHypothesis(const TopoDS_Shape & aSubShape,
450                                int anHypId)throw(SALOME_Exception)
451 {
452   Unexpect aCatch(SalomeException);
453   if(MYDEBUG) MESSAGE("SMESH_Mesh::RemoveHypothesis");
454   
455   SMESH_subMesh *subMesh = GetSubMesh(aSubShape);
456   SMESHDS_SubMesh *subMeshDS = subMesh->GetSubMeshDS();
457   if ( subMeshDS && subMeshDS->IsComplexSubmesh() )
458   {
459     // return the worst but not fatal state of all group memebers
460     SMESH_Hypothesis::Hypothesis_Status aBestRet, aWorstNotFatal, ret;
461     aBestRet = SMESH_Hypothesis::HYP_BAD_DIM;
462     aWorstNotFatal = SMESH_Hypothesis::HYP_OK;
463     for ( TopoDS_Iterator itS ( aSubShape ); itS.More(); itS.Next())
464     {
465       if ( !GetMeshDS()->ShapeToIndex( itS.Value() ))
466         continue; // not sub-shape
467       ret = RemoveHypothesis( itS.Value(), anHypId );
468       if ( !SMESH_Hypothesis::IsStatusFatal( ret ) && ret > aWorstNotFatal )
469         aWorstNotFatal = ret;
470       if ( ret < aBestRet )
471         aBestRet = ret;
472     }
473     SMESH_Hypothesis *anHyp = _gen->GetStudyContext(_studyId)->mapHypothesis[anHypId];
474     GetMeshDS()->RemoveHypothesis( aSubShape, anHyp );
475
476     if ( SMESH_Hypothesis::IsStatusFatal( aBestRet ))
477       return aBestRet;
478     return aWorstNotFatal;
479   }
480
481   StudyContextStruct *sc = _gen->GetStudyContext(_studyId);
482   if (sc->mapHypothesis.find(anHypId) == sc->mapHypothesis.end())
483     throw SALOME_Exception(LOCALIZED("hypothesis does not exist"));
484   
485   SMESH_Hypothesis *anHyp = sc->mapHypothesis[anHypId];
486   int hypType = anHyp->GetType();
487   if(MYDEBUG) SCRUTE(hypType);
488   
489   // shape 
490   
491   bool isAlgo = ( !anHyp->GetType() == SMESHDS_Hypothesis::PARAM_ALGO );
492   int event = isAlgo ? SMESH_subMesh::REMOVE_ALGO : SMESH_subMesh::REMOVE_HYP;
493
494   SMESH_Hypothesis::Hypothesis_Status ret = subMesh->AlgoStateEngine(event, anHyp);
495
496   // there may appear concurrent hyps that were covered by the removed hyp
497   if (ret < SMESH_Hypothesis::HYP_CONCURENT &&
498       subMesh->IsApplicableHypotesis( anHyp ) &&
499       subMesh->CheckConcurentHypothesis( anHyp->GetType() ) != SMESH_Hypothesis::HYP_OK)
500     ret = SMESH_Hypothesis::HYP_CONCURENT;
501
502   // subShapes
503   if (!SMESH_Hypothesis::IsStatusFatal(ret) &&
504       anHyp->GetDim() <= SMESH_Gen::GetShapeDim(aSubShape)) // is removed from father
505   {
506     event = isAlgo ? SMESH_subMesh::REMOVE_FATHER_ALGO : SMESH_subMesh::REMOVE_FATHER_HYP;
507
508     SMESH_Hypothesis::Hypothesis_Status ret2 =
509       subMesh->SubMeshesAlgoStateEngine(event, anHyp);
510     if (ret2 > ret) // more severe
511       ret = ret2;
512
513     // check concurent hypotheses on ansestors
514     if (ret < SMESH_Hypothesis::HYP_CONCURENT && !IsMainShape( aSubShape ) )
515     {
516       SMESH_subMeshIteratorPtr smIt = subMesh->getDependsOnIterator(false,false);
517       while ( smIt->more() ) {
518         SMESH_subMesh* sm = smIt->next();
519         if ( sm->IsApplicableHypotesis( anHyp )) {
520           ret2 = sm->CheckConcurentHypothesis( anHyp->GetType() );
521           if (ret2 > ret) {
522             ret = ret2;
523             break;
524           }
525         }
526       }
527     }
528   }
529   
530   if(MYDEBUG) subMesh->DumpAlgoState(true);
531   if(MYDEBUG) SCRUTE(ret);
532   return ret;
533 }
534
535 //=============================================================================
536 /*!
537  * 
538  */
539 //=============================================================================
540
541 const list<const SMESHDS_Hypothesis*>&
542 SMESH_Mesh::GetHypothesisList(const TopoDS_Shape & aSubShape) const
543   throw(SALOME_Exception)
544 {
545   Unexpect aCatch(SalomeException);
546   return _myMeshDS->GetHypothesis(aSubShape);
547 }
548
549 //=======================================================================
550 /*!
551  * \brief Return the hypothesis assigned to the shape
552   * \param aSubShape - the shape to check
553   * \param aFilter - the hypothesis filter
554   * \param andAncestors - flag to check hypos assigned to ancestors of the shape
555   * \retval SMESH_Hypothesis* - the first hypo passed through aFilter
556  */
557 //=======================================================================
558
559 const SMESH_Hypothesis * SMESH_Mesh::GetHypothesis(const TopoDS_Shape &    aSubShape,
560                                                    const SMESH_HypoFilter& aFilter,
561                                                    const bool              andAncestors) const
562 {
563   {
564     const list<const SMESHDS_Hypothesis*>& hypList = _myMeshDS->GetHypothesis(aSubShape);
565     list<const SMESHDS_Hypothesis*>::const_iterator hyp = hypList.begin();
566     for ( ; hyp != hypList.end(); hyp++ ) {
567       const SMESH_Hypothesis * h = cSMESH_Hyp( *hyp );
568       if ( aFilter.IsOk( h, aSubShape))
569         return h;
570     }
571   }
572   if ( andAncestors )
573   {
574     TopTools_ListIteratorOfListOfShape it( GetAncestors( aSubShape ));
575     for (; it.More(); it.Next() )
576     {
577       const list<const SMESHDS_Hypothesis*>& hypList = _myMeshDS->GetHypothesis(it.Value());
578       list<const SMESHDS_Hypothesis*>::const_iterator hyp = hypList.begin();
579       for ( ; hyp != hypList.end(); hyp++ ) {
580         const SMESH_Hypothesis * h = cSMESH_Hyp( *hyp );
581         if (aFilter.IsOk( h, it.Value() ))
582           return h;
583       }
584     }
585   }
586   return 0;
587 }
588
589 //================================================================================
590 /*!
591  * \brief Return hypothesis assigned to the shape
592   * \param aSubShape - the shape to check
593   * \param aFilter - the hypothesis filter
594   * \param aHypList - the list of the found hypotheses
595   * \param andAncestors - flag to check hypos assigned to ancestors of the shape
596   * \retval int - number of unique hypos in aHypList
597  */
598 //================================================================================
599
600 int SMESH_Mesh::GetHypotheses(const TopoDS_Shape &                aSubShape,
601                               const SMESH_HypoFilter&             aFilter,
602                               list <const SMESHDS_Hypothesis * >& aHypList,
603                               const bool                          andAncestors) const
604 {
605   set<string> hypTypes; // to exclude same type hypos from the result list
606   int nbHyps = 0;
607
608   // only one main hypothesis is allowed
609   bool mainHypFound = false;
610
611   // fill in hypTypes
612   list<const SMESHDS_Hypothesis*>::const_iterator hyp;
613   for ( hyp = aHypList.begin(); hyp != aHypList.end(); hyp++ ) {
614     if ( hypTypes.insert( (*hyp)->GetName() ).second )
615       nbHyps++;
616     if ( !cSMESH_Hyp(*hyp)->IsAuxiliary() )
617       mainHypFound = true;
618   }
619
620   // get hypos from aSubShape
621   {
622     const list<const SMESHDS_Hypothesis*>& hypList = _myMeshDS->GetHypothesis(aSubShape);
623     for ( hyp = hypList.begin(); hyp != hypList.end(); hyp++ )
624       if ( aFilter.IsOk (cSMESH_Hyp( *hyp ), aSubShape) &&
625            ( cSMESH_Hyp(*hyp)->IsAuxiliary() || !mainHypFound ) &&
626            hypTypes.insert( (*hyp)->GetName() ).second )
627       {
628         aHypList.push_back( *hyp );
629         nbHyps++;
630         if ( !cSMESH_Hyp(*hyp)->IsAuxiliary() )
631           mainHypFound = true;
632       }
633   }
634
635   // get hypos from ancestors of aSubShape
636   if ( andAncestors )
637   {
638     TopTools_MapOfShape map;
639     TopTools_ListIteratorOfListOfShape it( GetAncestors( aSubShape ));
640     for (; it.More(); it.Next() )
641     {
642      if ( !map.Add( it.Value() ))
643         continue;
644       const list<const SMESHDS_Hypothesis*>& hypList = _myMeshDS->GetHypothesis(it.Value());
645       for ( hyp = hypList.begin(); hyp != hypList.end(); hyp++ )
646         if (aFilter.IsOk( cSMESH_Hyp( *hyp ), it.Value() ) &&
647             ( cSMESH_Hyp(*hyp)->IsAuxiliary() || !mainHypFound ) &&
648             hypTypes.insert( (*hyp)->GetName() ).second )
649         {
650           aHypList.push_back( *hyp );
651           nbHyps++;
652           if ( !cSMESH_Hyp(*hyp)->IsAuxiliary() )
653             mainHypFound = true;
654         }
655     }
656   }
657   return nbHyps;
658 }
659
660 //=============================================================================
661 /*!
662  * 
663  */
664 //=============================================================================
665
666 const list<SMESHDS_Command*> & SMESH_Mesh::GetLog() throw(SALOME_Exception)
667 {
668   Unexpect aCatch(SalomeException);
669   if(MYDEBUG) MESSAGE("SMESH_Mesh::GetLog");
670   return _myMeshDS->GetScript()->GetCommands();
671 }
672
673 //=============================================================================
674 /*!
675  * 
676  */
677 //=============================================================================
678 void SMESH_Mesh::ClearLog() throw(SALOME_Exception)
679 {
680   Unexpect aCatch(SalomeException);
681   if(MYDEBUG) MESSAGE("SMESH_Mesh::ClearLog");
682   _myMeshDS->GetScript()->Clear();
683 }
684
685 //=============================================================================
686 /*!
687  * Get or Create the SMESH_subMesh object implementation
688  */
689 //=============================================================================
690
691 SMESH_subMesh *SMESH_Mesh::GetSubMesh(const TopoDS_Shape & aSubShape)
692   throw(SALOME_Exception)
693 {
694   Unexpect aCatch(SalomeException);
695   SMESH_subMesh *aSubMesh;
696   int index = _myMeshDS->ShapeToIndex(aSubShape);
697
698   // for submeshes on GEOM Group
699   if ( !index && aSubShape.ShapeType() == TopAbs_COMPOUND ) {
700     TopoDS_Iterator it( aSubShape );
701     if ( it.More() )
702       index = _myMeshDS->AddCompoundSubmesh( aSubShape, it.Value().ShapeType() );
703   }
704 //   if ( !index )
705 //     return NULL; // neither sub-shape nor a group
706
707   map <int, SMESH_subMesh *>::iterator i_sm = _mapSubMesh.find(index);
708   if ( i_sm != _mapSubMesh.end())
709   {
710     aSubMesh = i_sm->second;
711   }
712   else
713   {
714     aSubMesh = new SMESH_subMesh(index, this, _myMeshDS, aSubShape);
715     _mapSubMesh[index] = aSubMesh;
716   }
717   return aSubMesh;
718 }
719
720 //=============================================================================
721 /*!
722  * Get the SMESH_subMesh object implementation. Dont create it, return null
723  * if it does not exist.
724  */
725 //=============================================================================
726
727 SMESH_subMesh *SMESH_Mesh::GetSubMeshContaining(const TopoDS_Shape & aSubShape)
728   throw(SALOME_Exception)
729 {
730   Unexpect aCatch(SalomeException);
731   SMESH_subMesh *aSubMesh = NULL;
732   
733   int index = _myMeshDS->ShapeToIndex(aSubShape);
734
735   map <int, SMESH_subMesh *>::iterator i_sm = _mapSubMesh.find(index);
736   if ( i_sm != _mapSubMesh.end())
737     aSubMesh = i_sm->second;
738
739   return aSubMesh;
740 }
741
742 //=============================================================================
743 /*!
744  * Get the SMESH_subMesh object implementation. Dont create it, return null
745  * if it does not exist.
746  */
747 //=============================================================================
748
749 SMESH_subMesh *SMESH_Mesh::GetSubMeshContaining(const int aShapeID)
750 throw(SALOME_Exception)
751 {
752   Unexpect aCatch(SalomeException);
753   
754   map <int, SMESH_subMesh *>::iterator i_sm = _mapSubMesh.find(aShapeID);
755   if (i_sm == _mapSubMesh.end())
756     return NULL;
757   return i_sm->second;
758 }
759
760 //=======================================================================
761 //function : IsUsedHypothesis
762 //purpose  : Return True if anHyp is used to mesh aSubShape
763 //=======================================================================
764
765 bool SMESH_Mesh::IsUsedHypothesis(SMESHDS_Hypothesis * anHyp,
766                                   const SMESH_subMesh* aSubMesh)
767 {
768   SMESH_Hypothesis* hyp = static_cast<SMESH_Hypothesis*>(anHyp);
769
770   // check if anHyp can be used to mesh aSubMesh
771   if ( !aSubMesh || !aSubMesh->IsApplicableHypotesis( hyp ))
772     return false;
773
774   const TopoDS_Shape & aSubShape = const_cast<SMESH_subMesh*>( aSubMesh )->GetSubShape();
775
776   SMESH_Algo *algo = _gen->GetAlgo(*this, aSubShape );
777
778   // algorithm
779   if (anHyp->GetType() > SMESHDS_Hypothesis::PARAM_ALGO)
780     return ( anHyp == algo );
781
782   // algorithm parameter
783   if (algo)
784   {
785     // look trough hypotheses used by algo
786     SMESH_HypoFilter hypoKind;
787     if ( algo->InitCompatibleHypoFilter( hypoKind, !hyp->IsAuxiliary() )) {
788       list <const SMESHDS_Hypothesis * > usedHyps;
789       if ( GetHypotheses( aSubShape, hypoKind, usedHyps, true ))
790         return ( find( usedHyps.begin(), usedHyps.end(), anHyp ) != usedHyps.end() );
791     }
792   }
793
794   // look through all assigned hypotheses
795   //SMESH_HypoFilter filter( SMESH_HypoFilter::Is( hyp ));
796   return false; //GetHypothesis( aSubShape, filter, true );
797 }
798
799 //=============================================================================
800 /*!
801  *
802  */
803 //=============================================================================
804
805 const list < SMESH_subMesh * >&
806 SMESH_Mesh::GetSubMeshUsingHypothesis(SMESHDS_Hypothesis * anHyp)
807   throw(SALOME_Exception)
808 {
809   Unexpect aCatch(SalomeException);
810   if(MYDEBUG) MESSAGE("SMESH_Mesh::GetSubMeshUsingHypothesis");
811   map < int, SMESH_subMesh * >::iterator itsm;
812   _subMeshesUsingHypothesisList.clear();
813   for (itsm = _mapSubMesh.begin(); itsm != _mapSubMesh.end(); itsm++)
814   {
815     SMESH_subMesh *aSubMesh = (*itsm).second;
816     if ( IsUsedHypothesis ( anHyp, aSubMesh ))
817       _subMeshesUsingHypothesisList.push_back(aSubMesh);
818   }
819   return _subMeshesUsingHypothesisList;
820 }
821
822 //=======================================================================
823 //function : NotifySubMeshesHypothesisModification
824 //purpose  : Say all submeshes using theChangedHyp that it has been modified
825 //=======================================================================
826
827 void SMESH_Mesh::NotifySubMeshesHypothesisModification(const SMESH_Hypothesis* hyp)
828 {
829   Unexpect aCatch(SalomeException);
830
831   const SMESH_Algo *foundAlgo = 0;
832   SMESH_HypoFilter algoKind, compatibleHypoKind;
833   list <const SMESHDS_Hypothesis * > usedHyps;
834
835
836   map < int, SMESH_subMesh * >::iterator itsm;
837   for (itsm = _mapSubMesh.begin(); itsm != _mapSubMesh.end(); itsm++)
838   {
839     SMESH_subMesh *aSubMesh = (*itsm).second;
840     if ( aSubMesh->IsApplicableHypotesis( hyp ))
841     {
842       const TopoDS_Shape & aSubShape = aSubMesh->GetSubShape();
843
844       if ( !foundAlgo ) // init filter for algo search
845         algoKind.Init( THypType::IsAlgo() ).And( THypType::IsApplicableTo( aSubShape ));
846       
847       const SMESH_Algo *algo = static_cast<const SMESH_Algo*>
848         ( GetHypothesis( aSubShape, algoKind, true ));
849
850       if ( algo )
851       {
852         bool sameAlgo = ( algo == foundAlgo );
853         if ( !sameAlgo && foundAlgo )
854           sameAlgo = ( strcmp( algo->GetName(), foundAlgo->GetName() ) == 0);
855
856         if ( !sameAlgo ) { // init filter for used hypos search
857           if ( !algo->InitCompatibleHypoFilter( compatibleHypoKind, !hyp->IsAuxiliary() ))
858             continue; // algo does not use any hypothesis
859           foundAlgo = algo;
860         }
861
862         // check if hyp is used by algo
863         usedHyps.clear();
864         if ( GetHypotheses( aSubShape, compatibleHypoKind, usedHyps, true ) &&
865              find( usedHyps.begin(), usedHyps.end(), hyp ) != usedHyps.end() )
866         {
867           aSubMesh->AlgoStateEngine(SMESH_subMesh::MODIF_HYP,
868                                     const_cast< SMESH_Hypothesis*>( hyp ));
869
870           if ( algo->GetDim() == 1 && IsPropagationHypothesis( aSubShape ))
871             CleanMeshOnPropagationChain( aSubShape );
872         }
873       }
874     }
875   }
876 }
877
878 //=============================================================================
879 /*! Export* methods.
880  *  To store mesh contents on disk in different formats.
881  */
882 //=============================================================================
883
884 bool SMESH_Mesh::HasDuplicatedGroupNamesMED()
885 {
886   set<string> aGroupNames;
887   for ( map<int, SMESH_Group*>::iterator it = _mapGroup.begin(); it != _mapGroup.end(); it++ ) {
888     SMESH_Group* aGroup = it->second;
889     string aGroupName = aGroup->GetName();
890     aGroupName.resize(MAX_MED_GROUP_NAME_LENGTH);
891     if (!aGroupNames.insert(aGroupName).second)
892       return true;
893   }
894
895   return false;
896 }
897
898 void SMESH_Mesh::ExportMED(const char *file, 
899                            const char* theMeshName, 
900                            bool theAutoGroups,
901                            int theVersion) 
902   throw(SALOME_Exception)
903 {
904   Unexpect aCatch(SalomeException);
905
906   DriverMED_W_SMESHDS_Mesh myWriter;
907   myWriter.SetFile    ( file, MED::EVersion(theVersion) );
908   myWriter.SetMesh    ( _myMeshDS   );
909   if ( !theMeshName ) 
910     myWriter.SetMeshId  ( _idDoc      );
911   else {
912     myWriter.SetMeshId  ( -1          );
913     myWriter.SetMeshName( theMeshName );
914   }
915
916   if ( theAutoGroups ) {
917     myWriter.AddGroupOfNodes();
918     myWriter.AddGroupOfEdges();
919     myWriter.AddGroupOfFaces();
920     myWriter.AddGroupOfVolumes();
921   }
922
923   // Pass groups to writer. Provide unique group names.
924   set<string> aGroupNames;
925   char aString [256];
926   int maxNbIter = 10000; // to guarantee cycle finish
927   for ( map<int, SMESH_Group*>::iterator it = _mapGroup.begin(); it != _mapGroup.end(); it++ ) {
928     SMESH_Group*       aGroup   = it->second;
929     SMESHDS_GroupBase* aGroupDS = aGroup->GetGroupDS();
930     if ( aGroupDS ) {
931       string aGroupName0 = aGroup->GetName();
932       aGroupName0.resize(MAX_MED_GROUP_NAME_LENGTH);
933       string aGroupName = aGroupName0;
934       for (int i = 1; !aGroupNames.insert(aGroupName).second && i < maxNbIter; i++) {
935         sprintf(&aString[0], "GR_%d_%s", i, aGroupName0.c_str());
936         aGroupName = aString;
937         aGroupName.resize(MAX_MED_GROUP_NAME_LENGTH);
938       }
939       aGroupDS->SetStoreName( aGroupName.c_str() );
940       myWriter.AddGroup( aGroupDS );
941     }
942   }
943
944   // Perform export
945   myWriter.Perform();
946 }
947
948 void SMESH_Mesh::ExportDAT(const char *file) throw(SALOME_Exception)
949 {
950   Unexpect aCatch(SalomeException);
951   DriverDAT_W_SMDS_Mesh myWriter;
952   myWriter.SetFile(string(file));
953   myWriter.SetMesh(_myMeshDS);
954   myWriter.SetMeshId(_idDoc);
955   myWriter.Perform();
956 }
957
958 void SMESH_Mesh::ExportUNV(const char *file) throw(SALOME_Exception)
959 {
960   Unexpect aCatch(SalomeException);
961   DriverUNV_W_SMDS_Mesh myWriter;
962   myWriter.SetFile(string(file));
963   myWriter.SetMesh(_myMeshDS);
964   myWriter.SetMeshId(_idDoc);
965   //  myWriter.SetGroups(_mapGroup);
966
967   for ( map<int, SMESH_Group*>::iterator it = _mapGroup.begin(); it != _mapGroup.end(); it++ ) {
968     SMESH_Group*       aGroup   = it->second;
969     SMESHDS_GroupBase* aGroupDS = aGroup->GetGroupDS();
970     if ( aGroupDS ) {
971       string aGroupName = aGroup->GetName();
972       aGroupDS->SetStoreName( aGroupName.c_str() );
973       myWriter.AddGroup( aGroupDS );
974     }
975   }
976   myWriter.Perform();
977 }
978
979 void SMESH_Mesh::ExportSTL(const char *file, const bool isascii) throw(SALOME_Exception)
980 {
981   Unexpect aCatch(SalomeException);
982   DriverSTL_W_SMDS_Mesh myWriter;
983   myWriter.SetFile(string(file));
984   myWriter.SetIsAscii( isascii );
985   myWriter.SetMesh(_myMeshDS);
986   myWriter.SetMeshId(_idDoc);
987   myWriter.Perform();
988 }
989
990 //=============================================================================
991 /*!
992  *  
993  */
994 //=============================================================================
995 int SMESH_Mesh::NbNodes() throw(SALOME_Exception)
996 {
997   Unexpect aCatch(SalomeException);
998   return _myMeshDS->NbNodes();
999 }
1000
1001 //=============================================================================
1002 /*!
1003  *  
1004  */
1005 //=============================================================================
1006 int SMESH_Mesh::NbEdges(ElementOrder order) throw(SALOME_Exception)
1007 {
1008   Unexpect aCatch(SalomeException);
1009   if (order == ORDER_ANY)
1010     return _myMeshDS->NbEdges();
1011
1012   int Nb = 0;
1013   SMDS_EdgeIteratorPtr it = _myMeshDS->edgesIterator();
1014   while (it->more()) {
1015     const SMDS_MeshEdge* cur = it->next();
1016     if ( order == ORDER_LINEAR && !cur->IsQuadratic() ||
1017          order == ORDER_QUADRATIC && cur->IsQuadratic() )
1018       Nb++;
1019   }
1020   return Nb;
1021 }
1022
1023 //=============================================================================
1024 /*!
1025  *  
1026  */
1027 //=============================================================================
1028 int SMESH_Mesh::NbFaces(ElementOrder order) throw(SALOME_Exception)
1029 {
1030   Unexpect aCatch(SalomeException);
1031   if (order == ORDER_ANY)
1032     return _myMeshDS->NbFaces();
1033
1034   int Nb = 0;
1035   SMDS_FaceIteratorPtr it = _myMeshDS->facesIterator();
1036   while (it->more()) {
1037     const SMDS_MeshFace* cur = it->next();
1038     if ( order == ORDER_LINEAR && !cur->IsQuadratic() ||
1039          order == ORDER_QUADRATIC && cur->IsQuadratic() )
1040       Nb++;
1041   }
1042   return Nb;
1043 }
1044
1045 ///////////////////////////////////////////////////////////////////////////////
1046 /// Return the number of 3 nodes faces in the mesh. This method run in O(n)
1047 ///////////////////////////////////////////////////////////////////////////////
1048 int SMESH_Mesh::NbTriangles(ElementOrder order) throw(SALOME_Exception)
1049 {
1050   Unexpect aCatch(SalomeException);
1051   int Nb = 0;
1052   
1053   SMDS_FaceIteratorPtr itFaces=_myMeshDS->facesIterator();
1054   while (itFaces->more()) {
1055     const SMDS_MeshFace* curFace = itFaces->next();
1056     int nbnod = curFace->NbNodes();
1057     if ( !curFace->IsPoly() && 
1058          ( order == ORDER_ANY && (nbnod==3 || nbnod==6) ||
1059            order == ORDER_LINEAR && nbnod==3 ||
1060            order == ORDER_QUADRATIC && nbnod==6 ) )
1061       Nb++;
1062   }
1063   return Nb;
1064 }
1065
1066 ///////////////////////////////////////////////////////////////////////////////
1067 /// Return the number of 4 nodes faces in the mesh. This method run in O(n)
1068 ///////////////////////////////////////////////////////////////////////////////
1069 int SMESH_Mesh::NbQuadrangles(ElementOrder order) throw(SALOME_Exception)
1070 {
1071   Unexpect aCatch(SalomeException);
1072   int Nb = 0;
1073   
1074   SMDS_FaceIteratorPtr itFaces=_myMeshDS->facesIterator();
1075   while (itFaces->more()) {
1076     const SMDS_MeshFace* curFace = itFaces->next();
1077     int nbnod = curFace->NbNodes();
1078     if ( !curFace->IsPoly() && 
1079          ( order == ORDER_ANY && (nbnod==4 || nbnod==8) ||
1080            order == ORDER_LINEAR && nbnod==4 ||
1081            order == ORDER_QUADRATIC && nbnod==8 ) )
1082       Nb++;
1083   }
1084   return Nb;
1085 }
1086
1087 ///////////////////////////////////////////////////////////////////////////////
1088 /// Return the number of polygonal faces in the mesh. This method run in O(n)
1089 ///////////////////////////////////////////////////////////////////////////////
1090 int SMESH_Mesh::NbPolygons() throw(SALOME_Exception)
1091 {
1092   Unexpect aCatch(SalomeException);
1093   int Nb = 0;
1094   SMDS_FaceIteratorPtr itFaces = _myMeshDS->facesIterator();
1095   while (itFaces->more())
1096     if (itFaces->next()->IsPoly()) Nb++;
1097   return Nb;
1098 }
1099
1100 //=============================================================================
1101 /*!
1102  *  
1103  */
1104 //=============================================================================
1105 int SMESH_Mesh::NbVolumes(ElementOrder order) throw(SALOME_Exception)
1106 {
1107   Unexpect aCatch(SalomeException);
1108   if (order == ORDER_ANY)
1109     return _myMeshDS->NbVolumes();
1110
1111   int Nb = 0;
1112   SMDS_VolumeIteratorPtr it = _myMeshDS->volumesIterator();
1113   while (it->more()) {
1114     const SMDS_MeshVolume* cur = it->next();
1115     if ( order == ORDER_LINEAR && !cur->IsQuadratic() ||
1116          order == ORDER_QUADRATIC && cur->IsQuadratic() )
1117       Nb++;
1118   }
1119   return Nb;
1120 }
1121
1122 int SMESH_Mesh::NbTetras(ElementOrder order) throw(SALOME_Exception)
1123 {
1124   Unexpect aCatch(SalomeException);
1125   int Nb = 0;
1126   SMDS_VolumeIteratorPtr itVolumes=_myMeshDS->volumesIterator();
1127   while (itVolumes->more()) {
1128     const SMDS_MeshVolume* curVolume = itVolumes->next();
1129     int nbnod = curVolume->NbNodes();
1130     if ( !curVolume->IsPoly() && 
1131          ( order == ORDER_ANY && (nbnod==4 || nbnod==10) ||
1132            order == ORDER_LINEAR && nbnod==4 ||
1133            order == ORDER_QUADRATIC && nbnod==10 ) )
1134       Nb++;
1135   }
1136   return Nb;
1137 }
1138
1139 int SMESH_Mesh::NbHexas(ElementOrder order) throw(SALOME_Exception)
1140 {
1141   Unexpect aCatch(SalomeException);
1142   int Nb = 0;
1143   SMDS_VolumeIteratorPtr itVolumes=_myMeshDS->volumesIterator();
1144   while (itVolumes->more()) {
1145     const SMDS_MeshVolume* curVolume = itVolumes->next();
1146     int nbnod = curVolume->NbNodes();
1147     if ( !curVolume->IsPoly() && 
1148          ( order == ORDER_ANY && (nbnod==8 || nbnod==20) ||
1149            order == ORDER_LINEAR && nbnod==8 ||
1150            order == ORDER_QUADRATIC && nbnod==20 ) )
1151       Nb++;
1152   }
1153   return Nb;
1154 }
1155
1156 int SMESH_Mesh::NbPyramids(ElementOrder order) throw(SALOME_Exception)
1157 {
1158   Unexpect aCatch(SalomeException);
1159   int Nb = 0;
1160   SMDS_VolumeIteratorPtr itVolumes=_myMeshDS->volumesIterator();
1161   while (itVolumes->more()) {
1162     const SMDS_MeshVolume* curVolume = itVolumes->next();
1163     int nbnod = curVolume->NbNodes();
1164     if ( !curVolume->IsPoly() && 
1165          ( order == ORDER_ANY && (nbnod==5 || nbnod==13) ||
1166            order == ORDER_LINEAR && nbnod==5 ||
1167            order == ORDER_QUADRATIC && nbnod==13 ) )
1168       Nb++;
1169   }
1170   return Nb;
1171 }
1172
1173 int SMESH_Mesh::NbPrisms(ElementOrder order) throw(SALOME_Exception)
1174 {
1175   Unexpect aCatch(SalomeException);
1176   int Nb = 0;
1177   SMDS_VolumeIteratorPtr itVolumes=_myMeshDS->volumesIterator();
1178   while (itVolumes->more()) {
1179     const SMDS_MeshVolume* curVolume = itVolumes->next();
1180     int nbnod = curVolume->NbNodes();
1181     if ( !curVolume->IsPoly() && 
1182          ( order == ORDER_ANY && (nbnod==6 || nbnod==15) ||
1183            order == ORDER_LINEAR && nbnod==6 ||
1184            order == ORDER_QUADRATIC && nbnod==15 ) )
1185       Nb++;
1186   }
1187   return Nb;
1188 }
1189
1190 int SMESH_Mesh::NbPolyhedrons() throw(SALOME_Exception)
1191 {
1192   Unexpect aCatch(SalomeException);
1193   int Nb = 0;
1194   SMDS_VolumeIteratorPtr itVolumes = _myMeshDS->volumesIterator();
1195   while (itVolumes->more())
1196     if (itVolumes->next()->IsPoly()) Nb++;
1197   return Nb;
1198 }
1199
1200 //=============================================================================
1201 /*!
1202  *  
1203  */
1204 //=============================================================================
1205 int SMESH_Mesh::NbSubMesh() throw(SALOME_Exception)
1206 {
1207   Unexpect aCatch(SalomeException);
1208   return _myMeshDS->NbSubMesh();
1209 }
1210
1211 //=======================================================================
1212 //function : IsNotConformAllowed
1213 //purpose  : check if a hypothesis alowing notconform mesh is present
1214 //=======================================================================
1215
1216 bool SMESH_Mesh::IsNotConformAllowed() const
1217 {
1218   if(MYDEBUG) MESSAGE("SMESH_Mesh::IsNotConformAllowed");
1219
1220   SMESH_HypoFilter filter( SMESH_HypoFilter::HasName( "NotConformAllowed" ));
1221   return GetHypothesis( _myMeshDS->ShapeToMesh(), filter, false );
1222 }
1223
1224 //=======================================================================
1225 //function : IsMainShape
1226 //purpose  : 
1227 //=======================================================================
1228
1229 bool SMESH_Mesh::IsMainShape(const TopoDS_Shape& theShape) const
1230 {
1231   return theShape.IsSame(_myMeshDS->ShapeToMesh() );
1232 }
1233
1234 //=============================================================================
1235 /*!
1236  *  
1237  */
1238 //=============================================================================
1239
1240 SMESH_Group* SMESH_Mesh::AddGroup (const SMDSAbs_ElementType theType,
1241                                    const char*               theName,
1242                                    int&                      theId,
1243                                    const TopoDS_Shape&       theShape)
1244 {
1245   if (_mapGroup.find(_groupId) != _mapGroup.end())
1246     return NULL;
1247   theId = _groupId;
1248   SMESH_Group* aGroup = new SMESH_Group (theId, this, theType, theName, theShape);
1249   GetMeshDS()->AddGroup( aGroup->GetGroupDS() );
1250   _mapGroup[_groupId++] = aGroup;
1251   return aGroup;
1252 }
1253
1254 //=============================================================================
1255 /*!
1256  *  
1257  */
1258 //=============================================================================
1259
1260 SMESH_Group* SMESH_Mesh::GetGroup (const int theGroupID)
1261 {
1262   if (_mapGroup.find(theGroupID) == _mapGroup.end())
1263     return NULL;
1264   return _mapGroup[theGroupID];
1265 }
1266
1267
1268 //=============================================================================
1269 /*!
1270  *  
1271  */
1272 //=============================================================================
1273
1274 list<int> SMESH_Mesh::GetGroupIds()
1275 {
1276   list<int> anIds;
1277   for ( map<int, SMESH_Group*>::const_iterator it = _mapGroup.begin(); it != _mapGroup.end(); it++ )
1278     anIds.push_back( it->first );
1279   
1280   return anIds;
1281 }
1282
1283
1284 //=============================================================================
1285 /*!
1286  *  
1287  */
1288 //=============================================================================
1289
1290 void SMESH_Mesh::RemoveGroup (const int theGroupID)
1291 {
1292   if (_mapGroup.find(theGroupID) == _mapGroup.end())
1293     return;
1294   GetMeshDS()->RemoveGroup( _mapGroup[theGroupID]->GetGroupDS() );
1295   delete _mapGroup[theGroupID];
1296   _mapGroup.erase (theGroupID);
1297 }
1298
1299 //=============================================================================
1300 /*!
1301  *  IsLocal1DHypothesis
1302  *  Returns a local 1D hypothesis used for theEdge
1303  */
1304 //=============================================================================
1305 const SMESH_Hypothesis* SMESH_Mesh::IsLocal1DHypothesis (const TopoDS_Shape& theEdge)
1306 {
1307   SMESH_HypoFilter hypo ( SMESH_HypoFilter::HasDim( 1 ));
1308   hypo.AndNot( hypo.IsAlgo() ).AndNot( hypo.IsAssignedTo( GetMeshDS()->ShapeToMesh() ));
1309
1310   return GetHypothesis( theEdge, hypo, true );
1311 }
1312
1313 //=============================================================================
1314 /*!
1315  *  IsPropagationHypothesis
1316  */
1317 //=============================================================================
1318 bool SMESH_Mesh::IsPropagationHypothesis (const TopoDS_Shape& theEdge)
1319 {
1320   return _mapPropagationChains.Contains(theEdge);
1321 }
1322
1323 //=============================================================================
1324 /*!
1325  *  IsPropagatedHypothesis
1326  */
1327 //=============================================================================
1328 bool SMESH_Mesh::IsPropagatedHypothesis (const TopoDS_Shape& theEdge,
1329                                          TopoDS_Shape&       theMainEdge)
1330 {
1331   int nbChains = _mapPropagationChains.Extent();
1332   for (int i = 1; i <= nbChains; i++) {
1333     //const TopTools_IndexedMapOfShape& aChain = _mapPropagationChains.FindFromIndex(i);
1334     const SMESH_IndexedMapOfShape& aChain = _mapPropagationChains.FindFromIndex(i);
1335     if (aChain.Contains(theEdge)) {
1336       theMainEdge = _mapPropagationChains.FindKey(i);
1337       return true;
1338     }
1339   }
1340
1341   return false;
1342 }
1343 //=============================================================================
1344 /*!
1345  *  IsReversedInChain
1346  */
1347 //=============================================================================
1348
1349 bool SMESH_Mesh::IsReversedInChain (const TopoDS_Shape& theEdge,
1350                                     const TopoDS_Shape& theMainEdge)
1351 {
1352   if ( !theMainEdge.IsNull() && !theEdge.IsNull() &&
1353       _mapPropagationChains.Contains( theMainEdge ))
1354   {
1355     const SMESH_IndexedMapOfShape& aChain =
1356       _mapPropagationChains.FindFromKey( theMainEdge );
1357     int index = aChain.FindIndex( theEdge );
1358     if ( index )
1359       return aChain(index).Orientation() == TopAbs_REVERSED;
1360   }
1361   return false;
1362 }
1363
1364 //=============================================================================
1365 /*!
1366  *  CleanMeshOnPropagationChain
1367  */
1368 //=============================================================================
1369 void SMESH_Mesh::CleanMeshOnPropagationChain (const TopoDS_Shape& theMainEdge)
1370 {
1371   const SMESH_IndexedMapOfShape& aChain = _mapPropagationChains.FindFromKey(theMainEdge);
1372   int i, nbEdges = aChain.Extent();
1373   for (i = 1; i <= nbEdges; i++) {
1374     TopoDS_Shape anEdge = aChain.FindKey(i);
1375     SMESH_subMesh *subMesh = GetSubMesh(anEdge);
1376     SMESHDS_SubMesh *subMeshDS = subMesh->GetSubMeshDS();
1377     if (subMeshDS && subMeshDS->NbElements() > 0) {
1378       subMesh->ComputeStateEngine(SMESH_subMesh::CLEAN);
1379     }
1380   }
1381 }
1382
1383 //=============================================================================
1384 /*!
1385  *  RebuildPropagationChains
1386  *  Rebuild all existing propagation chains.
1387  *  Have to be used, if 1D hypothesis have been assigned/removed to/from any edge
1388  */
1389 //=============================================================================
1390 bool SMESH_Mesh::RebuildPropagationChains()
1391 {
1392   bool ret = true;
1393
1394   // Clean all chains, because they can be not up-to-date
1395   int i, nbChains = _mapPropagationChains.Extent();
1396   for (i = 1; i <= nbChains; i++) {
1397     TopoDS_Shape aMainEdge = _mapPropagationChains.FindKey(i);
1398     CleanMeshOnPropagationChain(aMainEdge);
1399     _mapPropagationChains.ChangeFromIndex(i).Clear();
1400   }
1401
1402   // Build all chains
1403   for (i = 1; i <= nbChains; i++) {
1404     TopoDS_Shape aMainEdge = _mapPropagationChains.FindKey(i);
1405     if (!BuildPropagationChain(aMainEdge))
1406       ret = false;
1407     CleanMeshOnPropagationChain(aMainEdge);
1408   }
1409
1410   return ret;
1411 }
1412
1413 //=============================================================================
1414 /*!
1415  *  RemovePropagationChain
1416  *  Have to be used, if Propagation hypothesis is removed from <theMainEdge>
1417  */
1418 //=============================================================================
1419 bool SMESH_Mesh::RemovePropagationChain (const TopoDS_Shape& theMainEdge)
1420 {
1421   if (!_mapPropagationChains.Contains(theMainEdge))
1422     return false;
1423
1424   // Clean mesh elements and nodes, built on the chain
1425   CleanMeshOnPropagationChain(theMainEdge);
1426
1427   // Clean the chain
1428   _mapPropagationChains.ChangeFromKey(theMainEdge).Clear();
1429
1430   // Remove the chain from the map
1431   int i = _mapPropagationChains.FindIndex(theMainEdge);
1432   if ( i == _mapPropagationChains.Extent() )
1433     _mapPropagationChains.RemoveLast();
1434   else {
1435     TopoDS_Vertex anEmptyShape;
1436     BRep_Builder BB;
1437     BB.MakeVertex(anEmptyShape, gp_Pnt(0,0,0), 0.1);
1438     SMESH_IndexedMapOfShape anEmptyMap;
1439     _mapPropagationChains.Substitute(i, anEmptyShape, anEmptyMap);
1440   }
1441
1442   return true;
1443 }
1444
1445 //=============================================================================
1446 /*!
1447  *  BuildPropagationChain
1448  */
1449 //=============================================================================
1450 bool SMESH_Mesh::BuildPropagationChain (const TopoDS_Shape& theMainEdge)
1451 {
1452   if (theMainEdge.ShapeType() != TopAbs_EDGE) return true;
1453
1454   // Add new chain, if there is no
1455   if (!_mapPropagationChains.Contains(theMainEdge)) {
1456     SMESH_IndexedMapOfShape aNewChain;
1457     _mapPropagationChains.Add(theMainEdge, aNewChain);
1458   }
1459
1460   // Check presence of 1D hypothesis to be propagated
1461   const SMESH_Hypothesis* aMainHyp = IsLocal1DHypothesis(theMainEdge);
1462   if (!aMainHyp) {
1463     MESSAGE("Warning: There is no 1D hypothesis to propagate. Please, assign.");
1464     return true;
1465   }
1466
1467   // Edges, on which the 1D hypothesis will be propagated from <theMainEdge>
1468   SMESH_IndexedMapOfShape& aChain = _mapPropagationChains.ChangeFromKey(theMainEdge);
1469   if (aChain.Extent() > 0) {
1470     CleanMeshOnPropagationChain(theMainEdge);
1471     aChain.Clear();
1472   }
1473
1474   // At first put <theMainEdge> in the chain
1475   aChain.Add(theMainEdge);
1476
1477   // List of edges, added to chain on the previous cycle pass
1478   TopTools_ListOfShape listPrevEdges;
1479   listPrevEdges.Append(theMainEdge.Oriented( TopAbs_FORWARD ));
1480
1481 //   5____4____3____4____5____6
1482 //   |    |    |    |    |    |
1483 //   |    |    |    |    |    |
1484 //   4____3____2____3____4____5
1485 //   |    |    |    |    |    |      Number in the each knot of
1486 //   |    |    |    |    |    |      grid indicates cycle pass,
1487 //   3____2____1____2____3____4      on which corresponding edge
1488 //   |    |    |    |    |    |      (perpendicular to the plane
1489 //   |    |    |    |    |    |      of view) will be found.
1490 //   2____1____0____1____2____3
1491 //   |    |    |    |    |    |
1492 //   |    |    |    |    |    |
1493 //   3____2____1____2____3____4
1494
1495   // Collect all edges pass by pass
1496   while (listPrevEdges.Extent() > 0) {
1497     // List of edges, added to chain on this cycle pass
1498     TopTools_ListOfShape listCurEdges;
1499
1500     // Find the next portion of edges
1501     TopTools_ListIteratorOfListOfShape itE (listPrevEdges);
1502     for (; itE.More(); itE.Next()) {
1503       TopoDS_Shape anE = itE.Value();
1504
1505       // Iterate on faces, having edge <anE>
1506       TopTools_ListIteratorOfListOfShape itA (GetAncestors(anE));
1507       for (; itA.More(); itA.Next()) {
1508         TopoDS_Shape aW = itA.Value();
1509
1510         // There are objects of different type among the ancestors of edge
1511         if (aW.ShapeType() == TopAbs_WIRE) {
1512           TopoDS_Shape anOppE;
1513
1514           BRepTools_WireExplorer aWE (TopoDS::Wire(aW));
1515           Standard_Integer nb = 1, found = 0;
1516           TopTools_Array1OfShape anEdges (1,4);
1517           for (; aWE.More(); aWE.Next(), nb++) {
1518             if (nb > 4) {
1519               found = 0;
1520               break;
1521             }
1522             anEdges(nb) = aWE.Current();
1523             if (!_mapAncestors.Contains(anEdges(nb))) {
1524               MESSAGE("WIRE EXPLORER HAVE GIVEN AN INVALID EDGE !!!");
1525               break;
1526             }
1527             if (anEdges(nb).IsSame(anE)) found = nb;
1528           }
1529
1530           if (nb == 5 && found > 0) {
1531             // Quadrangle face found, get an opposite edge
1532             Standard_Integer opp = found + 2;
1533             if (opp > 4) opp -= 4;
1534             anOppE = anEdges(opp);
1535
1536             // add anOppE to aChain if ...
1537             if (!aChain.Contains(anOppE)) { // ... anOppE is not in aChain
1538               if (!IsLocal1DHypothesis(anOppE)) { // ... no other 1d hyp on anOppE
1539                 TopoDS_Shape aMainEdgeForOppEdge; // ... no other hyp is propagated to anOppE
1540                 if (!IsPropagatedHypothesis(anOppE, aMainEdgeForOppEdge))
1541                 {
1542                   // Add found edge to the chain oriented so that to
1543                   // have it co-directed with a forward MainEdge
1544                   TopAbs_Orientation ori = anE.Orientation();
1545                   if ( anEdges(opp).Orientation() == anEdges(found).Orientation() )
1546                     ori = TopAbs::Reverse( ori );
1547                   anOppE.Orientation( ori );
1548                   aChain.Add(anOppE);
1549                   listCurEdges.Append(anOppE);
1550                 }
1551                 else {
1552                   // Collision!
1553                   MESSAGE("Error: Collision between propagated hypotheses");
1554                   CleanMeshOnPropagationChain(theMainEdge);
1555                   aChain.Clear();
1556                   return ( aMainHyp == IsLocal1DHypothesis(aMainEdgeForOppEdge) );
1557                 }
1558               }
1559             }
1560           } // if (nb == 5 && found > 0)
1561         } // if (aF.ShapeType() == TopAbs_WIRE)
1562       } // for (; itF.More(); itF.Next())
1563     } // for (; itE.More(); itE.Next())
1564
1565     listPrevEdges = listCurEdges;
1566   } // while (listPrevEdges.Extent() > 0)
1567
1568   CleanMeshOnPropagationChain(theMainEdge);
1569   return true;
1570 }
1571
1572 //=======================================================================
1573 //function : GetAncestors
1574 //purpose  : return list of ancestors of theSubShape in the order
1575 //           that lower dimention shapes come first.
1576 //=======================================================================
1577
1578 const TopTools_ListOfShape& SMESH_Mesh::GetAncestors(const TopoDS_Shape& theS) const
1579 {
1580   if ( _mapAncestors.Contains( theS ) )
1581     return _mapAncestors.FindFromKey( theS );
1582
1583   static TopTools_ListOfShape emptyList;
1584   return emptyList;
1585 }
1586
1587 //=======================================================================
1588 //function : Dump
1589 //purpose  : dumps contents of mesh to stream [ debug purposes ]
1590 //=======================================================================
1591 ostream& SMESH_Mesh::Dump(ostream& save)
1592 {
1593   int clause = 0;
1594   save << "========================== Dump contents of mesh ==========================" << endl << endl;
1595   save << ++clause << ") Total number of nodes:   \t"    << NbNodes() << endl;
1596   save << ++clause << ") Total number of edges:   \t"    << NbEdges() << endl;
1597   save << ++clause << ") Total number of faces:   \t"    << NbFaces() << endl;
1598   save << ++clause << ") Total number of polygons:\t"    << NbPolygons() << endl;
1599   save << ++clause << ") Total number of volumes:\t"     << NbVolumes() << endl;
1600   save << ++clause << ") Total number of polyhedrons:\t" << NbPolyhedrons() << endl << endl;
1601   for ( int isQuadratic = 0; isQuadratic < 2; ++isQuadratic )
1602   {
1603     string orderStr = isQuadratic ? "quadratic" : "linear";
1604     ElementOrder order  = isQuadratic ? ORDER_QUADRATIC : ORDER_LINEAR;
1605
1606     save << ++clause << ") Total number of " << orderStr << " edges:\t" << NbEdges(order) << endl;
1607     save << ++clause << ") Total number of " << orderStr << " faces:\t" << NbFaces(order) << endl;
1608     if ( NbFaces(order) > 0 ) {
1609       int nb3 = NbTriangles(order);
1610       int nb4 = NbQuadrangles(order);
1611       save << clause << ".1) Number of " << orderStr << " triangles:  \t" << nb3 << endl;
1612       save << clause << ".2) Number of " << orderStr << " quadrangles:\t" << nb4 << endl;
1613       if ( nb3 + nb4 !=  NbFaces(order) ) {
1614         map<int,int> myFaceMap;
1615         SMDS_FaceIteratorPtr itFaces=_myMeshDS->facesIterator();
1616         while( itFaces->more( ) ) {
1617           int nbNodes = itFaces->next()->NbNodes();
1618           if ( myFaceMap.find( nbNodes ) == myFaceMap.end() )
1619             myFaceMap[ nbNodes ] = 0;
1620           myFaceMap[ nbNodes ] = myFaceMap[ nbNodes ] + 1;
1621         }
1622         save << clause << ".3) Faces in detail: " << endl;
1623         map <int,int>::iterator itF;
1624         for (itF = myFaceMap.begin(); itF != myFaceMap.end(); itF++)
1625           save << "--> nb nodes: " << itF->first << " - nb elemens:\t" << itF->second << endl;
1626       }
1627     }
1628     save << ++clause << ") Total number of " << orderStr << " volumes:\t" << NbVolumes(order) << endl;
1629     if ( NbVolumes(order) > 0 ) {
1630       int nb8 = NbHexas(order);
1631       int nb4 = NbTetras(order);
1632       int nb5 = NbPyramids(order);
1633       int nb6 = NbPrisms(order);
1634       save << clause << ".1) Number of " << orderStr << " hexahedrons:\t" << nb8 << endl;
1635       save << clause << ".2) Number of " << orderStr << " tetrahedrons:\t" << nb4 << endl;
1636       save << clause << ".3) Number of " << orderStr << " prisms:      \t" << nb6 << endl;
1637       save << clause << ".4) Number of " << orderStr << " pyramids:\t" << nb5 << endl;
1638       if ( nb8 + nb4 + nb5 + nb6 != NbVolumes(order) ) {
1639         map<int,int> myVolumesMap;
1640         SMDS_VolumeIteratorPtr itVolumes=_myMeshDS->volumesIterator();
1641         while( itVolumes->more( ) ) {
1642           int nbNodes = itVolumes->next()->NbNodes();
1643           if ( myVolumesMap.find( nbNodes ) == myVolumesMap.end() )
1644             myVolumesMap[ nbNodes ] = 0;
1645           myVolumesMap[ nbNodes ] = myVolumesMap[ nbNodes ] + 1;
1646         }
1647         save << clause << ".5) Volumes in detail: " << endl;
1648         map <int,int>::iterator itV;
1649         for (itV = myVolumesMap.begin(); itV != myVolumesMap.end(); itV++)
1650           save << "--> nb nodes: " << itV->first << " - nb elemens:\t" << itV->second << endl;
1651       }
1652     }
1653     save << endl;
1654   }
1655   save << "===========================================================================" << endl;
1656   return save;
1657 }
1658
1659 //=======================================================================
1660 //function : GetElementType
1661 //purpose  : Returns type of mesh element with certain id
1662 //=======================================================================
1663 SMDSAbs_ElementType SMESH_Mesh::GetElementType( const int id, const bool iselem )
1664 {
1665   return _myMeshDS->GetElementType( id, iselem );
1666 }