1 // Copyright (C) 2007-2021 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
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, or (at your option) any later version.
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.
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
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // SMESH SMESH : implementation of SMESH idl descriptions
24 // File : StdMeshers_Propagation.cxx
27 #include "StdMeshers_Propagation.hxx"
29 #include "utilities.h"
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"
38 #include <BRepTools_WireExplorer.hxx>
39 #include <TopTools_ListIteratorOfListOfShape.hxx>
40 #include <TopTools_MapOfShape.hxx>
44 // cout << txt << endl;
50 // =======================================================================
52 * \brief Listener managing propagation of 1D hypotheses
54 // =======================================================================
56 class PropagationMgr: public SMESH_subMeshEventListener
59 static PropagationMgr* GetListener();
61 * \brief Set listener on edge submesh
63 static void Set(SMESH_subMesh * submesh);
65 * \brief Return an edge from which hypotheses are propagated from
67 static TopoDS_Edge GetSource(SMESH_subMesh * submesh,
68 bool& isPropagOfDistribution);
70 * \brief Does it's main job
72 void ProcessEvent(const int event,
74 SMESH_subMesh* subMesh,
75 SMESH_subMeshEventListenerData* data,
76 const SMESH_Hypothesis* hyp = 0);
82 //=============================================================================
84 * StdMeshers_Propagation Implementation
86 //=============================================================================
88 StdMeshers_Propagation::StdMeshers_Propagation (int hypId, SMESH_Gen * gen)
89 : SMESH_Hypothesis(hypId, gen)
92 _param_algo_dim = -1; // 1D auxiliary
94 StdMeshers_PropagOfDistribution::StdMeshers_PropagOfDistribution (int hypId,
96 : StdMeshers_Propagation(hypId, gen) { _name = GetName(); }
97 StdMeshers_Propagation::~StdMeshers_Propagation() {}
98 string StdMeshers_Propagation::GetName () { return "Propagation"; }
99 string StdMeshers_PropagOfDistribution::GetName () { return "PropagOfDistribution"; }
100 ostream & StdMeshers_Propagation::SaveTo (ostream & save) { return save; }
101 istream & StdMeshers_Propagation::LoadFrom (istream & load) { return load; }
102 bool StdMeshers_Propagation::SetParametersByMesh(const SMESH_Mesh*,
103 const TopoDS_Shape& ) { return false; }
104 bool StdMeshers_Propagation::SetParametersByDefaults(const TDefaults&,const SMESH_Mesh*) { return false; }
105 void StdMeshers_Propagation::SetPropagationMgr(SMESH_subMesh* subMesh) { PropagationMgr::Set( subMesh ); }
107 * \brief Return an edge from which hypotheses are propagated
109 TopoDS_Edge StdMeshers_Propagation::GetPropagationSource(SMESH_Mesh& theMesh,
110 const TopoDS_Shape& theEdge,
111 bool& isPropagOfDistribution)
113 return PropagationMgr::GetSource( theMesh.GetSubMeshContaining( theEdge ),
114 isPropagOfDistribution);
116 const SMESH_HypoFilter& StdMeshers_Propagation::GetFilter()
118 static SMESH_HypoFilter propagHypFilter;
119 if ( propagHypFilter.IsEmpty() )
122 Init( SMESH_HypoFilter::HasName( StdMeshers_Propagation::GetName ())).
123 Or ( SMESH_HypoFilter::HasName( StdMeshers_PropagOfDistribution::GetName ()));
125 return propagHypFilter;
127 //=============================================================================
128 //=============================================================================
129 // PROPAGATION MANAGEMENT
130 //=============================================================================
131 //=============================================================================
135 enum SubMeshState { WAIT_PROPAG_HYP, // propagation hyp or local 1D hyp is missing
136 HAS_PROPAG_HYP, // propag hyp on this submesh
137 IN_CHAIN, // submesh is in propagation chain
138 LAST_IN_CHAIN, // submesh with local 1D hyp breaking a chain
139 MEANINGLESS_LAST }; // meaningless
141 struct PropagationMgrData : public EventListenerData
143 bool myForward; //!< true if a curve of edge in chain is codirected with one of source edge
144 bool myIsPropagOfDistribution; //!< type of Propagation hyp
145 PropagationMgrData( SubMeshState state=WAIT_PROPAG_HYP ): EventListenerData(true) {
146 myType = state; myForward = true; myIsPropagOfDistribution = false;
149 myType = WAIT_PROPAG_HYP; mySubMeshes.clear(); myForward = true;
150 myIsPropagOfDistribution = false;
152 SubMeshState State() const {
153 return (SubMeshState) myType;
155 void SetState(SubMeshState state) {
158 void SetSource(SMESH_subMesh* sm ) {
159 mySubMeshes.clear(); if ( sm ) mySubMeshes.push_back( sm );
161 void AddSource(SMESH_subMesh* sm ) {
162 if ( sm ) mySubMeshes.push_back( sm );
164 void SetChain(list< SMESH_subMesh* >& chain ) {
165 mySubMeshes.clear(); mySubMeshes.splice( mySubMeshes.end(), chain );
167 SMESH_subMeshIteratorPtr GetChain() const;
168 SMESH_subMesh* GetSource() const;
171 //=============================================================================
173 * \brief return static PropagationMgr
175 PropagationMgr* PropagationMgr::GetListener()
177 static PropagationMgr theListener;
180 PropagationMgr* getListener()
182 return PropagationMgr::GetListener();
184 //=============================================================================
186 * \brief return PropagationMgrData found on a sub-mesh
188 PropagationMgrData* findData(SMESH_subMesh* sm)
191 return static_cast< PropagationMgrData* >( sm->GetEventListenerData( getListener() ));
194 //=============================================================================
196 * \brief return PropagationMgrData found on theEdge sub-mesh
198 // PropagationMgrData* findData(SMESH_Mesh& theMesh, const TopoDS_Shape& theEdge)
200 // if ( theEdge.ShapeType() == TopAbs_EDGE )
201 // return findData( theMesh.GetSubMeshContaining( theEdge ) );
204 //=============================================================================
206 * \brief return existing or a new PropagationMgrData
208 PropagationMgrData* getData(SMESH_subMesh* sm)
210 PropagationMgrData* data = findData( sm );
212 data = new PropagationMgrData();
213 sm->SetEventListener( getListener(), data, sm );
217 //=============================================================================
219 * \brief Returns a local 1D hypothesis used for theEdge
221 const SMESH_Hypothesis* getLocal1DHyp (SMESH_subMesh* theSubMesh,
222 //const TopoDS_Shape& theEdge,
223 TopoDS_Shape* theSssignedTo=0)
225 static SMESH_HypoFilter hypo;
226 hypo.Init( hypo.HasDim( 1 )).
227 AndNot ( hypo.IsAlgo() ).
228 AndNot ( hypo.HasName( StdMeshers_Propagation::GetName() )).
229 AndNot ( hypo.HasName( StdMeshers_PropagOfDistribution::GetName() )).
230 AndNot ( hypo.IsAssignedTo( theSubMesh->GetFather()->GetShapeToMesh() ));
232 return theSubMesh->GetFather()->GetHypothesis( theSubMesh, hypo, true, theSssignedTo );
234 //=============================================================================
236 * \brief Returns a propagation hypothesis assigned to theEdge
238 const SMESH_Hypothesis* getProagationHyp (SMESH_subMesh* theSubMesh)
240 return theSubMesh->GetFather()->GetHypothesis
241 ( theSubMesh, StdMeshers_Propagation::GetFilter(), true );
243 //================================================================================
245 * \brief Return an iterator on a list of submeshes
247 SMESH_subMeshIteratorPtr iterate( list<SMESH_subMesh*>::const_iterator from,
248 list<SMESH_subMesh*>::const_iterator to)
250 typedef SMESH_subMesh* TsubMesh;
251 typedef SMDS_SetIterator< TsubMesh, list< TsubMesh >::const_iterator > TIterator;
252 return SMESH_subMeshIteratorPtr ( new TIterator( from, to ));
254 //================================================================================
256 * \brief Build propagation chain
257 * \param theMainSubMesh - the submesh with Propagation hypothesis
259 bool buildPropagationChain ( SMESH_subMesh* theMainSubMesh )
261 DBGMSG( "buildPropagationChain from " << theMainSubMesh->GetId() );
262 const TopoDS_Shape& theMainEdge = theMainSubMesh->GetSubShape();
263 if (theMainEdge.ShapeType() != TopAbs_EDGE) return true;
265 SMESH_Mesh* mesh = theMainSubMesh->GetFather();
267 TopoDS_Shape shapeOfHyp1D; // shape to which an hyp being propagated is assigned
268 const SMESH_Hypothesis* hyp1D = getLocal1DHyp( theMainSubMesh, &shapeOfHyp1D );
269 SMESH_HypoFilter moreLocalCheck( SMESH_HypoFilter::IsMoreLocalThan( shapeOfHyp1D, *mesh ));
271 PropagationMgrData* chainData = getData( theMainSubMesh );
272 chainData->SetState( HAS_PROPAG_HYP );
274 if ( const SMESH_Hypothesis * propagHyp = getProagationHyp( theMainSubMesh ))
275 chainData->myIsPropagOfDistribution =
276 ( StdMeshers_PropagOfDistribution::GetName() == propagHyp->GetName() );
278 // Edge submeshes, to which the 1D hypothesis will be propagated from theMainEdge
279 list<SMESH_subMesh*> & chain = chainData->mySubMeshes;
281 chain.push_back( theMainSubMesh );
283 TopTools_MapOfShape checkedShapes;
284 checkedShapes.Add( theMainEdge );
286 vector<TopoDS_Edge> edges;
288 list<SMESH_subMesh*>::iterator smIt = chain.begin();
289 for ( ; smIt != chain.end(); ++smIt )
291 const TopoDS_Edge& anE = TopoDS::Edge( (*smIt)->GetSubShape() );
292 PropagationMgrData* data = findData( *smIt );
293 if ( !data ) continue;
295 // Iterate on faces, having edge <anE>
296 TopTools_ListIteratorOfListOfShape itA (mesh->GetAncestors(anE));
297 for (; itA.More(); itA.Next())
299 // there are objects of different type among the ancestors of edge
300 if ( itA.Value().ShapeType() != TopAbs_WIRE /*|| !checkedShapes.Add( itA.Value() )*/)
303 // Get ordered edges and find index of anE in a sequence
305 BRepTools_WireExplorer aWE (TopoDS::Wire(itA.Value()));
306 size_t edgeIndex = 0;
307 for (; aWE.More(); aWE.Next()) {
308 TopoDS_Edge edge = aWE.Current();
309 edge.Orientation( aWE.Orientation() );
310 if ( edge.IsSame( anE ))
311 edgeIndex = edges.size();
312 edges.push_back( edge );
315 // Find an edge opposite to anE
317 if ( edges.size() < 4 ) {
318 continue; // too few edges
320 else if ( edges.size() == 4 ) {
321 int oppIndex = ( edgeIndex + 2 ) % 4;
322 anOppE = edges[ oppIndex ];
326 TopoDS_Edge prevEdge = anE;
327 size_t nbSide = 0, eIndex = edgeIndex + 1;
328 for ( size_t i = 0; i < edges.size(); ++i, ++eIndex )
330 if ( eIndex == edges.size() )
332 if ( !SMESH_Algo::IsContinuous( prevEdge, edges[ eIndex ])) {
336 // check that anE is not a part of a composite side
337 if ( anE.IsSame( prevEdge ) || anE.IsSame( edges[ eIndex ])) {
338 anOppE.Nullify(); break;
341 if ( nbSide == 2 ) { // opposite side
342 if ( !anOppE.IsNull() ) {
343 // composite opposite side -> stop propagation
344 anOppE.Nullify(); break;
346 anOppE = edges[ eIndex ];
349 anOppE.Nullify(); break; // too many sides
351 prevEdge = edges[ eIndex ];
353 if ( anOppE.IsNull() )
356 DBGMSG( nbSide << " sides in wire #" << mesh->GetMeshDS()->ShapeToIndex( itA.Value() ) << " - SKIP" );
360 if ( anOppE.IsNull() || !checkedShapes.Add( anOppE ))
362 SMESH_subMesh* oppSM = mesh->GetSubMesh( anOppE );
363 PropagationMgrData* oppData = getData( oppSM );
365 // Add anOppE to aChain if ...
366 if ( oppData->State() == WAIT_PROPAG_HYP ) // ... anOppE is not in any chain
368 oppData->SetSource( theMainSubMesh );
369 if ( ! (hyp1D = getLocal1DHyp( oppSM, &shapeOfHyp1D )) || //...no 1d hyp on anOppE
370 ! (moreLocalCheck.IsOk( hyp1D, shapeOfHyp1D ))) // ... or hyp1D is "more global"
372 oppData->myForward = data->myForward;
373 if ( edges[ edgeIndex ].Orientation() == anOppE.Orientation() )
374 oppData->myForward = !oppData->myForward;
375 chain.push_back( oppSM );
376 oppSM->ComputeStateEngine( SMESH_subMesh::CLEAN );
377 oppData->SetState( IN_CHAIN );
378 DBGMSG( "set IN_CHAIN on " << oppSM->GetId() );
379 if ( oppSM->GetAlgoState() != SMESH_subMesh::HYP_OK )
380 // make oppSM check algo state
381 if ( SMESH_Algo* algo = oppSM->GetAlgo() )
382 oppSM->AlgoStateEngine(SMESH_subMesh::ADD_FATHER_ALGO, algo);
385 oppData->SetState( LAST_IN_CHAIN );
386 DBGMSG( "set LAST_IN_CHAIN on " << oppSM->GetId() );
389 else if ( oppData->State() == LAST_IN_CHAIN ) // anOppE breaks other chain
391 DBGMSG( "encounters LAST_IN_CHAIN on " << oppSM->GetId() );
392 oppData->AddSource( theMainSubMesh );
394 } // loop on face ancestors
395 } // loop on the chain
397 // theMainSubMesh must not be in a chain
402 //================================================================================
404 * \brief Clear propagation chain
406 bool clearPropagationChain( SMESH_subMesh* subMesh )
408 DBGMSG( "clearPropagationChain from " << subMesh->GetId() );
409 if ( PropagationMgrData* data = findData( subMesh ))
411 switch ( data->State() ) {
413 return clearPropagationChain( data->GetSource() );
415 case HAS_PROPAG_HYP: {
416 SMESH_subMeshIteratorPtr smIt = data->GetChain();
417 while ( smIt->more() ) {
418 SMESH_subMesh* sm = smIt->next();
419 getData( sm )->Init();
420 sm->ComputeStateEngine( SMESH_subMesh::CLEAN );
425 case LAST_IN_CHAIN: {
426 SMESH_subMeshIteratorPtr smIt = iterate( data->mySubMeshes.begin(),
427 data->mySubMeshes.end());
428 while ( smIt->more() )
429 clearPropagationChain( smIt->next() );
441 //================================================================================
443 * \brief Return an iterator on chain submeshes
445 //================================================================================
447 SMESH_subMeshIteratorPtr PropagationMgrData::GetChain() const
451 return iterate( mySubMeshes.begin(), mySubMeshes.end() );
453 if ( mySubMeshes.empty() ) break;
454 return getData( mySubMeshes.front() )->GetChain();
457 return iterate( mySubMeshes.end(), mySubMeshes.end() );
459 //================================================================================
461 * \brief Return a propagation source submesh
463 //================================================================================
465 SMESH_subMesh* PropagationMgrData::GetSource() const
467 if ( myType == IN_CHAIN )
468 if ( !mySubMeshes.empty() )
469 return mySubMeshes.front();
474 //================================================================================
478 //================================================================================
480 PropagationMgr::PropagationMgr()
481 : SMESH_subMeshEventListener( false, // won't be deleted by submesh
482 "StdMeshers_Propagation::PropagationMgr")
484 //================================================================================
486 * \brief Set PropagationMgr on a submesh
488 //================================================================================
490 void PropagationMgr::Set(SMESH_subMesh * submesh)
492 if ( findData( submesh )) return;
493 DBGMSG( "PropagationMgr::Set() on " << submesh->GetId() );
494 PropagationMgrData* data = new PropagationMgrData();
495 submesh->SetEventListener( getListener(), data, submesh );
497 const SMESH_Hypothesis * propagHyp =
498 getProagationHyp( submesh );
501 data->myIsPropagOfDistribution =
502 ( StdMeshers_PropagOfDistribution::GetName() == propagHyp->GetName() );
503 getListener()->ProcessEvent( SMESH_subMesh::ADD_HYP,
504 SMESH_subMesh::ALGO_EVENT,
510 //================================================================================
512 * \brief Return an edge from which hypotheses are propagated
514 //================================================================================
516 TopoDS_Edge PropagationMgr::GetSource(SMESH_subMesh * submesh,
517 bool& isPropagOfDistribution)
519 if ( PropagationMgrData* data = findData( submesh )) {
520 if ( data->State() == IN_CHAIN ) {
521 if ( SMESH_subMesh* sm = data->GetSource() )
523 TopoDS_Shape edge = sm->GetSubShape();
524 edge = edge.Oriented( data->myForward ? TopAbs_FORWARD : TopAbs_REVERSED );
525 DBGMSG( " GetSource() = edge " << sm->GetId() << " REV = " << (!data->myForward));
526 isPropagOfDistribution = false;
527 if ( PropagationMgrData* data = findData( sm ))
528 isPropagOfDistribution = data->myIsPropagOfDistribution;
529 if ( edge.ShapeType() == TopAbs_EDGE )
530 return TopoDS::Edge( edge );
534 return TopoDS_Edge();
536 //================================================================================
538 * \brief React on events on 1D submeshes
540 //================================================================================
542 void PropagationMgr::ProcessEvent(const int event,
544 SMESH_subMesh* subMesh,
545 SMESH_subMeshEventListenerData* listenerData,
546 const SMESH_Hypothesis* hyp)
550 if ( !hyp || hyp->GetType() != SMESHDS_Hypothesis::PARAM_ALGO || hyp->GetDim() != 1 )
552 if ( eventType != SMESH_subMesh::ALGO_EVENT )
554 DBGMSG( "PropagationMgr::ProcessEvent() on " << subMesh->GetId() );
556 bool isPropagHyp = ( StdMeshers_Propagation::GetName() == hyp->GetName() ||
557 StdMeshers_PropagOfDistribution::GetName() == hyp->GetName() );
559 PropagationMgrData* data = static_cast<PropagationMgrData*>( listenerData );
560 switch ( data->State() ) {
562 case WAIT_PROPAG_HYP: { // propagation hyp or local 1D hyp is missing
563 // --------------------------------------------------------
564 bool hasPropagHyp = ( isPropagHyp || getProagationHyp( subMesh ));
567 bool hasLocal1DHyp = getLocal1DHyp( subMesh );
568 if ( !hasLocal1DHyp )
570 if ( event == SMESH_subMesh::ADD_HYP ||
571 event == SMESH_subMesh::ADD_FATHER_HYP ) // add local or propagation hyp
573 DBGMSG( "ADD_HYP propagation to WAIT_PROPAG_HYP " << subMesh->GetId() );
574 // build propagation chain
575 buildPropagationChain( subMesh );
579 case HAS_PROPAG_HYP: { // propag hyp on this submesh
580 // --------------------------------------------------------
582 case SMESH_subMesh::REMOVE_HYP:
583 case SMESH_subMesh::REMOVE_FATHER_HYP: // remove propagation hyp
584 if ( isPropagHyp && !getProagationHyp( subMesh ))
586 DBGMSG( "REMOVE_HYP propagation from HAS_PROPAG_HYP " << subMesh->GetId() );
587 // clear propagation chain
588 clearPropagationChain( subMesh );
590 // return; -- hyp is modified any way
593 //case SMESH_subMesh::MODIF_HYP: // hyp modif
594 // clear mesh in a chain
595 DBGMSG( "MODIF_HYP on HAS_PROPAG_HYP " << subMesh->GetId() );
596 SMESH_subMeshIteratorPtr smIt = data->GetChain();
597 while ( smIt->more() ) {
598 SMESH_subMesh* smInChain = smIt->next();
599 smInChain->AlgoStateEngine( SMESH_subMesh::MODIF_HYP,
600 (SMESH_Hypothesis*) hyp );
606 case IN_CHAIN: { // submesh is in propagation chain
607 // --------------------------------------------------------
608 if ( event == SMESH_subMesh::ADD_HYP ) { // add local hypothesis
609 if ( isPropagHyp ) { // propagation hyp added
610 DBGMSG( "ADD_HYP propagation on IN_CHAIN " << subMesh->GetId() );
611 // collision - do nothing
613 else { // 1D hyp added
614 // rebuild propagation chain
615 DBGMSG( "ADD_HYP 1D on IN_CHAIN " << subMesh->GetId() );
616 SMESH_subMesh* sourceSM = data->GetSource();
617 clearPropagationChain( sourceSM );
618 buildPropagationChain( sourceSM );
623 case LAST_IN_CHAIN: { // submesh with local 1D hyp, breaking a chain
624 // --------------------------------------------------------
625 if ( event == SMESH_subMesh::REMOVE_HYP ) { // remove local hyp
626 // rebuild propagation chain
627 DBGMSG( "REMOVE_HYP 1D from LAST_IN_CHAIN " << subMesh->GetId() );
628 list<SMESH_subMesh*> sourceSM = data->mySubMeshes;
629 clearPropagationChain( subMesh );
630 SMESH_subMeshIteratorPtr smIt = iterate( sourceSM.begin(), sourceSM.end());
631 while ( smIt->more() )
632 buildPropagationChain( smIt->next() );
636 case MEANINGLESS_LAST: {
639 } // switch by SubMeshState