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