Salome HOME
Update of CheckDone
[modules/smesh.git] / src / StdMeshersGUI / StdMeshersGUI_CartesianParamCreator.cxx
index c2b58de8dabdcd40cd9f336bdb33b05b73a4d7ce..675f377cc33731d1b1272bb541ef1794ce8ffa4f 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2024  CEA, EDF, OPEN CASCADE
 //
 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
@@ -6,7 +6,7 @@
 // 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.
+// 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
 // SMESH includes
 #include "StdMeshersGUI_CartesianParamCreator.h"
 
-#include <SMESHGUI.h>
-#include <SMESHGUI_Utils.h>
-#include <SMESHGUI_HypothesesUtils.h>
-#include <SMESHGUI_SpinBox.h>
+#include "SMESHGUI.h"
+#include "SMESHGUI_Utils.h"
+#include "SMESHGUI_VTKUtils.h"
+#include "SMESHGUI_HypothesesUtils.h"
+#include "SMESHGUI_SpinBox.h"
+#include "SMESHGUI_MeshEditPreview.h"
 
 // IDL includes
 #include CORBA_SERVER_HEADER(SMESH_BasicHypothesis)
 
 // SALOME GUI includes
-#include <SalomeApp_Tools.h>
-#include <SalomeApp_IntSpinBox.h>
+#include <LightApp_SelectionMgr.h>
 #include <QtxComboBox.h>
+#include <SALOME_InteractiveObject.hxx>
+#include <SALOME_ListIO.hxx>
+#include <SUIT_ResourceMgr.h>
+#include <SalomeApp_IntSpinBox.h>
+#include <SalomeApp_Tools.h>
+
+#include <GEOMBase.h>
+
+#include <BRepBndLib.hxx>
+#include <Bnd_Box.hxx>
+#include <TopoDS_Iterator.hxx>
+#include <TopoDS_Shape.hxx>
+#include <gp_Pnt.hxx>
 
 // Qt includes
 #include <QAbstractItemModel>
 #include <QApplication>
 #include <QButtonGroup>
 #include <QCheckBox>
+#include <QFontMetrics>
 #include <QGridLayout>
 #include <QGroupBox>
 #include <QHBoxLayout>
@@ -162,7 +177,7 @@ namespace StdMeshersGUI
     myStepSpin->SetStep( 1. );
     myStepSpin->SetValue( myStep = 1. );
 
-    // 3) Coodrinates/Spacing group
+    // 3) Coordinates/Spacing group
     QFrame*    csFrame = new QFrame( this );
     QVBoxLayout* scLay = new QVBoxLayout( csFrame );
     scLay->setMargin( 0 );
@@ -189,8 +204,8 @@ namespace StdMeshersGUI
     axisTabLayout->setSpacing( SPACING );
 
     axisTabLayout->addWidget( modeBox    , 0, 0, 1, 3 );
-    axisTabLayout->addWidget( myInsertBtn  , 1, 0, 1, 2 );
-    axisTabLayout->addWidget( myDeleteBtn  , 2, 0, 1, 2 );
+    axisTabLayout->addWidget( myInsertBtn, 1, 0, 1, 2 );
+    axisTabLayout->addWidget( myDeleteBtn, 2, 0, 1, 2 );
     axisTabLayout->addWidget( myStepLabel, 3, 0 );
     axisTabLayout->addWidget( myStepSpin , 3, 1 );
     axisTabLayout->addWidget( csFrame    , 1, 2, 4, 1 );
@@ -201,11 +216,18 @@ namespace StdMeshersGUI
     connect( myInsertBtn,      SIGNAL( clicked() ),             SLOT( onInsert() ));
     connect( myDeleteBtn,      SIGNAL( clicked() ),             SLOT( onDelete() ));
     connect( myModeGroup,      SIGNAL( buttonClicked ( int )),  SLOT( onMode(int)));
+    connect( myModeGroup,      SIGNAL( buttonClicked ( int )),  SIGNAL( gridModeChanged(int)));
     connect( mySpacingTreeWdg, SIGNAL( itemSelectionChanged()), SLOT( updateButtons() ));
     connect( myCoordList,      SIGNAL( itemSelectionChanged()), SLOT( updateButtons() ));
     connect( myStepSpin,       SIGNAL( valueChanged(double)),   SLOT( onStepChange() ));
   }
 
+  //================================================================================
+  /*!
+   * \brief SLOT onInsert
+   */
+  //================================================================================
+
   void GridAxisTab::onInsert()
   {
     if ( isGridBySpacing() )
@@ -254,6 +276,12 @@ namespace StdMeshersGUI
     updateButtons();
   }
 
+  //================================================================================
+  /*!
+   * \brief SLOT onDelete
+   */
+  //================================================================================
+
   void GridAxisTab::onDelete()
   {
     if ( isGridBySpacing() )
@@ -283,12 +311,18 @@ namespace StdMeshersGUI
     updateButtons();
   }
 
