mirror of
https://git.salome-platform.org/gitpub/modules/smesh.git
synced 2024-12-26 09:20:34 +05:00
525 lines
16 KiB
C++
525 lines
16 KiB
C++
// Copyright (C) 2007-2022 CEA/DEN, EDF R&D, OPEN CASCADE
|
|
//
|
|
// This library is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU Lesser General Public
|
|
// License as published by the Free Software Foundation; either
|
|
// version 2.1 of the License, or (at your option) any later version.
|
|
//
|
|
// This library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
// Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
// License along with this library; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
//
|
|
// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
|
|
//
|
|
// File : StdMeshersGUI_PropagationHelperWdg.cxx
|
|
// Created : Thu Mar 19 18:46:24 2015
|
|
// Author : Edward AGAPOV (eap)
|
|
|
|
#include "StdMeshersGUI_PropagationHelperWdg.h"
|
|
|
|
#include "StdMeshersGUI_SubShapeSelectorWdg.h"
|
|
#include "SMESH_PreviewActorsCollection.h"
|
|
#include "SMESHGUI_VTKUtils.h"
|
|
|
|
#include <GEOM_Actor.h>
|
|
|
|
#include <LightApp_SelectionMgr.h>
|
|
#include <SUIT_OverrideCursor.h>
|
|
#include <SVTK_ViewWindow.h>
|
|
#include <vtkRenderer.h>
|
|
|
|
#include <QCheckBox>
|
|
#include <QGridLayout>
|
|
#include <QGroupBox>
|
|
#include <QLabel>
|
|
#include <QList>
|
|
#include <QListWidget>
|
|
#include <QListWidgetItem>
|
|
#include <QPushButton>
|
|
|
|
#include <BRepTools_WireExplorer.hxx>
|
|
#include <BRep_Builder.hxx>
|
|
#include <NCollection_DataMap.hxx>
|
|
#include <TColStd_IndexedMapOfInteger.hxx>
|
|
#include <TopExp_Explorer.hxx>
|
|
#include <TopoDS.hxx>
|
|
#include <TopoDS_Compound.hxx>
|
|
#include <TopoDS_Iterator.hxx>
|
|
|
|
#include <set>
|
|
|
|
#define SPACING 6
|
|
#define MARGIN 11
|
|
|
|
//================================================================================
|
|
/*!
|
|
* \brief Constructor
|
|
*/
|
|
//================================================================================
|
|
|
|
StdMeshersGUI_PropagationHelperWdg::
|
|
StdMeshersGUI_PropagationHelperWdg( StdMeshersGUI_SubShapeSelectorWdg* subSelectWdg,
|
|
QWidget* parent,
|
|
bool show ):
|
|
QWidget( parent ), mySubSelectWdg( subSelectWdg ), myActor( 0 ), myModelActor( 0 )
|
|
{
|
|
QGroupBox* helperBox = new QGroupBox( tr("HELPER"), this );
|
|
myShowGeomChkBox = new QCheckBox( tr("SHOW_GEOMETRY"), helperBox );
|
|
myChainBox = new QGroupBox( tr("PROPAGATION_CHAINS"), helperBox );
|
|
myChainBox->setCheckable( true );
|
|
myChainBox->setChecked( false );
|
|
myListWidget = new QListWidget( helperBox );
|
|
myListWidget->setSelectionMode( QAbstractItemView::SingleSelection );
|
|
myAddButton = new QPushButton( tr("ADD"), helperBox );
|
|
myReverseButton = new QPushButton( tr("REVERSE"), helperBox );
|
|
|
|
QGridLayout* chainsLayout = new QGridLayout( myChainBox );
|
|
chainsLayout->setMargin( MARGIN );
|
|
chainsLayout->setSpacing( SPACING );
|
|
chainsLayout->addWidget(myListWidget, 0, 0, 3, 3);
|
|
chainsLayout->addWidget(myAddButton, 0, 3);
|
|
chainsLayout->addWidget(myReverseButton, 1, 3);
|
|
|
|
QVBoxLayout* helperLayout = new QVBoxLayout( helperBox );
|
|
helperLayout->setMargin( MARGIN );
|
|
helperLayout->setSpacing( SPACING );
|
|
helperLayout->addWidget( myShowGeomChkBox );
|
|
helperLayout->addWidget( myChainBox );
|
|
|
|
QVBoxLayout* lay = new QVBoxLayout( this );
|
|
lay->setMargin( 0 );
|
|
lay->setSpacing( SPACING );
|
|
lay->addWidget( helperBox );
|
|
|
|
connect( myShowGeomChkBox,SIGNAL( toggled(bool)), SLOT( onShowGeometry(bool)));
|
|
connect( myChainBox, SIGNAL( toggled(bool)), SLOT( updateList(bool)));
|
|
connect( myListWidget, SIGNAL( itemSelectionChanged()), SLOT( onListSelectionChanged() ));
|
|
connect( myAddButton, SIGNAL( clicked(bool)), SLOT( onAdd() ));
|
|
connect( myReverseButton, SIGNAL( clicked(bool)), SLOT( onReverse() ));
|
|
|
|
if ( show )
|
|
onListSelectionChanged();
|
|
}
|
|
|
|
//================================================================================
|
|
/*!
|
|
* \brief Destructor
|
|
*/
|
|
//================================================================================
|
|
|
|
StdMeshersGUI_PropagationHelperWdg::~StdMeshersGUI_PropagationHelperWdg()
|
|
{
|
|
if ( myActor )
|
|
{
|
|
myActor->RemoveFromRender( myRenderer );
|
|
myActor->Delete();
|
|
myActor = 0;
|
|
}
|
|
if ( myModelActor )
|
|
{
|
|
myModelActor->RemoveFromRender( myRenderer );
|
|
myModelActor->Delete();
|
|
myModelActor = 0;
|
|
}
|
|
}
|
|
|
|
//================================================================================
|
|
/*!
|
|
* \brief Switch off all buttons and previews
|
|
*/
|
|
//================================================================================
|
|
|
|
void StdMeshersGUI_PropagationHelperWdg::Clear()
|
|
{
|
|
myShowGeomChkBox->setChecked( false );
|
|
|
|
myListWidget->blockSignals( true );
|
|
myListWidget->clear();
|
|
myListWidget->blockSignals( false );
|
|
|
|
myChainBox->blockSignals( true );
|
|
myChainBox->setChecked( false );
|
|
myChainBox->blockSignals( false );
|
|
|
|
if ( myActor )
|
|
myActor->SetVisibility( false );
|
|
|
|
if ( myModelActor )
|
|
myModelActor->SetVisibility( false );
|
|
}
|
|
|
|
//================================================================================
|
|
/*!
|
|
* \brief SLOT called when 'Show Geometry' is checked
|
|
*/
|
|
//================================================================================
|
|
|
|
void StdMeshersGUI_PropagationHelperWdg::onShowGeometry(bool toShow)
|
|
{
|
|
if ( ! myModelActor )
|
|
{
|
|
TopoDS_Shape shape = mySubSelectWdg->GetGeomShape();
|
|
TopoDS_Shape mainShape = mySubSelectWdg->GetMainShape();
|
|
if ( shape.IsNull() && mainShape.IsNull() ) return;
|
|
if ( mainShape.IsNull() ) mainShape = shape;
|
|
|
|
SUIT_OverrideCursor wc;
|
|
|
|
TopoDS_Compound aCompound;
|
|
BRep_Builder aBuilder;
|
|
aBuilder.MakeCompound( aCompound );
|
|
|
|
TopTools_MapOfShape edgesMap;
|
|
TopExp_Explorer edge( mainShape, TopAbs_EDGE );
|
|
for ( ; edge.More(); edge.Next() )
|
|
if ( edgesMap.Add( edge.Current() ))
|
|
aBuilder.Add( aCompound, edge.Current() );
|
|
|
|
myModelActor = GEOM_Actor::New();
|
|
myModelActor->SetShape( aCompound, 0, 0 );
|
|
myModelActor->SetPickable( false );
|
|
myModelActor->SetIsolatedEdgeColor( 0.5, 0.5, 0.5 );
|
|
|
|
if (( myRenderer = mySubSelectWdg->GetRenderer() ))
|
|
myModelActor->AddToRender( myRenderer );
|
|
}
|
|
|
|
if ( myModelActor )
|
|
myModelActor->SetVisibility( toShow );
|
|
|
|
SMESH::RepaintCurrentView();
|
|
}
|
|
|
|
//================================================================================
|
|
/*!
|
|
* \brief Build propagation chains. Return false if no chains found
|
|
*/
|
|
//================================================================================
|
|
|
|
bool StdMeshersGUI_PropagationHelperWdg::buildChains()
|
|
{
|
|
if ( !myChains.empty() ) return false;
|
|
|
|
if ( !mySubSelectWdg ) return false;
|
|
|
|
TopoDS_Shape shape = mySubSelectWdg->GetGeomShape();
|
|
TopoDS_Shape mainShape = mySubSelectWdg->GetMainShape();
|
|
if ( shape.IsNull() && mainShape.IsNull() ) return false;
|
|
|
|
if ( shape.IsNull() ) shape = mainShape;
|
|
if ( mainShape.IsNull() ) mainShape = shape;
|
|
|
|
SUIT_OverrideCursor wc;
|
|
|
|
// aPreviewActor holds a map od all sub-shapes of mainShape
|
|
SMESH_PreviewActorsCollection* previewActor = mySubSelectWdg->GetActorCollection();
|
|
if ( !previewActor ) return false;
|
|
const QList<int>& edgeIDs = previewActor->GetIndices();
|
|
|
|
// Make a 'map' of WIREs of EDGE with quadrilateral WIREs only
|
|
|
|
typedef int TGeomID; // index in the mainShape
|
|
typedef std::vector< TGeomID > TWire; // signed IDs of EDGEs, sign means orientation
|
|
typedef std::pair< int, TWire* > TEdgeInWire; // index in TWire + TWire*
|
|
typedef std::vector< TEdgeInWire > TWiresOfEdge;// WIREs including an EDGE
|
|
|
|
std::vector< TWire > quadWires;
|
|
quadWires.reserve( previewActor->NbShapesOfType( TopAbs_FACE ));
|
|
NCollection_DataMap< TGeomID, TWiresOfEdge >
|
|
wiresOfEdge( previewActor->NbShapesOfType( TopAbs_EDGE ));
|
|
|
|
TopExp_Explorer wire;
|
|
TopTools_MapOfShape faceMap;
|
|
for ( TopExp_Explorer face( mainShape, TopAbs_FACE ); face.More(); face.Next() )
|
|
{
|
|
if ( !faceMap.Add( face.Current() )) continue;
|
|
|
|
wire.Init( face.Current(), TopAbs_WIRE );
|
|
TopoDS_Shape W = wire.Current().Oriented( TopAbs_FORWARD );
|
|
|
|
wire.Next();
|
|
if ( wire.More() ) continue;
|
|
|
|
// count EDGEs
|
|
int nbE = 0;
|
|
for ( TopoDS_Iterator edge( W, false, false ); edge.More() && nbE < 5; ++nbE )
|
|
edge.Next();
|
|
if ( nbE != 4 ) continue;
|
|
|
|
// fill a TWire and TWiresOfEdge
|
|
quadWires.push_back( TWire() );
|
|
TWire& wire = quadWires.back();
|
|
wire.reserve( 4 );
|
|
for ( BRepTools_WireExplorer edge( TopoDS::Wire( W )); edge.More(); edge.Next() )
|
|
{
|
|
const TopoDS_Shape& E = edge.Current();
|
|
int iE = previewActor->GetIndexByShape( E );
|
|
if ( iE < 1 )
|
|
continue;
|
|
if ( !wiresOfEdge.IsBound( iE ))
|
|
wiresOfEdge.Bind( iE, TWiresOfEdge() );
|
|
wiresOfEdge( iE ).push_back( TEdgeInWire( wire.size(), & wire ));
|
|
|
|
wire.push_back( E.Orientation() == TopAbs_REVERSED ? -iE : iE );
|
|
}
|
|
}
|
|
if ( quadWires.empty() )
|
|
return false;
|
|
|
|
// Find chains
|
|
|
|
TColStd_IndexedMapOfInteger chain, chainedEdges;
|
|
|
|
TColStd_MapOfInteger shapeEdges;
|
|
if ( !shape.IsSame( mainShape ))
|
|
for ( QList<TGeomID>::const_iterator ieIt = edgeIDs.begin(); ieIt != edgeIDs.end(); ++ieIt )
|
|
shapeEdges.Add( *ieIt );
|
|
|
|
// loop on all EDGEs in mainShape
|
|
for ( QList<TGeomID>::const_iterator ieIt = edgeIDs.begin(); ieIt != edgeIDs.end(); ++ieIt )
|
|
{
|
|
if ( chainedEdges.Contains( *ieIt ))
|
|
continue;
|
|
// start a new chain
|
|
chain.Clear();
|
|
chain.Add( *ieIt );
|
|
chainedEdges.Add( *ieIt );
|
|
for ( int iC = 1; iC <= chain.Extent(); ++iC ) // loop on EDGE's in chain
|
|
{
|
|
TGeomID iE = chain( iC ), iEAbs = Abs( iE );
|
|
if ( !wiresOfEdge.IsBound( iEAbs ))
|
|
continue;
|
|
const TWiresOfEdge& wires = wiresOfEdge( iEAbs );
|
|
for (size_t i = 0; i < wires.size(); ++i ) // loop on WIREs sharing iE
|
|
{
|
|
const TEdgeInWire& eInW = wires[i];
|
|
const TWire& W = *eInW.second;
|
|
if ( W.size() != 4 ) continue;
|
|
const int iInW = eInW.first;
|
|
const int iInWOpp = ( iInW + 2 ) % 4; // an opposite edge index
|
|
TGeomID iEOppAbs = Abs( W[ iInWOpp ] );
|
|
|
|
int prevNbChained = chainedEdges.Extent();
|
|
if ( prevNbChained < chainedEdges.Add( iEOppAbs ))
|
|
{
|
|
int dir = iE / iEAbs;
|
|
bool isSameDir = ( W[ iInW ] * W[ iInWOpp ] < 0 );
|
|
if ( !isSameDir )
|
|
dir *= -1;
|
|
chain.Add( dir * iEOppAbs );
|
|
}
|
|
}
|
|
}
|
|
// store a chain
|
|
if ( chain.Extent() > 1 )
|
|
{
|
|
myChains.push_back( std::vector< TGeomID >() );
|
|
std::vector< TGeomID > & ch = myChains.back();
|
|
for ( int iC = 1; iC <= chain.Extent(); ++iC )
|
|
{
|
|
TGeomID iE = chain( iC );
|
|
if ( shapeEdges.IsEmpty() || shapeEdges.Contains( Abs( iE )))
|
|
ch.push_back( iE );
|
|
}
|
|
if ( ch.size() < 2 )
|
|
myChains.pop_back();
|
|
}
|
|
} // loop on edgeIDs
|
|
|
|
return !myChains.empty();
|
|
}
|
|
|
|
//================================================================================
|
|
/*!
|
|
* \brief Fills myListWidget
|
|
*/
|
|
//================================================================================
|
|
|
|
void StdMeshersGUI_PropagationHelperWdg::updateList(bool enable)
|
|
{
|
|
buildChains();
|
|
|
|
myListWidget->clear();
|
|
|
|
if ( enable )
|
|
{
|
|
QListWidgetItem* item;
|
|
if ( myChains.empty() || !enable )
|
|
{
|
|
item = new QListWidgetItem(tr("NO_CHAINS"), myListWidget );
|
|
item->setData( Qt::UserRole, -1 );
|
|
}
|
|
else
|
|
for ( int i = 0; i < (int)myChains.size(); ++i )
|
|
{
|
|
QString text = tr( "CHAIN_NUM_NB_EDGES" ).arg( i+1 ).arg( myChains[i].size() );
|
|
item = new QListWidgetItem( text, myListWidget );
|
|
item->setData( Qt::UserRole, i );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
onListSelectionChanged();
|
|
}
|
|
}
|
|
|
|
//================================================================================
|
|
/*!
|
|
* \brief Returns ids of a selected chain
|
|
*/
|
|
//================================================================================
|
|
|
|
std::vector< int > * StdMeshersGUI_PropagationHelperWdg::getSelectedChain()
|
|
{
|
|
std::vector< int > * chain = 0;
|
|
if ( QListWidgetItem * item = myListWidget->currentItem() )
|
|
{
|
|
int i = item->data( Qt::UserRole ).toInt();
|
|
if ( 0 <= i && i < (int)myChains.size() )
|
|
chain = & myChains[i];
|
|
}
|
|
return chain;
|
|
}
|
|
|
|
//================================================================================
|
|
/*!
|
|
* \brief SLOT called when a selected chain changes
|
|
*/
|
|
//================================================================================
|
|
|
|
void StdMeshersGUI_PropagationHelperWdg::onListSelectionChanged()
|
|
{
|
|
if ( !mySubSelectWdg ) return;
|
|
SMESH_PreviewActorsCollection* previewActor = mySubSelectWdg->GetActorCollection();
|
|
if ( !previewActor ) return;
|
|
|
|
bool hasReversedEdges = false;
|
|
const std::vector< int > * chain = getSelectedChain();
|
|
if ( chain )
|
|
{
|
|
SUIT_OverrideCursor wc;
|
|
|
|
TopoDS_Compound aCompound;
|
|
BRep_Builder aBuilder;
|
|
aBuilder.MakeCompound( aCompound );
|
|
|
|
for ( size_t i = 0; i < chain->size(); ++i )
|
|
{
|
|
int iE = Abs( (*chain)[ i ]);
|
|
TopoDS_Shape E = previewActor->GetShapeByIndex( iE );
|
|
if ( !E.IsNull() && E.ShapeType() == TopAbs_EDGE )
|
|
{
|
|
E.Orientation( (*chain)[ i ] < 0 ? TopAbs_REVERSED : TopAbs_FORWARD );
|
|
aBuilder.Add( aCompound, E );
|
|
if ( (*chain)[ i ] < 0 )
|
|
hasReversedEdges = true;
|
|
}
|
|
}
|
|
if ( myActor )
|
|
{
|
|
// SetShape() to an existing actor leads to a wrong FitAll
|
|
myActor->RemoveFromRender( myRenderer );
|
|
myActor->Delete();
|
|
}
|
|
myActor = GEOM_Actor::New();
|
|
myActor->SetShape( aCompound, 0, true );
|
|
myActor->SetIsolatedEdgeColor( 1, 0, 1 );
|
|
myActor->SetWidth( 2 );
|
|
myActor->SetVectorMode( true );
|
|
myActor->SetPickable( false );
|
|
|
|
if (( myRenderer = mySubSelectWdg->GetRenderer() ))
|
|
myActor->AddToRender( myRenderer );
|
|
|
|
if ( LightApp_SelectionMgr* selMrg = SMESHGUI::selectionMgr())
|
|
{
|
|
selMrg->clearSelected();
|
|
mySubSelectWdg->ClearSelected(); /* call this because the above call does not
|
|
lead to currentSelectionChanged signal (bug?)*/
|
|
}
|
|
}
|
|
bool enableButtons = chain;
|
|
if ( chain )
|
|
enableButtons = myListWidget->currentItem()->data( Qt::UserRole+1 ).isNull();
|
|
|
|
myAddButton->setEnabled( enableButtons && hasReversedEdges );
|
|
myReverseButton->setEnabled( enableButtons );
|
|
|
|
|
|
bool toShowChain = chain;
|
|
|
|
if ( myActor )
|
|
myActor->SetVisibility( toShowChain );
|
|
|
|
previewActor->SetShown( !toShowChain );
|
|
|
|
if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow())
|
|
aViewWindow->Repaint();
|
|
}
|
|
|
|
//================================================================================
|
|
/*!
|
|
* \brief SLOT called when 'Add' button is clicked
|
|
*/
|
|
//================================================================================
|
|
|
|
void StdMeshersGUI_PropagationHelperWdg::onAdd()
|
|
{
|
|
const std::vector< int > * chain = getSelectedChain();
|
|
if ( !chain || !mySubSelectWdg ) return;
|
|
|
|
// join current and new IDs
|
|
|
|
SMESH::long_array_var ids = mySubSelectWdg->GetListOfIDs();
|
|
|
|
std::set< int > idSet;
|
|
for ( int i = 0, nb = ids->length(); i < nb; ++i )
|
|
idSet.insert( idSet.end(), ids[i] );
|
|
|
|
for ( size_t i = 0; i < chain->size(); ++i )
|
|
if ( (*chain)[ i ] < 0 )
|
|
idSet.insert( -1 * (*chain)[ i ]);
|
|
|
|
if ( ids->length() != idSet.size() )
|
|
{
|
|
ids->length( idSet.size() );
|
|
std::set< int >::iterator id = idSet.begin();
|
|
for ( int i = 0, nb = ids->length(); i < nb; ++i, ++id )
|
|
ids[ i ] = *id;
|
|
|
|
mySubSelectWdg->SetListOfIDs( ids );
|
|
}
|
|
mySubSelectWdg->ClearSelected();
|
|
|
|
if ( QListWidgetItem * item = myListWidget->currentItem() )
|
|
{
|
|
//delete item;
|
|
item->setForeground( QBrush( QColor( 100, 100, 100 )));
|
|
item->setData( Qt::UserRole+1, 1 );
|
|
}
|
|
myAddButton->setEnabled( false );
|
|
myReverseButton->setEnabled( false );
|
|
}
|
|
|
|
//================================================================================
|
|
/*!
|
|
* \brief SLOT called when 'Reverse' button is clicked
|
|
*/
|
|
//================================================================================
|
|
|
|
void StdMeshersGUI_PropagationHelperWdg::onReverse()
|
|
{
|
|
if ( std::vector< int > * chain = getSelectedChain())
|
|
{
|
|
for ( size_t i = 0; i < chain->size(); ++i )
|
|
(*chain)[ i ] *= -1;
|
|
|
|
onListSelectionChanged();
|
|
}
|
|
}
|