Salome HOME
Merging from V3_2_6pre4
[modules/smesh.git] / src / StdMeshers / StdMeshers_Propagation.cxx
1 //  SMESH SMESH : implementaion of SMESH idl descriptions
2 //
3 //  Copyright (C) 2003  CEA
4 //
5 //  This library is free software; you can redistribute it and/or
6 //  modify it under the terms of the GNU Lesser General Public
7 //  License as published by the Free Software Foundation; either
8 //  version 2.1 of the License.
9 //
10 //  This library is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 //  Lesser General Public License for more details.
14 //
15 //  You should have received a copy of the GNU Lesser General Public
16 //  License along with this library; if not, write to the Free Software
17 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18 //
19 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 //
21 //
22 //
23 //  File   : StdMeshers_Propagation.cxx
24 //  Module : SMESH
25 //  $Header$
26
27 #include "StdMeshers_Propagation.hxx"
28
29 #include "utilities.h"
30
31 #include "SMESH_Mesh.hxx"
32 #include "SMESH_subMesh.hxx"
33 #include "SMESH_HypoFilter.hxx"
34 #include "SMDS_SetIterator.hxx"
35
36 using namespace std;
37
38 namespace {
39
40   // =======================================================================
41   /*!
42    * \brief Listener managing propagation of 1D hypotheses
43    */
44   // =======================================================================
45
46   class PropagationMgr: public SMESH_subMeshEventListener
47   {
48   public:
49     static PropagationMgr* GetListener();
50     /*!
51      * \brief Set listener on edge submesh
52      */
53     static void Set(SMESH_subMesh * submesh);
54     /*!
55      * \brief Return an edge from which hypotheses are propagated from
56      */
57     static TopoDS_Edge GetSource(SMESH_subMesh * submesh);
58     /*!
59      * \brief Does it's main job
60      */
61     void ProcessEvent(const int          event,
62                       const int          eventType,
63                       SMESH_subMesh*     subMesh,
64                       SMESH_subMeshEventListenerData* data,
65                       const SMESH_Hypothesis*         hyp = 0);
66   private:
67     PropagationMgr();
68   };
69 }
70
71 //=============================================================================
72 /*!
73  * StdMeshers_Propagation Implementation
74  */
75 //=============================================================================
76
77 StdMeshers_Propagation::StdMeshers_Propagation (int hypId, int studyId, SMESH_Gen * gen)
78   : SMESH_Hypothesis(hypId, studyId, gen)
79 {
80   _name = GetName();
81   _param_algo_dim = -1; // 1D auxiliary
82 }
83 StdMeshers_Propagation::~StdMeshers_Propagation()                      {}
84 string StdMeshers_Propagation::GetName ()                              { return "Propagation"; }
85 ostream & StdMeshers_Propagation::SaveTo (ostream & save)              { return save; }
86 istream & StdMeshers_Propagation::LoadFrom (istream & load)            { return load; }
87 ostream & operator << (ostream & save, StdMeshers_Propagation & hyp)   { return hyp.SaveTo(save); }
88 istream & operator >> (istream & load, StdMeshers_Propagation & hyp)   { return hyp.LoadFrom(load); }
89 bool StdMeshers_Propagation::SetParametersByMesh(const SMESH_Mesh*,
90                                                  const TopoDS_Shape& ) { return false; }
91 void StdMeshers_Propagation::SetPropagationMgr(SMESH_subMesh* subMesh) { PropagationMgr::Set( subMesh ); }
92 /*!
93  * \brief Return an edge from which hypotheses are propagated from
94  */
95 TopoDS_Edge StdMeshers_Propagation::GetPropagationSource(SMESH_Mesh& theMesh,
96                                                          const TopoDS_Shape& theEdge)
97 {
98   return PropagationMgr::GetSource(theMesh.GetSubMeshContaining( theEdge ));
99 }
100
101 //=============================================================================
102 //=============================================================================
103 // PROPAGATION MANAGEMENT
104 //=============================================================================
105 //=============================================================================
106
107 namespace {
108
109   enum SubMeshState { WAIT_PROPAG_HYP, // no propagation hyp in chain
110                       HAS_PROPAG_HYP,  // propag hyp on this submesh
111                       IN_CHAIN,        // submesh is in propagation chain
112                       LAST_IN_CHAIN,   // submesh with local 1D hyp breaking a chain
113                       MEANINGLESS_LAST };          // meaningless
114
115   struct PropagationMgrData : public EventListenerData
116   {
117     bool myForward; //!< true if a curve of edge in chain is codirected with one of source edge
118     PropagationMgrData( SubMeshState state ): EventListenerData(true) {
119       myType = state;
120     }
121     SubMeshState State() const {
122       return (SubMeshState) myType;
123     }
124     void SetSource(SMESH_subMesh* sm ) {
125       mySubMeshes.clear(); if ( sm ) mySubMeshes.push_back( sm );
126     }
127     void SetChain(list< SMESH_subMesh* >& chain ) {
128       mySubMeshes.clear(); mySubMeshes.splice( mySubMeshes.end(), chain );
129     }
130     SMESH_subMeshIteratorPtr GetChain() const;
131     SMESH_subMesh* GetSource() const;
132   };
133
134   //=============================================================================
135   /*!
136    * \brief return filter to find Propagation hypothesis
137    */
138   SMESH_HypoFilter & propagHypFilter()
139   {
140     static SMESH_HypoFilter propagHypFilter
141       ( SMESH_HypoFilter::HasName( StdMeshers_Propagation::GetName ()));
142     return propagHypFilter;
143   }
144   //=============================================================================
145   /*!
146    * \brief return static PropagationMgr
147    */
148   PropagationMgr* PropagationMgr::GetListener()
149   {
150     static PropagationMgr theListener;
151     return &theListener;
152   }
153   PropagationMgr* getListener()
154   {
155     return PropagationMgr::GetListener();
156   }
157   //=============================================================================
158   /*!
159    * \brief return PropagationMgrData
160    */
161   PropagationMgrData* getData(SMESH_subMesh* sm)
162   {
163     if ( sm )
164       return static_cast< PropagationMgrData* >( sm->GetEventListenerData( getListener() ));
165     return 0;
166   }
167   //=============================================================================
168   /*!
169    * \brief return PropagationMgrData
170    */
171   PropagationMgrData* getData(SMESH_Mesh& theMesh, const TopoDS_Shape& theEdge)
172   {
173     if ( theEdge.ShapeType() == TopAbs_EDGE )
174       return getData( theMesh.GetSubMeshContaining( theEdge ) );
175     return 0;
176   }
177   //================================================================================
178   /*!
179    * \brief Return an iterator on a chain
180    */
181   SMESH_subMeshIteratorPtr PropagationMgrData::GetChain() const
182   {
183     typedef SMESH_subMesh* TsubMesh;
184     typedef SMDS_SetIterator< TsubMesh, list< TsubMesh >::const_iterator > TIterator;
185     switch ( State() ) {
186     case HAS_PROPAG_HYP:
187       return SMESH_subMeshIteratorPtr
188         ( new TIterator( mySubMeshes.begin(), mySubMeshes.end() ));
189     case IN_CHAIN:
190     case LAST_IN_CHAIN:
191       if ( mySubMeshes.empty() ) break;
192       return getData( mySubMeshes.front() )->GetChain();
193     default:;
194     }
195     return SMESH_subMeshIteratorPtr
196       ( new TIterator( mySubMeshes.end(), mySubMeshes.end() ));
197   }
198   //================================================================================
199   /*!
200    * \brief Return a propagation source submesh
201    */
202   SMESH_subMesh* PropagationMgrData::GetSource() const
203   {
204     if ( myType == IN_CHAIN || myType == LAST_IN_CHAIN )
205       if ( !mySubMeshes.empty() ) 
206         return mySubMeshes.front();
207     return 0;
208   }
209   //=============================================================================
210   /*!
211    * \brief Returns a local 1D hypothesis used for theEdge
212    */
213   const SMESH_Hypothesis* isLocal1DHypothesis (SMESH_Mesh& theMesh,
214                                                const TopoDS_Shape& theEdge)
215   {
216     static SMESH_HypoFilter hypo ( SMESH_HypoFilter::HasDim( 1 ));
217     hypo.AndNot( hypo.IsAlgo() ).AndNot( hypo.IsAssignedTo( theMesh.GetMeshDS()->ShapeToMesh() ));
218
219     return theMesh.GetHypothesis( theEdge, hypo, true );
220   }
221   //================================================================================
222   /*!
223    * \brief Build propagation chain
224     * \param theMainSubMesh - the submesh with Propagation hypothesis
225    */
226   bool buildPropagationChain ( SMESH_subMesh* theMainSubMesh )
227   {
228   //   const TopoDS_Shape& theMainEdge = theMainSubMesh->GetSubShape();
229 //     if (theMainEdge.ShapeType() != TopAbs_EDGE) return true;
230
231 //     SMESH_Mesh* mesh = theMainSubMesh->GetFather();
232
233 //     EventListenerData* chainData = new PropagationMgrData(HAS_PROPAG_HYP);
234 //     theMainSubMesh->SetEventListener( getListener(), chainData, theMainSubMesh );
235
236 //     // Edges submeshes, on which the 1D hypothesis will be propagated from <theMainEdge>
237 //     list<SMESH_subMesh*> & chain = chainData->mySubMeshes;
238
239 //     // List of edges, added to chain on the previous cycle pass
240 //     TopTools_ListOfShape listPrevEdges;
241 //     listPrevEdges.Append(theMainEdge.Oriented( TopAbs_FORWARD ));
242
243 //     //   4____3____2____3____4____5
244 //     //   |    |    |    |    |    |      Number in the each knot of
245 //     //   |    |    |    |    |    |      grid indicates cycle pass,
246 //     //   3____2____1____2____3____4      on which corresponding edge
247 //     //   |    |    |    |    |    |      (perpendicular to the plane
248 //     //   |    |    |    |    |    |      of view) will be found.
249 //     //   2____1____0____1____2____3
250 //     //   |    |    |    |    |    |
251 //     //   |    |    |    |    |    |
252 //     //   3____2____1____2____3____4
253
254 //     // Collect all edges pass by pass
255 //     while (listPrevEdges.Extent() > 0) {
256 //       // List of edges, added to chain on this cycle pass
257 //       TopTools_ListOfShape listCurEdges;
258
259 //       // Find the next portion of edges
260 //       TopTools_ListIteratorOfListOfShape itE (listPrevEdges);
261 //       for (; itE.More(); itE.Next()) {
262 //         TopoDS_Shape anE = itE.Value();
263
264 //         // Iterate on faces, having edge <anE>
265 //         TopTools_ListIteratorOfListOfShape itA (mesh->GetAncestors(anE));
266 //         for (; itA.More(); itA.Next()) {
267 //           TopoDS_Shape aW = itA.Value();
268
269 //           // There are objects of different type among the ancestors of edge
270 //           if (aW.ShapeType() == TopAbs_WIRE) {
271 //             TopoDS_Shape anOppE;
272
273 //             BRepTools_WireExplorer aWE (TopoDS::Wire(aW));
274 //             Standard_Integer nb = 1, found = 0;
275 //             TopTools_Array1OfShape anEdges (1,4);
276 //             for (; aWE.More(); aWE.Next(), nb++) {
277 //               if (nb > 4) {
278 //                 found = 0;
279 //                 break;
280 //               }
281 //               anEdges(nb) = aWE.Current();
282 //               if (!_mapAncestors.Contains(anEdges(nb))) {
283 //                 MESSAGE("WIRE EXPLORER HAVE GIVEN AN INVALID EDGE !!!");
284 //                 break;
285 //               }
286 //               if (anEdges(nb).IsSame(anE)) found = nb;
287 //             }
288
289 //             if (nb == 5 && found > 0) {
290 //               // Quadrangle face found, get an opposite edge
291 //               Standard_Integer opp = ( found + 2 ) % 4;
292 //               anOppE = anEdges(opp);
293
294 //               // add anOppE to aChain if ...
295 //               PropagationMgrData* data = getData( *mesh, anOppE );
296 //               if ( !data || data->State() == WAIT_PROPAG_HYP ) { // ... anOppE is not in any chain
297 //                 if ( !isLocal1DHypothesis( *mesh, anOppE )) { // ... no other 1d hyp on anOppE
298 //                   // Add found edge to the chain oriented so that to
299 //                   // have it co-directed with a forward MainEdge
300 //                     TopAbs_Orientation ori = anE.Orientation();
301 //                     if ( anEdges(opp).Orientation() == anEdges(found).Orientation() )
302 //                       ori = TopAbs::Reverse( ori );
303 //                     anOppE.Orientation( ori );
304 //                     aChain.Add(anOppE);
305 //                     listCurEdges.Append(anOppE);
306 //                   }
307 //                   else {
308 //                     // Collision!
309 //                     MESSAGE("Error: Collision between propagated hypotheses");
310 //                     CleanMeshOnPropagationChain(theMainEdge);
311 //                     aChain.Clear();
312 //                     return ( aMainHyp == isLocal1DHypothesis(aMainEdgeForOppEdge) );
313 //                   }
314 //                 }
315 //               }
316 //             } // if (nb == 5 && found > 0)
317 //           } // if (aF.ShapeType() == TopAbs_WIRE)
318 //         } // for (; itF.More(); itF.Next())
319 //       } // for (; itE.More(); itE.Next())
320
321 //       listPrevEdges = listCurEdges;
322 //     } // while (listPrevEdges.Extent() > 0)
323
324 //     CleanMeshOnPropagationChain(theMainEdge);
325     return true;
326   }
327   //================================================================================
328   /*!
329    * \brief Clear propagation chain
330    */
331   //================================================================================
332
333   bool clearPropagationChain( SMESH_subMesh* subMesh )
334   {
335     if ( PropagationMgrData* data = getData( subMesh )) {
336       if ( data->State() == IN_CHAIN )
337         return clearPropagationChain( data->GetSource() );
338       return true;
339     }
340     return false;
341   }  
342
343
344   //================================================================================
345   /*!
346    * \brief Constructor
347    */
348   PropagationMgr::PropagationMgr()
349     : SMESH_subMeshEventListener( false ) // won't be deleted by submesh
350   {}
351   //================================================================================
352   /*!
353    * \brief Set PropagationMgr on a submesh
354    */
355   void PropagationMgr::Set(SMESH_subMesh * submesh)
356   {
357     EventListenerData* data = EventListenerData::MakeData(submesh,WAIT_PROPAG_HYP);
358
359     submesh->SetEventListener( getListener(), data, submesh );
360
361     const SMESH_Hypothesis * propagHyp =
362       submesh->GetFather()->GetHypothesis( submesh->GetSubShape(), propagHypFilter(), true );
363     if ( propagHyp )
364       getListener()->ProcessEvent( SMESH_subMesh::ADD_HYP,
365                                    SMESH_subMesh::ALGO_EVENT,
366                                    submesh,
367                                    data,
368                                    propagHyp);
369   }
370
371   //================================================================================
372   /*!
373    * \brief React on events on 1D submeshes
374    */
375   //================================================================================
376
377   void PropagationMgr::ProcessEvent(const int          event,
378                                     const int          eventType,
379                                     SMESH_subMesh*     subMesh,
380                                     SMESH_subMeshEventListenerData* data,
381                                     const SMESH_Hypothesis*         hyp)
382   {
383     if ( !data )
384       return;
385     if ( !hyp || hyp->GetType() != SMESHDS_Hypothesis::PARAM_ALGO || hyp->GetDim() != 1 )
386       return;
387     if ( eventType != SMESH_subMesh::ALGO_EVENT )
388       return;
389
390     bool isPropagHyp = ( StdMeshers_Propagation::GetName() != hyp->GetName() );
391
392     switch ( data->myType ) {
393
394     case WAIT_PROPAG_HYP: { // no propagation hyp in chain
395       // --------------------------------------------------------
396       if ( !isPropagHyp )
397         return;
398       if ( !isLocal1DHypothesis( *subMesh->GetFather(), subMesh->GetSubShape()))
399         return;
400       if ( event == SMESH_subMesh::ADD_HYP ||
401            event == SMESH_subMesh::ADD_FATHER_HYP ) // add propagation hyp
402       {
403         // build propagation chain
404         clearPropagationChain( subMesh );
405         buildPropagationChain( subMesh );
406       }
407       return;
408     }
409     case HAS_PROPAG_HYP: {  // propag hyp on this submesh
410       // --------------------------------------------------------
411       switch ( event ) {
412       case SMESH_subMesh::REMOVE_HYP:
413       case SMESH_subMesh::REMOVE_FATHER_HYP: // remove propagation hyp
414         if ( isPropagHyp )
415         {
416           // clear propagation chain
417         }
418         return;
419       case SMESH_subMesh::MODIF_HYP: // hyp modif
420         // clear mesh in a chain
421         return;
422       }
423       return;
424     }
425     case IN_CHAIN: {       // submesh is in propagation chain
426       // --------------------------------------------------------
427       if ( event == SMESH_subMesh::ADD_HYP ) // add local hypothesis
428         if ( isPropagHyp )
429           ; // collision
430         else
431           ; // rebuild propagation chain
432         return;
433     }
434     case LAST_IN_CHAIN: { // submesh with local 1D hyp, breaking a chain
435       // --------------------------------------------------------
436       if ( event == SMESH_subMesh::REMOVE_HYP ) // remove local hyp
437         ; // rebuild propagation chain
438       return;
439     }
440     } // switch by SubMeshState
441   }
442 } // namespace