+  //================================================================================
+  /*!
+   * \brief SLOT onMode
+   */
+  //================================================================================
+
   void GridAxisTab::onMode(int isSpacing)
   {
-    mySpacingTreeWdg->setShown( isSpacing );
-    myCoordList->setShown( !isSpacing );
-    myStepSpin->setShown( !isSpacing );
-    myStepLabel->setShown( !isSpacing );
+    mySpacingTreeWdg->setVisible( isSpacing );
+    myCoordList->setVisible( !isSpacing );
+    myStepSpin->setVisible( !isSpacing );
+    myStepLabel->setVisible( !isSpacing );
     if ( isSpacing )
     {
       if ( mySpacingTreeWdg->topLevelItemCount() == 0 )
@@ -313,6 +347,12 @@ namespace StdMeshersGUI
     updateButtons();
   }
 
+  //================================================================================
+  /*!
+   * \brief SLOT onStepChange
+   */
+  //================================================================================
+
   void GridAxisTab::onStepChange()
   {
     if ( fabs( myStepSpin->GetValue() ) < 1e-100 )
@@ -323,6 +363,12 @@ namespace StdMeshersGUI
     myStep = myStepSpin->GetValue();
   }
 
+  //================================================================================
+  /*!
+   * \brief Enables/disables buttons
+   */
+  //================================================================================
+
   void GridAxisTab::updateButtons()
   {
     bool insertEnable = false, deleteEnable = false;
@@ -347,6 +393,12 @@ namespace StdMeshersGUI
     myDeleteBtn->setEnabled( deleteEnable );
   }
 
+  //================================================================================
+  /*!
+   * \brief Inserts coordinates into myCoordList
+   */
+  //================================================================================
+
   void GridAxisTab::setCoordinates( SMESH::double_array_var coords )
   {
     myCoordList->clear();
@@ -357,6 +409,12 @@ namespace StdMeshersGUI
     onMode( COORD_BUT );
   }
 
+  //================================================================================
+  /*!
+   * \brief Sets spacing got from hypothesis
+   */
+  //================================================================================
+
   void GridAxisTab::setSpacing( SMESH::string_array_var funs, SMESH::double_array_var points )
   {
     mySpacingTreeWdg->clear();
@@ -370,11 +428,23 @@ namespace StdMeshersGUI
     onMode( SPACING_BUT );
   }
 
+  //================================================================================
+  /*!
+   * \brief Checks grid definition mode
+   */
+  //================================================================================
+
   bool GridAxisTab::isGridBySpacing() const
   {
     return ( myModeGroup->checkedId() == SPACING_BUT );
   }
 
+  //================================================================================
+  /*!
+   * \brief Returns coordinates to set to a hypothesis
+   */
+  //================================================================================
+
   SMESH::double_array* GridAxisTab::getCoordinates()
   {
     SMESH::double_array_var coords = new SMESH::double_array;
@@ -385,6 +455,12 @@ namespace StdMeshersGUI
     return coords._retn();
   }
 
+  //================================================================================
+  /*!
+   * \brief Returns spacing to set to a hypothesis
+   */
+  //================================================================================
+
   void GridAxisTab::getSpacing(SMESH::string_array_out funs,
                                SMESH::double_array_out points) const
   {
@@ -404,6 +480,12 @@ namespace StdMeshersGUI
   }
 
 
+  //================================================================================
+  /*!
+   * \brief Verifies parameters
+   */
+  //================================================================================
+
   bool GridAxisTab::checkParams(QString& msg, SMESH::SMESH_Hypothesis_var& hyp) const
   {
     if ( isGridBySpacing() )
@@ -432,6 +514,12 @@ namespace StdMeshersGUI
     return true;
   }
 
+  //================================================================================
+  /*!
+   * \brief LineDelegate constructor
+   */
+  //================================================================================
+
   LineDelegate::LineDelegate( QWidget* parent ):
     QItemDelegate( parent ),
     mySpacingTreeWdg( qobject_cast<QTreeWidget*>( parent )),
@@ -439,8 +527,14 @@ namespace StdMeshersGUI
   {
   }
 
+  //================================================================================
+  /*!
+   * \brief Creates an editor depending on a current item
+   */
+  //================================================================================
+
   QWidget* LineDelegate::createEditor( QWidget*                    parent,
-                                       const QStyleOptionViewItem& opt,
+                                       const QStyleOptionViewItem& /*opt*/,
                                        const QModelIndex&          index) const
   {
     QWidget* w = 0;
@@ -472,6 +566,12 @@ namespace StdMeshersGUI
     return w;
   }
 
+  //================================================================================
+  /*!
+   * \brief Limit value range in the spin of a neighbor range
+   */
+  //================================================================================
+
   void LineDelegate::setEditorData ( QWidget * editor, const QModelIndex & index ) const
   {
     if ( mySpacingTreeWdg && index.column() == 0 )
@@ -494,6 +594,13 @@ namespace StdMeshersGUI
       QItemDelegate::setEditorData( editor, index );
     }
   }
+
+  //================================================================================
+  /*!
+   * \brief
+   */
+  //================================================================================
+
   void LineDelegate::setModelData( QWidget*            editor,
                                    QAbstractItemModel* model,
                                    const QModelIndex&  index ) const
@@ -530,6 +637,69 @@ namespace StdMeshersGUI
 
 } // namespace StdMeshersGUI
 
