Salome HOME
0021077: EDF 1695 SMESH: Netgen works bad with 1D hypothesis on an elliptic torus
[modules/smesh.git] / src / StdMeshers / StdMeshers_Propagation.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   : StdMeshers_Propagation.cxx
25 //  Module : SMESH
26 //
27 #include "StdMeshers_Propagation.hxx"
28
29 #include "utilities.h"
30
31 #include "SMDS_SetIterator.hxx"
32 #include "SMESH_Algo.hxx"
33 #include "SMESH_Gen.hxx"
34 #include "SMESH_HypoFilter.hxx"
35 #include "SMESH_Mesh.hxx"
36 #include "SMESH_subMesh.hxx"
37
38 #include <BRepTools_WireExplorer.hxx>
39 #include <TopTools_ListIteratorOfListOfShape.hxx>
40 #include <TopTools_MapOfShape.hxx>
41 #include <TopoDS.hxx>
42
43 #define DBGMSG(txt) \
44   //  cout << txt << endl;
45
46 using namespace std;
47
48 namespace {
49
50   // =======================================================================
51   /*!
52    * \brief Listener managing propagation of 1D hypotheses
53    */
54   // =======================================================================
55
56   class PropagationMgr: public SMESH_subMeshEventListener
57   {
58   public:
59     static PropagationMgr* GetListener();
60     /*!
61      * \brief Set listener on edge submesh
62      */
63     static void Set(SMESH_subMesh * submesh);
64     /*!
65      * \brief Return an edge from which hypotheses are propagated from
66      */
67     static TopoDS_Edge GetSource(SMESH_subMesh * submesh);
68     /*!
69      * \brief Does it's main job
70      */
71     void ProcessEvent(const int          event,
72                       const int          eventType,
73                       SMESH_subMesh*     subMesh,
74                       SMESH_subMeshEventListenerData* data,
75                       const SMESH_Hypothesis*         hyp = 0);
76   private:
77     PropagationMgr();
78   };
79 }
80
81 //=============================================================================
82 /*!
83  * StdMeshers_Propagation Implementation
84  */
85 //=============================================================================
86
87 StdMeshers_Propagation::StdMeshers_Propagation (int hypId, int studyId, SMESH_Gen * gen)
88   : SMESH_Hypothesis(hypId, studyId, gen)
89 {
90   _name = GetName();
91   _param_algo_dim = -1; // 1D auxiliary
92 }
93 StdMeshers_Propagation::~StdMeshers_Propagation()                      {}
94 string StdMeshers_Propagation::GetName ()                              { return "Propagation"; }
95 ostream & StdMeshers_Propagation::SaveTo (ostream & save)              { return save; }
96 istream & StdMeshers_Propagation::LoadFrom (istream & load)            { return load; }
97 ostream & operator << (ostream & save, StdMeshers_Propagation & hyp)   { return hyp.SaveTo(save); }
98 istream & operator >> (istream & load, StdMeshers_Propagation & hyp)   { return hyp.LoadFrom(load); }
99 bool StdMeshers_Propagation::SetParametersByMesh(const SMESH_Mesh*,
100                                                  const TopoDS_Shape& ) { return false; }
101 bool StdMeshers_Propagation::SetParametersByDefaults(const TDefaults&,const SMESH_Mesh*) { return false; }
102 void StdMeshers_Propagation::SetPropagationMgr(SMESH_subMesh* subMesh) { PropagationMgr::Set( subMesh ); }
103 /*!
104  * \brief Return an edge from which hypotheses are propagated from
105  */
106 TopoDS_Edge StdMeshers_Propagation::GetPropagationSource(SMESH_Mesh& theMesh,
107                                                          const TopoDS_Shape& theEdge)
108 {
109   return PropagationMgr::GetSource(theMesh.GetSubMeshContaining( theEdge ));
110 }
111
112 //=============================================================================
113 //=============================================================================
114 // PROPAGATION MANAGEMENT
115 //=============================================================================
116 //=============================================================================
117
118 namespace {
119
120   enum SubMeshState { WAIT_PROPAG_HYP, // propagation hyp or local 1D hyp is missing
121                       HAS_PROPAG_HYP,  // propag hyp on this submesh
122                       IN_CHAIN,        // submesh is in propagation chain
123                       LAST_IN_CHAIN,   // submesh with local 1D hyp breaking a chain
124                       MEANINGLESS_LAST };          // meaningless
125
126   struct PropagationMgrData : public EventListenerData
127   {
128     bool myForward; //!< true if a curve of edge in chain is codirected with one of source edge
129     PropagationMgrData( SubMeshState state=WAIT_PROPAG_HYP ): EventListenerData(true) {
130       myType = state; myForward = true;
131     }
132     void Init() {
133       myType = WAIT_PROPAG_HYP;  mySubMeshes.clear(); myForward = true;
134     }
135     SubMeshState State() const {
136       return (SubMeshState) myType;
137     }
138     void SetState(SubMeshState state) {
139       myType = state;
140     }
141     void SetSource(SMESH_subMesh* sm ) {
142       mySubMeshes.clear(); if ( sm ) mySubMeshes.push_back( sm );
143     }
144     void AddSource(SMESH_subMesh* sm ) {
145       if ( sm ) mySubMeshes.push_back( sm );
146     }
147     void SetChain(list< SMESH_subMesh* >& chain ) {
148       mySubMeshes.clear(); mySubMeshes.splice( mySubMeshes.end(), chain );
149     }
150     SMESH_subMeshIteratorPtr GetChain() const;
151     SMESH_subMesh* GetSource() const;
152   };
153
154   //=============================================================================
155   /*!
156    * \brief return static PropagationMgr
157    */
158   PropagationMgr* PropagationMgr::GetListener()
159   {
160     static PropagationMgr theListener;
161     return &theListener;
162   }
163   PropagationMgr* getListener()
164   {
165     return PropagationMgr::GetListener();
166   }
167   //=============================================================================
168   /*!
169    * \brief return PropagationMgrData found on a submesh
170    */
171   PropagationMgrData* findData(SMESH_subMesh* sm)
172   {
173     if ( sm )
174       return static_cast< PropagationMgrData* >( sm->GetEventListenerData( getListener() ));
175     return 0;
176   }
177   //=============================================================================
178   /*!
179    * \brief return PropagationMgrData found on theEdge submesh
180    */
181   PropagationMgrData* findData(SMESH_Mesh& theMesh, const TopoDS_Shape& theEdge)
182   {
183     if ( theEdge.ShapeType() == TopAbs_EDGE )
184       return findData( theMesh.GetSubMeshContaining( theEdge ) );
185     return 0;
186   }
187   //=============================================================================
188   /*!
189    * \brief return existing or a new PropagationMgrData
190    */
191   PropagationMgrData* getData(SMESH_subMesh* sm)
192   {
193     PropagationMgrData* data = findData( sm );
194     if ( !data && sm ) {
195       data = new PropagationMgrData();
196       sm->SetEventListener( getListener(), data, sm );
197     }
198     return data;
199   }
200   //=============================================================================
201   /*!
202    * \brief Returns a local 1D hypothesis used for theEdge
203    */
204   const SMESH_Hypothesis* getLocal1DHyp (SMESH_Mesh&         theMesh,
205                                          const TopoDS_Shape& theEdge)
206   {
207     static SMESH_HypoFilter hypo;
208     hypo.Init( hypo.HasDim( 1 )).
209       AndNot ( hypo.IsAlgo() ).
210       AndNot ( hypo.IsAssignedTo( theMesh.GetMeshDS()->ShapeToMesh() ));
211     return theMesh.GetHypothesis( theEdge, hypo, true );
212   }
213   //=============================================================================
214   /*!
215    * \brief Returns a propagation hypothesis assigned to theEdge
216    */
217   const SMESH_Hypothesis* getProagationHyp (SMESH_Mesh&         theMesh,
218                                             const TopoDS_Shape& theEdge)
219   {
220     static SMESH_HypoFilter propagHypFilter
221       ( SMESH_HypoFilter::HasName( StdMeshers_Propagation::GetName ()));
222     return theMesh.GetHypothesis( theEdge, propagHypFilter, true );
223   }
224   //================================================================================
225   /*!
226    * \brief Return an iterator on a list of submeshes
227    */
228   SMESH_subMeshIteratorPtr iterate( list<SMESH_subMesh*>::const_iterator from,
229                                     list<SMESH_subMesh*>::const_iterator to)
230   {
231     typedef SMESH_subMesh* TsubMesh;
232     typedef SMDS_SetIterator< TsubMesh, list< TsubMesh >::const_iterator > TIterator;
233     return SMESH_subMeshIteratorPtr ( new TIterator( from, to ));
234   }
235   //================================================================================
236   /*!
237    * \brief Build propagation chain
238     * \param theMainSubMesh - the submesh with Propagation hypothesis
239    */
240   bool buildPropagationChain ( SMESH_subMesh* theMainSubMesh )
241   {
242     DBGMSG( "buildPropagationChain from " << theMainSubMesh->GetId() );
243     const TopoDS_Shape& theMainEdge = theMainSubMesh->GetSubShape();
244     if (theMainEdge.ShapeType() != TopAbs_EDGE) return true;
245
246     SMESH_Mesh* mesh = theMainSubMesh->GetFather();
247
248     PropagationMgrData* chainData = getData( theMainSubMesh );
249     chainData->SetState( HAS_PROPAG_HYP );
250
251     // Edge submeshes, to which the 1D hypothesis will be propagated from theMainEdge
252     list<SMESH_subMesh*> & chain = chainData->mySubMeshes;
253     chain.clear();
254     chain.push_back( theMainSubMesh );
255
256     TopTools_MapOfShape checkedShapes;
257     checkedShapes.Add( theMainEdge );
258
259     list<SMESH_subMesh*>::iterator smIt = chain.begin();
260     for ( ; smIt != chain.end(); ++smIt )
261     {
262       const TopoDS_Edge& anE = TopoDS::Edge( (*smIt)->GetSubShape() );
263       PropagationMgrData* data = findData( *smIt );
264       if ( !data ) continue;
265
266       // Iterate on faces, having edge <anE>
267       TopTools_ListIteratorOfListOfShape itA (mesh->GetAncestors(anE));
268       for (; itA.More(); itA.Next())
269       {
270         // there are objects of different type among the ancestors of edge
271         if ( itA.Value().ShapeType() != TopAbs_WIRE || !checkedShapes.Add( itA.Value() ))
272           continue;
273
274         // Get ordered edges and find index of anE in a sequence
275         BRepTools_WireExplorer aWE (TopoDS::Wire(itA.Value()));
276         vector<TopoDS_Edge> edges;
277         edges.reserve(4);
278         int edgeIndex = 0;
279         for (; aWE.More(); aWE.Next()) {
280           TopoDS_Edge edge = aWE.Current();
281           edge.Orientation( aWE.Orientation() );
282           if ( edge.IsSame( anE ))
283             edgeIndex = edges.size();
284           edges.push_back( edge );
285         }
286
287         // Find an edge opposite to anE
288         TopoDS_Edge anOppE;
289         if ( edges.size() < 4 ) {
290           continue; // too few edges
291         }
292         else if ( edges.size() == 4 ) {
293           int oppIndex = edgeIndex + 2;
294           if ( oppIndex > 3 ) oppIndex -= 4;
295           anOppE = edges[ oppIndex ];
296         }
297         else {
298           // count nb sides
299           TopoDS_Edge prevEdge = anE;
300           int nbSide = 0, eIndex = edgeIndex + 1;
301           for ( int i = 0; i < edges.size(); ++i, ++eIndex )
302           {
303             if ( eIndex == edges.size() )
304               eIndex = 0;
305             if ( !SMESH_Algo::IsContinuous( prevEdge, edges[ eIndex ])) {
306               nbSide++;
307             }
308             else {
309               // check that anE is not a part of a composite side
310               if ( anE.IsSame( prevEdge ) || anE.IsSame( edges[ eIndex ])) {
311                 anOppE.Nullify(); break;
312               }
313             }
314             if ( nbSide == 2 ) { // opposite side
315               if ( !anOppE.IsNull() ) {
316                 // composite opposite side -> stop propagation
317                 anOppE.Nullify(); break;
318               }
319               anOppE = edges[ eIndex ];
320             }
321             if ( nbSide == 5 ) {
322               anOppE.Nullify(); break; // too many sides
323             }
324             prevEdge = edges[ eIndex ];
325           }
326           if ( anOppE.IsNull() )
327             continue;
328           if ( nbSide != 4 ) {
329             DBGMSG( nbSide << " sides in wire #" << mesh->GetMeshDS()->ShapeToIndex( itA.Value() ) << " - SKIP" );
330             continue;
331           }
332         }
333         if ( anOppE.IsNull() || !checkedShapes.Add( anOppE ))
334           continue;
335         SMESH_subMesh* oppSM = mesh->GetSubMesh( anOppE );
336         PropagationMgrData* oppData = getData( oppSM );
337
338         // Add anOppE to aChain if ...
339         if ( oppData->State() == WAIT_PROPAG_HYP ) // ... anOppE is not in any chain
340         {
341           oppData->SetSource( theMainSubMesh );
342           if ( !getLocal1DHyp( *mesh, anOppE )) // ... no 1d hyp on anOppE
343           {
344             oppData->myForward = data->myForward;
345             if ( edges[ edgeIndex ].Orientation() == anOppE.Orientation() )
346               oppData->myForward = !oppData->myForward;
347             chain.push_back( oppSM );
348             oppSM->ComputeStateEngine( SMESH_subMesh::CLEAN );
349             oppData->SetState( IN_CHAIN );
350             DBGMSG( "set IN_CHAIN on " << oppSM->GetId() );
351             if ( oppSM->GetAlgoState() != SMESH_subMesh::HYP_OK )
352               // make oppSM check algo state
353               if ( SMESH_Algo* algo = mesh->GetGen()->GetAlgo( *mesh, anOppE ))
354                 oppSM->AlgoStateEngine(SMESH_subMesh::ADD_FATHER_ALGO,algo);
355           }
356           else {
357             oppData->SetState( LAST_IN_CHAIN );
358             DBGMSG( "set LAST_IN_CHAIN on " << oppSM->GetId() );
359           }
360         }
361         else if ( oppData->State() == LAST_IN_CHAIN ) // anOppE breaks other chain
362         {
363           DBGMSG( "encounters LAST_IN_CHAIN on " << oppSM->GetId() );
364           oppData->AddSource( theMainSubMesh );
365         }
366       } // loop on face ancestors
367     } // loop on the chain
368
369     // theMainSubMesh must not be in a chain
370     chain.pop_front();
371
372     return true;
373   }
374   //================================================================================
375   /*!
376    * \brief Clear propagation chain
377    */
378   bool clearPropagationChain( SMESH_subMesh* subMesh )
379   {
380     DBGMSG( "clearPropagationChain from " << subMesh->GetId() );
381     if ( PropagationMgrData* data = findData( subMesh ))
382     {
383       switch ( data->State() ) {
384       case IN_CHAIN:
385         return clearPropagationChain( data->GetSource() );
386
387       case HAS_PROPAG_HYP: {
388         SMESH_subMeshIteratorPtr smIt = data->GetChain();
389         while ( smIt->more() ) {
390           SMESH_subMesh* sm = smIt->next();
391           getData( sm )->Init();
392           sm->ComputeStateEngine( SMESH_subMesh::CLEAN );
393         }
394         data->Init();
395         break;
396       }
397       case LAST_IN_CHAIN: {
398         SMESH_subMeshIteratorPtr smIt = iterate( data->mySubMeshes.begin(),
399                                                  data->mySubMeshes.end());
400         while ( smIt->more() )
401           clearPropagationChain( smIt->next() );
402         data->Init();
403         break;
404       }
405       default:;
406       }
407       return true;
408     }
409     return false;
410   }
411
412
413   //================================================================================
414   /*!
415    * \brief Return an iterator on chain submeshes
416    */
417   //================================================================================
418
419   SMESH_subMeshIteratorPtr PropagationMgrData::GetChain() const
420   {
421     switch ( State() ) {
422     case HAS_PROPAG_HYP:
423       return iterate( mySubMeshes.begin(), mySubMeshes.end() );
424     case IN_CHAIN:
425       if ( mySubMeshes.empty() ) break;
426       return getData( mySubMeshes.front() )->GetChain();
427     default:;
428     }
429     return iterate( mySubMeshes.end(), mySubMeshes.end() );
430   }
431   //================================================================================
432   /*!
433    * \brief Return a propagation source submesh
434    */
435   //================================================================================
436
437   SMESH_subMesh* PropagationMgrData::GetSource() const
438   {
439     if ( myType == IN_CHAIN )
440       if ( !mySubMeshes.empty() ) 
441         return mySubMeshes.front();
442     return 0;
443   }
444
445
446   //================================================================================
447   /*!
448    * \brief Constructor
449    */
450   //================================================================================
451
452   PropagationMgr::PropagationMgr()
453     : SMESH_subMeshEventListener( false ) // won't be deleted by submesh
454   {}
455   //================================================================================
456   /*!
457    * \brief Set PropagationMgr on a submesh
458    */
459   //================================================================================
460
461   void PropagationMgr::Set(SMESH_subMesh * submesh)
462   {
463     if ( findData( submesh )) return;
464     DBGMSG( "PropagationMgr::Set() on  " << submesh->GetId() );
465     EventListenerData* data = new PropagationMgrData();
466     submesh->SetEventListener( getListener(), data, submesh );
467
468     const SMESH_Hypothesis * propagHyp =
469       getProagationHyp( *submesh->GetFather(), submesh->GetSubShape() );
470     if ( propagHyp )
471       getListener()->ProcessEvent( SMESH_subMesh::ADD_HYP,
472                                    SMESH_subMesh::ALGO_EVENT,
473                                    submesh,
474                                    data,
475                                    propagHyp);
476   }
477   //================================================================================
478   /*!
479    * \brief Return an edge from which hypotheses are propagated
480    */
481   //================================================================================
482
483   TopoDS_Edge PropagationMgr::GetSource(SMESH_subMesh * submesh)
484   {
485     if ( PropagationMgrData* data = findData( submesh )) {
486       if ( data->State() == IN_CHAIN ) {
487         if ( SMESH_subMesh* sm = data->GetSource() )
488         {
489           TopoDS_Shape edge = sm->GetSubShape();
490           edge = edge.Oriented( data->myForward ? TopAbs_FORWARD : TopAbs_REVERSED );
491           DBGMSG( " GetSource() = edge " << sm->GetId() << " REV = " << (!data->myForward));
492           if ( edge.ShapeType() == TopAbs_EDGE )
493             return TopoDS::Edge( edge );
494         }
495       }
496     }
497     return TopoDS_Edge();
498   }
499   //================================================================================
500   /*!
501    * \brief React on events on 1D submeshes
502    */
503   //================================================================================
504
505   void PropagationMgr::ProcessEvent(const int          event,
506                                     const int          eventType,
507                                     SMESH_subMesh*     subMesh,
508                                     SMESH_subMeshEventListenerData* listenerData,
509                                     const SMESH_Hypothesis*         hyp)
510   {
511     if ( !listenerData )
512       return;
513     if ( !hyp || hyp->GetType() != SMESHDS_Hypothesis::PARAM_ALGO || hyp->GetDim() != 1 )
514       return;
515     if ( eventType != SMESH_subMesh::ALGO_EVENT )
516       return;
517     DBGMSG( "PropagationMgr::ProcessEvent() on  " << subMesh->GetId() );
518
519     bool isPropagHyp = ( StdMeshers_Propagation::GetName() == hyp->GetName() );
520
521     PropagationMgrData* data = static_cast<PropagationMgrData*>( listenerData );
522     switch ( data->State() ) {
523
524     case WAIT_PROPAG_HYP: { // propagation hyp or local 1D hyp is missing
525       // --------------------------------------------------------
526       bool hasPropagHyp = ( isPropagHyp ||
527                             getProagationHyp( *subMesh->GetFather(), subMesh->GetSubShape()) );
528       if ( !hasPropagHyp )
529         return;
530       bool hasLocal1DHyp =  getLocal1DHyp( *subMesh->GetFather(), subMesh->GetSubShape());
531       if ( !hasLocal1DHyp )
532         return;
533       if ( event == SMESH_subMesh::ADD_HYP ||
534            event == SMESH_subMesh::ADD_FATHER_HYP ) // add local or propagation hyp
535       {
536         DBGMSG( "ADD_HYP propagation to WAIT_PROPAG_HYP " << subMesh->GetId() );
537         // build propagation chain
538         buildPropagationChain( subMesh );
539       }
540       return;
541     }
542     case HAS_PROPAG_HYP: {  // propag hyp on this submesh
543       // --------------------------------------------------------
544       switch ( event ) {
545       case SMESH_subMesh::REMOVE_HYP:
546       case SMESH_subMesh::REMOVE_FATHER_HYP: // remove propagation hyp
547         if ( isPropagHyp && !getProagationHyp( *subMesh->GetFather(), subMesh->GetSubShape()) )
548         {
549           DBGMSG( "REMOVE_HYP propagation from HAS_PROPAG_HYP " << subMesh->GetId() );
550           // clear propagation chain
551           clearPropagationChain( subMesh );
552         }
553         // return; -- hyp is modified any way
554       default:
555         //case SMESH_subMesh::MODIF_HYP: // hyp modif
556         // clear mesh in a chain
557         DBGMSG( "MODIF_HYP on HAS_PROPAG_HYP " << subMesh->GetId() );
558         SMESH_subMeshIteratorPtr smIt = data->GetChain();
559         while ( smIt->more() ) {
560           SMESH_subMesh* smInChain = smIt->next();
561           smInChain->AlgoStateEngine( SMESH_subMesh::MODIF_HYP,
562                                       (SMESH_Hypothesis*) hyp );
563         }
564         return;
565       }
566       return;
567     }
568     case IN_CHAIN: {       // submesh is in propagation chain
569       // --------------------------------------------------------
570       if ( event == SMESH_subMesh::ADD_HYP ) { // add local hypothesis
571         if ( isPropagHyp ) { // propagation hyp added
572           DBGMSG( "ADD_HYP propagation on IN_CHAIN " << subMesh->GetId() );
573           // collision - do nothing
574         }
575         else { // 1D hyp added
576           // rebuild propagation chain
577           DBGMSG( "ADD_HYP 1D on IN_CHAIN " << subMesh->GetId() );
578           SMESH_subMesh* sourceSM = data->GetSource();
579           clearPropagationChain( sourceSM );
580           buildPropagationChain( sourceSM );
581         }
582       }
583       return;
584     }
585     case LAST_IN_CHAIN: { // submesh with local 1D hyp, breaking a chain
586       // --------------------------------------------------------
587       if ( event == SMESH_subMesh::REMOVE_HYP ) { // remove local hyp
588         // rebuild propagation chain
589         DBGMSG( "REMOVE_HYP 1D from LAST_IN_CHAIN " << subMesh->GetId() );
590         list<SMESH_subMesh*> sourceSM = data->mySubMeshes;
591         clearPropagationChain( subMesh );
592         SMESH_subMeshIteratorPtr smIt = iterate( sourceSM.begin(), sourceSM.end());
593         while ( smIt->more() )
594           buildPropagationChain( smIt->next() );
595       }
596       return;
597     }
598     } // switch by SubMeshState
599   }
600
601 } // namespace