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