+namespace
+{
+  const double theAngTol = M_PI / 180.;
+
+  //================================================================================
+  /*!
+   * \brief Set variables to groups of spin boxes
+   */
+  //================================================================================
+
+  void setText( const QString& vars, SMESHGUI_SpinBox** spins )
+  {
+    QStringList varList = vars.split( ':' );
+    for ( int i = 0; i < 3 && i < varList.count(); ++i )
+      if ( !varList[i].isEmpty() )
+        spins[i]->setText( varList[i] );
+  }
+  
+  //================================================================================
+  /*!
+   * \brief Computes more 2 axes by one
+   *  \param [in] iOk - index of a given axis
+   *  \param [in,out] dirs - directions of 3 axes
+   */
+  //================================================================================
+
+  void get3Dirs( int iOk, gp_XYZ dirs[3] )
+  {
+    dirs[ ( iOk+1 ) % 3 ] = dirs[ iOk ];
+
+    if ( Abs( dirs[ iOk ].Y() ) < 1e-100 &&
+         Abs( dirs[ iOk ].Z() ) < 1e-100 )
+      // dirs[ iOk ] || OX
+      dirs[ ( iOk+1 ) % 3 ].SetY( dirs[ iOk ].Y() + 1. );
+    else
+      dirs[ ( iOk+1 ) % 3 ].SetX( dirs[ iOk ].X() + 1. );
+
+    dirs[( iOk+2 ) % 3] = dirs[ iOk ] ^ dirs[ ( iOk+1 ) % 3 ];
+    dirs[( iOk+1 ) % 3] = dirs[ ( iOk+2 ) % 3 ] ^ dirs[ iOk ];
+  }
+
+  //================================================================================
+  /*!
+   * \brief Returns a minimal width of a SpinBox depending on a precision type
+   */
+  //================================================================================
+
+  int getMinWidth( const char* precisionType )
+  {
+    int nb = SMESHGUI::resourceMgr()->integerValue( "SMESH", precisionType, -3 );
+    QString s;
+    s.fill('0', qAbs(nb)+7 );
+    QLineEdit le;
+    QFontMetrics metrics( le.font() );
+    return metrics.width( s );
+  }
+}
+
+//================================================================================
+/*!
+ * \brief StdMeshersGUI_CartesianParamCreator constructor
+ */
+//================================================================================
 
 StdMeshersGUI_CartesianParamCreator::StdMeshersGUI_CartesianParamCreator(const QString& aHypType)
   : StdMeshersGUI_StdHypothesisCreator( aHypType ),
@@ -538,8 +708,23 @@ StdMeshersGUI_CartesianParamCreator::StdMeshersGUI_CartesianParamCreator(const Q
   myAxisTabs[0] = 0;
   myAxisTabs[1] = 0;
   myAxisTabs[2] = 0;
+
+  myAxesPreview = new SMESHGUI_MeshEditPreview( SMESH::GetViewWindow( SMESHGUI::GetSMESHGUI() ));
+  myAxesPreview->SetArrowShapeAndNb( /*nbArrows=*/3,
+                                     /*headLength=*/0.1,
+                                     /*headRadius=*/0.01,
+                                     /*start=*/0.,
+                                     /*labels=*/"XYZ");
+
+  myDirTic[0] = myDirTic[1] = myDirTic[2] = 0;
 }
 
+//================================================================================
+/*!
+ * \brief StdMeshersGUI_CartesianParamCreator destructor
+ */
+//================================================================================
+
 StdMeshersGUI_CartesianParamCreator::~StdMeshersGUI_CartesianParamCreator()
 {
   if ( myAxisTabs[0] ) delete myAxisTabs[0];
@@ -548,8 +733,16 @@ StdMeshersGUI_CartesianParamCreator::~StdMeshersGUI_CartesianParamCreator()
   myAxisTabs[0] = 0;
   myAxisTabs[1] = 0;
   myAxisTabs[2] = 0;
+
+  delete myAxesPreview;
 }
 
+//================================================================================
+/*!
+ * \brief Validate parameters
+ */
+//================================================================================
+
 bool StdMeshersGUI_CartesianParamCreator::checkParams( QString& msg ) const
 {
   if( !SMESHGUI_GenericHypothesisCreator::checkParams( msg ) )
@@ -568,9 +761,22 @@ bool StdMeshersGUI_CartesianParamCreator::checkParams( QString& msg ) const
   if ( !myAxisTabs[1]->checkParams( msg, hyp )) return false;
   if ( !myAxisTabs[2]->checkParams( msg, hyp )) return false;
 
+  StdMeshersGUI_CartesianParamCreator* me = (StdMeshersGUI_CartesianParamCreator*) this;
+  if ( !me->updateAxesPreview() )
+  {
+    msg = tr("INVALID_AXES_DIR");
+    return false;
+  }
+
   return true;
 }
 
