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