Salome HOME
eb0f0392df127cf163d191336af218de0d2e3ea9
[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.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
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 "SMESHDS_Group.hxx"
35 #include "SMESHDS_Script.hxx"
36 #include "SMESHDS_GroupOnGeom.hxx"
37 #include "SMDS_MeshVolume.hxx"
38
39 #include "utilities.h"
40
41 #include "DriverMED_W_SMESHDS_Mesh.h"
42 #include "DriverDAT_W_SMDS_Mesh.h"
43 #include "DriverUNV_W_SMDS_Mesh.h"
44 #include "DriverSTL_W_SMDS_Mesh.h"
45
46 #include "DriverMED_R_SMESHDS_Mesh.h"
47 #include "DriverUNV_R_SMDS_Mesh.h"
48 #include "DriverSTL_R_SMDS_Mesh.h"
49
50 #include <BRepTools_WireExplorer.hxx>
51 #include <BRep_Builder.hxx>
52 #include <gp_Pnt.hxx>
53
54 #include <TCollection_AsciiString.hxx>
55 #include <TopExp.hxx>
56 #include <TopTools_ListOfShape.hxx>
57 #include <TopTools_Array1OfShape.hxx>
58 #include <TopTools_ListIteratorOfListOfShape.hxx>
59
60 #include <memory>
61
62 #include "Utils_ExceptHandlers.hxx"
63
64 #ifdef _DEBUG_
65 static int MYDEBUG = 0;
66 #else
67 static int MYDEBUG = 0;
68 #endif
69
70
71 //=============================================================================
72 /*!
73  * 
74  */
75 //=============================================================================
76
77 SMESH_Mesh::SMESH_Mesh(int localId, int studyId, SMESH_Gen * gen, SMESHDS_Document * myDocument)
78 : _groupId( 0 )
79 {
80   INFOS("SMESH_Mesh::SMESH_Mesh(int localId)");
81         _id = localId;
82         _studyId = studyId;
83         _gen = gen;
84         _myDocument = myDocument;
85         _idDoc = _myDocument->NewMesh();
86         _myMeshDS = _myDocument->GetMesh(_idDoc);
87         _isShapeToMesh = false;
88 }
89
90 //=============================================================================
91 /*!
92  * 
93  */
94 //=============================================================================
95
96 SMESH_Mesh::~SMESH_Mesh()
97 {
98   INFOS("SMESH_Mesh::~SMESH_Mesh");
99
100   // delete groups
101   map < int, SMESH_Group * >::iterator itg;
102   for (itg = _mapGroup.begin(); itg != _mapGroup.end(); itg++) {
103     SMESH_Group *aGroup = (*itg).second;
104     delete aGroup;
105   }
106 }
107
108 //=============================================================================
109 /*!
110  * 
111  */
112 //=============================================================================
113
114 void SMESH_Mesh::ShapeToMesh(const TopoDS_Shape & aShape)
115 {
116   if(MYDEBUG) MESSAGE("SMESH_Mesh::ShapeToMesh");
117
118   if ( !_myMeshDS->ShapeToMesh().IsNull() && aShape.IsNull() )
119   {
120     // removal of a shape to mesh, delete objects referring to sub-shapes:
121     // - sub-meshes
122     map <int, SMESH_subMesh *>::iterator i_sm = _mapSubMesh.begin();
123     for ( ; i_sm != _mapSubMesh.end(); ++i_sm )
124       delete i_sm->second;
125     _mapSubMesh.clear();
126     //  - groups on geometry
127     map <int, SMESH_Group *>::iterator i_gr = _mapGroup.begin();
128     while ( i_gr != _mapGroup.end() ) {
129       if ( dynamic_cast<SMESHDS_GroupOnGeom*>( i_gr->second->GetGroupDS() )) {
130         _myMeshDS->RemoveGroup( i_gr->second->GetGroupDS() );
131         delete i_gr->second;
132         _mapGroup.erase( i_gr++ );
133       }
134       else
135         i_gr++;
136     }
137     _mapAncestors.Clear();
138     _mapPropagationChains.Clear();
139   }
140   else
141   {
142     if (_isShapeToMesh)
143       throw SALOME_Exception(LOCALIZED ("a shape to mesh has already been defined"));
144   }
145   _isShapeToMesh = true;
146   _myMeshDS->ShapeToMesh(aShape);
147   // NRI : 24/02/03
148   //EAP: 1/9/04 TopExp::MapShapes(aShape, _subShapes); USE the same map of _myMeshDS
149 }
150
151 //=======================================================================
152 //function : UNVToMesh
153 //purpose  : 
154 //=======================================================================
155
156 int SMESH_Mesh::UNVToMesh(const char* theFileName)
157 {
158   if(MYDEBUG) MESSAGE("UNVToMesh - theFileName = "<<theFileName);
159   if(_isShapeToMesh)
160     throw SALOME_Exception(LOCALIZED("a shape to mesh has already been defined"));
161   _isShapeToMesh = true;
162   DriverUNV_R_SMDS_Mesh myReader;
163   myReader.SetMesh(_myMeshDS);
164   myReader.SetFile(theFileName);
165   myReader.SetMeshId(-1);
166   myReader.Perform();
167   if(MYDEBUG){
168     MESSAGE("MEDToMesh - _myMeshDS->NbNodes() = "<<_myMeshDS->NbNodes());
169     MESSAGE("MEDToMesh - _myMeshDS->NbEdges() = "<<_myMeshDS->NbEdges());
170     MESSAGE("MEDToMesh - _myMeshDS->NbFaces() = "<<_myMeshDS->NbFaces());
171     MESSAGE("MEDToMesh - _myMeshDS->NbVolumes() = "<<_myMeshDS->NbVolumes());
172   }
173   return 1;
174 }
175
176 //=======================================================================
177 //function : MEDToMesh
178 //purpose  : 
179 //=======================================================================
180
181 int SMESH_Mesh::MEDToMesh(const char* theFileName, const char* theMeshName)
182 {
183   if(MYDEBUG) MESSAGE("MEDToMesh - theFileName = "<<theFileName<<", mesh name = "<<theMeshName);
184   if(_isShapeToMesh)
185     throw SALOME_Exception(LOCALIZED("a shape to mesh has already been defined"));
186   _isShapeToMesh = true;
187   DriverMED_R_SMESHDS_Mesh myReader;
188   myReader.SetMesh(_myMeshDS);
189   myReader.SetMeshId(-1);
190   myReader.SetFile(theFileName);
191   myReader.SetMeshName(theMeshName);
192   Driver_Mesh::Status status = myReader.Perform();
193   if(MYDEBUG){
194     MESSAGE("MEDToMesh - _myMeshDS->NbNodes() = "<<_myMeshDS->NbNodes());
195     MESSAGE("MEDToMesh - _myMeshDS->NbEdges() = "<<_myMeshDS->NbEdges());
196     MESSAGE("MEDToMesh - _myMeshDS->NbFaces() = "<<_myMeshDS->NbFaces());
197     MESSAGE("MEDToMesh - _myMeshDS->NbVolumes() = "<<_myMeshDS->NbVolumes());
198   }
199
200   // Reading groups (sub-meshes are out of scope of MED import functionality)
201   list<string> aGroupNames = myReader.GetGroupNames();
202   if(MYDEBUG) MESSAGE("MEDToMesh - Nb groups = "<<aGroupNames.size()); 
203   int anId;
204   for ( list<string>::iterator it = aGroupNames.begin(); it != aGroupNames.end(); it++ ) {
205     SMESH_Group* aGroup = AddGroup( SMDSAbs_All, it->c_str(), anId );
206     if ( aGroup ) {
207       if(MYDEBUG) MESSAGE("MEDToMesh - group added: "<<it->c_str());      
208       SMESHDS_Group* aGroupDS = dynamic_cast<SMESHDS_Group*>( aGroup->GetGroupDS() );
209       if ( aGroupDS ) {
210         aGroupDS->SetStoreName( it->c_str() );
211         myReader.GetGroup( aGroupDS );
212       }
213     }
214   }
215   return (int) status;
216 }
217
218 //=======================================================================
219 //function : STLToMesh
220 //purpose  : 
221 //=======================================================================
222
223 int SMESH_Mesh::STLToMesh(const char* theFileName)
224 {
225   if(MYDEBUG) MESSAGE("UNVToMesh - theFileName = "<<theFileName);
226   if(_isShapeToMesh)
227     throw SALOME_Exception(LOCALIZED("a shape to mesh has already been defined"));
228   _isShapeToMesh = true;
229   DriverSTL_R_SMDS_Mesh myReader;
230   myReader.SetMesh(_myMeshDS);
231   myReader.SetFile(theFileName);
232   myReader.SetMeshId(-1);
233   myReader.Perform();
234   if(MYDEBUG){
235     MESSAGE("MEDToMesh - _myMeshDS->NbNodes() = "<<_myMeshDS->NbNodes());
236     MESSAGE("MEDToMesh - _myMeshDS->NbEdges() = "<<_myMeshDS->NbEdges());
237     MESSAGE("MEDToMesh - _myMeshDS->NbFaces() = "<<_myMeshDS->NbFaces());
238     MESSAGE("MEDToMesh - _myMeshDS->NbVolumes() = "<<_myMeshDS->NbVolumes());
239   }
240   return 1;
241 }
242
243 //=============================================================================
244 /*!
245  * 
246  */
247 //=============================================================================
248
249 SMESH_Hypothesis::Hypothesis_Status
250   SMESH_Mesh::AddHypothesis(const TopoDS_Shape & aSubShape,
251                             int                  anHypId  ) throw(SALOME_Exception)
252 {
253   Unexpect aCatch(SalomeException);
254   if(MYDEBUG) MESSAGE("SMESH_Mesh::AddHypothesis");
255
256   SMESH_subMesh *subMesh = GetSubMesh(aSubShape);
257   SMESHDS_SubMesh *subMeshDS = subMesh->GetSubMeshDS();
258   if ( subMeshDS && subMeshDS->IsComplexSubmesh() )
259   {
260     // return the worst but not fatal state of all group memebers
261     SMESH_Hypothesis::Hypothesis_Status aBestRet, aWorstNotFatal, ret;
262     aBestRet = SMESH_Hypothesis::HYP_BAD_DIM;
263     aWorstNotFatal = SMESH_Hypothesis::HYP_OK;
264     for ( TopoDS_Iterator itS ( aSubShape ); itS.More(); itS.Next())
265     {
266       ret = AddHypothesis( itS.Value(), anHypId );
267       if ( !SMESH_Hypothesis::IsStatusFatal( ret ) && ret > aWorstNotFatal )
268         aWorstNotFatal = ret;
269       if ( ret < aBestRet )
270         aBestRet = ret;
271     }
272     if ( SMESH_Hypothesis::IsStatusFatal( aBestRet ))
273       return aBestRet;
274     return aWorstNotFatal;
275   }
276
277   StudyContextStruct *sc = _gen->GetStudyContext(_studyId);
278   if (sc->mapHypothesis.find(anHypId) == sc->mapHypothesis.end())
279   {
280     if(MYDEBUG) MESSAGE("Hypothesis ID does not give an hypothesis");
281     if(MYDEBUG) {
282       SCRUTE(_studyId);
283       SCRUTE(anHypId);
284     }
285     throw SALOME_Exception(LOCALIZED("hypothesis does not exist"));
286   }
287
288   SMESH_Hypothesis *anHyp = sc->mapHypothesis[anHypId];
289   MESSAGE( "SMESH_Mesh::AddHypothesis " << anHyp->GetName() );
290
291   bool isGlobalHyp = IsMainShape( aSubShape );
292
293   // NotConformAllowed can be only global
294   if ( !isGlobalHyp )
295   {
296     string hypName = anHyp->GetName();
297     if ( hypName == "NotConformAllowed" )
298     {
299       if(MYDEBUG) MESSAGE( "Hypotesis <NotConformAllowed> can be only global" );
300       return SMESH_Hypothesis::HYP_INCOMPATIBLE;
301     }
302   }
303
304   // shape 
305
306   int event;
307   if (anHyp->GetType() == SMESHDS_Hypothesis::PARAM_ALGO)
308     event = SMESH_subMesh::ADD_HYP;
309   else
310     event = SMESH_subMesh::ADD_ALGO;
311   SMESH_Hypothesis::Hypothesis_Status ret = subMesh->AlgoStateEngine(event, anHyp);
312
313   // subShapes
314   if (!SMESH_Hypothesis::IsStatusFatal(ret) &&
315       !subMesh->IsApplicableHypotesis( anHyp )) // is added on father
316   {
317     if (anHyp->GetType() == SMESHDS_Hypothesis::PARAM_ALGO)
318       event = SMESH_subMesh::ADD_FATHER_HYP;
319     else
320       event = SMESH_subMesh::ADD_FATHER_ALGO;
321     SMESH_Hypothesis::Hypothesis_Status ret2 =
322       subMesh->SubMeshesAlgoStateEngine(event, anHyp);
323     if (ret2 > ret)
324       ret = ret2;
325
326     // check concurent hypotheses on ansestors
327     if (ret < SMESH_Hypothesis::HYP_CONCURENT && !isGlobalHyp )
328     {
329       const map < int, SMESH_subMesh * >& smMap = subMesh->DependsOn();
330       map < int, SMESH_subMesh * >::const_iterator smIt = smMap.begin();
331       for ( ; smIt != smMap.end(); smIt++ ) {
332         if ( smIt->second->IsApplicableHypotesis( anHyp )) {
333           ret2 = smIt->second->CheckConcurentHypothesis( anHyp->GetType() );
334           if (ret2 > ret) {
335             ret = ret2;
336             break;
337           }
338         }
339       }
340     }
341   }
342
343   if(MYDEBUG) subMesh->DumpAlgoState(true);
344   SCRUTE(ret);
345   return ret;
346 }
347
348 //=============================================================================
349 /*!
350  * 
351  */
352 //=============================================================================
353
354 SMESH_Hypothesis::Hypothesis_Status
355   SMESH_Mesh::RemoveHypothesis(const TopoDS_Shape & aSubShape,
356                                int anHypId)throw(SALOME_Exception)
357 {
358   Unexpect aCatch(SalomeException);
359   if(MYDEBUG) MESSAGE("SMESH_Mesh::RemoveHypothesis");
360   
361   SMESH_subMesh *subMesh = GetSubMesh(aSubShape);
362   SMESHDS_SubMesh *subMeshDS = subMesh->GetSubMeshDS();
363   if ( subMeshDS && subMeshDS->IsComplexSubmesh() )
364   {
365     // return the worst but not fatal state of all group memebers
366     SMESH_Hypothesis::Hypothesis_Status aBestRet, aWorstNotFatal, ret;
367     aBestRet = SMESH_Hypothesis::HYP_BAD_DIM;
368     aWorstNotFatal = SMESH_Hypothesis::HYP_OK;
369     for ( TopoDS_Iterator itS ( aSubShape ); itS.More(); itS.Next())
370     {
371       ret = RemoveHypothesis( itS.Value(), anHypId );
372       if ( !SMESH_Hypothesis::IsStatusFatal( ret ) && ret > aWorstNotFatal )
373         aWorstNotFatal = ret;
374       if ( ret < aBestRet )
375         aBestRet = ret;
376     }
377     if ( SMESH_Hypothesis::IsStatusFatal( aBestRet ))
378       return aBestRet;
379     return aWorstNotFatal;
380   }
381
382   StudyContextStruct *sc = _gen->GetStudyContext(_studyId);
383   if (sc->mapHypothesis.find(anHypId) == sc->mapHypothesis.end())
384     throw SALOME_Exception(LOCALIZED("hypothesis does not exist"));
385   
386   SMESH_Hypothesis *anHyp = sc->mapHypothesis[anHypId];
387   int hypType = anHyp->GetType();
388   if(MYDEBUG) SCRUTE(hypType);
389   int event;
390   
391   // shape 
392   
393   if (anHyp->GetType() == SMESHDS_Hypothesis::PARAM_ALGO)
394     event = SMESH_subMesh::REMOVE_HYP;
395   else
396     event = SMESH_subMesh::REMOVE_ALGO;
397   SMESH_Hypothesis::Hypothesis_Status ret = subMesh->AlgoStateEngine(event, anHyp);
398
399   // there may appear concurrent hyps that were covered by the removed hyp
400   if (ret < SMESH_Hypothesis::HYP_CONCURENT &&
401       subMesh->IsApplicableHypotesis( anHyp ) &&
402       subMesh->CheckConcurentHypothesis( anHyp->GetType() ) != SMESH_Hypothesis::HYP_OK)
403     ret = SMESH_Hypothesis::HYP_CONCURENT;
404
405   // subShapes
406   if (!SMESH_Hypothesis::IsStatusFatal(ret) &&
407       !subMesh->IsApplicableHypotesis( anHyp )) // is removed from father
408   {
409     if (anHyp->GetType() == SMESHDS_Hypothesis::PARAM_ALGO)
410       event = SMESH_subMesh::REMOVE_FATHER_HYP;
411     else
412       event = SMESH_subMesh::REMOVE_FATHER_ALGO;
413     SMESH_Hypothesis::Hypothesis_Status ret2 =
414       subMesh->SubMeshesAlgoStateEngine(event, anHyp);
415     if (ret2 > ret) // more severe
416       ret = ret2;
417
418     // check concurent hypotheses on ansestors
419     if (ret < SMESH_Hypothesis::HYP_CONCURENT && !IsMainShape( aSubShape ) )
420     {
421       const map < int, SMESH_subMesh * >& smMap = subMesh->DependsOn();
422       map < int, SMESH_subMesh * >::const_iterator smIt = smMap.begin();
423       for ( ; smIt != smMap.end(); smIt++ ) {
424         if ( smIt->second->IsApplicableHypotesis( anHyp )) {
425           ret2 = smIt->second->CheckConcurentHypothesis( anHyp->GetType() );
426           if (ret2 > ret) {
427             ret = ret2;
428             break;
429           }
430         }
431       }
432     }
433   }
434   
435   if(MYDEBUG) subMesh->DumpAlgoState(true);
436   if(MYDEBUG) SCRUTE(ret);
437   return ret;
438 }
439
440 //=============================================================================
441 /*!
442  * 
443  */
444 //=============================================================================
445
446 SMESHDS_Mesh * SMESH_Mesh::GetMeshDS()
447 {
448   return _myMeshDS;
449 }
450
451 //=============================================================================
452 /*!
453  * 
454  */
455 //=============================================================================
456
457 const list<const SMESHDS_Hypothesis*>&
458 SMESH_Mesh::GetHypothesisList(const TopoDS_Shape & aSubShape) const
459   throw(SALOME_Exception)
460 {
461   Unexpect aCatch(SalomeException);
462   return _myMeshDS->GetHypothesis(aSubShape);
463 }
464
465 //=============================================================================
466 /*!
467  * 
468  */
469 //=============================================================================
470
471 const list<SMESHDS_Command*> & SMESH_Mesh::GetLog() throw(SALOME_Exception)
472 {
473   Unexpect aCatch(SalomeException);
474   if(MYDEBUG) MESSAGE("SMESH_Mesh::GetLog");
475   return _myMeshDS->GetScript()->GetCommands();
476 }
477
478 //=============================================================================
479 /*!
480  * 
481  */
482 //=============================================================================
483 void SMESH_Mesh::ClearLog() throw(SALOME_Exception)
484 {
485   Unexpect aCatch(SalomeException);
486   if(MYDEBUG) MESSAGE("SMESH_Mesh::ClearLog");
487   _myMeshDS->GetScript()->Clear();
488 }
489
490 //=============================================================================
491 /*!
492  * 
493  */
494 //=============================================================================
495
496 int SMESH_Mesh::GetId()
497 {
498   if(MYDEBUG) MESSAGE("SMESH_Mesh::GetId");
499   return _id;
500 }
501
502 //=============================================================================
503 /*!
504  * 
505  */
506 //=============================================================================
507
508 SMESH_Gen *SMESH_Mesh::GetGen()
509 {
510   return _gen;
511 }
512
513 //=============================================================================
514 /*!
515  * Get or Create the SMESH_subMesh object implementation
516  */
517 //=============================================================================
518
519 SMESH_subMesh *SMESH_Mesh::GetSubMesh(const TopoDS_Shape & aSubShape)
520 throw(SALOME_Exception)
521 {
522   Unexpect aCatch(SalomeException);
523   SMESH_subMesh *aSubMesh;
524   int index = _myMeshDS->ShapeToIndex(aSubShape);
525   
526   // for submeshes on GEOM Group
527   if ( !index && aSubShape.ShapeType() == TopAbs_COMPOUND ) {
528     TopoDS_Iterator it( aSubShape );
529     if ( it.More() )
530       index = _myMeshDS->AddCompoundSubmesh( aSubShape, it.Value().ShapeType() );
531   }
532
533   if (_mapSubMesh.find(index) != _mapSubMesh.end())
534     {
535       aSubMesh = _mapSubMesh[index];
536     }
537   else
538     {
539       aSubMesh = new SMESH_subMesh(index, this, _myMeshDS, aSubShape);
540       _mapSubMesh[index] = aSubMesh;
541     }
542   return aSubMesh;
543 }
544
545 //=============================================================================
546 /*!
547  * Get the SMESH_subMesh object implementation. Dont create it, return null
548  * if it does not exist.
549  */
550 //=============================================================================
551
552 SMESH_subMesh *SMESH_Mesh::GetSubMeshContaining(const TopoDS_Shape & aSubShape)
553 throw(SALOME_Exception)
554 {
555   Unexpect aCatch(SalomeException);
556   bool isFound = false;
557   SMESH_subMesh *aSubMesh = NULL;
558   
559   int index = _myMeshDS->ShapeToIndex(aSubShape);
560   if (_mapSubMesh.find(index) != _mapSubMesh.end())
561     {
562       aSubMesh = _mapSubMesh[index];
563       isFound = true;
564     }
565   if (!isFound)
566     aSubMesh = NULL;
567   return aSubMesh;
568 }
569
570 //=======================================================================
571 //function : IsUsedHypothesis
572 //purpose  : Return True if anHyp is used to mesh aSubShape
573 //=======================================================================
574
575 bool SMESH_Mesh::IsUsedHypothesis(SMESHDS_Hypothesis * anHyp,
576                                   const TopoDS_Shape & aSubShape)
577 {
578   // check if anHyp is applicable to aSubShape
579   SMESH_subMesh * subMesh = GetSubMeshContaining( aSubShape );
580   if (!subMesh ||
581       !subMesh->IsApplicableHypotesis(static_cast<SMESH_Hypothesis*>(anHyp)))
582     return false;
583
584   SMESH_Algo *algo = _gen->GetAlgo(*this, aSubShape);
585
586   // algorithm
587   if (anHyp->GetType() > SMESHDS_Hypothesis::PARAM_ALGO)
588     return ( anHyp == algo );
589
590   // algorithm parameter
591   if (algo)
592   {
593     // look trough hypotheses used by algo
594     const list <const SMESHDS_Hypothesis * >&usedHyps =
595       algo->GetUsedHypothesis(*this, aSubShape);
596     list <const SMESHDS_Hypothesis * >::const_iterator itl;
597     for (itl = usedHyps.begin(); itl != usedHyps.end(); itl++)
598       if (anHyp == (*itl))
599         return true;
600   }
601   else
602   {
603     // look through all assigned hypotheses
604     {
605       const list <const SMESHDS_Hypothesis * >&usedHyps =
606         _myMeshDS->GetHypothesis( aSubShape );
607       list <const SMESHDS_Hypothesis * >::const_iterator itl;
608       for (itl = usedHyps.begin(); itl != usedHyps.end(); itl++)
609         if (anHyp == (*itl))
610           return true;
611     }
612
613     // on ancestors
614     TopTools_ListIteratorOfListOfShape it( GetAncestors( aSubShape ));
615     for (; it.More(); it.Next())
616     {
617       const list <const SMESHDS_Hypothesis * >&usedHyps =
618         _myMeshDS->GetHypothesis( aSubShape );
619       list <const SMESHDS_Hypothesis * >::const_iterator itl;
620       for (itl = usedHyps.begin(); itl != usedHyps.end(); itl++)
621         if (anHyp == (*itl))
622           return true;
623     }
624   }
625     
626   return false;
627 }
628
629
630 //=============================================================================
631 /*!
632  *
633  */
634 //=============================================================================
635
636 const list < SMESH_subMesh * >&
637         SMESH_Mesh::GetSubMeshUsingHypothesis(SMESHDS_Hypothesis * anHyp)
638 throw(SALOME_Exception)
639 {
640   Unexpect aCatch(SalomeException);
641         if(MYDEBUG) MESSAGE("SMESH_Mesh::GetSubMeshUsingHypothesis");
642         map < int, SMESH_subMesh * >::iterator itsm;
643         _subMeshesUsingHypothesisList.clear();
644         for (itsm = _mapSubMesh.begin(); itsm != _mapSubMesh.end(); itsm++)
645         {
646                 SMESH_subMesh *aSubMesh = (*itsm).second;
647                 if ( IsUsedHypothesis ( anHyp, aSubMesh->GetSubShape() ))
648                         _subMeshesUsingHypothesisList.push_back(aSubMesh);
649         }
650         return _subMeshesUsingHypothesisList;
651 }
652
653 //=============================================================================
654 /*!
655  *
656  */
657 //=============================================================================
658
659 void SMESH_Mesh::ExportMED(const char *file, 
660                            const char* theMeshName, 
661                            bool theAutoGroups,
662                            int theVersion) 
663   throw(SALOME_Exception)
664 {
665   Unexpect aCatch(SalomeException);
666   DriverMED_W_SMESHDS_Mesh myWriter;
667   myWriter.SetFile    ( file, MED::EVersion(theVersion) );
668   myWriter.SetMesh    ( _myMeshDS   );
669   if ( !theMeshName ) 
670     myWriter.SetMeshId  ( _idDoc      );
671   else {
672     myWriter.SetMeshId  ( -1          );
673     myWriter.SetMeshName( theMeshName );
674   }
675
676   if ( theAutoGroups ) {
677     myWriter.AddGroupOfNodes();
678     myWriter.AddGroupOfEdges();
679     myWriter.AddGroupOfFaces();
680     myWriter.AddGroupOfVolumes();
681   }
682
683   for ( map<int, SMESH_Group*>::iterator it = _mapGroup.begin(); it != _mapGroup.end(); it++ ) {
684     SMESH_Group*       aGroup   = it->second;
685     SMESHDS_GroupBase* aGroupDS = aGroup->GetGroupDS();
686     if ( aGroupDS ) {
687       aGroupDS->SetStoreName( aGroup->GetName() );
688       myWriter.AddGroup( aGroupDS );
689     }
690   }
691
692   myWriter.Perform();
693 }
694
695 void SMESH_Mesh::ExportDAT(const char *file) throw(SALOME_Exception)
696 {
697   Unexpect aCatch(SalomeException);
698   DriverDAT_W_SMDS_Mesh myWriter;
699   myWriter.SetFile(string(file));
700   myWriter.SetMesh(_myMeshDS);
701   myWriter.SetMeshId(_idDoc);
702   myWriter.Perform();
703 }
704
705 void SMESH_Mesh::ExportUNV(const char *file) throw(SALOME_Exception)
706 {
707   Unexpect aCatch(SalomeException);
708   DriverUNV_W_SMDS_Mesh myWriter;
709   myWriter.SetFile(string(file));
710   myWriter.SetMesh(_myMeshDS);
711   myWriter.SetMeshId(_idDoc);
712   myWriter.Perform();
713 }
714
715 void SMESH_Mesh::ExportSTL(const char *file, const bool isascii) throw(SALOME_Exception)
716 {
717   Unexpect aCatch(SalomeException);
718   DriverSTL_W_SMDS_Mesh myWriter;
719   myWriter.SetFile(string(file));
720   myWriter.SetIsAscii( isascii );
721   myWriter.SetMesh(_myMeshDS);
722   myWriter.SetMeshId(_idDoc);
723   myWriter.Perform();
724 }
725
726 //=============================================================================
727 /*!
728  *  
729  */
730 //=============================================================================
731 int SMESH_Mesh::NbNodes() throw(SALOME_Exception)
732 {
733   Unexpect aCatch(SalomeException);
734   return _myMeshDS->NbNodes();
735 }
736
737 //=============================================================================
738 /*!
739  *  
740  */
741 //=============================================================================
742 int SMESH_Mesh::NbEdges() throw(SALOME_Exception)
743 {
744   Unexpect aCatch(SalomeException);
745   return _myMeshDS->NbEdges();
746 }
747
748 //=============================================================================
749 /*!
750  *  
751  */
752 //=============================================================================
753 int SMESH_Mesh::NbFaces() throw(SALOME_Exception)
754 {
755   Unexpect aCatch(SalomeException);
756   return _myMeshDS->NbFaces();
757 }
758
759 ///////////////////////////////////////////////////////////////////////////////
760 /// Return the number of 3 nodes faces in the mesh. This method run in O(n)
761 ///////////////////////////////////////////////////////////////////////////////
762 int SMESH_Mesh::NbTriangles() throw(SALOME_Exception)
763 {
764   Unexpect aCatch(SalomeException);
765   int Nb = 0;
766   
767   SMDS_FaceIteratorPtr itFaces=_myMeshDS->facesIterator();
768   while(itFaces->more()) if(itFaces->next()->NbNodes()==3) Nb++;
769   return Nb;
770 }
771
772 ///////////////////////////////////////////////////////////////////////////////
773 /// Return the number of 4 nodes faces in the mesh. This method run in O(n)
774 ///////////////////////////////////////////////////////////////////////////////
775 int SMESH_Mesh::NbQuadrangles() throw(SALOME_Exception)
776 {
777   Unexpect aCatch(SalomeException);
778   int Nb = 0;
779   
780   SMDS_FaceIteratorPtr itFaces=_myMeshDS->facesIterator();
781   while(itFaces->more()) if(itFaces->next()->NbNodes()==4) Nb++;
782   return Nb;
783 }
784
785 //=============================================================================
786 /*!
787  *  
788  */
789 //=============================================================================
790 int SMESH_Mesh::NbVolumes() throw(SALOME_Exception)
791 {
792   Unexpect aCatch(SalomeException);
793   return _myMeshDS->NbVolumes();
794 }
795
796 int SMESH_Mesh::NbTetras() throw(SALOME_Exception)
797 {
798   Unexpect aCatch(SalomeException);
799   int Nb = 0;
800   SMDS_VolumeIteratorPtr itVolumes=_myMeshDS->volumesIterator();
801   while(itVolumes->more()) if(itVolumes->next()->NbNodes()==4) Nb++;
802   return Nb;
803 }
804
805 int SMESH_Mesh::NbHexas() throw(SALOME_Exception)
806 {
807   Unexpect aCatch(SalomeException);
808   int Nb = 0;
809   SMDS_VolumeIteratorPtr itVolumes=_myMeshDS->volumesIterator();
810   while(itVolumes->more()) if(itVolumes->next()->NbNodes()==8) Nb++;
811   return Nb;
812 }
813
814 int SMESH_Mesh::NbPyramids() throw(SALOME_Exception)
815 {
816   Unexpect aCatch(SalomeException);
817   int Nb = 0;
818   SMDS_VolumeIteratorPtr itVolumes=_myMeshDS->volumesIterator();
819   while(itVolumes->more()) if(itVolumes->next()->NbNodes()==5) Nb++;
820   return Nb;
821 }
822
823 int SMESH_Mesh::NbPrisms() throw(SALOME_Exception)
824 {
825   Unexpect aCatch(SalomeException);
826   int Nb = 0;
827   SMDS_VolumeIteratorPtr itVolumes=_myMeshDS->volumesIterator();
828   while(itVolumes->more()) if(itVolumes->next()->NbNodes()==6) Nb++;
829   return Nb;
830 }
831
832 //=============================================================================
833 /*!
834  *  
835  */
836 //=============================================================================
837 int SMESH_Mesh::NbSubMesh() throw(SALOME_Exception)
838 {
839   Unexpect aCatch(SalomeException);
840   return _myMeshDS->NbSubMesh();
841 }
842
843 //=======================================================================
844 //function : IsNotConformAllowed
845 //purpose  : check if a hypothesis alowing notconform mesh is present
846 //=======================================================================
847
848 bool SMESH_Mesh::IsNotConformAllowed() const
849 {
850   if(MYDEBUG) MESSAGE("SMESH_Mesh::IsNotConformAllowed");
851
852   const list<const SMESHDS_Hypothesis*>& listHyp =
853     _myMeshDS->GetHypothesis( _myMeshDS->ShapeToMesh() );
854   list<const SMESHDS_Hypothesis*>::const_iterator it=listHyp.begin();
855   while (it!=listHyp.end())
856   {
857     const SMESHDS_Hypothesis *aHyp = *it;
858     string hypName = aHyp->GetName();
859     if ( hypName == "NotConformAllowed" )
860       return true;
861     it++;
862   }
863   return false;
864 }
865
866 //=======================================================================
867 //function : IsMainShape
868 //purpose  : 
869 //=======================================================================
870
871 bool SMESH_Mesh::IsMainShape(const TopoDS_Shape& theShape) const
872 {
873   return theShape.IsSame(_myMeshDS->ShapeToMesh() );
874 }
875
876 //=============================================================================
877 /*!
878  *  
879  */
880 //=============================================================================
881
882 SMESH_Group* SMESH_Mesh::AddGroup (const SMDSAbs_ElementType theType,
883                                    const char*               theName,
884                                    int&                      theId,
885                                    const TopoDS_Shape&       theShape)
886 {
887   if (_mapGroup.find(_groupId) != _mapGroup.end())
888     return NULL;
889   theId = _groupId;
890   SMESH_Group* aGroup = new SMESH_Group (theId, this, theType, theName, theShape);
891   GetMeshDS()->AddGroup( aGroup->GetGroupDS() );
892   _mapGroup[_groupId++] = aGroup;
893   return aGroup;
894 }
895
896 //=============================================================================
897 /*!
898  *  
899  */
900 //=============================================================================
901
902 SMESH_Group* SMESH_Mesh::GetGroup (const int theGroupID)
903 {
904   if (_mapGroup.find(theGroupID) == _mapGroup.end())
905     return NULL;
906   return _mapGroup[theGroupID];
907 }
908
909
910 //=============================================================================
911 /*!
912  *  
913  */
914 //=============================================================================
915
916 list<int> SMESH_Mesh::GetGroupIds()
917 {
918   list<int> anIds;
919   for ( map<int, SMESH_Group*>::const_iterator it = _mapGroup.begin(); it != _mapGroup.end(); it++ )
920     anIds.push_back( it->first );
921   
922   return anIds;
923 }
924
925
926 //=============================================================================
927 /*!
928  *  
929  */
930 //=============================================================================
931
932 void SMESH_Mesh::RemoveGroup (const int theGroupID)
933 {
934   if (_mapGroup.find(theGroupID) == _mapGroup.end())
935     return;
936   GetMeshDS()->RemoveGroup( _mapGroup[theGroupID]->GetGroupDS() );
937   _mapGroup.erase (theGroupID);
938   delete _mapGroup[theGroupID];
939 }
940
941 //=============================================================================
942 /*!
943  *  IsLocal1DHypothesis
944  *  Check, if there is 1D hypothesis assigned directly on <theEdge>
945  */
946 //=============================================================================
947 bool SMESH_Mesh::IsLocal1DHypothesis (const TopoDS_Shape& theEdge)
948 {
949   const SMESHDS_Mesh* meshDS = GetMeshDS();
950   const list<const SMESHDS_Hypothesis*>& listHyp = meshDS->GetHypothesis(theEdge);
951   list<const SMESHDS_Hypothesis*>::const_iterator it = listHyp.begin();
952
953   for (; it != listHyp.end(); it++) {
954     const SMESH_Hypothesis * aHyp = static_cast<const SMESH_Hypothesis*>(*it);
955     if (aHyp->GetType() == SMESHDS_Hypothesis::PARAM_ALGO &&
956         aHyp->GetDim() == 1) { // 1D Hypothesis found
957       return true;
958     }
959   }
960   return false;
961 }
962
963 //=============================================================================
964 /*!
965  *  IsPropagationHypothesis
966  */
967 //=============================================================================
968 bool SMESH_Mesh::IsPropagationHypothesis (const TopoDS_Shape& theEdge)
969 {
970   return _mapPropagationChains.Contains(theEdge);
971 }
972
973 //=============================================================================
974 /*!
975  *  IsPropagatedHypothesis
976  */
977 //=============================================================================
978 bool SMESH_Mesh::IsPropagatedHypothesis (const TopoDS_Shape& theEdge,
979                                          TopoDS_Shape&       theMainEdge)
980 {
981   int nbChains = _mapPropagationChains.Extent();
982   for (int i = 1; i <= nbChains; i++) {
983     const TopTools_IndexedMapOfShape& aChain = _mapPropagationChains.FindFromIndex(i);
984     if (aChain.Contains(theEdge)) {
985       theMainEdge = _mapPropagationChains.FindKey(i);
986       return true;
987     }
988   }
989
990   return false;
991 }
992 //=============================================================================
993 /*!
994  *  IsReversedInChain
995  */
996 //=============================================================================
997
998 bool SMESH_Mesh::IsReversedInChain (const TopoDS_Shape& theEdge,
999                                     const TopoDS_Shape& theMainEdge)
1000 {
1001   if ( !theMainEdge.IsNull() && !theEdge.IsNull() &&
1002       _mapPropagationChains.Contains( theMainEdge ))
1003   {
1004     const TopTools_IndexedMapOfShape& aChain =
1005       _mapPropagationChains.FindFromKey( theMainEdge );
1006     int index = aChain.FindIndex( theEdge );
1007     if ( index )
1008       return aChain(index).Orientation() == TopAbs_REVERSED;
1009   }
1010   return false;
1011 }
1012
1013 //=============================================================================
1014 /*!
1015  *  CleanMeshOnPropagationChain
1016  */
1017 //=============================================================================
1018 void SMESH_Mesh::CleanMeshOnPropagationChain (const TopoDS_Shape& theMainEdge)
1019 {
1020   const TopTools_IndexedMapOfShape& aChain = _mapPropagationChains.FindFromKey(theMainEdge);
1021   int i, nbEdges = aChain.Extent();
1022   for (i = 1; i <= nbEdges; i++) {
1023     TopoDS_Shape anEdge = aChain.FindKey(i);
1024     SMESH_subMesh *subMesh = GetSubMesh(anEdge);
1025     SMESHDS_SubMesh *subMeshDS = subMesh->GetSubMeshDS();
1026     if (subMeshDS && subMeshDS->NbElements() > 0) {
1027       subMesh->ComputeStateEngine(SMESH_subMesh::CLEANDEP);
1028     }
1029   }
1030 }
1031
1032 //=============================================================================
1033 /*!
1034  *  RebuildPropagationChains
1035  *  Rebuild all existing propagation chains.
1036  *  Have to be used, if 1D hypothesis have been assigned/removed to/from any edge
1037  */
1038 //=============================================================================
1039 bool SMESH_Mesh::RebuildPropagationChains()
1040 {
1041   bool ret = true;
1042
1043   // Clean all chains, because they can be not up-to-date
1044   int i, nbChains = _mapPropagationChains.Extent();
1045   for (i = 1; i <= nbChains; i++) {
1046     TopoDS_Shape aMainEdge = _mapPropagationChains.FindKey(i);
1047     CleanMeshOnPropagationChain(aMainEdge);
1048     _mapPropagationChains.ChangeFromIndex(i).Clear();
1049   }
1050
1051   // Build all chains
1052   for (i = 1; i <= nbChains; i++) {
1053     TopoDS_Shape aMainEdge = _mapPropagationChains.FindKey(i);
1054     if (!BuildPropagationChain(aMainEdge))
1055       ret = false;
1056     CleanMeshOnPropagationChain(aMainEdge);
1057   }
1058
1059   return ret;
1060 }
1061
1062 //=============================================================================
1063 /*!
1064  *  RemovePropagationChain
1065  *  Have to be used, if Propagation hypothesis is removed from <theMainEdge>
1066  */
1067 //=============================================================================
1068 bool SMESH_Mesh::RemovePropagationChain (const TopoDS_Shape& theMainEdge)
1069 {
1070   if (!_mapPropagationChains.Contains(theMainEdge))
1071     return false;
1072
1073   // Clean mesh elements and nodes, built on the chain
1074   CleanMeshOnPropagationChain(theMainEdge);
1075
1076   // Clean the chain
1077   _mapPropagationChains.ChangeFromKey(theMainEdge).Clear();
1078
1079   // Remove the chain from the map
1080   int i = _mapPropagationChains.FindIndex(theMainEdge);
1081   TopoDS_Vertex anEmptyShape;
1082   BRep_Builder BB;
1083   BB.MakeVertex(anEmptyShape, gp_Pnt(0,0,0), 0.1);
1084   TopTools_IndexedMapOfShape anEmptyMap;
1085   _mapPropagationChains.Substitute(i, anEmptyShape, anEmptyMap);
1086
1087   return true;
1088 }
1089
1090 //=============================================================================
1091 /*!
1092  *  BuildPropagationChain
1093  */
1094 //=============================================================================
1095 bool SMESH_Mesh::BuildPropagationChain (const TopoDS_Shape& theMainEdge)
1096 {
1097   if (theMainEdge.ShapeType() != TopAbs_EDGE) return true;
1098
1099   // Add new chain, if there is no
1100   if (!_mapPropagationChains.Contains(theMainEdge)) {
1101     TopTools_IndexedMapOfShape aNewChain;
1102     _mapPropagationChains.Add(theMainEdge, aNewChain);
1103   }
1104
1105   // Check presence of 1D hypothesis to be propagated
1106   if (!IsLocal1DHypothesis(theMainEdge)) {
1107     MESSAGE("Warning: There is no 1D hypothesis to propagate. Please, assign.");
1108     return true;
1109   }
1110
1111   // Edges, on which the 1D hypothesis will be propagated from <theMainEdge>
1112   TopTools_IndexedMapOfShape& aChain = _mapPropagationChains.ChangeFromKey(theMainEdge);
1113   if (aChain.Extent() > 0) {
1114     CleanMeshOnPropagationChain(theMainEdge);
1115     aChain.Clear();
1116   }
1117
1118   // At first put <theMainEdge> in the chain
1119   aChain.Add(theMainEdge);
1120
1121   // List of edges, added to chain on the previous cycle pass
1122   TopTools_ListOfShape listPrevEdges;
1123   listPrevEdges.Append(theMainEdge.Oriented( TopAbs_FORWARD ));
1124
1125 //   5____4____3____4____5____6
1126 //   |    |    |    |    |    |
1127 //   |    |    |    |    |    |
1128 //   4____3____2____3____4____5
1129 //   |    |    |    |    |    |      Number in the each knot of
1130 //   |    |    |    |    |    |      grid indicates cycle pass,
1131 //   3____2____1____2____3____4      on which corresponding edge
1132 //   |    |    |    |    |    |      (perpendicular to the plane
1133 //   |    |    |    |    |    |      of view) will be found.
1134 //   2____1____0____1____2____3
1135 //   |    |    |    |    |    |
1136 //   |    |    |    |    |    |
1137 //   3____2____1____2____3____4
1138
1139   // Collect all edges pass by pass
1140   while (listPrevEdges.Extent() > 0) {
1141     // List of edges, added to chain on this cycle pass
1142     TopTools_ListOfShape listCurEdges;
1143
1144     // Find the next portion of edges
1145     TopTools_ListIteratorOfListOfShape itE (listPrevEdges);
1146     for (; itE.More(); itE.Next()) {
1147       TopoDS_Shape anE = itE.Value();
1148
1149       // Iterate on faces, having edge <anE>
1150       TopTools_ListIteratorOfListOfShape itA (GetAncestors(anE));
1151       for (; itA.More(); itA.Next()) {
1152         TopoDS_Shape aW = itA.Value();
1153
1154         // There are objects of different type among the ancestors of edge
1155         if (aW.ShapeType() == TopAbs_WIRE) {
1156           TopoDS_Shape anOppE;
1157
1158           BRepTools_WireExplorer aWE (TopoDS::Wire(aW));
1159           Standard_Integer nb = 1, found = 0;
1160           TopTools_Array1OfShape anEdges (1,4);
1161           for (; aWE.More(); aWE.Next(), nb++) {
1162             if (nb > 4) {
1163               found = 0;
1164               break;
1165             }
1166             anEdges(nb) = aWE.Current();
1167             if (!_mapAncestors.Contains(anEdges(nb))) {
1168               MESSAGE("WIRE EXPLORER HAVE GIVEN AN INVALID EDGE !!!");
1169               break;
1170             }
1171             if (anEdges(nb).IsSame(anE)) found = nb;
1172           }
1173
1174           if (nb == 5 && found > 0) {
1175             // Quadrangle face found, get an opposite edge
1176             Standard_Integer opp = found + 2;
1177             if (opp > 4) opp -= 4;
1178             anOppE = anEdges(opp);
1179
1180             if (!aChain.Contains(anOppE)) {
1181               if (!IsLocal1DHypothesis(anOppE)) {
1182                 TopoDS_Shape aMainEdgeForOppEdge;
1183                 if (IsPropagatedHypothesis(anOppE, aMainEdgeForOppEdge)) {
1184                   // Collision!
1185                   MESSAGE("Error: Collision between propagated hypotheses");
1186                   CleanMeshOnPropagationChain(theMainEdge);
1187                   aChain.Clear();
1188                   return false;
1189                 } else {
1190                   // Add found edge to the chain oriented so that to
1191                   // have it in aChain co-directed with theMainEdge
1192                   TopAbs_Orientation ori = anE.Orientation();
1193                   if ( anEdges(opp).Orientation() == anEdges(found).Orientation() )
1194                     ori = TopAbs::Reverse( ori );
1195                   anOppE.Orientation( ori );
1196                   aChain.Add(anOppE);
1197                   listCurEdges.Append(anOppE);
1198                 }
1199               }
1200             }
1201           } // if (nb == 5 && found > 0)
1202         } // if (aF.ShapeType() == TopAbs_WIRE)
1203       } // for (; itF.More(); itF.Next())
1204     } // for (; itE.More(); itE.Next())
1205
1206     listPrevEdges = listCurEdges;
1207   } // while (listPrevEdges.Extent() > 0)
1208
1209   CleanMeshOnPropagationChain(theMainEdge);
1210   return true;
1211 }
1212
1213 //=======================================================================
1214 //function : GetAncestors
1215 //purpose  : return list of ancestors of theSubShape in the order
1216 //           that lower dimention shapes come first.
1217 //=======================================================================
1218
1219 const TopTools_ListOfShape& SMESH_Mesh::GetAncestors(const TopoDS_Shape& theS)
1220 {
1221   if ( _mapAncestors.IsEmpty() )
1222   {
1223     // fill _mapAncestors
1224     int desType, ancType;
1225     for ( desType = TopAbs_EDGE; desType > TopAbs_COMPOUND; desType-- )
1226       for ( ancType = desType - 1; ancType >= TopAbs_COMPOUND; ancType-- )
1227         TopExp::MapShapesAndAncestors (_myMeshDS->ShapeToMesh(),
1228                                        (TopAbs_ShapeEnum) desType,
1229                                        (TopAbs_ShapeEnum) ancType,
1230                                        _mapAncestors );
1231   }
1232
1233   if ( _mapAncestors.Contains( theS ) )
1234     return _mapAncestors.FindFromKey( theS );
1235
1236   static TopTools_ListOfShape emptyList;
1237   return emptyList;
1238 }
1239
1240 //=======================================================================
1241 //function : Dump
1242 //purpose  : dumps contents of mesh to stream [ debug purposes ]
1243 //=======================================================================
1244 ostream& SMESH_Mesh::Dump(ostream& save)
1245 {
1246   save << "========================== Dump contents of mesh ==========================" << endl;
1247   save << "1) Total number of nodes:     " << NbNodes() << endl;
1248   save << "2) Total number of edges:     " << NbEdges() << endl;
1249   save << "3) Total number of faces:     " << NbFaces() << endl;
1250   if ( NbFaces() > 0 ) {
1251     int nb3 = NbTriangles();
1252     int nb4 = NbQuadrangles();
1253     save << "3.1.) Number of triangles:    " << nb3 << endl;
1254     save << "3.2.) Number of quadrangles:  " << nb4 << endl;
1255     if ( nb3 + nb4 !=  NbFaces() ) {
1256       map<int,int> myFaceMap;
1257       SMDS_FaceIteratorPtr itFaces=_myMeshDS->facesIterator();
1258       while( itFaces->more( ) ) {
1259         int nbNodes = itFaces->next()->NbNodes();
1260         if ( myFaceMap.find( nbNodes ) == myFaceMap.end() )
1261           myFaceMap[ nbNodes ] = 0;
1262         myFaceMap[ nbNodes ] = myFaceMap[ nbNodes ] + 1;
1263       }
1264       save << "3.3.) Faces in detail: " << endl;
1265       map <int,int>::iterator itF;
1266       for (itF = myFaceMap.begin(); itF != myFaceMap.end(); itF++)
1267         save << "--> nb nodes: " << itF->first << " - nb elemens: " << itF->second << endl;
1268     }
1269   }
1270   save << "4) Total number of volumes:   " << NbVolumes() << endl;
1271   if ( NbVolumes() > 0 ) {
1272     int nb8 = NbHexas();
1273     int nb4 = NbTetras();
1274     int nb5 = NbPyramids();
1275     int nb6 = NbPrisms();
1276     save << "4.1.) Number of hexahedrons:  " << nb8 << endl;
1277     save << "4.2.) Number of tetrahedrons: " << nb4 << endl;
1278     save << "4.3.) Number of prisms:       " << nb6 << endl;
1279     save << "4.4.) Number of pyramides:    " << nb5 << endl;
1280     if ( nb8 + nb4 + nb5 + nb6 != NbVolumes() ) {
1281       map<int,int> myVolumesMap;
1282       SMDS_VolumeIteratorPtr itVolumes=_myMeshDS->volumesIterator();
1283       while( itVolumes->more( ) ) {
1284         int nbNodes = itVolumes->next()->NbNodes();
1285         if ( myVolumesMap.find( nbNodes ) == myVolumesMap.end() )
1286           myVolumesMap[ nbNodes ] = 0;
1287         myVolumesMap[ nbNodes ] = myVolumesMap[ nbNodes ] + 1;
1288       }
1289       save << "4.5.) Volumes in detail: " << endl;
1290       map <int,int>::iterator itV;
1291       for (itV = myVolumesMap.begin(); itV != myVolumesMap.end(); itV++)
1292         save << "--> nb nodes: " << itV->first << " - nb elemens: " << itV->second << endl;
1293     }
1294   }
1295   save << "===========================================================================" << endl;
1296   return save;
1297 }