+//================================================================================
+/*!
+ * \brief Create widgets
+ */
+//================================================================================
+
 QFrame* StdMeshersGUI_CartesianParamCreator::buildFrame()
 {
   QFrame* fr = new QFrame();
@@ -615,6 +821,26 @@ QFrame* StdMeshersGUI_CartesianParamCreator::buildFrame()
   myAddEdges = new QCheckBox( tr("ADD_EDGES"), GroupC1 );
   argGroupLayout->addWidget( myAddEdges, row, 0, 1, 2 );
   row++;
+  myCreateFaces = new QCheckBox( tr("CREATE_FACES"), GroupC1 );
+  argGroupLayout->addWidget( myCreateFaces, row, 0, 1, 2 );
+  row++;
+  myConsiderInternalFaces = new QCheckBox( tr("CONSIDER_INTERNAL_FACES"), GroupC1 );
+  argGroupLayout->addWidget( myConsiderInternalFaces, row, 0, 1, 2 );
+  row++;
+  myUseThresholdForInternalFaces = new QCheckBox( tr("USE_THRESHOLD_FOR_INTERNAL_FACES"), GroupC1 );
+  argGroupLayout->addWidget( myUseThresholdForInternalFaces, row, 0, 1, 2 );
+  row++;
+  mySetQuanta = new QCheckBox( tr("SET_QUANTA"), GroupC1 );
+  argGroupLayout->addWidget( mySetQuanta, row, 0, 1, 2 );
+  row++;
+
+  argGroupLayout->addWidget( new QLabel( tr("QUANTA_VALUE"), GroupC1 ), row, 0 );
+  myQuanta = new SMESHGUI_SpinBox( GroupC1 );
+  myQuanta->setAcceptNames( false );
+  myQuanta->RangeStepAndValidator( 1e-6, 1, 0.05, "length_precision" );
+  myQuanta->setEnabled(false);
+  argGroupLayout->addWidget( myQuanta, row, 1 );  
+  row++;
 
   // 3)  Grid definition
   QTabWidget* tabWdg = new QTabWidget( fr );
@@ -625,10 +851,160 @@ QFrame* StdMeshersGUI_CartesianParamCreator::buildFrame()
   tabWdg->addTab( myAxisTabs[ 1 ], tr( "AXIS_Y" ) );
   tabWdg->addTab( myAxisTabs[ 2 ], tr( "AXIS_Z" ) );
   argGroupLayout->addWidget( tabWdg, row, 0, 1, 2 );
+  row++;
+
+  QPixmap aPix = SMESHGUI::resourceMgr()->loadPixmap("SMESH", tr("ICON_SELECT"));
+
+  // 4) Fixed point
+  myFixedPointGrp = new QGroupBox( tr("FIXED_POINT"), fr );
+  myFixedPointGrp->setCheckable( true );
+  //QPushButton* pointBtn = new QPushButton( QIcon(aPix), "", myFixedPointGrp );
+  QLabel* pXLbl = new QLabel( tr("SMESH_X"), myFixedPointGrp );
+  QLabel* pYLbl = new QLabel( tr("SMESH_Y"), myFixedPointGrp );
+  QLabel* pZLbl = new QLabel( tr("SMESH_Z"), myFixedPointGrp );
+  for ( int i = 0; i < 3; ++i )
+  {
+    myPointSpin[i] = new SMESHGUI_SpinBox( myFixedPointGrp );
+    myPointSpin[i]->RangeStepAndValidator( -1e20, 1e20, 10 );
+    myPointSpin[i]->SetValue( 0. );
+  }
+  QHBoxLayout* aFixedPointLay = new QHBoxLayout( myFixedPointGrp );
+  aFixedPointLay->addWidget( pXLbl, 0, Qt::AlignRight );
+  aFixedPointLay->addWidget( myPointSpin[0], 1 );
+  aFixedPointLay->addWidget( pYLbl, 0, Qt::AlignRight );
+  aFixedPointLay->addWidget( myPointSpin[1], 1 );
+  aFixedPointLay->addWidget( pZLbl, 0, Qt::AlignRight );
+  aFixedPointLay->addWidget( myPointSpin[2], 1 );
+  argGroupLayout->addWidget( myFixedPointGrp, row, 0, 1, 2 );
+  row++;
+
+  // 5) Axes direction
+  QGroupBox* axesDirGrp = new QGroupBox( tr("AXES_DIRECTION"), fr );
+  QGridLayout* axisDirLay = new QGridLayout( axesDirGrp );
+  axisDirLay->setSpacing( SPACING );
+  axisDirLay->setMargin( MARGIN );
+  axisDirLay->setColumnStretch( 0, 2 );
+  // is orthogonal
+  myOrthogonalChk = new QCheckBox( tr("ORTHOGONAL_AXES"), axesDirGrp );
+  axisDirLay->addWidget( myOrthogonalChk, 0, 0, 1, 7 );
+  // axes
+  QLabel* axisLbl[3];
+  axisLbl[0] = new QLabel( tr( "AXIS_X"), axesDirGrp );
+  axisLbl[1] = new QLabel( tr( "AXIS_Y"), axesDirGrp );
+  axisLbl[2] = new QLabel( tr( "AXIS_Z"), axesDirGrp );
+  QLabel* dLbl[3];
+  myAxisBtnGrp = new QButtonGroup( axesDirGrp );
+  // get spin width
+  const char * const precisionType = "len_tol_precision";
+  int minWidth = getMinWidth( precisionType );
+  for ( int i = 0; i < 3; ++i )
+  {
+    QPushButton* axisBtn = new QPushButton( QIcon(aPix), "", axesDirGrp );
+    axisBtn->setCheckable( true );
+    myAxisBtnGrp->addButton( axisBtn, i );
+    myXDirSpin[i] = new SMESHGUI_SpinBox( axesDirGrp );
+    myYDirSpin[i] = new SMESHGUI_SpinBox( axesDirGrp );
+    myZDirSpin[i] = new SMESHGUI_SpinBox( axesDirGrp );
+    myXDirSpin[i]->RangeStepAndValidator( -1, 1, 0.1, precisionType );
+    myYDirSpin[i]->RangeStepAndValidator( -1, 1, 0.1, precisionType );
+    myZDirSpin[i]->RangeStepAndValidator( -1, 1, 0.1, precisionType );
+    myXDirSpin[i]->setMinimumWidth( minWidth );
+    myYDirSpin[i]->setMinimumWidth( minWidth );
+    myZDirSpin[i]->setMinimumWidth( minWidth );
+    dLbl[0] = new QLabel( tr("SMESH_DX"), axesDirGrp );
+    dLbl[1] = new QLabel( tr("SMESH_DY"), axesDirGrp );
+    dLbl[2] = new QLabel( tr("SMESH_DZ"), axesDirGrp );
+    axisDirLay->addWidget( axisLbl[i],    i+1, 0 );
+    axisDirLay->addWidget( axisBtn,       i+1, 1 );
+    axisDirLay->addWidget( dLbl[0],       i+1, 2 );
+    axisDirLay->addWidget( dLbl[1],       i+1, 4 );
+    axisDirLay->addWidget( dLbl[2],       i+1, 6 );
+    axisDirLay->addWidget( myXDirSpin[i], 1, 3+i*2 );
+    axisDirLay->addWidget( myYDirSpin[i], 2, 3+i*2 );
+    axisDirLay->addWidget( myZDirSpin[i], 3, 3+i*2 );
+  }
+  axisDirLay->setColumnStretch( 3, 10 );
+  axisDirLay->setColumnStretch( 5, 10 );
+  axisDirLay->setColumnStretch( 7, 10 );
+
+  // set optimal axes
+  QPushButton* optimBtn = new QPushButton( tr("OPTIMAL_AXES"), axesDirGrp );
+  QPushButton* resetBtn = new QPushButton( tr("RESET_AXES"), axesDirGrp );
+  axisDirLay->addWidget( optimBtn, 4, 0, 1, 4 );
+  axisDirLay->addWidget( resetBtn, 4, 4, 1, 4 );
+
+  argGroupLayout->addWidget( axesDirGrp, row, 0, 1, 2 );
+  row++;
+
+  // Signals
+
+  LightApp_SelectionMgr* selMgr = SMESH::GetSelectionMgr( SMESHGUI::GetSMESHGUI() );
+
+  connect( selMgr,          SIGNAL( currentSelectionChanged()), SLOT( onSelectionChange()));
+  connect( myOrthogonalChk, SIGNAL( toggled(bool)),             SLOT( onOrthogonalAxes(bool)));
+  connect( optimBtn,        SIGNAL( clicked(bool)),             SLOT( onOptimalAxes(bool)));
+  connect( resetBtn,        SIGNAL( clicked(bool)),             SLOT( onResetAxes(bool)));
+  connect( myConsiderInternalFaces,      SIGNAL( toggled(bool)),
+           myUseThresholdForInternalFaces, SLOT( setEnabled(bool)));
+  connect( mySetQuanta,     SIGNAL( clicked(bool)), SLOT( onSetQuanta(bool)) );
+  for ( int i = 0; i < 3; ++i )
+  {
+    connect( myXDirSpin[i], SIGNAL(valueChanged   (const QString&)),
+             this,          SLOT  (onAxisDirChange(const QString&)) );
+    connect( myYDirSpin[i], SIGNAL(valueChanged   (const QString&)),
+             this,          SLOT  (onAxisDirChange(const QString&)) );
+    connect( myZDirSpin[i], SIGNAL(valueChanged   (const QString&)),
+             this,          SLOT  (onAxisDirChange(const QString&)) );
+    connect( myAxisTabs[i], SIGNAL(gridModeChanged(int)),
+             this,          SLOT  (onGridModeChanged(int)));
+  }
+
+  // Show axes
+  myAxesLen = 120; // default trihedron size is 100
+  myOrigin[0] = myOrigin[1] = myOrigin[2] = 0.;
+  TopoDS_Shape shape;
+  QString shapeEntry = getMainShapeEntry();
+  if ( !shapeEntry.isEmpty() )
+  {
+    // find origin
+    GEOM::GEOM_Object_var geomObj = SMESH::EntryToInterface<GEOM::GEOM_Object>( shapeEntry );
+    if ( GEOMBase::GetShape( geomObj, shape ) && !shape.IsNull())
+    {
+      Bnd_Box box;
+      BRepBndLib::Add( shape, box );
+      double max[3];
+      if ( !box.IsVoid() )
+      {
+        box.Get( myOrigin[0], myOrigin[1], myOrigin[2], max[0], max[1], max[2] );
+        gp_Pnt o( myOrigin[0], myOrigin[1], myOrigin[2] );
+        gp_Pnt x( max[0], max[1], max[2] );
+        myAxesLen = o.Distance( x );
+
+        double step = 1e20;
+        while ( step > myAxesLen / 5 )
+          step /= 10;
+        myPointSpin[0]->SetStep( step );
+        myPointSpin[1]->SetStep( step );
+        myPointSpin[2]->SetStep( step );
+      }
+    }
+  }
+  myAxisBtnGrp->button(0)->setEnabled( !shape.IsNull() );
+  myAxisBtnGrp->button(1)->setEnabled( !shape.IsNull() );
+  myAxisBtnGrp->button(2)->setEnabled( !shape.IsNull() );
+  optimBtn->setEnabled( !shape.IsNull() );
+
+  updateAxesPreview();
 
   return fr;
 }
 
