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