\image html hypo_quad_params_dialog.png "Quadrangle parameters creation/edition dialog"
-<b>Quadrangle parameters</b> is a hypothesis for Quadrangle (Mapping).
+<b>Quadrangle parameters</b> is a hypothesis for Quadrangle (Mapping) algorithm.
-<b>Base vertex</b> parameter allows using Quadrangle (Mapping)
-algorithm for meshing of trilateral faces. In this case it is
-necessary to select the vertex, which will be used as the fourth edge
-(degenerated).
-
-\image html hypo_quad_params_1.png "A face built from 3 edges"
-
-\image html hypo_quad_params_res.png "The resulting mesh"
-
-This parameter can be also used to mesh a segment of a circular face.
-Please, consider that there is a limitation on the selection of the
-vertex for the faces built with the angle > 180 degrees (see the picture).
-
-\image html hypo_quad_params_2.png "3/4 of a circular face"
-
-In this case, selection of a wrong vertex for the <b>Base vertex</b>
-parameter will generate a wrong mesh. The picture below
-shows the good (left) and the bad (right) results of meshing.
-
-\image html hypo_quad_params_res_2.png "The resulting meshes"
-
-<b>Type</b> parameter is used on faces with a different number of
-segments on opposite sides to define the algorithm of transition
-between them. The following types are available:
+<b>Transition</b> tab is used to define the algorithm of transition
+between opposite sides of faces with a different number of
+segments on opposite sides. The following types of transition
+algorithms are available:
- <b>Standard</b> is the default case, when both triangles and quadrangles
are possible in the transition area along the finer meshed sides.
to Nmin segments is log<sub>3</sub>( Nmax / Nmin ). The number of
face rows is equal to the number of segments on each of equally
discretized sides.
- \image html reduce_three_to_one.png "The fastest transition pattern: 3 to 1"
+
+\image html reduce_three_to_one.png "The fastest transition pattern: 3 to 1"
+
+<b>Base vertex</b> tab allows using Quadrangle (Mapping)
+algorithm for meshing of trilateral faces. In this case it is
+necessary to select the vertex, which will be used as the fourth edge
+(degenerated).
+
+\image html hypo_quad_params_dialog_vert.png "Base Vertex tab of Quadrangle parameters creation/edition dialog"
+
+\image html hypo_quad_params_1.png "A face built from 3 edges"
+
+\image html hypo_quad_params_res.png "The resulting mesh"
+
+This parameter can be also used to mesh a segment of a circular face.
+Please, consider that there is a limitation on the selection of the
+vertex for the faces built with the angle > 180 degrees (see the picture).
+
+\image html hypo_quad_params_2.png "3/4 of a circular face"
+
+In this case, selection of a wrong vertex for the <b>Base vertex</b>
+parameter will generate a wrong mesh. The picture below
+shows the good (left) and the bad (right) results of meshing.
+
+\image html hypo_quad_params_res_2.png "The resulting meshes"
+
+\image html hypo_quad_params_dialog_enf.png "Enforced nodes tab of Quadrangle parameters creation/edition dialog"
+
+<b>Enforced nodes</b> tab allows for defining points where the
+algorithm should create nodes. There are two ways to define positions
+of the enforced nodes.
+<ul>
+ <li>\b Vertices group allows to set up shapes whose vertices will
+ define positions of the enforced nodes. Only vertices successfully
+ projected to the meshed face and located close enough to the
+ meshed face will be used to create the enforced nodes.</li>
+ <li> \b Points group allows to explicitly define coordinates of
+ points used to create the enforced nodes. Only points successfully
+ projected to the meshed face and located close enough to the
+ meshed face will be used to create the enforced nodes.</li>
+</ul>
+Algorithm of creation of the enforced nodes is following.
+
+\image html hypo_quad_params_enfnodes_algo.png "Steps of the algorithm of creation of the enforced nodes"
+<ol>
+ <li> Left image: Positions of nodes are computed without taking into
+ account the enforced vertex (yellow point).</li>
+ <li> Middle image: A node closest to the enforced vertex is
+ detected. Extreme nodes of the row and column of the detected node
+ are used to create virtual edges (yellow lines) ending at the
+ enforced vertex. </li>
+ <li> Right image: The meshed face is thus divided by the virtual
+ edges into four quadrilateral sub-domains each of which is meshed
+ as usually: the nodes of the row and column of detected node are
+ moved to the virtual edges and the quadrilateral elements are
+ constructed.
+</ol>
+If there are several enforced vertices, the algorithm is applied
+recursively to the formed sub-domains.
<b>See Also</b> a sample TUI Script of a
\ref tui_quadrangle_parameters "Quadrangle Parameters" hypothesis.
#include "StdMeshersGUI_QuadrangleParamWdg.h"
#include "SMESHGUI.h"
+#include "SMESHGUI_SpinBox.h"
+#include "StdMeshersGUI_SubShapeSelectorWdg.h"
-#include "SUIT_ResourceMgr.h"
+#include <GEOMBase.h>
+#include <LightApp_SelectionMgr.h>
+#include <SALOME_ListIO.hxx>
+#include <SALOME_ListIteratorOfListIO.hxx>
+#include <SUIT_ResourceMgr.h>
// Qt includes
#include <QButtonGroup>
-#include <QRadioButton>
-#include <QLabel>
+#include <QFrame>
#include <QGridLayout>
+#include <QGroupBox>
+#include <QLabel>
+#include <QLineEdit>
+#include <QListWidget>
+#include <QListWidgetItem>
+#include <QPushButton>
+#include <QRadioButton>
+#include <QTreeWidget>
+#include <QVBoxLayout>
// IDL includes
#include <SALOMEconfig.h>
#include CORBA_CLIENT_HEADER(SMESH_BasicHypothesis)
+#include CORBA_CLIENT_HEADER(GEOM_Gen)
+
#define SPACING 6
-#define MARGIN 0
+#define MARGIN 11
+
+enum { TAB_TRANSITION, TAB_VERTEX, TAB_ENF_POINTS };
+
+//================================================================================
+// function : Constructor
+// purpose :
+//================================================================================
+
+StdMeshersGUI_QuadrangleParamCreator::StdMeshersGUI_QuadrangleParamCreator(const QString& aHypType)
+ : StdMeshersGUI_StdHypothesisCreator( aHypType )
+{
+}
+
+//=======================================================================
+//function : helpPage
+//purpose :
+//=======================================================================
+
+QString StdMeshersGUI_QuadrangleParamCreator::helpPage() const
+{
+ return "a2d_meshing_hypo_page.html#hypo_quad_params_anchor";
+}
+
+//=======================================================================
+//function : buildFrame
+//purpose :
+//=======================================================================
+
+QFrame* StdMeshersGUI_QuadrangleParamCreator::buildFrame()
+{
+ QFrame* fr = new QFrame();
+
+ QGridLayout* lay = new QGridLayout( fr );
+ lay->setMargin( MARGIN );
+ lay->setSpacing( SPACING );
+ int row = 0;
+
+ myName = 0;
+ if ( isCreation() )
+ {
+ myName = new QLineEdit( fr );
+ QLabel* nameLab = new QLabel( tr("SMESH_NAME"));
+ lay->addWidget( nameLab, row, 0 );
+ lay->addWidget( myName, row, 1 );
+ ++row;
+ }
+
+ // Transition type
+
+ myTypeWdg = new StdMeshersGUI_QuadrangleParamWdg( fr );
+
+ // Vertexes
+
+ myVertexSelWdg = new StdMeshersGUI_SubShapeSelectorWdg( fr, TopAbs_VERTEX );
+ myVertexSelWdg->layout()->setMargin( MARGIN );
+
+ // Enforced Points
+
+ QWidget* pointsFrame = new QWidget( fr );
+ QVBoxLayout* pointsLay = new QVBoxLayout( pointsFrame );
+ pointsLay->setMargin(MARGIN);
+ pointsLay->setSpacing(SPACING);
+
+ // shapes
+ QGroupBox* shapesGroup = new QGroupBox( tr("SHAPES"), pointsFrame );
+ myShapesList = new QListWidget( shapesGroup );
+ myAddShapeBut = new QPushButton( tr("SMESH_BUT_ADD"), shapesGroup );
+ QPushButton* remShapeBut = new QPushButton( tr("SMESH_BUT_REMOVE"), shapesGroup );
+ //
+ QGridLayout* shapesLay = new QGridLayout( shapesGroup );
+ shapesLay->setMargin(MARGIN);
+ shapesLay->setSpacing(SPACING);
+ shapesLay->addWidget( myShapesList, 0, 0, 3, 2 );
+ shapesLay->addWidget( myAddShapeBut, 0, 2 );
+ shapesLay->addWidget( remShapeBut, 1, 2 );
+ shapesLay->setColumnStretch( 0, 1 );
+ shapesLay->setRowStretch ( 2, 1 );
+
+ // coords
+ QGroupBox* coordsGroup = new QGroupBox( tr("POINTS"), pointsFrame );
+ myCoordsTreeWdg = new QTreeWidget( coordsGroup );
+ myCoordsTreeWdg->setColumnCount ( 3 );
+ myCoordsTreeWdg->setHeaderLabels( QStringList() << "X" << "Y" << "Z" );
+ myCoordsTreeWdg->setItemDelegate( new ItemDelegate( myCoordsTreeWdg ));
+ QPushButton* addCoordBut = new QPushButton( tr("SMESH_BUT_ADD"), coordsGroup );
+ QPushButton* remCoordBut = new QPushButton( tr("SMESH_BUT_REMOVE"), coordsGroup );
+ //
+ QGridLayout* coordsLay = new QGridLayout( coordsGroup );
+ coordsLay->setMargin(MARGIN);
+ coordsLay->setSpacing(SPACING);
+ coordsLay->addWidget( myCoordsTreeWdg, 0, 0, 3, 2 );
+ coordsLay->addWidget( addCoordBut, 0, 2 );
+ coordsLay->addWidget( remCoordBut, 1, 2 );
+ coordsLay->setColumnStretch( 0, 1 );
+ coordsLay->setRowStretch ( 2, 1 );
+
+ pointsLay->addWidget( shapesGroup );
+ pointsLay->addWidget( coordsGroup );
+
+ // Tabs
+ myTabs = new QTabWidget( fr );
+ myTabs->addTab( myTypeWdg, tr("TRANSITION"));
+ myTabs->addTab( myVertexSelWdg, tr("SMESH_BASE_VERTEX"));
+ myTabs->addTab( pointsFrame, tr("ENF_NODES"));
+
+ lay->addWidget( myTabs, row, 0, 2, 3 );
+
+ // signals
+ connect( myTypeWdg, SIGNAL( typeChanged(int)), SLOT( onTypeChanged(int)));
+ connect( myAddShapeBut, SIGNAL( clicked()), SLOT( onAddShape() ));
+ connect( remShapeBut, SIGNAL( clicked()), SLOT( onRemoveShape() ));
+ connect( addCoordBut, SIGNAL( clicked()), SLOT( onAddPoint() ));
+ connect( remCoordBut, SIGNAL( clicked()), SLOT( onRemovePoint() ));
+ connect( myTabs, SIGNAL( currentChanged(int)),SLOT( onTabChanged(int)));
+
+ LightApp_SelectionMgr* selMgr = SMESHGUI::GetSMESHGUI()->selectionMgr();
+ connect( selMgr, SIGNAL(currentSelectionChanged()), SLOT( onSelectionChanged()));
+
+ return fr;
+}
+
+//=======================================================================
+//function : retrieveParams
+//purpose :
+//=======================================================================
+
+void StdMeshersGUI_QuadrangleParamCreator::retrieveParams() const
+{
+ StdMeshers::StdMeshers_QuadrangleParams_var h =
+ StdMeshers::StdMeshers_QuadrangleParams::_narrow( initParamsHypothesis() );
+
+ // name
+ if( myName )
+ myName->setText( hypName() );
+
+ // main shape
+ myVertexSelWdg->SetMaxSize(1);
+ QString anEntry = SMESHGUI_GenericHypothesisCreator::getShapeEntry();
+ QString aMainEntry = SMESHGUI_GenericHypothesisCreator::getMainShapeEntry();
+ if ( anEntry.isEmpty() )
+ anEntry = h->GetObjectEntry();
+ myVertexSelWdg->SetGeomShapeEntry(anEntry);
+ myVertexSelWdg->SetMainShapeEntry(aMainEntry);
+
+ if ( !isCreation())
+ {
+ // type
+ myTypeWdg->SetType(int(h->GetQuadType()));
+
+ // vertex
+ int vertID = h->GetTriaVertex();
+ if (vertID > 0) {
+ SMESH::long_array_var aVec = new SMESH::long_array;
+ aVec->length(1);
+ aVec[0] = vertID;
+ myVertexSelWdg->SetListOfIDs(aVec);
+ }
+
+ // enforced nodes
+ GEOM::ListOfGO_var shapes;
+ SMESH::nodes_array_var points;
+ h->GetEnforcedNodes( shapes, points );
+ for ( int i = 0; i < shapes->length(); ++i )
+ {
+ CORBA::String_var name = shapes[i]->GetName();
+ CORBA::String_var entry = shapes[i]->GetStudyEntry();
+ QListWidgetItem* item = new QListWidgetItem( name.in() );
+ item->setData( Qt::UserRole, entry.in() );
+ myShapesList->addItem( item );
+ }
+ for ( int i = 0; i < points->length(); ++i )
+ {
+ QTreeWidgetItem* item = new QTreeWidgetItem
+ ( QStringList()
+ << QString::number( points[i].x )
+ << QString::number( points[i].y )
+ << QString::number( points[i].z ));
+ item->setFlags( item->flags() | Qt::ItemIsEditable );
+ myCoordsTreeWdg->addTopLevelItem( item );
+ }
+ }
+ ((StdMeshersGUI_QuadrangleParamCreator*) this)->onSelectionChanged();
+}
+
+//=======================================================================
+//function : storeParams
+//purpose :
+//=======================================================================
+
+QString StdMeshersGUI_QuadrangleParamCreator::storeParams() const
+{
+ StdMeshers::StdMeshers_QuadrangleParams_var h =
+ StdMeshers::StdMeshers_QuadrangleParams::_narrow( hypothesis() );
+
+ // name
+ if( myName )
+ SMESH::SetName( SMESH::FindSObject( h ), myName->text().toLatin1().constData() );
+
+ // transition
+ h->SetQuadType( StdMeshers::QuadType( myTypeWdg->GetType()) );
+
+ // vertex
+ if ( myVertexSelWdg->GetListSize() > 0 )
+ {
+ h->SetTriaVertex( myVertexSelWdg->GetListOfIDs()[0] ); // getlist must be called once
+ h->SetObjectEntry( myVertexSelWdg->GetMainShapeEntry() );
+ }
+ else
+ {
+ h->SetTriaVertex( -1 );
+ }
+
+ // enfored nodes
+
+ GEOM::ListOfGO_var goList = new GEOM::ListOfGO;
+ int nbShapes = 0;
+ goList->length( myShapesList->count() );
+ for ( int i = 0; i < myShapesList->count(); ++i )
+ {
+ QListWidgetItem* item = myShapesList->item(i);
+ QString entry = item->data( Qt::UserRole ).toString();
+ Handle(SALOME_InteractiveObject) io =
+ new SALOME_InteractiveObject( entry.toStdString().c_str(), "GEOM" );
+ GEOM::GEOM_Object_var go = GEOMBase::ConvertIOinGEOMObject( io );
+ if ( !go->_is_nil() )
+ goList[ nbShapes++ ] = go;
+ }
+ goList->length( nbShapes );
+
+ SMESH::nodes_array_var points = new SMESH::nodes_array;
+ points->length( myCoordsTreeWdg->topLevelItemCount() );
+ for ( int i = 0; i < myCoordsTreeWdg->topLevelItemCount(); ++i )
+ {
+ QTreeWidgetItem* item = myCoordsTreeWdg->topLevelItem( i );
+ points[i].x = item->text(0).toInt();
+ points[i].y = item->text(1).toInt();
+ points[i].z = item->text(2).toInt();
+ }
+ h->SetEnforcedNodes( goList, points );
+
+ return "";
+}
+
+//=======================================================================
+//function : onTypeChanged
+//purpose :
+//=======================================================================
+
+void StdMeshersGUI_QuadrangleParamCreator::onTypeChanged(int type)
+{
+ myTabs->setTabEnabled( TAB_ENF_POINTS, ( type != StdMeshers::QUAD_REDUCED ));
+}
+
+//=======================================================================
+//function : onAddShape
+//purpose :
+//=======================================================================
+
+void StdMeshersGUI_QuadrangleParamCreator::onAddShape()
+{
+ if ( !mySelectedShapeIO.IsNull() )
+ {
+ QListWidgetItem* item = new QListWidgetItem( mySelectedShapeIO->getName() );
+ item->setData( Qt::UserRole, mySelectedShapeIO->getEntry() );
+ myShapesList->addItem( item );
+ mySelectedShapeIO.Nullify();
+ myAddShapeBut->setEnabled( false );
+ }
+}
+
+//=======================================================================
+//function : onRemoveShape
+//purpose :
+//=======================================================================
+
+void StdMeshersGUI_QuadrangleParamCreator::onRemoveShape()
+{
+ if ( QListWidgetItem * item = myShapesList->currentItem() )
+ delete item;
+ onSelectionChanged();
+}
+
+//=======================================================================
+//function : onAddPoint
+//purpose :
+//=======================================================================
+
+void StdMeshersGUI_QuadrangleParamCreator::onAddPoint()
+{
+ QTreeWidgetItem* item = new QTreeWidgetItem( QStringList() << "0" << "0" << "0" );
+ item->setFlags( item->flags() | Qt::ItemIsEditable );
+ myCoordsTreeWdg->addTopLevelItem( item );
+}
+
+//=======================================================================
+//function : onRemovePoint
+//purpose :
+//=======================================================================
+
+void StdMeshersGUI_QuadrangleParamCreator::onRemovePoint()
+{
+ if ( myCoordsTreeWdg->topLevelItemCount() )
+ delete myCoordsTreeWdg->currentItem();
+}
+
+//=======================================================================
+//function : onSelectionChanged
+//purpose :
+//=======================================================================
+
+void StdMeshersGUI_QuadrangleParamCreator::onSelectionChanged()
+{
+ mySelectedShapeIO.Nullify();
+
+ // find a sole selected geometry
+ LightApp_SelectionMgr* selMgr = SMESHGUI::GetSMESHGUI()->selectionMgr();
+ SALOME_ListIO selList;
+ selMgr->selectedObjects( selList );
+ SALOME_ListIteratorOfListIO selIt( selList );
+ for ( ; selIt.More(); selIt.Next() )
+ {
+ GEOM::GEOM_Object_var go = GEOMBase::ConvertIOinGEOMObject( selIt.Value() );
+ if ( !go->_is_nil() )
+ {
+ if ( !mySelectedShapeIO.IsNull() )
+ {
+ mySelectedShapeIO.Nullify();
+ break;
+ }
+ mySelectedShapeIO = selIt.Value();
+ if ( !mySelectedShapeIO->getName() || !mySelectedShapeIO->getName()[0] )
+ mySelectedShapeIO.Nullify();
+ }
+ }
+ // check if a selected geometry is not already in myShapesList
+ if ( !mySelectedShapeIO.IsNull() )
+ {
+ for ( int i = 0; i < myShapesList->count(); ++i )
+ if ( myShapesList->item(i)->data( Qt::UserRole ) == mySelectedShapeIO->getEntry() )
+ {
+ mySelectedShapeIO.Nullify();
+ break;
+ }
+ }
+ myAddShapeBut->setEnabled( !mySelectedShapeIO.IsNull() );
+}
+
+//=======================================================================
+//function : onTabChanged
+//purpose :
+//=======================================================================
+
+void StdMeshersGUI_QuadrangleParamCreator::onTabChanged(int i)
+{
+ myVertexSelWdg->showPreview( i == TAB_VERTEX );
+}
//================================================================================
// function : Constructor
// purpose :
//================================================================================
+
StdMeshersGUI_QuadrangleParamWdg::StdMeshersGUI_QuadrangleParamWdg (QWidget * parent)
- : QWidget(parent),
- myType(0)
+ : QWidget(parent), myType(0)
{
myType = new QButtonGroup (this);
setLayout(typeLay);
setMinimumWidth(300);
+
+ connect( myType, SIGNAL( buttonClicked(int)), this, SIGNAL( typeChanged(int)));
}
//================================================================================
{
return myType->checkedId();
}
+
+//================================================================================
+/*!
+ \brief Constructor
+*/
+StdMeshersGUI_QuadrangleParamCreator::
+ItemDelegate::ItemDelegate( QObject* parent ) : QItemDelegate( parent )
+{
+}
+//================================================================================
+/*!
+ \brief Create item editor widget
+*/
+QWidget* StdMeshersGUI_QuadrangleParamCreator::
+ItemDelegate::createEditor( QWidget* parent,
+ const QStyleOptionViewItem& option,
+ const QModelIndex& index ) const
+{
+ SMESHGUI_SpinBox* sb = new SMESHGUI_SpinBox( parent );
+ sb->RangeStepAndValidator( COORD_MIN, COORD_MAX, 10 );
+ return sb;
+}