+//================================================================================
+/*!
+ * \brief Transfer parameters from hypothesis to widgets
+ */
+//================================================================================
+
 void StdMeshersGUI_CartesianParamCreator::retrieveParams() const
 {
   StdMeshers::StdMeshers_CartesianParameters3D_var h =
@@ -644,7 +1020,15 @@ void StdMeshersGUI_CartesianParamCreator::retrieveParams() const
     myThreshold->setText( varName );
 
   myAddEdges->setChecked( h->GetToAddEdges() );
-
+  myCreateFaces->setChecked( h->GetToCreateFaces() );
+  myConsiderInternalFaces->setChecked( h->GetToConsiderInternalFaces() );
+  myUseThresholdForInternalFaces->setChecked( h->GetToUseThresholdForInternalFaces() );
+  mySetQuanta->setChecked( h->GetToUseQuanta() );
+  myQuanta->setValue( h->GetQuanta() );
+  if (h->GetToUseQuanta())
+    myQuanta->setEnabled(true);
+
+  // grid definition
   for ( int ax = 0; ax < 3; ++ax )
   {
     if ( h->IsGridBySpacing( ax ))
@@ -660,11 +1044,62 @@ void StdMeshersGUI_CartesianParamCreator::retrieveParams() const
       myAxisTabs[ax]->setCoordinates( coords );
     }
   }
