1 // Copyright (C) 2007-2024 CEA, EDF, OPEN CASCADE
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // File : StdMeshersGUI_PropagationHelperWdg.cxx
20 // Created : Thu Mar 19 18:46:24 2015
21 // Author : Edward AGAPOV (eap)
23 #include "StdMeshersGUI_PropagationHelperWdg.h"
25 #include "StdMeshersGUI_SubShapeSelectorWdg.h"
26 #include "SMESH_PreviewActorsCollection.h"
27 #include "SMESHGUI_VTKUtils.h"
29 #include <GEOM_Actor.h>
31 #include <LightApp_SelectionMgr.h>
32 #include <SUIT_OverrideCursor.h>
33 #include <SVTK_ViewWindow.h>
34 #include <vtkRenderer.h>
37 #include <QGridLayout>
41 #include <QListWidget>
42 #include <QListWidgetItem>
43 #include <QPushButton>
45 #include <BRepTools_WireExplorer.hxx>
46 #include <BRep_Builder.hxx>
47 #include <NCollection_DataMap.hxx>
48 #include <TColStd_IndexedMapOfInteger.hxx>
49 #include <TopExp_Explorer.hxx>
51 #include <TopoDS_Compound.hxx>
52 #include <TopoDS_Iterator.hxx>
59 //================================================================================
63 //================================================================================
65 StdMeshersGUI_PropagationHelperWdg::
66 StdMeshersGUI_PropagationHelperWdg( StdMeshersGUI_SubShapeSelectorWdg* subSelectWdg,
69 QWidget( parent ), mySubSelectWdg( subSelectWdg ), myActor( 0 ), myModelActor( 0 )
71 QGroupBox* helperBox = new QGroupBox( tr("HELPER"), this );
72 myShowGeomChkBox = new QCheckBox( tr("SHOW_GEOMETRY"), helperBox );
73 myChainBox = new QGroupBox( tr("PROPAGATION_CHAINS"), helperBox );
74 myChainBox->setCheckable( true );
75 myChainBox->setChecked( false );
76 myListWidget = new QListWidget( helperBox );
77 myListWidget->setSelectionMode( QAbstractItemView::SingleSelection );
78 myAddButton = new QPushButton( tr("ADD"), helperBox );
79 myReverseButton = new QPushButton( tr("REVERSE"), helperBox );
81 QGridLayout* chainsLayout = new QGridLayout( myChainBox );
82 chainsLayout->setMargin( MARGIN );
83 chainsLayout->setSpacing( SPACING );
84 chainsLayout->addWidget(myListWidget, 0, 0, 3, 3);
85 chainsLayout->addWidget(myAddButton, 0, 3);
86 chainsLayout->addWidget(myReverseButton, 1, 3);
88 QVBoxLayout* helperLayout = new QVBoxLayout( helperBox );
89 helperLayout->setMargin( MARGIN );
90 helperLayout->setSpacing( SPACING );
91 helperLayout->addWidget( myShowGeomChkBox );
92 helperLayout->addWidget( myChainBox );
94 QVBoxLayout* lay = new QVBoxLayout( this );
96 lay->setSpacing( SPACING );
97 lay->addWidget( helperBox );
99 connect( myShowGeomChkBox,SIGNAL( toggled(bool)), SLOT( onShowGeometry(bool)));
100 connect( myChainBox, SIGNAL( toggled(bool)), SLOT( updateList(bool)));
101 connect( myListWidget, SIGNAL( itemSelectionChanged()), SLOT( onListSelectionChanged() ));
102 connect( myAddButton, SIGNAL( clicked(bool)), SLOT( onAdd() ));
103 connect( myReverseButton, SIGNAL( clicked(bool)), SLOT( onReverse() ));
106 onListSelectionChanged();
109 //================================================================================
113 //================================================================================
115 StdMeshersGUI_PropagationHelperWdg::~StdMeshersGUI_PropagationHelperWdg()
119 myActor->RemoveFromRender( myRenderer );
125 myModelActor->RemoveFromRender( myRenderer );
126 myModelActor->Delete();
131 //================================================================================
133 * \brief Switch off all buttons and previews
135 //================================================================================
137 void StdMeshersGUI_PropagationHelperWdg::Clear()
139 myShowGeomChkBox->setChecked( false );
141 myListWidget->blockSignals( true );
142 myListWidget->clear();
143 myListWidget->blockSignals( false );
145 myChainBox->blockSignals( true );
146 myChainBox->setChecked( false );
147 myChainBox->blockSignals( false );
150 myActor->SetVisibility( false );
153 myModelActor->SetVisibility( false );
156 //================================================================================
158 * \brief SLOT called when 'Show Geometry' is checked
160 //================================================================================
162 void StdMeshersGUI_PropagationHelperWdg::onShowGeometry(bool toShow)
164 if ( ! myModelActor )
166 TopoDS_Shape shape = mySubSelectWdg->GetGeomShape();
167 TopoDS_Shape mainShape = mySubSelectWdg->GetMainShape();
168 if ( shape.IsNull() && mainShape.IsNull() ) return;
169 if ( mainShape.IsNull() ) mainShape = shape;
171 SUIT_OverrideCursor wc;
173 TopoDS_Compound aCompound;
174 BRep_Builder aBuilder;
175 aBuilder.MakeCompound( aCompound );
177 TopTools_MapOfShape edgesMap;
178 TopExp_Explorer edge( mainShape, TopAbs_EDGE );
179 for ( ; edge.More(); edge.Next() )
180 if ( edgesMap.Add( edge.Current() ))
181 aBuilder.Add( aCompound, edge.Current() );
183 myModelActor = GEOM_Actor::New();
184 myModelActor->SetShape( aCompound, 0, 0 );
185 myModelActor->SetPickable( false );
186 myModelActor->SetIsolatedEdgeColor( 0.5, 0.5, 0.5 );
188 if (( myRenderer = mySubSelectWdg->GetRenderer() ))
189 myModelActor->AddToRender( myRenderer );
193 myModelActor->SetVisibility( toShow );
195 SMESH::RepaintCurrentView();
198 //================================================================================
200 * \brief Build propagation chains. Return false if no chains found
202 //================================================================================
204 bool StdMeshersGUI_PropagationHelperWdg::buildChains()
206 if ( !myChains.empty() ) return false;
208 if ( !mySubSelectWdg ) return false;
210 TopoDS_Shape shape = mySubSelectWdg->GetGeomShape();
211 TopoDS_Shape mainShape = mySubSelectWdg->GetMainShape();
212 if ( shape.IsNull() && mainShape.IsNull() ) return false;
214 if ( shape.IsNull() ) shape = mainShape;
215 if ( mainShape.IsNull() ) mainShape = shape;
217 SUIT_OverrideCursor wc;
219 // aPreviewActor holds a map od all sub-shapes of mainShape
220 SMESH_PreviewActorsCollection* previewActor = mySubSelectWdg->GetActorCollection();
221 if ( !previewActor ) return false;
222 const QList<int>& edgeIDs = previewActor->GetIndices();
224 // Make a 'map' of WIREs of EDGE with quadrilateral WIREs only
226 typedef int TGeomID; // index in the mainShape
227 typedef std::vector< TGeomID > TWire; // signed IDs of EDGEs, sign means orientation
228 typedef std::pair< int, TWire* > TEdgeInWire; // index in TWire + TWire*
229 typedef std::vector< TEdgeInWire > TWiresOfEdge;// WIREs including an EDGE
231 std::vector< TWire > quadWires;
232 quadWires.reserve( previewActor->NbShapesOfType( TopAbs_FACE ));
233 NCollection_DataMap< TGeomID, TWiresOfEdge >
234 wiresOfEdge( previewActor->NbShapesOfType( TopAbs_EDGE ));
236 TopExp_Explorer wire;
237 TopTools_MapOfShape faceMap;
238 for ( TopExp_Explorer face( mainShape, TopAbs_FACE ); face.More(); face.Next() )
240 if ( !faceMap.Add( face.Current() )) continue;
242 wire.Init( face.Current(), TopAbs_WIRE );
243 TopoDS_Shape W = wire.Current().Oriented( TopAbs_FORWARD );
246 if ( wire.More() ) continue;
250 for ( TopoDS_Iterator edge( W, false, false ); edge.More() && nbE < 5; ++nbE )
252 if ( nbE != 4 ) continue;
254 // fill a TWire and TWiresOfEdge
255 quadWires.push_back( TWire() );
256 TWire& wire = quadWires.back();
258 for ( BRepTools_WireExplorer edge( TopoDS::Wire( W )); edge.More(); edge.Next() )
260 const TopoDS_Shape& E = edge.Current();
261 int iE = previewActor->GetIndexByShape( E );
264 if ( !wiresOfEdge.IsBound( iE ))
265 wiresOfEdge.Bind( iE, TWiresOfEdge() );
266 wiresOfEdge( iE ).push_back( TEdgeInWire( wire.size(), & wire ));
268 wire.push_back( E.Orientation() == TopAbs_REVERSED ? -iE : iE );
271 if ( quadWires.empty() )
276 TColStd_IndexedMapOfInteger chain, chainedEdges;
278 TColStd_MapOfInteger shapeEdges;
279 if ( !shape.IsSame( mainShape ))
280 for ( QList<TGeomID>::const_iterator ieIt = edgeIDs.begin(); ieIt != edgeIDs.end(); ++ieIt )
281 shapeEdges.Add( *ieIt );
283 // loop on all EDGEs in mainShape
284 for ( QList<TGeomID>::const_iterator ieIt = edgeIDs.begin(); ieIt != edgeIDs.end(); ++ieIt )
286 if ( chainedEdges.Contains( *ieIt ))
291 chainedEdges.Add( *ieIt );
292 for ( int iC = 1; iC <= chain.Extent(); ++iC ) // loop on EDGE's in chain
294 TGeomID iE = chain( iC ), iEAbs = Abs( iE );
295 if ( !wiresOfEdge.IsBound( iEAbs ))
297 const TWiresOfEdge& wires = wiresOfEdge( iEAbs );
298 for (size_t i = 0; i < wires.size(); ++i ) // loop on WIREs sharing iE
300 const TEdgeInWire& eInW = wires[i];
301 const TWire& W = *eInW.second;
302 if ( W.size() != 4 ) continue;
303 const int iInW = eInW.first;
304 const int iInWOpp = ( iInW + 2 ) % 4; // an opposite edge index
305 TGeomID iEOppAbs = Abs( W[ iInWOpp ] );
307 int prevNbChained = chainedEdges.Extent();
308 if ( prevNbChained < chainedEdges.Add( iEOppAbs ))
310 int dir = iE / iEAbs;
311 bool isSameDir = ( W[ iInW ] * W[ iInWOpp ] < 0 );
314 chain.Add( dir * iEOppAbs );
319 if ( chain.Extent() > 1 )
321 myChains.push_back( std::vector< TGeomID >() );
322 std::vector< TGeomID > & ch = myChains.back();
323 for ( int iC = 1; iC <= chain.Extent(); ++iC )
325 TGeomID iE = chain( iC );
326 if ( shapeEdges.IsEmpty() || shapeEdges.Contains( Abs( iE )))
334 return !myChains.empty();
337 //================================================================================
339 * \brief Fills myListWidget
341 //================================================================================
343 void StdMeshersGUI_PropagationHelperWdg::updateList(bool enable)
347 myListWidget->clear();
351 QListWidgetItem* item;
352 if ( myChains.empty() || !enable )
354 item = new QListWidgetItem(tr("NO_CHAINS"), myListWidget );
355 item->setData( Qt::UserRole, -1 );
358 for ( int i = 0; i < (int)myChains.size(); ++i )
360 QString text = tr( "CHAIN_NUM_NB_EDGES" ).arg( i+1 ).arg( myChains[i].size() );
361 item = new QListWidgetItem( text, myListWidget );
362 item->setData( Qt::UserRole, i );
367 onListSelectionChanged();
371 //================================================================================
373 * \brief Returns ids of a selected chain
375 //================================================================================
377 std::vector< int > * StdMeshersGUI_PropagationHelperWdg::getSelectedChain()
379 std::vector< int > * chain = 0;
380 if ( QListWidgetItem * item = myListWidget->currentItem() )
382 int i = item->data( Qt::UserRole ).toInt();
383 if ( 0 <= i && i < (int)myChains.size() )
384 chain = & myChains[i];
389 //================================================================================
391 * \brief SLOT called when a selected chain changes
393 //================================================================================
395 void StdMeshersGUI_PropagationHelperWdg::onListSelectionChanged()
397 if ( !mySubSelectWdg ) return;
398 SMESH_PreviewActorsCollection* previewActor = mySubSelectWdg->GetActorCollection();
399 if ( !previewActor ) return;
401 bool hasReversedEdges = false;
402 const std::vector< int > * chain = getSelectedChain();
405 SUIT_OverrideCursor wc;
407 TopoDS_Compound aCompound;
408 BRep_Builder aBuilder;
409 aBuilder.MakeCompound( aCompound );
411 for ( size_t i = 0; i < chain->size(); ++i )
413 int iE = Abs( (*chain)[ i ]);
414 TopoDS_Shape E = previewActor->GetShapeByIndex( iE );
415 if ( !E.IsNull() && E.ShapeType() == TopAbs_EDGE )
417 E.Orientation( (*chain)[ i ] < 0 ? TopAbs_REVERSED : TopAbs_FORWARD );
418 aBuilder.Add( aCompound, E );
419 if ( (*chain)[ i ] < 0 )
420 hasReversedEdges = true;
425 // SetShape() to an existing actor leads to a wrong FitAll
426 myActor->RemoveFromRender( myRenderer );
429 myActor = GEOM_Actor::New();
430 myActor->SetShape( aCompound, 0, true );
431 myActor->SetIsolatedEdgeColor( 1, 0, 1 );
432 myActor->SetWidth( 2 );
433 myActor->SetVectorMode( true );
434 myActor->SetPickable( false );
436 if (( myRenderer = mySubSelectWdg->GetRenderer() ))
437 myActor->AddToRender( myRenderer );
439 if ( LightApp_SelectionMgr* selMrg = SMESHGUI::selectionMgr())
441 selMrg->clearSelected();
442 mySubSelectWdg->ClearSelected(); /* call this because the above call does not
443 lead to currentSelectionChanged signal (bug?)*/
446 bool enableButtons = chain;
448 enableButtons = myListWidget->currentItem()->data( Qt::UserRole+1 ).isNull();
450 myAddButton->setEnabled( enableButtons && hasReversedEdges );
451 myReverseButton->setEnabled( enableButtons );
454 bool toShowChain = chain;
457 myActor->SetVisibility( toShowChain );
459 previewActor->SetShown( !toShowChain );
461 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow())
462 aViewWindow->Repaint();
465 //================================================================================
467 * \brief SLOT called when 'Add' button is clicked
469 //================================================================================
471 void StdMeshersGUI_PropagationHelperWdg::onAdd()
473 const std::vector< int > * chain = getSelectedChain();
474 if ( !chain || !mySubSelectWdg ) return;
476 // join current and new IDs
478 SMESH::long_array_var ids = mySubSelectWdg->GetListOfIDs();
480 std::set< int > idSet;
481 for ( int i = 0, nb = ids->length(); i < nb; ++i )
482 idSet.insert( idSet.end(), ids[i] );
484 for ( size_t i = 0; i < chain->size(); ++i )
485 if ( (*chain)[ i ] < 0 )
486 idSet.insert( -1 * (*chain)[ i ]);
488 if ( ids->length() != idSet.size() )
490 ids->length( idSet.size() );
491 std::set< int >::iterator id = idSet.begin();
492 for ( int i = 0, nb = ids->length(); i < nb; ++i, ++id )
495 mySubSelectWdg->SetListOfIDs( ids );
497 mySubSelectWdg->ClearSelected();
499 if ( QListWidgetItem * item = myListWidget->currentItem() )
502 item->setForeground( QBrush( QColor( 100, 100, 100 )));
503 item->setData( Qt::UserRole+1, 1 );
505 myAddButton->setEnabled( false );
506 myReverseButton->setEnabled( false );
509 //================================================================================
511 * \brief SLOT called when 'Reverse' button is clicked
513 //================================================================================
515 void StdMeshersGUI_PropagationHelperWdg::onReverse()
517 if ( std::vector< int > * chain = getSelectedChain())
519 for ( size_t i = 0; i < chain->size(); ++i )
522 onListSelectionChanged();