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