+
+  // fixed point
+  SMESH::PointStruct fp;
+  StdMeshersGUI_CartesianParamCreator* me = (StdMeshersGUI_CartesianParamCreator*) this;
+  if ( h->GetFixedPoint( fp ))
+  {
+    me->myPointSpin[0]->SetValue( fp.x );
+    me->myPointSpin[1]->SetValue( fp.y );
+    me->myPointSpin[2]->SetValue( fp.z );
+    setText( getVariableName("GetFixedPoint"), &me->myPointSpin[0] );
+    myFixedPointGrp->setChecked( true );
+  }
+  else
+  {
+    myFixedPointGrp->setChecked( false );
+  }
+
+  // axes directions
+  SMESHGUI_SpinBox** spins[3] = { &me->myXDirSpin[0], &me->myYDirSpin[0], &me->myZDirSpin[0] };
+  SMESH::DirStruct axisDir[3];
+  h->GetAxesDirs( axisDir[0],
+                  axisDir[1],
+                  axisDir[2]);
+  QString vars = getVariableName("GetAxesDirs");
+  for ( int i = 0; i < 3; ++i )
+  {
+    spins[i][0]->SetValue( axisDir[i].PS.x );
+    spins[i][1]->SetValue( axisDir[i].PS.y );
+    spins[i][2]->SetValue( axisDir[i].PS.z );
+    setText( vars, spins[i] );
+
+    // cut off 3 used vars
+    if ( !vars.isEmpty() )
+    {
+      int ind = -1;
+      for ( int j = 0; j < 3; ++j )
+        if (( ind = vars.indexOf(':', ind+1 )) < 0 )
+          break;
+      if ( ind < 0 )
+        vars.clear();
+      else
+        vars.remove( 0, ind+1 );
+    }
+  }
+
   if ( dlg() )
     dlg()->setMinimumSize( dlg()->minimumSizeHint().width(),
                            dlg()->minimumSizeHint().height() );
 }
 
+//================================================================================
+/*!
+ * \brief Transfer parameters from widgets to hypothesis
+ */
+//================================================================================
+
 QString StdMeshersGUI_CartesianParamCreator::storeParams() const
 {
   StdMeshers::StdMeshers_CartesianParameters3D_var h =
@@ -673,12 +1108,19 @@ QString StdMeshersGUI_CartesianParamCreator::storeParams() const
   try
   {
     if( isCreation() )
-      SMESH::SetName( SMESH::FindSObject( h ), myName->text().toLatin1().constData() );
+      SMESH::SetName( SMESH::FindSObject( h ), myName->text().toUtf8().constData() );
 
+    // threshold
     h->SetVarParameter( myThreshold->text().toLatin1().constData(), "SetSizeThreshold" );
     h->SetSizeThreshold( myThreshold->text().toDouble() );
     h->SetToAddEdges( myAddEdges->isChecked() );
+    h->SetToCreateFaces( myCreateFaces->isChecked() );
+    h->SetToConsiderInternalFaces( myConsiderInternalFaces->isChecked() );
+    h->SetToUseThresholdForInternalFaces( myUseThresholdForInternalFaces->isChecked() );
+    h->SetToUseQuanta( mySetQuanta->isChecked() );
+    h->SetQuanta( myQuanta->text().toDouble() );
 
+    // grid
     for ( int ax = 0; ax < 3; ++ax )
     {
       if ( myAxisTabs[ax]->isGridBySpacing())
@@ -694,6 +1136,40 @@ QString StdMeshersGUI_CartesianParamCreator::storeParams() const
         h->SetGrid( coords, ax );
       }
     }
+
+    // fixed point
+    QStringList params;
+    params << myPointSpin[0]->text();
+    params << myPointSpin[1]->text();
+    params << myPointSpin[2]->text();
+    h->SetVarParameter( params.join(":").toUtf8().constData(), "SetFixedPoint" );
+    params.clear();
+
+    SMESH::PointStruct ps;
+    ps.x = myPointSpin[0]->GetValue();
+    ps.y = myPointSpin[1]->GetValue();
+    ps.z = myPointSpin[2]->GetValue();
+    h->SetFixedPoint( ps, !myFixedPointGrp->isEnabled() || !myFixedPointGrp->isChecked() );
+
+    // axes directions
+    SMESHGUI_SpinBox* const * spins[3] = { &myXDirSpin[0], &myYDirSpin[0], &myZDirSpin[0] };
+    for ( int ax = 0; ax < 3; ++ax )
+    {
+      params << spins[ax][0]->text();
+      params << spins[ax][1]->text();
+      params << spins[ax][2]->text();
+    }
+    h->SetVarParameter( params.join(":").toUtf8().constData(), "SetAxesDirs" );
+
+    SMESH::DirStruct axDir[3];
+    for ( int ax = 0; ax < 3; ++ax )
+    {
+      axDir[ax].PS.x = spins[ax][0]->GetValue();
+      axDir[ax].PS.y = spins[ax][1]->GetValue();
+      axDir[ax].PS.z = spins[ax][2]->GetValue();
+    }
+    h->SetAxesDirs( axDir[0], axDir[1], axDir[2] );
+
   }
   catch(const SALOME::SALOME_Exception& ex)
   {
@@ -702,7 +1178,312 @@ QString StdMeshersGUI_CartesianParamCreator::storeParams() const
   return "";
 }
 
+//================================================================================
+/*!
+ * \brief Returns a name of help page
+ */
+//================================================================================
+
 QString StdMeshersGUI_CartesianParamCreator::helpPage() const
 {
-  return "cartesian_algo_page.html#cartesian_hyp_anchor";
+  return "cartesian_algo.html#cartesian-hyp-anchor";
+}
+
+//================================================================================
+/*!
+ * \brief Show axes if they are OK
+ */
+//================================================================================
+
+bool StdMeshersGUI_CartesianParamCreator::updateAxesPreview()
+{
+  bool isOk = true;
+  gp_Ax1 axes[3];
+  SMESHGUI_SpinBox** spins[3] = { &myXDirSpin[0], &myYDirSpin[0], &myZDirSpin[0] };
+  for ( int i = 0; i < 3 && isOk; ++i )
+  {
+    gp_XYZ dir( spins[i][0]->GetValue(),
+                spins[i][1]->GetValue(),
+                spins[i][2]->GetValue());
+    if (( isOk = ( dir.Modulus() > 1e-100 )))
+      axes[i].SetDirection( gp_Dir( dir ));
+
+    axes[i].SetLocation ( gp_Pnt( myOrigin[0],
+                                  myOrigin[1],
+                                  myOrigin[2]));
+  }
+  gp_Vec norm01 = axes[0].Direction().XYZ() ^ axes[1].Direction().XYZ();
+  gp_Vec norm12 = axes[1].Direction().XYZ() ^ axes[2].Direction().XYZ();
+  if ( isOk )
+    isOk = ( !axes[0].Direction().IsParallel( axes[1].Direction(), theAngTol ) &&
+             !axes[1].Direction().IsParallel( axes[2].Direction(), theAngTol ) &&
+             !axes[2].Direction().IsParallel( axes[0].Direction(), theAngTol ) &&
+             !norm01.IsParallel( norm12, theAngTol ) );
+  if ( isOk )
+    myAxesPreview->SetArrows( axes, myAxesLen );
+
+  myAxesPreview->SetVisibility( isOk );
+
+  return isOk;
+}
+
+//================================================================================
+/*!
+ * \brief Makes axes orthogonal if necessary
+ */
+//================================================================================
+
+void StdMeshersGUI_CartesianParamCreator::onOrthogonalAxes(bool isOrtho)
+{
+  if ( !isOrtho )
+  {
+    updateAxesPreview();
+    return;
+  }
+
+  std::multimap< int, int > ageOfAxis;
+  gp_XYZ dirs[3];
+  SMESHGUI_SpinBox** spins[3] = { &myXDirSpin[0], &myYDirSpin[0], &myZDirSpin[0] };
+  int nbOk = 0, isOk;
+  for ( int iAx = 0; iAx < 3; ++iAx )
+  {
+    dirs[iAx].SetCoord( spins[iAx][0]->GetValue(),
+                        spins[iAx][1]->GetValue(),
+                        spins[iAx][2]->GetValue());
+    if (( isOk = ( dirs[iAx].Modulus() > 1e-100 )))
+      ageOfAxis.insert( std::make_pair( myDirTic[iAx], iAx ));
+    else
+      ageOfAxis.insert( std::make_pair( -1, iAx ));
+    nbOk += isOk;
+  }
+  switch ( nbOk )
+  {
+  case 0:
+  {
+    dirs[0].SetCoord( 1, 0, 0 );
+    dirs[1].SetCoord( 0, 1, 0 );
+    dirs[2].SetCoord( 0, 0, 1 );
+    break;
+  }
+  case 1:
+  {
+    int iOk = ageOfAxis.rbegin()->second;
+    get3Dirs( iOk, dirs );
+    break;
+  }
+  default:
+    std::multimap< int, int >::reverse_iterator ag2ax = ageOfAxis.rbegin();
+    int iOk1 = ag2ax->second;
+    int iOk2 = (++ag2ax)->second;
+    int iKo  = (++ag2ax)->second;
+    if ( gp_Vec( dirs[ iOk1 ]).IsParallel( gp_Vec( dirs[ iOk2 ]), theAngTol ))
+      std::swap( iOk2, iKo );
+    if ( gp_Vec( dirs[ iOk1 ]).IsParallel( gp_Vec( dirs[ iOk2 ]), theAngTol ))
+    {
+      get3Dirs( iOk1, dirs );
+    }
+    else
+    {
+      dirs[ iKo  ] = dirs[ iOk1 ] ^ dirs[ iOk2 ];
+      dirs[ iOk2 ] = dirs[ iKo  ] ^ dirs[ iOk1 ];
+      if ( ( iOk1+1 ) % 3 != iOk2 )
+        dirs[ iKo ].Reverse();
+    }
+  }
+
+  for ( int iAx = 0; iAx < 3; ++iAx )
+  {
+    double size = dirs[iAx].Modulus();
+    if ( size > 1e-100 )
+      dirs[iAx] /= size;
+    for (int i = 0; i < 3; ++i )
+    {
+      bool isBlocked = spins[iAx][i]->blockSignals( true );
+      spins[iAx][i]->SetValue( dirs[iAx].Coord( i+1 ));
+      spins[iAx][i]->blockSignals( isBlocked );
+    }
+  }
+
+  updateAxesPreview();
+}
+
+//================================================================================
+/*!
+ * \brief Increment myDirTic and update the preview of axes
+ */
+//================================================================================
+
+void StdMeshersGUI_CartesianParamCreator::onAxisDirChange(const QString&)
+{
+  QObject* changedSpin = sender();
+  SMESHGUI_SpinBox** spins[3] = { &myXDirSpin[0], &myYDirSpin[0], &myZDirSpin[0] };
+  for ( int iAx = 0; iAx < 3; ++iAx )
+    if ( spins[iAx][0] == changedSpin ||
+         spins[iAx][1] == changedSpin ||
+         spins[iAx][2] == changedSpin )
+    {
+      myDirTic[ iAx ] = 1 + Max( Max( myDirTic[0], myDirTic[1] ), myDirTic[2] );
+      break;
+    }
+
+  onOrthogonalAxes( myOrthogonalChk->isChecked() );
+}
+
+//================================================================================
+/*!
+ * \brief Sets axis direction by a selected EDGE
+ */
+//================================================================================
+
+void StdMeshersGUI_CartesianParamCreator::onSelectionChange()
+{
+  int iAxis = myAxisBtnGrp->checkedId();
+  if ( iAxis < 0 )
+    return;
+
+  SALOME_ListIO aList;
+  SMESHGUI::GetSMESHGUI()->selectionMgr()->selectedObjects(aList);
+
+  TopoDS_Shape edge, shape;
+  for( SALOME_ListIteratorOfListIO anIt( aList ); anIt.More(); anIt.Next() )
+  {
+    GEOM::GEOM_Object_var go = SMESH::IObjectToInterface<GEOM::GEOM_Object>( anIt.Value() );
+    if ( GEOMBase::GetShape( go, shape ) && shape.ShapeType() == TopAbs_EDGE )
+    {
+      if ( !edge.IsNull() )
+        return; // several EDGEs selected
+      edge = shape;
+    }
+  }
+  if ( edge.IsNull() )
+    return;
+
+  TopoDS_Shape vv[2];
+  TopoDS_Iterator vIt( edge );
+  for ( ; vIt.More() && vv[1].IsNull(); vIt.Next() )
+    vv[ !vv[0].IsNull() ] = vIt.Value();
+
+  gp_Pnt pp[2];
+  if ( !GEOMBase::VertexToPoint( vv[0], pp[0] ) ||
+       !GEOMBase::VertexToPoint( vv[1], pp[1] ))
+    return;
+
+  SMESHGUI_SpinBox** spins[3] = { &myXDirSpin[0], &myYDirSpin[0], &myZDirSpin[0] };
+
+  gp_Vec newDir( pp[0], pp[1] );
+  gp_Vec curDir( spins[iAxis][0]->GetValue(),
+                 spins[iAxis][1]->GetValue(),
+                 spins[iAxis][2]->GetValue());
+  if ( newDir * curDir < 0 )
+    newDir.Reverse();
+
+  double size = newDir.Magnitude();
+  if ( size < 1e-100 )
+    return;
+  newDir /= size;
+
+  for (int i = 0; i < 3; ++i )
+  {
+    bool isBlocked = spins[iAxis][i]->blockSignals( true );
+    spins[iAxis][i]->SetValue( newDir.Coord( i+1 ));
+    spins[iAxis][i]->blockSignals( isBlocked );
+  }
+  myDirTic[ iAxis ] = 1 + Max( Max( myDirTic[0], myDirTic[1] ), myDirTic[2] );
+
+  onOrthogonalAxes( myOrthogonalChk->isChecked() );
+}
+
+//================================================================================
+/*!
+ * \brief Sets axes at which number of hexahedra is maximal
+ */
+//================================================================================
+
+void StdMeshersGUI_CartesianParamCreator::onOptimalAxes(bool)
+{
+  StdMeshers::StdMeshers_CartesianParameters3D_var h =
+    StdMeshers::StdMeshers_CartesianParameters3D::_narrow( hypothesis() );
+  if ( h->_is_nil() )
+    return;
+
+  QString shapeEntry = getMainShapeEntry();
+  if ( shapeEntry.isEmpty() )
+    return;
+
+  GEOM::GEOM_Object_var geomObj = SMESH::EntryToInterface<GEOM::GEOM_Object>( shapeEntry );
+  if ( geomObj->_is_nil() )
+    return;
+
+  SMESH::DirStruct axDirs[3];
+  h->ComputeOptimalAxesDirs( geomObj,
+                             myOrthogonalChk->isChecked(),
+                             axDirs[0],
+                             axDirs[1],
+                             axDirs[2]);
+
+  SMESHGUI_SpinBox** spins[3] = { &myXDirSpin[0], &myYDirSpin[0], &myZDirSpin[0] };
+  for ( int iAx = 0; iAx < 3; ++iAx )
+  {
+    double coords[3] = { axDirs[iAx].PS.x, axDirs[iAx].PS.y, axDirs[iAx].PS.z };
+    for (int i = 0; i < 3; ++i )
+    {
+      bool isBlocked = spins[iAx][i]->blockSignals( true );
+      spins[iAx][i]->SetValue( coords[ i ]);
+      spins[iAx][i]->blockSignals( isBlocked );
+    }
+  }
+  updateAxesPreview();
+}
+
+//================================================================================
+/*!
+ * \brief Sets axes || to the axes of global CS
+ */
+//================================================================================
+
+void StdMeshersGUI_CartesianParamCreator::onResetAxes(bool)
+{
+  SMESHGUI_SpinBox** spins[3] = { &myXDirSpin[0], &myYDirSpin[0], &myZDirSpin[0] };
+  for ( int iAx = 0; iAx < 3; ++iAx )
+  {
+    for (int i = 0; i < 3; ++i )
+    {
+      bool isBlocked = spins[iAx][i]->blockSignals( true );
+      spins[iAx][i]->SetValue( iAx == i ? 1. : 0. );
+      spins[iAx][i]->blockSignals( isBlocked );
+    }
+    myDirTic[iAx] = 0;
+  }
+  updateAxesPreview();
+}
+
+//================================================================================
+/*!
+ * \brief SLOT called when the grid definition mode changes
+ */
+//================================================================================
+
+void StdMeshersGUI_CartesianParamCreator::onGridModeChanged(int)
+{
+  bool haveSpacing = ( myAxisTabs[0]->isGridBySpacing() ||
+                       myAxisTabs[1]->isGridBySpacing() ||
+                       myAxisTabs[2]->isGridBySpacing() );
+
+  myFixedPointGrp->setEnabled( haveSpacing );
+}
+
+//================================================================================
+/*!
+ * \brief Enable and disable quanta value combo box 
+ */
+//================================================================================
+
+void StdMeshersGUI_CartesianParamCreator::onSetQuanta(bool)
+{
+  StdMeshers::StdMeshers_CartesianParameters3D_var h =
+    StdMeshers::StdMeshers_CartesianParameters3D::_narrow( hypothesis() );
+  if ( h->_is_nil() )
+    return;
+
+  myQuanta->setEnabled( mySetQuanta->isChecked() );
 }