From 90dbc5f10c66da5c69987766aaa141585b4f636f Mon Sep 17 00:00:00 2001 From: eap Date: Wed, 9 Oct 2019 15:49:18 +0300 Subject: [PATCH] #17784 [EDF] MESH-GEMS-2.9.6 Meshers options --- .../images/hybrid_hypothesis_advanced.png | Bin 29810 -> 31996 bytes .../images/hybrid_hypothesis_arguments.png | Bin 34492 -> 42094 bytes .../gui/HYBRIDPLUGIN/input/hybrid_hypo.doc | 160 +++-- idl/HYBRIDPlugin_Algorithm.idl | 44 +- src/GUI/CMakeLists.txt | 5 + src/GUI/HYBRIDPluginGUI_AdvWidget.cxx | 93 ++- src/GUI/HYBRIDPluginGUI_AdvWidget_QTD.ui | 188 ++---- src/GUI/HYBRIDPluginGUI_Dlg.h | 48 +- src/GUI/HYBRIDPluginGUI_HypothesisCreator.cxx | 475 ++++--------- src/GUI/HYBRIDPluginGUI_HypothesisCreator.h | 38 +- src/GUI/HYBRIDPluginGUI_StdWidget.cxx | 54 ++ src/GUI/HYBRIDPluginGUI_StdWidget_QTD.ui | 250 +++++++ src/GUI/HYBRIDPluginGUI_TreeWidget.cxx | 91 +++ src/GUI/HYBRIDPluginGUI_TreeWidget.h | 36 + src/GUI/HYBRIDPlugin_msg_en.ts | 98 ++- src/HYBRIDPlugin/HYBRIDPluginBuilder.py | 76 +-- src/HYBRIDPlugin/HYBRIDPlugin_Hypothesis.cxx | 630 +++++++++++++----- src/HYBRIDPlugin/HYBRIDPlugin_Hypothesis.hxx | 142 ++-- .../HYBRIDPlugin_Hypothesis_i.cxx | 338 +++++++++- .../HYBRIDPlugin_Hypothesis_i.hxx | 27 +- 20 files changed, 1940 insertions(+), 853 deletions(-) create mode 100644 src/GUI/HYBRIDPluginGUI_StdWidget.cxx create mode 100644 src/GUI/HYBRIDPluginGUI_StdWidget_QTD.ui create mode 100644 src/GUI/HYBRIDPluginGUI_TreeWidget.cxx create mode 100644 src/GUI/HYBRIDPluginGUI_TreeWidget.h diff --git a/doc/salome/gui/HYBRIDPLUGIN/images/hybrid_hypothesis_advanced.png b/doc/salome/gui/HYBRIDPLUGIN/images/hybrid_hypothesis_advanced.png index 50b6cf4045b4aa262693d4f922aa1cc8ad207beb..bde2d19f9b68af77161f4777c60befe509386b57 100644 GIT binary patch literal 31996 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

r6pgyeP_ic%6@>}A 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 NSt*4_ITD7i{tukpg>nD@ literal 29810 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 N95uGUmKvQV{S%qulW+h4 literal 34492 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 O mg-hybrid.exe --help - - ============================================== - MG-Hybrid -- MeshGems 2.1-11 (September, 2015) - ============================================== + ========================================== + MG-Hybrid -- MeshGems 2.9-6 (August, 2019) + ========================================== Distene SAS Campus Teratec @@ -33,11 +32,11 @@ $> mg-hybrid.exe --help Phone: +33(0)970-650-219 Fax: +33(0)169-269-033 EMail: - Running MG-Hybrid (Copyright 2014-2015 by Distene SAS) - date of run: 26-Jan-2016 AT 12:24:16 - running on : Linux 3.6.10-4.fc18.x86_64 x86_64 + Running MG-Hybrid (Copyright 2014-2019 by Distene SAS) + date of run: 07-Oct-2019 AT 17:40:47 + running on : Linux 3.16.0-4-amd64 x86_64 using modules: - MeshGems-Core 2.1-11 + MeshGems-Core 2.9-6 MeshGems is a Registered Trademark of Distene SAS @@ -45,20 +44,19 @@ $> mg-hybrid.exe --help MG-HYBRID USAGE mg-hybrid.exe [-h] [-v ] [-i ] [-o ] \ - [--global_physical_size ] \ - [--max_number_of_threads ] \ + [--global_physical_size ] [--max_number_of_threads ] \ [--boundary_layer_size_mode ] \ - [--number_of_boundary_layers ] \ - [--boundary_layer_global_initial_height ] \ + [--boundary_layer_height_relative_to_local_surface_size ] \ + [--number_of_boundary_layers ] [--boundary_layer_global_initial_height ] \ [--boundary_layer_surface_tags ] \ [--boundary_layer_initial_height_on_surface_tags ] \ - [--boundary_layer_imprint_tags ] \ [--boundary_layer_geometric_progression ] \ - [--boundary_layer_max_element_angle ] \ - [--normal_direction

] [--gradation ] \ - [--element_generation ] [--collision_mode ] \ - [--add_multinormals ] [--multinormal_angle_threshold ] \ - [--smooth_normals ] [--optimisation ] + [--boundary_layer_max_element_angle ] [--boundary_layer_imprinting ] \ + [--boundary_layer_imprinting_tags ] [--boundary_layer_snapping ] \ + [--boundary_layer_snapping_tags ] [--normal_direction ] [--gradation ] \ + [--element_generation ] [--collision_mode ] [--add_multinormals ] \ + [--multinormal_angle_threshold ] [--smooth_normals ] \ + [--optimisation ] -h --help prints this help. @@ -91,13 +89,15 @@ MG-HYBRID USAGE --boundary_layer_size_mode Sets the behavior for the boundary layer sizes. If is: - global: the boundary_layer_global_initial_height is used to compute - the layer heights + global: the boundary_layer_global_initial_height is used to compute the layer heights local: the boundary_layer_surface_tags and - boundary_layer_initial_height_on_surface_tags are used to compute - the layer heights + boundary_layer_initial_height_on_surface_tags are used to compute the layer heights Default: global + --boundary_layer_height_relative_to_local_surface_size + If set to yes, the given sizes are relative to the surface size + Default: no + --number_of_boundary_layers Sets the number of boundary layers. Default: 0 @@ -106,64 +106,72 @@ MG-HYBRID USAGE Sets the height of the first layer. --boundary_layer_surface_tags - Comma separated list of surface references to be used to grow - boundary layers. + Comma separated list of surface references to be used to grow boundary layers. --boundary_layer_initial_height_on_surface_tags - Comma separated list of initial heights to be used to grow boundary - layers. - - --boundary_layer_imprint_tags - Comma separated list of surface references that are imprinted by - boundary layers. + Comma separated list of initial heights to be used to grow boundary layers. --boundary_layer_geometric_progression - Sets the geometric progression for all the boundary layer growths - (position of layer number i is h * g^(i-1)). + Sets the geometric progression for all the boundary layer growths (position of layer + number i is h * g^(i-1)). Default: 1.0 --boundary_layer_max_element_angle - Sets the maximum internal angles of elements (in degree). This - setting applies to the boundary layer elements only. + Sets the maximum internal angles of elements (in degree). This setting applies to the + boundary layer elements only. Default: 165. + --boundary_layer_imprinting + Activates the imprinting of the boundary layers. The parts of the surface where the + layers have to be imprinted are defined through the option + --boundary_layer_imprinting_tags + Default: no imprinting + + --boundary_layer_imprinting_tags + Comma separated list of surface references that have to be imprinted by boundary layers. + + --boundary_layer_snapping + Activates the snapping of the generated boundary layers on the surface. The parts of the + surface where the layers have to be snapped into are defined through the option + --boundary_layer_snapping_tags + Default: no snapping + + --boundary_layer_snapping_tags + Comma separated list of surface references that are imprinted by boundary layers. + --normal_direction - Specifies whether mg-hybrid should use the surface normals or the - inverse of the surface normals. + Specifies whether mg-hybrid should use the surface normals or the inverse of the surface + normals. if is: - 1 : means the layers grow in the same direction as the normals to - the surface - -1 : means the layers grow in the opposite direction to the normals - of the surface + 1 : means the layers grow in the same direction as the normals to the surface + -1 : means the layers grow in the opposite direction to the normals of the surface Default: 1 --gradation - Sets the desired maximum ratio between 2 adjacent edges. It applies - only to the edges which belong to the tetrahedra. + Sets the desired maximum ratio between 2 adjacent edges. It applies only to the edges + which belong to the tetrahedra. Default: 2.0 --element_generation Sets the element type for the mesh generation. If is: - tetra_dominant : prismatic or hexahedral elements in the boundary - layers, tetrahedra in the remaining volume - hexa_dominant : prismatic or hexahedral elements in the boundary - layers, mixture of hexahedra and tetrahedra in the remaining + tetra_dominant : prismatic or hexahedral elements in the boundary layers, tetrahedra in + the remaining volume + hexa_dominant : prismatic or hexahedral elements in the boundary layers, mixture of + hexahedra and tetrahedra in the remaining volume + cartesian_core : cartesian hexa core with tetrahedra and pyramids in the remaining volume - cartesian_core : cartesian hexa core with tetrahedra and pyramids - in the remaining volume - extrusion_only : only prismatic or hexahedral elements near the - boundary are generated. The remaining volume is not filled. + extrusion_only : only prismatic or hexahedral elements near the boundary are generated. + The remaining volume is not filled. Default: tetra_dominant --collision_mode Sets the behavior in case of collision between layers. If is: - decrease : keeps the number of desired layer but decreases the - height of the layers to avoid any collision - stop : stops locally the generation of layers to avoid collisions; - the number of generated layers may differ from the specified - desired number + decrease : keeps the number of desired layer but decreases the height of the layers to + avoid any collision + stop : stops locally the generation of layers to avoid collisions; the number of + generated layers may differ from the specified desired number Default: stop --add_multinormals @@ -188,9 +196,9 @@ MG-HYBRID USAGE ================================================================================ - MG-Hybrid -- MeshGems 2.1-11 (September, 2015) - END OF SESSION - MG-Hybrid (Copyright 2014-2015 by Distene SAS) - compiled Sep 3 2015 13:52:38 on Linux_64 + MG-Hybrid -- MeshGems 2.9-6 (August, 2019) + END OF SESSION - MG-Hybrid (Copyright 2014-2019 by Distene SAS) + compiled Sep 2 2019 23:42:41 on Linux_64 MeshGems is a Registered Trademark of Distene SAS ================================================================================ ( Distene SAS @@ -205,6 +213,34 @@ MG-HYBRID USAGE \image html hybrid_hypothesis_advanced.png +\subsection advanced_meshing_options Advanced meshing options + +- A table allows to input in the command line any text + for hybrid argument from "mg-hybrid.exe help", and future advanced options...
+Add option - adds a line to the table where you can type an option and its value as text. +A check box in the first column activates/deactivates the option of the current row. A deactivated option will be erased upon pressing \a Ok. + +- Add multi normals - Add extra normals at opening ridges and +corners. + +- Collision mode - Sets the behavior in case of collision between layers. + + - decrease - keeps the number of desired layer but decreases the height of the layers to + avoid any collision + + - stop - stops locally the generation of layers to avoid collisions; the number of + generated layers may differ from the specified desired number + +- Gradation - Sets the desired maximum ratio between 2 adjacent edges. + It applies only to the edges which belong to the tetrahedra. + +- Maximum number of threads - Sets the maximum number of threads to be used in parallel. + +- Multi normal angle threshold - Set the maximum angle (in + degrees) between the multiple normals at opening ridges. + +- Smooth normals - Smooth normals at closed ridges and corners. + \subsection log Logs and debug - Working directory - allows defining the folder for input and output @@ -235,14 +271,6 @@ is enabled (there must be a log file to delete it) and Keep all working files of hybrid software, while usually these files are removed after the launch of the mesher. The log file (if any) is also kept if this option is checked. -\subsection advanced_meshing_options Advanced meshing options - -- A table allows to input in the command line any text -for hybrid argument from "mg-hybrid.exe help", and future advanced options...
-Add option - adds a line to the table where you can type an option and its value as text. -A check box in the first column activates/deactivates the option of the current row. A deactivated option will be erased upon pressing \a Ok. - - \ref hybrid_top "Back to top" \section hybrid_layers_meshes Layers meshes diff --git a/idl/HYBRIDPlugin_Algorithm.idl b/idl/HYBRIDPlugin_Algorithm.idl index 1147a95..4795e91 100644 --- a/idl/HYBRIDPlugin_Algorithm.idl +++ b/idl/HYBRIDPlugin_Algorithm.idl @@ -34,6 +34,8 @@ */ module HYBRIDPlugin { + typedef sequence string_array; + typedef sequence TCoords; struct HYBRIDEnforcedVertex { string name; @@ -68,6 +70,16 @@ module HYBRIDPlugin */ interface HYBRIDPlugin_Hypothesis : SMESH::SMESH_Hypothesis { + /*! + * Sizes of boundary layers are relative to the surface size. Default no + */ + void SetHeightIsRelative( in boolean isRelative ); + boolean GetHeightIsRelative(); + /*! + * Maximum internal angles of boundary elements (in degree) + */ + void SetBoundaryLayersMaxElemAngle( in double angle ); + double GetBoundaryLayersMaxElemAngle(); /*! * To mesh "holes" in a solid or not. Default is to mesh. */ @@ -227,12 +239,38 @@ module HYBRIDPlugin void SetToRemoveCentralPoint(in boolean toRemove); boolean GetToRemoveCentralPoint(); /*! - * To set hiden/undocumented/advanced options + * Set advanced option value + */ + void SetOptionValue(in string optionName, + in string optionValue) raises (SALOME::SALOME_Exception); + string GetOptionValue(in string optionName) raises (SALOME::SALOME_Exception); + void UnsetOption(in string optionName); + /*! + * Adds custom advanced option and its value */ - void SetAdvancedOption( in string optAndVals ); + void SetAdvancedOption(in string optionsAndValues) // in a form "option_1 v1 option_2 v2'" + raises (SALOME::SALOME_Exception); string GetAdvancedOption(); + void AddOption(in string optionName, in string optionValue); + string GetOption(in string optionName); void SetTextOption(in string option); // obsolete - string GetTextOption(); + string GetTextOption(); // obsolete + /*! + * Return array of strings each of which is option name concatenated + * with option value devided by semicolon - "option_name:option_value:option_type". + * Option value is empty if an option is not set. + * option_type: 1 if user-define, 0 if default + * Note: the method is mostly for interaction with GUI. + */ + string_array GetOptionValues(); + string_array GetAdvancedOptionValues(); + /*! + * Set option values each in the form "option_name[:option_value][:option_type]". + * Note: the method is mostly for interaction with GUI. + */ + void SetOptionValues(in string_array options) raises (SALOME::SALOME_Exception); + void SetAdvancedOptionValues(in string_array options); + /*! * To define the volumic gradation */ diff --git a/src/GUI/CMakeLists.txt b/src/GUI/CMakeLists.txt index 7b9233d..ac0dff3 100644 --- a/src/GUI/CMakeLists.txt +++ b/src/GUI/CMakeLists.txt @@ -34,6 +34,7 @@ INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR} ${PROJECT_BINARY_DIR}/idl ${PROJECT_SOURCE_DIR}/src/HYBRIDPlugin + ${PROJECT_SOURCE_DIR}/src/GUI ) # additional preprocessor / compiler flags @@ -64,6 +65,7 @@ SET(_link_LIBRARIES # header files / to be processed by moc SET(_moc_HEADERS + HYBRIDPluginGUI_TreeWidget.h HYBRIDPluginGUI_HypothesisCreator.h HYBRIDPluginGUI_Dlg.h ) @@ -84,7 +86,9 @@ QT_WRAP_MOC(_moc_SOURCES ${_moc_HEADERS}) SET(_other_SOURCES HYBRIDPluginGUI.cxx HYBRIDPluginGUI_HypothesisCreator.cxx + HYBRIDPluginGUI_StdWidget.cxx HYBRIDPluginGUI_AdvWidget.cxx + HYBRIDPluginGUI_TreeWidget.cxx ) # --- resources --- @@ -99,6 +103,7 @@ SET(_ts_RESOURCES # resource files / to be processed by uic SET(_uic_files + HYBRIDPluginGUI_StdWidget_QTD.ui HYBRIDPluginGUI_AdvWidget_QTD.ui ) diff --git a/src/GUI/HYBRIDPluginGUI_AdvWidget.cxx b/src/GUI/HYBRIDPluginGUI_AdvWidget.cxx index e6b967c..50913ba 100644 --- a/src/GUI/HYBRIDPluginGUI_AdvWidget.cxx +++ b/src/GUI/HYBRIDPluginGUI_AdvWidget.cxx @@ -28,7 +28,23 @@ #include #include +#include +namespace +{ + enum { EDITABLE_ROLE = Qt::UserRole + 1, PARAM_NAME, + NAME_COL = 0, VALUE_COL }; + + class ItemDelegate: public QItemDelegate { + public: + ItemDelegate(QObject* parent=0): QItemDelegate(parent) {} + QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &o, const QModelIndex &index) const + { + bool editable = index.data( EDITABLE_ROLE ).toInt(); + return editable ? QItemDelegate::createEditor( parent, o, index ) : 0; + } + }; +} ////////////////////////////////////////// // HYBRIDPluginGUI_AdvWidget @@ -38,9 +54,84 @@ HYBRIDPluginGUI_AdvWidget::HYBRIDPluginGUI_AdvWidget( QWidget* parent, Qt::Windo : QWidget( parent, f ) { setupUi( this ); - myAdvOptionsTable->layout()->setMargin( 0 ); + //myOptionTable->layout()->setMargin( 0 ); + myOptionTable->header()->setSectionResizeMode( QHeaderView::ResizeToContents ); + myOptionTable->setItemDelegate( new ItemDelegate( myOptionTable ) ); + + connect( myOptionTable, SIGNAL( itemChanged(QTreeWidgetItem *, int)), SLOT( itemChanged(QTreeWidgetItem *, int ))); } HYBRIDPluginGUI_AdvWidget::~HYBRIDPluginGUI_AdvWidget() { } + +void HYBRIDPluginGUI_AdvWidget::AddOption( const char* option, bool isCustom ) +{ + QTreeWidget * table = myOptionTable; + //table->setExpanded( true ); + + QTreeWidgetItem * row = new QTreeWidgetItem( table ); + row->setData( NAME_COL, EDITABLE_ROLE, int( isCustom && !option )); + row->setFlags( row->flags() | Qt::ItemIsEditable ); + + QString name, value; + bool isDefault = false; + if ( option ) + { + QStringList name_value_type = QString(option).split( ":", QString::KeepEmptyParts ); + if ( name_value_type.size() > 0 ) + name = name_value_type[0]; + if ( name_value_type.size() > 1 ) + value = name_value_type[1]; + if ( name_value_type.size() > 2 ) + isDefault = !name_value_type[2].toInt(); + + // if ( value == HYBRIDPlugin_Hypothesis::NoValue() ) + // value.clear(); + } + row->setText( 0, tr( name.toLatin1().constData() )); + row->setText( 1, tr( value.toLatin1().constData() )); + row->setCheckState( 0, isDefault ? Qt::Unchecked : Qt::Checked); + row->setData( NAME_COL, PARAM_NAME, name ); + + if ( isCustom ) + { + myOptionTable->scrollToItem( row ); + myOptionTable->setCurrentItem( row ); + myOptionTable->editItem( row, NAME_COL ); + } +} + +void HYBRIDPluginGUI_AdvWidget::GetOptionAndValue( QTreeWidgetItem * tblRow, + QString& option, + QString& value, + bool& isDefault) +{ + option = tblRow->data( NAME_COL, PARAM_NAME ).toString(); + value = tblRow->text( VALUE_COL ); + isDefault = ! tblRow->checkState( NAME_COL ); + + // if ( value.isEmpty() ) + // value = HYBRIDPlugin_Hypothesis::NoValue(); +} + + +void HYBRIDPluginGUI_AdvWidget::itemChanged(QTreeWidgetItem * tblRow, int column) +{ + if ( tblRow ) + { + myOptionTable->blockSignals( true ); + + tblRow->setData( VALUE_COL, EDITABLE_ROLE, int( tblRow->checkState( NAME_COL ))); + + int c = tblRow->checkState( NAME_COL ) ? 0 : 150; + tblRow->setForeground( VALUE_COL, QBrush( QColor( c, c, c ))); + + if ( column == NAME_COL && tblRow->data( NAME_COL, EDITABLE_ROLE ).toInt() ) // custom table + { + tblRow->setData( NAME_COL, PARAM_NAME, tblRow->text( NAME_COL )); + } + + myOptionTable->blockSignals( false ); + } +} diff --git a/src/GUI/HYBRIDPluginGUI_AdvWidget_QTD.ui b/src/GUI/HYBRIDPluginGUI_AdvWidget_QTD.ui index b5a7350..cdc6bc3 100644 --- a/src/GUI/HYBRIDPluginGUI_AdvWidget_QTD.ui +++ b/src/GUI/HYBRIDPluginGUI_AdvWidget_QTD.ui @@ -6,81 +6,73 @@ 0 0 - 465 - 477 + 337 + 369 Form - - - 0 - - - 0 - - - 0 - - - - - Memory settings + + + + + + 0 + 2 + + + + QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed + + + true + + + + OPTION_NAME_COLUMN + + + + 50 + false + + + + + + OPTION_VALUE_COLUMN + + + + 50 + false + + + + + + + + + Qt::Horizontal + + + + 188 + 20 + + + + + + + + HYBRID_ADD_OPTION - - - - - MB - - - - - - - Initial memory size - - - - - - - Max memory size - - - - - - - MB - - - - - - - - 1 - 0 - - - - - - - - - 1 - 0 - - - - - - + Logs and debug @@ -154,69 +146,13 @@ - - - - Advanced meshing options - - - - - - Remove initial central point - - - - - - - Volumic gradation - - - - - - - - - - Use FEM correction - - - - - - - Use boundary recovery version - - - - - - - Create new nodes - - - - - - - - - - SMESHGUI_SpinBox - QDoubleSpinBox -
SMESHGUI_SpinBox.h
-
- - SMESH_AdvOptionsWdg - QWidget -
SMESH_AdvOptionsWdg.h
- 1 + HYBRIDPluginGUI_TreeWidget + QTreeWidget +
HYBRIDPluginGUI_TreeWidget.h
diff --git a/src/GUI/HYBRIDPluginGUI_Dlg.h b/src/GUI/HYBRIDPluginGUI_Dlg.h index d6805d6..6ba86fb 100644 --- a/src/GUI/HYBRIDPluginGUI_Dlg.h +++ b/src/GUI/HYBRIDPluginGUI_Dlg.h @@ -23,13 +23,48 @@ #ifndef HYBRIDPLUGINGUI_H #define HYBRIDPLUGINGUI_H -////////////////////////////////////////// -// HYBRIDPluginGUI_AdvWidget -////////////////////////////////////////// +enum { + OPTION_ID_COLUMN = 0, + OPTION_TYPE_COLUMN, + OPTION_NAME_COLUMN = 0, + OPTION_VALUE_COLUMN, + NB_COLUMNS, +}; + +#include "ui_HYBRIDPluginGUI_StdWidget_QTD.h" #include "ui_HYBRIDPluginGUI_AdvWidget_QTD.h" #include "HYBRIDPluginGUI_HypothesisCreator.h" +////////////////////////////////////////// +// HYBRIDPluginGUI_StdWidget +////////////////////////////////////////// + +class HYBRIDPLUGINGUI_EXPORT HYBRIDPluginGUI_StdWidget : public QWidget, + public Ui::HYBRIDPluginGUI_StdWidget_QTD +{ + Q_OBJECT + +public: + HYBRIDPluginGUI_StdWidget( QWidget* = 0, Qt::WindowFlags = 0 ); + ~HYBRIDPluginGUI_StdWidget(); + + bool GetLayersOnAllWrap() const + { + return myBoundaryLayersSizeMode->currentIndex() == 0; // == global + } + void SetLayersOnAllWrap(bool is) + { + myBoundaryLayersSizeMode->setCurrentIndex( !is ); // Global == 0, Local == 1 + } + +public: +}; + +////////////////////////////////////////// +// HYBRIDPluginGUI_AdvWidget +////////////////////////////////////////// + class HYBRIDPLUGINGUI_EXPORT HYBRIDPluginGUI_AdvWidget : public QWidget, public Ui::HYBRIDPluginGUI_AdvWidget_QTD { @@ -38,6 +73,13 @@ class HYBRIDPLUGINGUI_EXPORT HYBRIDPluginGUI_AdvWidget : public QWidget, public: HYBRIDPluginGUI_AdvWidget( QWidget* = 0, Qt::WindowFlags = 0 ); ~HYBRIDPluginGUI_AdvWidget(); + + void AddOption( const char* name_value_type, bool isCustom = false ); + void GetOptionAndValue( QTreeWidgetItem * tblRow, QString& option, QString& value, bool& dflt ); + +public slots: + + void itemChanged(QTreeWidgetItem * tblRow, int column); }; #endif diff --git a/src/GUI/HYBRIDPluginGUI_HypothesisCreator.cxx b/src/GUI/HYBRIDPluginGUI_HypothesisCreator.cxx index 7c0ea49..8d0a163 100644 --- a/src/GUI/HYBRIDPluginGUI_HypothesisCreator.cxx +++ b/src/GUI/HYBRIDPluginGUI_HypothesisCreator.cxx @@ -390,126 +390,12 @@ QFrame* HYBRIDPluginGUI_HypothesisCreator::buildFrame() aStdLayout->addWidget( myName, row++, 1, 1, 1 ); } - myToMeshHolesCheck = new QCheckBox( tr( "HYBRID_TO_MESH_HOLES" ), myStdGroup ); - //aStdLayout->addWidget( myToMeshHolesCheck, row, 0, 1, 1 ); #stay, not view, may be used tomorrow... - myToMeshHolesCheck->hide(); - myToMakeGroupsOfDomains = new QCheckBox( tr( "HYBRID_TO_MAKE_DOMAIN_GROUPS" ), myStdGroup ); - //aStdLayout->addWidget( myToMakeGroupsOfDomains, row++, 1, 1, 1 ); #stay, not view, may be used tomorrow... - myToMakeGroupsOfDomains->hide(); - //aStdLayout->addWidget( new QLabel( tr( "HYBRID_OPTIMIZATIOL_LEVEL" ), myStdGroup ), row, 0, 1, 1 ); - myOptimizationLevelCombo = new QComboBox( myStdGroup ); - //aStdLayout->addWidget( myOptimizationLevelCombo, row++, 1, 1, 1 ); #stay, not view, may be used tomorrow... - myOptimizationLevelCombo->hide(); - - QStringList types; - types << tr( "LEVEL_NONE" ) << tr( "LEVEL_LIGHT" ) << tr( "LEVEL_MEDIUM" ) << tr( "LEVEL_STANDARDPLUS" ) << tr( "LEVEL_STRONG" ); - myOptimizationLevelCombo->addItems( types ); - - QLabel* aLabel = new QLabel( tr( "HYBRID_BOUNDARY_LAYERS_GROWTH" ), myStdGroup ); - aLabel->setToolTip(tr( "HYBRID_BOUNDARY_LAYERS_HELP" )); - aStdLayout->addWidget( aLabel, row, 0, 1, 1 ); - myBoundaryLayersGrowthCombo = new QComboBox( myStdGroup ); - myBoundaryLayersGrowthCombo->setToolTip(tr( "HYBRID_BOUNDARY_LAYERS_HELP" )); - - aStdLayout->addWidget( myBoundaryLayersGrowthCombo, row++, 1, 1, 1 ); - - QStringList typesBoundaryLayersGrowth; - typesBoundaryLayersGrowth << tr( "HYBRID_LAYER_GROWTH_DOWNWARD" ) << tr( "HYBRID_LAYER_GROWTH_UPWARD" ); - myBoundaryLayersGrowthCombo->addItems( typesBoundaryLayersGrowth ); - - aStdLayout->addWidget( new QLabel( tr( "HYBRID_HeightFirstLayer" ), myStdGroup ), row, 0, 1, 1 ); - myHeightFirstLayerSpin = new SMESHGUI_SpinBox( myStdGroup ); - myHeightFirstLayerSpin->RangeStepAndValidator(0., COORD_MAX, .1, "length_precision"); - aStdLayout->addWidget( myHeightFirstLayerSpin, row++, 1, 1, 1 ); - - aStdLayout->addWidget( new QLabel( tr( "HYBRID_NbOfBoundaryLayers" ), myStdGroup ), row, 0, 1, 1 ); - myNbOfBoundaryLayersSpin = new QSpinBox( myStdGroup ); - aStdLayout->addWidget( myNbOfBoundaryLayersSpin, row++, 1, 1, 1 ); - - aStdLayout->addWidget( new QLabel( tr( "HYBRID_BoundaryLayersProgression" ), myStdGroup ), row, 0, 1, 1 ); - myBoundaryLayersProgressionSpin = new SMESHGUI_SpinBox( myStdGroup ); - myBoundaryLayersProgressionSpin->RangeStepAndValidator(0., 10., .1, "length_precision"); - aStdLayout->addWidget( myBoundaryLayersProgressionSpin, row++, 1, 1, 1 ); - - aStdLayout->addWidget( new QLabel( tr( "COLLISION_MODE" ), myStdGroup ), row, 0, 1, 1 ); - myCollisionModeCombo = new QComboBox( myStdGroup ); - aStdLayout->addWidget( myCollisionModeCombo, row++, 1, 1, 1 ); - - QStringList typescoll; - typescoll << tr( "COLLISION_DECREASE" ) << tr( "COLLISION_STOP" ); - myCollisionModeCombo->addItems( typescoll ); - - aStdLayout->addWidget( new QLabel( tr( "HYBRID_GENERATION_ELEMENT" ), myStdGroup ), row, 0, 1, 1 ); - myElementGenerationCombo = new QComboBox( myStdGroup ); - aStdLayout->addWidget( myElementGenerationCombo, row++, 1, 1, 1 ); - - QStringList typesElementGeneration; - typesElementGeneration << tr( "HYBRID_GENERATION_TETRA_DOMINANT" ) << tr( "HYBRID_GENERATION_HEXA_DOMINANT" ) << tr( "HYBRID_GENERATION_CARTESIAN_CORE" ); - myElementGenerationCombo->addItems( typesElementGeneration ); - - aStdLayout->addWidget( new QLabel( tr( "HYBRID_CORE_SIZE" ), myStdGroup ), row, 0, 1, 1 ); - myCoreSizeSpin = new SMESHGUI_SpinBox( myStdGroup ); - myCoreSizeSpin->RangeStepAndValidator(0., COORD_MAX, 10., "length_precision"); - aStdLayout->addWidget( myCoreSizeSpin, row++, 1, 1, 1 ); - - myAddMultinormalsCheck = new QCheckBox( tr( "HYBRID_ADD_MULTINORMALS" ), myStdGroup ); - aStdLayout->addWidget( myAddMultinormalsCheck, row++, 0, 1, 1 ); - - aStdLayout->addWidget( new QLabel( tr( "HYBRID_MULTINORMAL_ANGLE" ), myStdGroup ), row, 0, 1, 1 ); - myMultinormalsAngleSpin = new SMESHGUI_SpinBox( myStdGroup ); - myMultinormalsAngleSpin->RangeStepAndValidator(0., 90., 2., "threshold"); - aStdLayout->addWidget( myMultinormalsAngleSpin, row++, 1, 1, 1 ); - - mySmoothNormalsCheck = new QCheckBox( tr( "HYBRID_SMOOTH_NORMALS" ), myStdGroup ); - aStdLayout->addWidget( mySmoothNormalsCheck, row++, 0, 1, 1 ); - aStdLayout->setRowStretch( row, 10 ); + myStdWidget = new HYBRIDPluginGUI_StdWidget( myStdGroup ); + myStdWidget->verticalLayout->setMargin( 0 ); + aStdLayout->addWidget( myStdWidget, row++, 0, 1, 2 ); // advanced parameters - myAdvGroup = new QWidget(); - QGridLayout* anAdvLayout = new QGridLayout( myAdvGroup ); - anAdvLayout->setSpacing( 6 ); - anAdvLayout->setMargin( 11 ); - myAdvWidget = new HYBRIDPluginGUI_AdvWidget(myAdvGroup); - anAdvLayout->addWidget( myAdvWidget); - - myAdvWidget->maxMemoryCheck->setText(tr( "MAX_MEMORY_SIZE" )); - myAdvWidget->initialMemoryCheck->setText(tr( "INIT_MEMORY_SIZE" )); - - myAdvWidget->maxMemorySpin->RangeStepAndValidator(20.0, 1e6, 10.0); - myAdvWidget->maxMemorySpin->setValue( 128.0 ); - - myAdvWidget->initialMemorySpin->RangeStepAndValidator(0.0, 1e6, 10.0); - myAdvWidget->initialMemorySpin->setValue( 100.0 ); - - myAdvWidget->initialMemoryLabel ->setText (tr( "MEGABYTE" )); - myAdvWidget->maxMemoryLabel ->setText (tr( "MEGABYTE" )); - - myAdvWidget->workingDirectoryPushButton ->setText (tr( "SELECT_DIR" )); - myAdvWidget->keepWorkingFilesCheck ->setText (tr( "KEEP_WORKING_FILES" )); - myAdvWidget->verboseLevelLabel ->setText (tr( "VERBOSE_LEVEL" )); - myAdvWidget->removeLogOnSuccessCheck ->setText (tr( "REMOVE_LOG_ON_SUCCESS" )); - myAdvWidget->logInFileCheck ->setText (tr( "LOG_IN_FILE" )); - - myAdvWidget->memoryGroupBox ->setTitle(tr( "MEMORY_GROUP_TITLE" )); - myAdvWidget->logGroupBox ->setTitle(tr( "LOG_GROUP_TITLE" )); - myAdvWidget->advancedMeshingGroupBox ->setTitle(tr( "ADVANCED_MESHING_GROUP_TITLE" )); - - myAdvWidget->memoryGroupBox->hide(); - - myAdvWidget->createNewNodesCheck->hide(); - //myAdvWidget->createNewNodesLabel->hide(); - myAdvWidget->removeInitialCentralPointCheck->hide(); - myAdvWidget->boundaryRecoveryCheck->hide(); - myAdvWidget->FEMCorrectionCheck->hide(); - myAdvWidget->gradationLabel->hide(); - myAdvWidget->gradationSpinBox->hide(); - - myAdvWidget->createNewNodesCheck ->setText (tr( "TO_ADD_NODES" )); - myAdvWidget->removeInitialCentralPointCheck->setText (tr( "NO_INITIAL_CENTRAL_POINT" )); - myAdvWidget->boundaryRecoveryCheck ->setText (tr( "RECOVERY_VERSION" )); - myAdvWidget->FEMCorrectionCheck ->setText (tr( "FEM_CORRECTION" )); - myAdvWidget->gradationLabel ->setText (tr( "HYBRID_GRADATION" )); - myAdvWidget->gradationSpinBox->RangeStepAndValidator(1.05, 5.0, 0.05, "length_precision"); + myAdvWidget = new HYBRIDPluginGUI_AdvWidget( tab ); // Enforced vertices parameters myEnfGroup = new QWidget(); @@ -684,9 +570,9 @@ QFrame* HYBRIDPluginGUI_HypothesisCreator::buildFrame() // selection of faces for layers QWidget* faceSelLayersGroup = new QWidget( dlg() ); - myLayersOnAllWrapCheck = new QCheckBox( tr( "HYBRID_LAYERS_ON_ALL_WRAP" ), faceSelLayersGroup ); + //myLayersOnAllWrapCheck = new QCheckBox( tr( "HYBRID_LAYERS_ON_ALL_WRAP" ), faceSelLayersGroup ); QGridLayout* faceSelLayersLayout = new QGridLayout( faceSelLayersGroup ); - faceSelLayersLayout->addWidget(myLayersOnAllWrapCheck, 0, 0 ); + //faceSelLayersLayout->addWidget(myLayersOnAllWrapCheck, 0, 0 ); myFacesLbl = new QLabel( tr("HYBRID_FACE_IDS"), faceSelLayersGroup ); faceSelLayersLayout->addWidget( myFacesLbl, 1, 0 ); @@ -726,7 +612,7 @@ QFrame* HYBRIDPluginGUI_HypothesisCreator::buildFrame() // add tabs tab->insertTab( STD_TAB, myStdGroup, tr( "SMESH_ARGUMENTS" ) ); - tab->insertTab( ADV_TAB, myAdvGroup, tr( "HYBRID_ADV_ARGS" ) ); + tab->insertTab( ADV_TAB, myAdvWidget, tr( "HYBRID_ADV_ARGS" ) ); if ( aMainEntry.isEmpty() && aSubEntry.isEmpty() ) // mesh not based of geometry faceSelLayersGroup->hide(); else { @@ -739,18 +625,10 @@ QFrame* HYBRIDPluginGUI_HypothesisCreator::buildFrame() // connections connect( tab, SIGNAL( currentChanged ( int )), this, SLOT( onTabChanged( int ) ) ); - //connect( myLayersOnAllWrapCheck, SIGNAL( toggled( bool ) ), this, SLOT( onLayersOnAllWrap(bool))); - connect( myLayersOnAllWrapCheck, SIGNAL( toggled( bool ) ), this, SLOT( updateWidgets() ) ); - //connect( myToMeshHolesCheck, SIGNAL( toggled( bool ) ), this, SLOT( onToMeshHoles(bool))); - //connect( myAdvWidget->maxMemoryCheck, SIGNAL( toggled( bool ) ), this, SLOT( updateWidgets() ) ); - //connect( myAdvWidget->initialMemoryCheck, SIGNAL( toggled( bool ) ), this, SLOT( updateWidgets() ) ); - //connect( myAdvWidget->boundaryRecoveryCheck, SIGNAL( toggled( bool ) ), this, SLOT( updateWidgets() ) ); - - //connect( myBoundaryLayersGrowthCombo, SIGNAL( toggled( bool ) ), this, SLOT( updateWidgets() ) ); - //connect( myElementGenerationCombo, SIGNAL( toggled( bool ) ), this, SLOT( updateWidgets() ) ); - connect( myAddMultinormalsCheck, SIGNAL( toggled( bool ) ), this, SLOT( updateWidgets() ) ); - connect( mySmoothNormalsCheck, SIGNAL( toggled( bool ) ), this, SLOT( updateWidgets() ) ); - + connect( myAdvWidget->addBtn, SIGNAL( clicked() ), this, SLOT( onAddOption() ) ); + connect( myStdWidget->myBoundaryLayersSizeMode, SIGNAL( currentIndexChanged(int)), SLOT( updateWidgets())); + connect( myStdWidget->myImprinting, SIGNAL( currentIndexChanged(int)), SLOT( updateWidgets())); + connect( myStdWidget->mySnapping, SIGNAL( currentIndexChanged(int)), SLOT( updateWidgets())); connect( myAdvWidget->logInFileCheck, SIGNAL( toggled( bool ) ), this, SLOT( updateWidgets() ) ); connect( myAdvWidget->keepWorkingFilesCheck, SIGNAL( toggled( bool ) ), this, SLOT( updateWidgets() ) ); connect( myAdvWidget->workingDirectoryPushButton, SIGNAL( clicked() ), this, SLOT( onDirBtnClicked() ) ); @@ -904,8 +782,8 @@ void HYBRIDPluginGUI_HypothesisCreator::onSelectEnforcedVertex() { myEnfVertex = myEnfVertexWdg->GetObject< GEOM::GEOM_Object >(nbSelEnfVertex-1); if (myEnfVertex == GEOM::GEOM_Object::_nil()) return; - if (myEnfVertex->GetShapeType() == GEOM::VERTEX) { - HYBRIDPluginGUI_HypothesisCreator* that = (HYBRIDPluginGUI_HypothesisCreator*)this; + if (myEnfVertex->GetShapeType() == GEOM::VERTEX) + { GEOM::GEOM_IMeasureOperations_var measureOp = getGeomEngine()->GetIMeasureOperations(); if (CORBA::is_nil(measureOp)) return; @@ -1452,20 +1330,6 @@ void HYBRIDPluginGUI_HypothesisCreator::onRemoveEnforcedVertex() myEnforcedTableWidget->selectionModel()->clearSelection(); } -void HYBRIDPluginGUI_HypothesisCreator::onLayersOnAllWrap(bool isOn) -{ - // myToMakeGroupsOfDomains->setEnabled( isOn ); - // if ( !isOn ) - // myToMakeGroupsOfDomains->setChecked( false ); -} - -void HYBRIDPluginGUI_HypothesisCreator::onToMeshHoles(bool isOn) -{ - // myToMakeGroupsOfDomains->setEnabled( isOn ); - // if ( !isOn ) - // myToMakeGroupsOfDomains->setChecked( false ); -} - void HYBRIDPluginGUI_HypothesisCreator::onDirBtnClicked() { QString dir = SUIT_FileDlg::getExistingDirectory( dlg(), myAdvWidget->workingDirectoryLineEdit->text(), QString() ); @@ -1487,27 +1351,24 @@ void HYBRIDPluginGUI_HypothesisCreator::onTabChanged( int ) void HYBRIDPluginGUI_HypothesisCreator::updateWidgets() { - //customs automatic set - //myToMakeGroupsOfDomains->setEnabled( myToMeshHolesCheck->isChecked() ); - //myAdvWidget->maxMemorySpin->setEnabled( myAdvWidget->maxMemoryCheck->isChecked() ); - //myAdvWidget->initialMemoryCheck->setEnabled( !myAdvWidget->boundaryRecoveryCheck->isChecked() ); - //myAdvWidget->initialMemorySpin->setEnabled( myAdvWidget->initialMemoryCheck->isChecked() && !myAdvWidget->boundaryRecoveryCheck->isChecked() ); - //myOptimizationLevelCombo->setEnabled( !myAdvWidget->boundaryRecoveryCheck->isChecked() ); - myMultinormalsAngleSpin->setEnabled( myAddMultinormalsCheck->isChecked() ); if ( sender() == myAdvWidget->logInFileCheck || sender() == myAdvWidget->keepWorkingFilesCheck ) { - bool logFileRemovable = myAdvWidget->logInFileCheck->isChecked() && - !myAdvWidget->keepWorkingFilesCheck->isChecked(); - + bool logFileRemovable = ( myAdvWidget->logInFileCheck->isChecked() && + !myAdvWidget->keepWorkingFilesCheck->isChecked() ); myAdvWidget->removeLogOnSuccessCheck->setEnabled( logFileRemovable ); } - bool enabled = !myLayersOnAllWrapCheck->isChecked(); - myFacesLbl->setEnabled(enabled); - myFaceSelectorLayers->setEnabled(enabled); - if ( QTabWidget* tab = qobject_cast( myStdGroup->parentWidget()->parentWidget() )) { - tab->setTabEnabled( FACE_SEL_IMPRINTING_TAB, enabled ); - tab->setTabEnabled( FACE_SEL_SNAPPING_TAB, enabled ); + + myStdWidget->myCoreSize->setEnabled( myStdWidget->myCoreSizeEnabled->isChecked() ); + + if ( QTabWidget* tab = qobject_cast( myStdGroup->parentWidget()->parentWidget() )) + { + bool isGlobal = myStdWidget->GetLayersOnAllWrap(); + bool isImprinting = myStdWidget->myImprinting->currentIndex(); + bool isSnapping = myStdWidget->mySnapping->currentIndex(); + tab->setTabEnabled( FACE_SEL_LAYERS_TAB, !isGlobal ); + tab->setTabEnabled( FACE_SEL_IMPRINTING_TAB, isImprinting ); + tab->setTabEnabled( FACE_SEL_SNAPPING_TAB, isSnapping ); } } @@ -1521,7 +1382,43 @@ bool HYBRIDPluginGUI_HypothesisCreator::checkParams(QString& msg) const return false; } - return true; + HYBRIDPlugin::HYBRIDPlugin_Hypothesis_var h = + HYBRIDPlugin::HYBRIDPlugin_Hypothesis::_narrow( hypothesis() ); + + myAdvWidget->myOptionTable->setFocus(); + QApplication::instance()->processEvents(); + + QString name, value; + bool isDefault, ok = true; + int iRow = 0, nbRows = myAdvWidget->myOptionTable->topLevelItemCount(); + for ( ; iRow < nbRows; ++iRow ) + { + QTreeWidgetItem* row = myAdvWidget->myOptionTable->topLevelItem( iRow ); + myAdvWidget->GetOptionAndValue( row, name, value, isDefault ); + + if ( name.simplified().isEmpty() ) + continue; // invalid custom option + + if ( isDefault ) // not selected option + value.clear(); + + try { + h->SetOptionValue( name.toLatin1().constData(), value.toLatin1().constData() ); + } + catch ( const SALOME::SALOME_Exception& ex ) + { + msg = ex.details.text.in(); + ok = false; + break; + } + } + + if ( !ok ) + { + h->SetOptionValues( myOptions ); // restore values + } + + return ok; } void HYBRIDPluginGUI_HypothesisCreator::retrieveParams() const @@ -1532,30 +1429,24 @@ void HYBRIDPluginGUI_HypothesisCreator::retrieveParams() const if ( myName ) myName->setText( data.myName ); - myLayersOnAllWrapCheck ->setChecked ( data.myLayersOnAllWrap ); - myToMeshHolesCheck ->setChecked ( data.myToMeshHoles ); - myToMakeGroupsOfDomains ->setChecked ( data.myToMakeGroupsOfDomains ); - myOptimizationLevelCombo ->setCurrentIndex( data.myOptimizationLevel ); - myAdvWidget->maxMemoryCheck ->setChecked ( data.myMaximumMemory > 0 ); - myAdvWidget->maxMemorySpin ->setValue ( qMax( data.myMaximumMemory, - myAdvWidget->maxMemorySpin->minimum() )); - myAdvWidget->initialMemoryCheck ->setChecked ( data.myInitialMemory > 0 ); - myAdvWidget->initialMemorySpin ->setValue ( qMax( data.myInitialMemory, - myAdvWidget->initialMemorySpin->minimum() )); - - myCollisionModeCombo ->setCurrentIndex( data.myCollisionMode ); - myBoundaryLayersGrowthCombo ->setCurrentIndex( data.myBoundaryLayersGrowth ); - myElementGenerationCombo ->setCurrentIndex( data.myElementGeneration ); - myAddMultinormalsCheck -> setChecked ( data.myAddMultinormals ); - mySmoothNormalsCheck -> setChecked ( data.mySmoothNormals ); - myHeightFirstLayerSpin -> setValue( data.myHeightFirstLayer ); - myNbOfBoundaryLayersSpin -> setValue( data.myNbOfBoundaryLayers ); - myBoundaryLayersProgressionSpin -> setValue( data.myBoundaryLayersProgression ); + myStdWidget->SetLayersOnAllWrap( data.myLayersOnAllWrap ); + + myStdWidget->myNbOfBoundaryLayers ->setValue( data.myNbOfBoundaryLayers ); + myStdWidget ->SetLayersOnAllWrap( data.myLayersOnAllWrap ); + myStdWidget->myHeightFirstLayer ->setValue( data.myHeightFirstLayer ); + myStdWidget->myHeightIsRelative ->setCurrentIndex( data.myHeightIsRelative ); + myStdWidget->myBoundaryLayersGrowth ->setCurrentIndex( data.myBoundaryLayersGrowth ); + myStdWidget->myBoundaryLayersMaxElemAngle->setValue( data.myBoundaryLayersMaxElemAngle ); + myStdWidget->myBoundaryLayersProgression ->setValue( data.myBoundaryLayersProgression ); + myStdWidget->myImprinting ->setCurrentIndex( data.myImprinting ); + myStdWidget->mySnapping ->setCurrentIndex( data.mySnapping ); + myStdWidget->myElementGeneration ->setCurrentIndex( data.myElementGeneration ); if (data.myCoreSize <= 0) - myCoreSizeSpin->setText(""); + myStdWidget->myCoreSize->setText(""); else - myCoreSizeSpin -> setValue( data.myCoreSize ); - myMultinormalsAngleSpin -> setValue( data.myMultinormalsAngle ); + myStdWidget->myCoreSize->setValue( data.myCoreSize ); + myStdWidget->myCoreSizeEnabled->setChecked( data.myCoreSize > 0 ); + myFaceSelectorLayers ->SetListOfIDs( data.myFaceWLIds ); myFaceSelectorImprinting ->SetListOfIDs( data.myFaceWIIds ); myFaceSelectorSnapping ->SetListOfIDs( data.myFaceWSIds ); @@ -1563,15 +1454,19 @@ void HYBRIDPluginGUI_HypothesisCreator::retrieveParams() const myAdvWidget->workingDirectoryLineEdit ->setText ( data.myWorkingDir ); myAdvWidget->keepWorkingFilesCheck ->setChecked( data.myKeepFiles ); myAdvWidget->verboseLevelSpin ->setValue ( data.myVerboseLevel ); - myAdvWidget->createNewNodesCheck ->setChecked( data.myToCreateNewNodes ); - myAdvWidget->removeInitialCentralPointCheck ->setChecked( data.myRemoveInitialCentralPoint ); - myAdvWidget->boundaryRecoveryCheck ->setChecked( data.myBoundaryRecovery ); - myAdvWidget->FEMCorrectionCheck ->setChecked( data.myFEMCorrection ); - myAdvWidget->gradationSpinBox ->setValue ( data.myGradation ); - myAdvWidget->myAdvOptionsTable ->SetCustomOptions( data.myTextOption ); myAdvWidget->logInFileCheck ->setChecked( !data.myLogInStandardOutput ); myAdvWidget->removeLogOnSuccessCheck ->setChecked( data.myRemoveLogOnSuccess ); + if ( myOptions.operator->() ) { + for ( int i = 0, nb = myOptions->length(); i < nb; ++i ) + myAdvWidget->AddOption( that->myOptions[i].in() ); + } + if ( myCustomOptions.operator->() ) { + for ( int i = 0, nb = myCustomOptions->length(); i < nb; ++i ) + myAdvWidget->AddOption( that->myCustomOptions[i].in() ); + } + myAdvWidget->myOptionTable->resizeColumnToContents( OPTION_NAME_COLUMN ); + TEnfVertexList::const_iterator it; int rowCount = 0; myEnforcedTableWidget->clearContents(); @@ -1708,65 +1603,6 @@ QString HYBRIDPluginGUI_HypothesisCreator::storeParams() const storeParamsToHypo( data ); QString valStr = ""; - - if ( !data.myBoundaryRecovery ) - valStr = "-c " + QString::number( !data.myToMeshHoles ); - - if ( data.myOptimizationLevel >= 0 && data.myOptimizationLevel < 5 && !data.myBoundaryRecovery) { - const char* level[] = { "none" , "light" , "standard" , "standard+" , "strong" }; - valStr += " -o "; - valStr += level[ data.myOptimizationLevel ]; - } - if ( data.myMaximumMemory > 0 ) { - valStr += " -m "; - valStr += QString::number( data.myMaximumMemory ); - } - if ( data.myInitialMemory > 0 && !data.myBoundaryRecovery ) { - valStr += " -M "; - valStr += QString::number( data.myInitialMemory ); - } - valStr += " -v "; - valStr += QString::number( data.myVerboseLevel ); - - if ( !data.myToCreateNewNodes ) - valStr += " -p0"; - - if ( data.myRemoveInitialCentralPoint ) - valStr += " -no_initial_central_point"; - - if ( data.myBoundaryRecovery ) - valStr += " -C"; - - if ( data.myFEMCorrection ) - valStr += " -FEM"; - - if ( data.myGradation != 1.05 ) { - valStr += " -Dcpropa="; - valStr += QString::number( data.myGradation ); - } - - valStr += " "; - valStr += data.myTextOption; - - // valStr += " #BEGIN ENFORCED VERTICES#"; - // // Add size map parameters storage - // for (int i=0 ; irowCount() ; i++) { - // valStr += " ("; - // double x = mySmpModel->data(mySmpModel->index(i,ENF_VER_X_COLUMN)).toDouble(); - // double y = mySmpModel->data(mySmpModel->index(i,ENF_VER_Y_COLUMN)).toDouble(); - // double z = mySmpModel->data(mySmpModel->index(i,ENF_VER_Z_COLUMN)).toDouble(); - // double size = mySmpModel->data(mySmpModel->index(i,ENF_VER_SIZE_COLUMN)).toDouble(); - // valStr += QString::number( x ); - // valStr += ","; - // valStr += QString::number( y ); - // valStr += ","; - // valStr += QString::number( z ); - // valStr += ")="; - // valStr += QString::number( size ); - // if (i!=mySmpModel->rowCount()-1) - // valStr += ";"; - // } - // valStr += " #END ENFORCED VERTICES#"; return valStr; } @@ -1778,40 +1614,36 @@ bool HYBRIDPluginGUI_HypothesisCreator::readParamsFromHypo( HYBRIDHypothesisData HypothesisData* data = SMESH::GetHypothesisData( hypType() ); h_data.myName = isCreation() && data ? hypName() : ""; - h_data.myCollisionMode = h->GetCollisionMode(); - h_data.myBoundaryLayersGrowth = h->GetBoundaryLayersGrowth(); - h_data.myElementGeneration = h->GetElementGeneration(); - h_data.myAddMultinormals = h->GetAddMultinormals(); - h_data.mySmoothNormals = h->GetSmoothNormals(); + h_data.myNbOfBoundaryLayers = h->GetNbOfBoundaryLayers(); + h_data.myLayersOnAllWrap = h->GetLayersOnAllWrap(); h_data.myHeightFirstLayer = h->GetHeightFirstLayer(); + h_data.myHeightIsRelative = h->GetHeightIsRelative(); + h_data.myBoundaryLayersGrowth = h->GetBoundaryLayersGrowth(); + h_data.myBoundaryLayersMaxElemAngle = h->GetBoundaryLayersMaxElemAngle(); h_data.myBoundaryLayersProgression = h->GetBoundaryLayersProgression(); + h_data.myElementGeneration = h->GetElementGeneration(); h_data.myCoreSize = h->GetCoreSize(); - h_data.myMultinormalsAngle = h->GetMultinormalsAngle(); - h_data.myNbOfBoundaryLayers = h->GetNbOfBoundaryLayers(); + h_data.myFaceWLIds = h->GetFacesWithLayers(); h_data.myFaceWIIds = h->GetFacesWithImprinting(); h_data.myFaceWSIds = h->GetFacesWithSnapping(); + h_data.myImprinting = h_data.myFaceWIIds->length();//h->GetImprinting(); + h_data.mySnapping = h_data.myFaceWSIds->length();//h->GetSnapping(); - h_data.myLayersOnAllWrap = h->GetLayersOnAllWrap(); - h_data.myToMeshHoles = h->GetToMeshHoles(); - h_data.myToMakeGroupsOfDomains = /*h->GetToMeshHoles() &&*/ h->GetToMakeGroupsOfDomains(); - h_data.myMaximumMemory = h->GetMaximumMemory(); - h_data.myInitialMemory = h->GetInitialMemory(); - h_data.myInitialMemory = h->GetInitialMemory(); + h_data.myCollisionMode = h->GetCollisionMode(); h_data.myOptimizationLevel = h->GetOptimizationLevel(); - + h_data.myKeepFiles = h->GetKeepFiles(); h_data.myWorkingDir = h->GetWorkingDirectory(); h_data.myVerboseLevel = h->GetVerboseLevel(); - h_data.myToCreateNewNodes = h->GetToCreateNewNodes(); - h_data.myRemoveInitialCentralPoint = h->GetToRemoveCentralPoint(); - h_data.myBoundaryRecovery = h->GetToUseBoundaryRecoveryVersion(); - h_data.myFEMCorrection = h->GetFEMCorrection(); - h_data.myGradation = h->GetGradation(); - h_data.myTextOption = h->GetAdvancedOption(); h_data.myLogInStandardOutput = h->GetStandardOutputLog(); h_data.myRemoveLogOnSuccess = h->GetRemoveLogOnSuccess(); - + + HYBRIDPluginGUI_HypothesisCreator* that = (HYBRIDPluginGUI_HypothesisCreator*)this; + that->myOptions = h->GetOptionValues(); + that->myCustomOptions = h->GetAdvancedOptionValues(); + + HYBRIDPlugin::HYBRIDEnforcedVertexList_var vertices = h->GetEnforcedVertices(); h_data.myEnforcedVertices.clear(); for (CORBA::ULong i=0 ; ilength() ; i++) { @@ -1865,42 +1697,28 @@ bool HYBRIDPluginGUI_HypothesisCreator::storeParamsToHypo( const HYBRIDHypothesi if( isCreation() ) SMESH::SetName( SMESH::FindSObject( h ), h_data.myName.toLatin1().constData() ); + if ( h->GetNbOfBoundaryLayers() != h_data.myNbOfBoundaryLayers ) + h->SetNbOfBoundaryLayers ( h_data.myNbOfBoundaryLayers ); if ( h->GetLayersOnAllWrap() != h_data.myLayersOnAllWrap ) // avoid duplication of DumpPython commands h->SetLayersOnAllWrap ( h_data.myLayersOnAllWrap ); - if ( h->GetToMeshHoles() != h_data.myToMeshHoles ) // avoid duplication of DumpPython commands - h->SetToMeshHoles ( h_data.myToMeshHoles ); - if ( h->GetToMakeGroupsOfDomains() != h_data.myToMakeGroupsOfDomains ) - h->SetToMakeGroupsOfDomains( h_data.myToMakeGroupsOfDomains ); - if ( h->GetMaximumMemory() != h_data.myMaximumMemory ) - h->SetMaximumMemory ( h_data.myMaximumMemory ); - if ( h->GetInitialMemory() != h_data.myInitialMemory ) - h->SetInitialMemory ( h_data.myInitialMemory ); - if ( h->GetInitialMemory() != h_data.myInitialMemory ) - h->SetInitialMemory ( h_data.myInitialMemory ); - if ( h->GetOptimizationLevel() != h_data.myOptimizationLevel ) - h->SetOptimizationLevel( h_data.myOptimizationLevel ); - - if ( h->GetCollisionMode() != h_data.myCollisionMode ) - h->SetCollisionMode( h_data.myCollisionMode ); - if ( h->GetBoundaryLayersGrowth() != h_data.myBoundaryLayersGrowth ) - h->SetBoundaryLayersGrowth( h_data.myBoundaryLayersGrowth ); - if ( h->GetElementGeneration() != h_data.myElementGeneration ) - h->SetElementGeneration( h_data.myElementGeneration ); - - if ( h->GetAddMultinormals() != h_data.myAddMultinormals ) - h->SetAddMultinormals ( h_data.myAddMultinormals ); - if ( h->GetSmoothNormals() != h_data.mySmoothNormals ) - h->SetSmoothNormals ( h_data.mySmoothNormals ); if ( h->GetHeightFirstLayer() != h_data.myHeightFirstLayer ) h->SetHeightFirstLayer ( h_data.myHeightFirstLayer ); + h->SetHeightIsRelative( h_data.myHeightIsRelative ); + if ( h->GetBoundaryLayersGrowth() != h_data.myBoundaryLayersGrowth ) + h->SetBoundaryLayersGrowth( h_data.myBoundaryLayersGrowth ); + h->SetBoundaryLayersMaxElemAngle( h_data.myBoundaryLayersMaxElemAngle ); if ( h->GetBoundaryLayersProgression() != h_data.myBoundaryLayersProgression ) h->SetBoundaryLayersProgression ( h_data.myBoundaryLayersProgression ); + if ( h->GetElementGeneration() != h_data.myElementGeneration ) + h->SetElementGeneration( h_data.myElementGeneration ); if ( h->GetCoreSize() != h_data.myCoreSize ) h->SetCoreSize ( h_data.myCoreSize ); - if ( h->GetMultinormalsAngle() != h_data.myMultinormalsAngle ) - h->SetMultinormalsAngle ( h_data.myMultinormalsAngle ); - if ( h->GetNbOfBoundaryLayers() != h_data.myNbOfBoundaryLayers ) - h->SetNbOfBoundaryLayers ( h_data.myNbOfBoundaryLayers ); + + // if ( h->GetOptimizationLevel() != h_data.myOptimizationLevel ) + // h->SetOptimizationLevel( h_data.myOptimizationLevel ); + // if ( h->GetCollisionMode() != h_data.myCollisionMode ) + // h->SetCollisionMode( h_data.myCollisionMode ); + h->SetFacesWithLayers( h_data.myFaceWLIds ); h->SetFacesWithImprinting( h_data.myFaceWIIds ); h->SetFacesWithSnapping( h_data.myFaceWSIds ); @@ -1911,18 +1729,6 @@ bool HYBRIDPluginGUI_HypothesisCreator::storeParamsToHypo( const HYBRIDHypothesi h->SetWorkingDirectory ( h_data.myWorkingDir.toLatin1().constData() ); if ( h->GetVerboseLevel() != h_data.myVerboseLevel ) h->SetVerboseLevel ( h_data.myVerboseLevel ); - if ( h->GetToCreateNewNodes() != h_data.myToCreateNewNodes ) - h->SetToCreateNewNodes ( h_data.myToCreateNewNodes ); - if ( h->GetToRemoveCentralPoint() != h_data.myRemoveInitialCentralPoint ) - h->SetToRemoveCentralPoint ( h_data.myRemoveInitialCentralPoint ); - if ( h->GetToUseBoundaryRecoveryVersion() != h_data.myBoundaryRecovery ) - h->SetToUseBoundaryRecoveryVersion ( h_data.myBoundaryRecovery ); - if ( h->GetFEMCorrection() != h_data.myFEMCorrection ) - h->SetFEMCorrection ( h_data.myFEMCorrection ); - if ( h->GetGradation() != h_data.myGradation ) - h->SetGradation ( h_data.myGradation ); - if ( h->GetTextOption() != h_data.myTextOption ) - h->SetAdvancedOption ( h_data.myTextOption.toLatin1().constData() ); if ( h->GetStandardOutputLog() != h_data.myLogInStandardOutput ) h->SetStandardOutputLog ( h_data.myLogInStandardOutput ); if ( h->GetRemoveLogOnSuccess() != h_data.myRemoveLogOnSuccess ) @@ -1988,7 +1794,6 @@ bool HYBRIDPluginGUI_HypothesisCreator::storeParamsToHypo( const HYBRIDHypothesi break; } - std::cout << "h->p_SetEnforcedMesh(theSource, "<< elementType <<", \""<< enfMesh->name << "\", \"" << enfMesh->groupName.c_str() <<"\")"<p_SetEnforcedMesh(theSource, elementType, enfMesh->name.c_str(), enfMesh->groupName.c_str()); } // for } // try @@ -2007,24 +1812,16 @@ bool HYBRIDPluginGUI_HypothesisCreator::storeParamsToHypo( const HYBRIDHypothesi bool HYBRIDPluginGUI_HypothesisCreator::readParamsFromWidgets( HYBRIDHypothesisData& h_data ) const { h_data.myName = myName ? myName->text() : ""; - h_data.myLayersOnAllWrap = myLayersOnAllWrapCheck->isChecked(); - h_data.myToMeshHoles = myToMeshHolesCheck->isChecked(); - h_data.myToMakeGroupsOfDomains = myToMakeGroupsOfDomains->isChecked(); - h_data.myMaximumMemory = myAdvWidget->maxMemoryCheck->isChecked() ? myAdvWidget->maxMemorySpin->value() : -1; - h_data.myInitialMemory = myAdvWidget->initialMemoryCheck->isChecked() ? myAdvWidget->initialMemorySpin->value() : -1; - h_data.myOptimizationLevel = myOptimizationLevelCombo->currentIndex(); - - h_data.myCollisionMode = myCollisionModeCombo->currentIndex(); - h_data.myBoundaryLayersGrowth = myBoundaryLayersGrowthCombo->currentIndex(); - h_data.myElementGeneration = myElementGenerationCombo->currentIndex(); - h_data.myAddMultinormals = myAddMultinormalsCheck->isChecked(); - h_data.mySmoothNormals = mySmoothNormalsCheck->isChecked(); - - h_data.myHeightFirstLayer = myHeightFirstLayerSpin -> value(); - h_data.myNbOfBoundaryLayers = myNbOfBoundaryLayersSpin -> value(); - h_data.myBoundaryLayersProgression = myBoundaryLayersProgressionSpin -> value(); - h_data.myCoreSize = myCoreSizeSpin->text().isEmpty() ? 0.0 : myCoreSizeSpin -> value(); - h_data.myMultinormalsAngle = myMultinormalsAngleSpin -> value(); + h_data.myNbOfBoundaryLayers = myStdWidget->myNbOfBoundaryLayers -> value(); + h_data.myLayersOnAllWrap = myStdWidget->GetLayersOnAllWrap(); + h_data.myHeightFirstLayer = myStdWidget->myHeightFirstLayer -> value(); + h_data.myHeightIsRelative = myStdWidget->myHeightIsRelative->currentIndex(); + h_data.myBoundaryLayersGrowth = myStdWidget->myBoundaryLayersGrowth->currentIndex(); + h_data.myBoundaryLayersMaxElemAngle = myStdWidget->myBoundaryLayersMaxElemAngle->value(); + h_data.myBoundaryLayersProgression = myStdWidget->myBoundaryLayersProgression -> value(); + h_data.myElementGeneration = myStdWidget->myElementGeneration->currentIndex(); + h_data.myCoreSize = myStdWidget->myCoreSizeEnabled->isChecked() ? myStdWidget->myCoreSize -> value() : 0; + h_data.myFaceWLIds = myFaceSelectorLayers->GetListOfIDs(); h_data.myFaceWIIds = myFaceSelectorImprinting->GetListOfIDs(); h_data.myFaceWSIds = myFaceSelectorSnapping->GetListOfIDs(); @@ -2032,12 +1829,6 @@ bool HYBRIDPluginGUI_HypothesisCreator::readParamsFromWidgets( HYBRIDHypothesisD h_data.myKeepFiles = myAdvWidget->keepWorkingFilesCheck->isChecked(); h_data.myWorkingDir = myAdvWidget->workingDirectoryLineEdit->text().trimmed(); h_data.myVerboseLevel = myAdvWidget->verboseLevelSpin->value(); - h_data.myToCreateNewNodes = myAdvWidget->createNewNodesCheck->isChecked(); - h_data.myRemoveInitialCentralPoint = myAdvWidget->removeInitialCentralPointCheck->isChecked(); - h_data.myBoundaryRecovery = myAdvWidget->boundaryRecoveryCheck->isChecked(); - h_data.myFEMCorrection = myAdvWidget->FEMCorrectionCheck->isChecked(); - h_data.myGradation = myAdvWidget->gradationSpinBox->value(); - h_data.myTextOption = myAdvWidget->myAdvOptionsTable->GetCustomOptions(); h_data.myLogInStandardOutput = !myAdvWidget->logInFileCheck->isChecked(); h_data.myRemoveLogOnSuccess = myAdvWidget->removeLogOnSuccessCheck->isChecked(); @@ -2077,7 +1868,6 @@ bool HYBRIDPluginGUI_HypothesisCreator::readParamsFromWidgets( HYBRIDHypothesisD QComboBox* combo = qobject_cast(myEnforcedMeshTableWidget->cellWidget(row,ENF_MESH_CONSTRAINT_COLUMN)); myEnfMesh->elementType = combo->currentIndex(); h_data.myEnforcedMeshes.insert(myEnfMesh); - std::cout << "h_data.myEnforcedMeshes.size(): " << h_data.myEnforcedMeshes.size() << std::endl; } return true; @@ -2102,3 +1892,8 @@ QString HYBRIDPluginGUI_HypothesisCreator::helpPage() const { return "hybrid_hypo_page.html"; } + +void HYBRIDPluginGUI_HypothesisCreator::onAddOption() +{ + myAdvWidget->AddOption( NULL, true ); +} diff --git a/src/GUI/HYBRIDPluginGUI_HypothesisCreator.h b/src/GUI/HYBRIDPluginGUI_HypothesisCreator.h index 028aa80..af82f23 100644 --- a/src/GUI/HYBRIDPluginGUI_HypothesisCreator.h +++ b/src/GUI/HYBRIDPluginGUI_HypothesisCreator.h @@ -57,6 +57,7 @@ class QTableWidget; class QTableWidgetItem; class QWidget; +class HYBRIDPluginGUI_StdWidget; class HYBRIDPluginGUI_AdvWidget; class LightApp_SelectionMgr; class SMESHGUI_SpinBox; @@ -142,27 +143,18 @@ typedef std::set< TEnfMesh*, CompareEnfMeshes > TEnfMeshList; typedef struct { - bool myLayersOnAllWrap, myToMeshHoles, myToMakeGroupsOfDomains, - myKeepFiles, myToCreateNewNodes, - myBoundaryRecovery, myFEMCorrection, - myRemoveInitialCentralPoint, - myLogInStandardOutput, myRemoveLogOnSuccess; - double myMaximumMemory,myInitialMemory; - int myOptimizationLevel; - int myCollisionMode; - int myBoundaryLayersGrowth; - int myElementGeneration; - QString myName,myWorkingDir,myTextOption; + bool myHeightIsRelative, myImprinting, mySnapping, myLayersOnAllWrap, + myKeepFiles, myLogInStandardOutput, myRemoveLogOnSuccess; + int myOptimizationLevel, myCollisionMode, myBoundaryLayersGrowth, myElementGeneration; + QString myName,myWorkingDir; double myGradation; short myVerboseLevel; TEnfVertexList myEnforcedVertices; TEnfMeshList myEnforcedMeshes; - bool myAddMultinormals, - mySmoothNormals; double myHeightFirstLayer, myBoundaryLayersProgression, myCoreSize, - myMultinormalsAngle; + myBoundaryLayersMaxElemAngle; short myNbOfBoundaryLayers; // IDs of faces with layers SMESH::long_array_var myFaceWLIds; @@ -197,8 +189,7 @@ protected: virtual QString type() const; protected slots: - void onLayersOnAllWrap(bool); - void onToMeshHoles(bool); + void onAddOption(); void onDirBtnClicked(); void updateWidgets(); @@ -235,18 +226,11 @@ private: private: QWidget* myStdGroup; QLineEdit* myName; - QCheckBox* myLayersOnAllWrapCheck; - QCheckBox* myToMeshHolesCheck; - QCheckBox* myToMakeGroupsOfDomains; - QComboBox* myOptimizationLevelCombo; - QComboBox* myCollisionModeCombo; - QComboBox* myBoundaryLayersGrowthCombo; - QComboBox* myElementGenerationCombo; - QCheckBox* myAddMultinormalsCheck; - QCheckBox* mySmoothNormals; - QWidget* myAdvGroup; + HYBRIDPluginGUI_StdWidget* myStdWidget; HYBRIDPluginGUI_AdvWidget* myAdvWidget; - + + mutable HYBRIDPlugin::string_array_var myOptions, myCustomOptions; + QWidget* myEnfGroup; QPixmap iconVertex, iconCompound; StdMeshersGUI_ObjectReferenceParamWdg *myEnfVertexWdg; diff --git a/src/GUI/HYBRIDPluginGUI_StdWidget.cxx b/src/GUI/HYBRIDPluginGUI_StdWidget.cxx new file mode 100644 index 0000000..f796542 --- /dev/null +++ b/src/GUI/HYBRIDPluginGUI_StdWidget.cxx @@ -0,0 +1,54 @@ +// Copyright (C) 2007-2019 CEA/DEN, EDF R&D +// +// 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 : BLSURFPluginGUI_StdWidget.cxx +// Authors : Gilles DAVID (OCC) +// --- +// + +#include "HYBRIDPluginGUI_Dlg.h" + +#include +#include +#include +#include + +//using namespace std; + +////////////////////////////////////////// +// HYBRIDPluginGUI_StdWidget +////////////////////////////////////////// + +HYBRIDPluginGUI_StdWidget::HYBRIDPluginGUI_StdWidget( QWidget* parent, Qt::WindowFlags f ) + : QWidget( parent, f ) +{ + setupUi( this ); + + myHeightFirstLayer->RangeStepAndValidator( 0, 1e+6, 1, "length_precision" ); + myBoundaryLayersMaxElemAngle->RangeStepAndValidator( 90, 360, 5, "angle_precision" ); + myBoundaryLayersProgression->RangeStepAndValidator( -100, 100, 0.1, "length_precision" ); + myCoreSize->RangeStepAndValidator( 0, 1e+6, 1, "length_precision" ); + + connect( myCoreSizeEnabled, SIGNAL( toggled(bool)), myCoreSize, SLOT( setEnabled(bool) )); +} + +HYBRIDPluginGUI_StdWidget::~HYBRIDPluginGUI_StdWidget() +{ +} diff --git a/src/GUI/HYBRIDPluginGUI_StdWidget_QTD.ui b/src/GUI/HYBRIDPluginGUI_StdWidget_QTD.ui new file mode 100644 index 0000000..750a12b --- /dev/null +++ b/src/GUI/HYBRIDPluginGUI_StdWidget_QTD.ui @@ -0,0 +1,250 @@ + + + HYBRIDPluginGUI_StdWidget_QTD + + + + 0 + 0 + 480 + 398 + + + + Form + + + + + + HYBRID_VL_OPTIONS + + + + + + HYBRID_NB_LAYERS + + + + + + + + + + HYBRID_SIZE_MODE + + + + + + + + HYBRID_GLOBAL + + + + + HYBRID_LOCAL + + + + + + + + HYBRID_1ST_LAYER_HEIGHT + + + + + + + HYBRID_HEIGHT_IS_RELATIVE + + + + + + + + HYBRID_NO + + + + + HYBRID_YES + + + + + + + + HYBRID_GROWTH_OF_LAYERS + + + + + + + + HYBRID_LAYER_GROWTH_DOWNWARD + + + + + HYBRID_LAYER_GROWTH_UPWARD + + + + + + + + HYBRID_MAX_ELEM_ANGLE + + + + + + + + + + HYBRID_GEOM_PROGRESSION + + + + + + + + + + HYBRID_IMPRINTING + + + + + + + + HYBRID_NO + + + + + HYBRID_YES + + + + + + + + HYBRID_SNAPPING + + + + + + + + HYBRID_NO + + + + + HYBRID_YES + + + + + + + + + + + + + + HYBRID_OTHER_OPTIONS + + + + + + HYBRID_GENERATION_ELEMENT + + + + + + + + HYBRID_GENERATION_TETRA_DOMINANT + + + + + HYBRID_GENERATION_HEXA_DOMINANT + + + + + HYBRID_GENERATION_CARTESIAN_CORE + + + + + HYBRID_GENERATION_EXTRUSION_ONLY + + + + + + + + HYBRID_CORE_SIZE + + + + + + + + + + + + + Qt::Vertical + + + + 438 + 7 + + + + + + + + + SalomeApp_IntSpinBox + QLineEdit +
SalomeApp_IntSpinBox.h
+
+ + SMESHGUI_SpinBox + QDoubleSpinBox +
SMESHGUI_SpinBox.h
+
+
+ + +
diff --git a/src/GUI/HYBRIDPluginGUI_TreeWidget.cxx b/src/GUI/HYBRIDPluginGUI_TreeWidget.cxx new file mode 100644 index 0000000..0fc743b --- /dev/null +++ b/src/GUI/HYBRIDPluginGUI_TreeWidget.cxx @@ -0,0 +1,91 @@ +// Copyright (C) 2007-2019 CEA/DEN, EDF R&D +// +// 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 +// + +#include "HYBRIDPluginGUI_TreeWidget.h" +#include + +namespace +{ + bool isEditable( const QModelIndex& index ) + { + return index.isValid() && + index.flags() & Qt::ItemIsEditable && + index.flags() & Qt::ItemIsEnabled && + ( !index.data( Qt::UserRole + 1 ).isValid() || index.data( Qt::UserRole + 1 ).toInt() != 0 ); + } +} + +HYBRIDPluginGUI_TreeWidget::HYBRIDPluginGUI_TreeWidget( QWidget* parent ) + : QTreeWidget( parent ) +{ +} + +QModelIndex HYBRIDPluginGUI_TreeWidget::moveCursor( CursorAction action, Qt::KeyboardModifiers modifiers ) +{ + QModelIndex current = currentIndex(); + int column = current.column(); + if ( action == MoveNext ) { + if ( column < columnCount()-1 ) { + QModelIndex next = current.sibling( current.row(), column+1 ); + if ( isEditable( next ) ) + return next; + } + else { + QModelIndex next = current.sibling( current.row()+1, 0 ); + if ( isEditable( next ) ) + return next; + } + } + else if ( action == MovePrevious ) { + if ( column == 0 ) { + QModelIndex next = current.sibling( current.row()-1, columnCount()-1 ); + if ( isEditable( next ) ) + return next; + } + else { + QModelIndex next = current.sibling( current.row(), column-1 ); + if ( isEditable( next ) ) + return next; + } + } + return QTreeWidget::moveCursor( action, modifiers ); +} + +void HYBRIDPluginGUI_TreeWidget::keyPressEvent( QKeyEvent* e ) +{ + switch ( e->key() ) { + case Qt::Key_F2: + { + QModelIndex index = currentIndex(); + if ( !isEditable( index ) ) { + for ( int i = 0; i < columnCount(); i++ ) { + QModelIndex sibling = index.sibling( index.row(), i ); + if ( isEditable( sibling ) ) { + if ( !edit( sibling, EditKeyPressed, e ) ) + e->ignore(); + } + } + } + } + break; + default: + break; + } + QTreeWidget::keyPressEvent( e ); +} diff --git a/src/GUI/HYBRIDPluginGUI_TreeWidget.h b/src/GUI/HYBRIDPluginGUI_TreeWidget.h new file mode 100644 index 0000000..0b9b297 --- /dev/null +++ b/src/GUI/HYBRIDPluginGUI_TreeWidget.h @@ -0,0 +1,36 @@ +// Copyright (C) 2007-2019 CEA/DEN, EDF R&D +// +// 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 +// + +#if !defined(HYBRIDPluginGUI_TreeWidget_H) +#define HYBRIDPluginGUI_TreeWidget_H + +#include + +class HYBRIDPluginGUI_TreeWidget : public QTreeWidget +{ + Q_OBJECT +public: + HYBRIDPluginGUI_TreeWidget( QWidget* ); + +protected: + QModelIndex moveCursor( CursorAction, Qt::KeyboardModifiers ); + void keyPressEvent( QKeyEvent* ); +}; + +#endif // HYBRIDPluginGUI_TreeWidget_H diff --git a/src/GUI/HYBRIDPlugin_msg_en.ts b/src/GUI/HYBRIDPlugin_msg_en.ts index 536c322..8b031fa 100644 --- a/src/GUI/HYBRIDPlugin_msg_en.ts +++ b/src/GUI/HYBRIDPlugin_msg_en.ts @@ -28,7 +28,7 @@ Hypothesis Construction - HYBRID_BOUNDARY_LAYERS_GROWTH + HYBRID_GROWTH_OF_LAYERS Growth of boundary layers @@ -56,7 +56,7 @@ downward means inward and upward means outward ... HYBRID_GENERATION_ELEMENT - Element type for mesh in the remaining volume + Element generation HYBRID_GENERATION_TETRA_DOMINANT @@ -70,9 +70,13 @@ downward means inward and upward means outward ... HYBRID_GENERATION_CARTESIAN_CORE Cartesian core + + HYBRID_GENERATION_EXTRUSION_ONLY + Extrusion only + HYBRID_CORE_SIZE - Core elements size (cartesian core only) + Core elements size HYBRID_ADD_MULTINORMALS @@ -87,16 +91,68 @@ downward means inward and upward means outward ... Smooth normals at closed ridges and corners - HYBRID_HeightFirstLayer + HYBRID_1ST_LAYER_HEIGHT Height of first layer - HYBRID_NbOfBoundaryLayers + HYBRID_NB_LAYERS Number of boundary layers - HYBRID_BoundaryLayersProgression - Geometric progression of boundary layers + HYBRID_HEIGHT_IS_RELATIVE + Height relative to local surface + + + HYBRID_SIZE_MODE + Size mode + + + HYBRID_GLOBAL + Global + + + HYBRID_LOCAL + Local + + + HYBRID_MAX_ELEM_ANGLE + Maximal element angle (degrees) + + + HYBRID_IMPRINTING + Imprinting + + + HYBRID_SNAPPING + Snapping + + + HYBRID_NO + No + + + HYBRID_YES + Yes + + + HYBRID_VL_OPTIONS + Options for boundary layers + + + HYBRID_OTHER_OPTIONS + Other options + + + + + + + + + + + HYBRID_GEOM_PROGRESSION + Geometric progression HYBRID_TO_MESH_HOLES @@ -334,5 +390,33 @@ downward means inward and upward means outward ... HYBRID_FACE_IDS Face IDs + + add_multinormals + Add multi normals + + + smooth_normals + Smooth normals + + + max_number_of_threads + Maximum number of threads + + + gradation + Gradation + + + multinormal_angle_threshold + Multi normal angle threshold + + + collision_mode + Collision mode + + + HYBRID_ADD_OPTION + Add option + diff --git a/src/HYBRIDPlugin/HYBRIDPluginBuilder.py b/src/HYBRIDPlugin/HYBRIDPluginBuilder.py index 2ac5ec4..12f1013 100644 --- a/src/HYBRIDPlugin/HYBRIDPluginBuilder.py +++ b/src/HYBRIDPlugin/HYBRIDPluginBuilder.py @@ -163,49 +163,6 @@ class HYBRID_Algorithm(Mesh_Algorithm): self.SetLayersOnAllWrap( False ) pass - """ - obsolete - ## To mesh "holes" in a solid or not. Default is to mesh. - # @param toMesh "mesh holes" flag value - def SetToMeshHoles(self, toMesh): - self.Parameters().SetToMeshHoles(toMesh) - pass - - ## To make groups of volumes of different domains when mesh is generated from skin. - # Default is to make groups. - # This option works only (1) for the mesh w/o shape and (2) if GetToMeshHoles() == true - # @param toMesh "mesh holes" flag value - def SetToMakeGroupsOfDomains(self, toMakeGroups): - self.Parameters().SetToMakeGroupsOfDomains(toMakeGroups) - pass - - ## Set Optimization level: - # @param level optimization level, one of the following values - # - None_Optimization - # - Light_Optimization - # - Standard_Optimization - # - StandardPlus_Optimization - # - Strong_Optimization. - # . - # Default is Standard_Optimization - def SetOptimizationLevel(self, level): - self.Parameters().SetOptimizationLevel(level) - pass - - ## Set maximal size of memory to be used by the algorithm (in Megabytes). - # @param MB maximal size of memory - def SetMaximumMemory(self, MB): - self.Parameters().SetMaximumMemory(MB) - pass - - ## Set initial size of memory to be used by the algorithm (in Megabytes) in - # automatic memory adjustment mode. - # @param MB initial size of memory - def SetInitialMemory(self, MB): - self.Parameters().SetInitialMemory(MB) - pass - """ - ## Set Collision Mode: # @param mode Collision Mode, one of the following values # - Decrease_Collision_Mode @@ -258,6 +215,12 @@ class HYBRID_Algorithm(Mesh_Algorithm): self.Parameters().SetHeightFirstLayer(heightFirstLayer) pass + ## Sizes of boundary layers are relative to the surface size. Default no + # @param isRelative boolean flag + def SetHeightIsRelative(self, isRelative): + self.Parameters().SetHeightIsRelative( isRelative ) + pass + ## To set boundary layers coefficient of geometric progression. # Default is 1.0 # @param boundaryLayersProgression double value @@ -286,6 +249,12 @@ class HYBRID_Algorithm(Mesh_Algorithm): self.Parameters().SetNbOfBoundaryLayers(nbOfBoundaryLayers) pass + ## Set maximum internal angles of boundary elements (in degree) + # @param angle angle in degree + def SetBoundaryLayersMaxElemAngle(self, angle): + self.Parameters().SetBoundaryLayersMaxElemAngle( angle ) + pass + ## Set path to working directory. # @param path working directory def SetWorkingDirectory(self, path): @@ -422,18 +391,25 @@ class HYBRID_Algorithm(Mesh_Algorithm): pass pass + ## Set advanced option value + # @param optionName option name + # @param optionValue option value + def SetOptionValue(self, optionName, optionValue): + self.Parameters().SetOptionValue( optionName, optionValue ) + pass + ## Sets command line option as text. - # - # OBSOLETE. Use SetAdvancedOption() - # @param option command line option - def SetTextOption(self, option): - self.Parameters().SetAdvancedOption(option) + # @param optionAndValue command line option in a form "option value" + def SetAdvancedOption(self, optionAndValue): + self.Parameters().SetAdvancedOption(optionAndValue) pass ## Sets command line option as text. + # + # OBSOLETE. Use SetAdvancedOption() # @param option command line option - def SetAdvancedOption(self, option): + def SetTextOption(self, option): self.Parameters().SetAdvancedOption(option) pass - + pass # end of HYBRID_Algorithm class diff --git a/src/HYBRIDPlugin/HYBRIDPlugin_Hypothesis.cxx b/src/HYBRIDPlugin/HYBRIDPlugin_Hypothesis.cxx index fb18c59..4ef1873 100644 --- a/src/HYBRIDPlugin/HYBRIDPlugin_Hypothesis.cxx +++ b/src/HYBRIDPlugin/HYBRIDPlugin_Hypothesis.cxx @@ -34,54 +34,136 @@ #define getpid _getpid #endif +namespace +{ + struct GET_DEFAULT // struct used to get default value from GetOptionValue() + { + bool isDefault; + operator bool* () { return &isDefault; } + }; +} + //======================================================================= //function : HYBRIDPlugin_Hypothesis //======================================================================= HYBRIDPlugin_Hypothesis::HYBRIDPlugin_Hypothesis(int hypId, SMESH_Gen * gen) : SMESH_Hypothesis(hypId, gen), - myToMeshHoles(DefaultMeshHoles()), - myLayersOnAllWrap(DefaultLayersOnAllWrap()), - myToMakeGroupsOfDomains(DefaultToMakeGroupsOfDomains()), - myMaximumMemory(-1), - myInitialMemory(-1), - myOptimizationLevel(DefaultOptimizationLevel()), - myCollisionMode(DefaultCollisionMode()), - myBoundaryLayersGrowth(DefaultBoundaryLayersGrowth()), - myElementGeneration(DefaultElementGeneration()), - myKeepFiles(DefaultKeepFiles()), - myWorkingDirectory(DefaultWorkingDirectory()), - myVerboseLevel(DefaultVerboseLevel()), - myToCreateNewNodes(DefaultToCreateNewNodes()), - myToUseBoundaryRecoveryVersion(DefaultToUseBoundaryRecoveryVersion()), - myToUseFemCorrection(DefaultToUseFEMCorrection()), - myToRemoveCentralPoint(DefaultToRemoveCentralPoint()), - myLogInStandardOutput(DefaultStandardOutputLog()), - myGradation(DefaultGradation()), - myAddMultinormals(DefaultAddMultinormals()), - mySmoothNormals(DefaultSmoothNormals()), - myHeightFirstLayer(DefaultHeightFirstLayer()), - myBoundaryLayersProgression(DefaultBoundaryLayersProgression()), - myCoreSize(DefaultCoreSize()), - myMultinormalsAngle(DefaultMultinormalsAngle()), - myNbOfBoundaryLayers(DefaultNbOfBoundaryLayers()), - _enfVertexList(DefaultHYBRIDEnforcedVertexList()), - _enfVertexCoordsSizeList(DefaultHYBRIDEnforcedVertexCoordsValues()), - _enfVertexEntrySizeList(DefaultHYBRIDEnforcedVertexEntryValues()), - _coordsEnfVertexMap(DefaultCoordsHYBRIDEnforcedVertexMap()), - _geomEntryEnfVertexMap(DefaultGeomEntryHYBRIDEnforcedVertexMap()), - _enfMeshList(DefaultHYBRIDEnforcedMeshList()), - _entryEnfMeshMap(DefaultEntryHYBRIDEnforcedMeshListMap()), - _enfNodes(TIDSortedNodeGroupMap()), - _enfEdges(TIDSortedElemGroupMap()), - _enfTriangles(TIDSortedElemGroupMap()), - _nodeIDToSizeMap(DefaultID2SizeMap()), - _groupsToRemove(DefaultGroupsToRemove()) + myNbOfBoundaryLayers(DefaultNbOfBoundaryLayers()), + myHeightFirstLayer(DefaultHeightFirstLayer()), + myHeightIsRelative(DefaultHeightIsRelative()), + myBoundaryLayersGrowth(DefaultBoundaryLayersGrowth()), + myBoundaryLayersMaxElemAngle(DefaultBoundaryLayersMaxElemAngle()), + myBoundaryLayersProgression(DefaultBoundaryLayersProgression()), + myElementGeneration(DefaultElementGeneration()), + myCoreSize(DefaultCoreSize()), + myLayersOnAllWrap(DefaultLayersOnAllWrap()), + myCollisionMode(DefaultCollisionMode()), + myAddMultinormals(DefaultAddMultinormals()), + mySmoothNormals(DefaultSmoothNormals()), + myMultinormalsAngle(DefaultMultinormalsAngle()), + myGradation(DefaultGradation()), + myWorkingDirectory(DefaultWorkingDirectory()), + myVerboseLevel(DefaultVerboseLevel()), + myLogInStandardOutput(DefaultStandardOutputLog()), + myRemoveLogOnSuccess(DefaultRemoveLogOnSuccess()), + myKeepFiles(DefaultKeepFiles()), + myOptimizationLevel(DefaultOptimizationLevel()), + myToMakeGroupsOfDomains(DefaultToMakeGroupsOfDomains()), + myToMeshHoles(DefaultMeshHoles()), + myMaximumMemory(-1), + myInitialMemory(-1), + myToCreateNewNodes(DefaultToCreateNewNodes()), + myToUseBoundaryRecoveryVersion(DefaultToUseBoundaryRecoveryVersion()), + myToUseFemCorrection(DefaultToUseFEMCorrection()), + myToRemoveCentralPoint(DefaultToRemoveCentralPoint()) { _name = "HYBRID_Parameters"; _param_algo_dim = 3; + + const char* boolOptionNames[] = { "add_multinormals", // no + "smooth_normals", // no + "" // mark of end + }; + const char* intOptionNames[] = { "max_number_of_threads", // 4 + "" // mark of end + }; + const char* doubleOptionNames[] = { //"global_physical_size", // 0.0 = not set -- myCoreSize + "gradation", // 2.0 + //"boundary_layer_max_element_angle", // 165.0 -- myBoundaryLayersMaxElemAngle + "multinormal_angle_threshold", // 30.0 + "" // mark of end + }; + const char* charOptionNames[] = { "collision_mode", // stop/decrease + "" // mark of end + }; + + int i = 0; + while (boolOptionNames[i][0]) + { + _boolOptions.insert( boolOptionNames[i] ); + _option2value[boolOptionNames[i++]].clear(); + } + i = 0; + while (intOptionNames[i][0]) + _option2value[intOptionNames[i++]].clear(); + + i = 0; + while (doubleOptionNames[i][0]) { + _doubleOptions.insert(doubleOptionNames[i]); + _option2value[doubleOptionNames[i++]].clear(); + } + i = 0; + while (charOptionNames[i][0]) { + _charOptions.insert(charOptionNames[i]); + _option2value[charOptionNames[i++]].clear(); + } + + // default values to be used while MG meshing + + _defaultOptionValues["add_multinormals" ] = "no"; + _defaultOptionValues["smooth_normals" ] = "no"; + _defaultOptionValues["max_number_of_threads" ] = "4"; + //_defaultOptionValues["global_physical_size" ] = "0"; + _defaultOptionValues["gradation" ] = "2"; + //_defaultOptionValues["boundary_layer_max_element_angle"] = "165"; + _defaultOptionValues["multinormal_angle_threshold" ] = "30"; + _defaultOptionValues["collision_mode" ] = "stop"; + +#ifdef _DEBUG_ + // check validity of option names of _defaultOptionValues + TOptionValues::iterator n2v = _defaultOptionValues.begin(); + for ( ; n2v != _defaultOptionValues.end(); ++n2v ) + ASSERT( _option2value.count( n2v->first )); + ASSERT( _option2value.size() == _defaultOptionValues.size() ); +#endif +} + +//======================================================================= +//function : SetHeightIsRelative +//======================================================================= + +void HYBRIDPlugin_Hypothesis::SetHeightIsRelative(bool isRelative) +{ + if ( myHeightIsRelative != isRelative ) { + myHeightIsRelative = isRelative; + NotifySubMeshesHypothesisModification(); + } +} + +//======================================================================= +//function : SetBoundaryLayersMaxElemAngle +//======================================================================= + +void HYBRIDPlugin_Hypothesis::SetBoundaryLayersMaxElemAngle( double angle ) +{ + if ( myBoundaryLayersMaxElemAngle != angle ) { + myBoundaryLayersMaxElemAngle = angle; + NotifySubMeshesHypothesisModification(); + } } + //======================================================================= //function : SetLayersOnAllWrap //======================================================================= @@ -199,12 +281,6 @@ void HYBRIDPlugin_Hypothesis::SetToMeshHoles(bool toMesh) bool HYBRIDPlugin_Hypothesis::GetToMeshHoles(bool checkFreeOption) const { - if (checkFreeOption && !myTextOption.empty()) { - if ( myTextOption.find("-c 0")) - return true; - if ( myTextOption.find("-c 1")) - return false; - } return myToMeshHoles; } @@ -309,10 +385,8 @@ HYBRIDPlugin_Hypothesis::OptimizationLevel HYBRIDPlugin_Hypothesis::GetOptimizat //======================================================================= void HYBRIDPlugin_Hypothesis::SetCollisionMode(CollisionMode mode) { - if ( myCollisionMode != mode ) { - myCollisionMode = mode; - NotifySubMeshesHypothesisModification(); - } + SetOptionValue( "collision_mode", mode == Decrease ? "decrease" : "stop" ); + myCollisionMode = mode; } //======================================================================= @@ -366,10 +440,8 @@ HYBRIDPlugin_Hypothesis::ElementGeneration HYBRIDPlugin_Hypothesis::GetElementGe //======================================================================= void HYBRIDPlugin_Hypothesis::SetAddMultinormals(bool toAddMultinormals) { - if ( myAddMultinormals != toAddMultinormals ) { - myAddMultinormals = toAddMultinormals; - NotifySubMeshesHypothesisModification(); - } + SetOptionValue( "add_multinormals", toAddMultinormals ? "yes" : "no" ); + myAddMultinormals = toAddMultinormals; } //======================================================================= @@ -387,10 +459,8 @@ bool HYBRIDPlugin_Hypothesis::GetAddMultinormals() const void HYBRIDPlugin_Hypothesis::SetSmoothNormals(bool toSmoothNormals) { - if ( mySmoothNormals != toSmoothNormals ) { - mySmoothNormals = toSmoothNormals; - NotifySubMeshesHypothesisModification(); - } + SetOptionValue( "smooth_normals", toSmoothNormals ? "yes" : "no" ); + mySmoothNormals = toSmoothNormals; } //======================================================================= @@ -471,10 +541,8 @@ double HYBRIDPlugin_Hypothesis::GetCoreSize() const void HYBRIDPlugin_Hypothesis::SetMultinormalsAngle(double toMultinormalsAngle) { - if ( myMultinormalsAngle != toMultinormalsAngle ) { - myMultinormalsAngle = toMultinormalsAngle; - NotifySubMeshesHypothesisModification(); - } + SetOptionValue( "multinormal_angle_threshold", SMESH_Comment( toMultinormalsAngle )); + myMultinormalsAngle = toMultinormalsAngle; } //======================================================================= @@ -664,9 +732,16 @@ bool HYBRIDPlugin_Hypothesis::GetToRemoveCentralPoint() const void HYBRIDPlugin_Hypothesis::SetAdvancedOption(const std::string& option) { - if ( myTextOption != option ) { - myTextOption = option; - NotifySubMeshesHypothesisModification(); + size_t wsPos = option.find(' '); + if ( wsPos == std::string::npos ) + { + SetOptionValue( option, "" ); + } + else + { + std::string opt( option, 0, wsPos ); + std::string val( option, wsPos + 1 ); + SetOptionValue( opt, val ); } } @@ -676,7 +751,23 @@ void HYBRIDPlugin_Hypothesis::SetAdvancedOption(const std::string& option) std::string HYBRIDPlugin_Hypothesis::GetAdvancedOption() const { - return myTextOption; + SMESH_Comment txt; + + TOptionValues::const_iterator o2v = _option2value.begin(); + for ( ; o2v != _option2value.end(); ++o2v ) + if ( !o2v->second.empty() ) + { + if ( !txt.empty() ) + txt << " "; + txt << o2v->first << " " << o2v->second; + } + for ( o2v = _customOption2value.begin(); o2v != _customOption2value.end(); ++o2v ) + { + if ( !txt.empty() ) + txt << " "; + txt << o2v->first << " " << o2v->second; + } + return txt; } //======================================================================= @@ -685,10 +776,8 @@ std::string HYBRIDPlugin_Hypothesis::GetAdvancedOption() const void HYBRIDPlugin_Hypothesis::SetGradation(double gradation) { - if ( myGradation != gradation ) { - myGradation = gradation; - NotifySubMeshesHypothesisModification(); - } + SetOptionValue( "gradation", SMESH_Comment( gradation )); + myGradation = gradation; } //======================================================================= @@ -1395,11 +1484,11 @@ std::ostream & HYBRIDPlugin_Hypothesis::SaveTo(std::ostream & save) save << myVerboseLevel << " "; save << myCoreSize << " "; - if (!myTextOption.empty()) { - save << "__OPTIONS_BEGIN__ "; - save << myTextOption << " "; - save << "__OPTIONS_END__ "; - } + // if (!myTextOption.empty()) { + // save << "__OPTIONS_BEGIN__ "; + // save << myTextOption << " "; + // save << "__OPTIONS_END__ "; + // } THYBRIDEnforcedVertexList::iterator it = _enfVertexList.begin(); @@ -1482,6 +1571,23 @@ std::ostream & HYBRIDPlugin_Hypothesis::SaveTo(std::ostream & save) for ( size_t i = 0; i < myFacesWithSnapping.size(); ++i ) save << " " << myFacesWithSnapping[i]; + // New options in 2.9.6 (issue #17784) + + save << " " << myHeightIsRelative; + save << " " << myBoundaryLayersMaxElemAngle; + save << " " << myCollisionMode; + save << " " << myGradation; + save << " " << myOptimizationLevel; + + save << " " << _option2value.size(); + TOptionValues::iterator o2v = _option2value.begin(); + for ( ; o2v != _option2value.end(); ++o2v ) + save << " -" << o2v->first << " -" << o2v->second; + + save << " " << _customOption2value.size(); + for ( o2v = _customOption2value.begin(); o2v != _customOption2value.end(); ++o2v ) + save << " -" << o2v->first << " -" << o2v->second; + return save; } @@ -1587,12 +1693,6 @@ std::istream & HYBRIDPlugin_Hypothesis::LoadFrom(std::istream & load) bool hasEnforcedMeshes = false; isOK = static_cast(load >> separator); - if ( isOK && ( separator == "0" || separator == "1" )) - { - myToMakeGroupsOfDomains = ( separator == "1" ); - isOK = static_cast(load >> separator); - } - if (isOK) { if (separator == "__OPTIONS_BEGIN__") hasOptions = true; @@ -1608,15 +1708,10 @@ std::istream & HYBRIDPlugin_Hypothesis::LoadFrom(std::istream & load) isOK = static_cast(load >> txt); if (isOK) { if (txt == "__OPTIONS_END__") { - if (!myTextOption.empty()) { - // Remove last space - myTextOption.erase(myTextOption.end()-1); - } isOK = false; break; } - myTextOption += txt; - myTextOption += " "; + // myTextOption += txt; } } } @@ -1841,6 +1936,35 @@ std::istream & HYBRIDPlugin_Hypothesis::LoadFrom(std::istream & load) } } + // New options in 2.9.6 (issue #17784) + + if ( static_cast(load >> i)) + { + myHeightIsRelative = (bool) i; + load >> myBoundaryLayersMaxElemAngle; + load >> myCollisionMode; + load >> myGradation; + load >> myOptimizationLevel; + + std::string option, value; + if ( static_cast( load >> i ) && i >= 0 ) + { + for ( int nbRead = 0; nbRead < i; ++nbRead ) + { + load >> option >> value; + _option2value[ std::string( option, 1 )] = std::string( value, 1 ); + } + } + if ( static_cast( load >> i ) && i >= 0 ) + { + for ( int nbRead = 0; nbRead < i; ++nbRead ) + { + load >> option >> value; + _customOption2value[ std::string( option, 1 )] = std::string( value, 1 ); + } + } + } + return load; } @@ -1853,7 +1977,6 @@ bool HYBRIDPlugin_Hypothesis::SetParametersByMesh(const SMESH_Mesh* ,const TopoD return false; } - //================================================================================ /*! * \brief Sets myToMakeGroupsOfDomains depending on whether theMesh is on shape or not @@ -1877,27 +2000,15 @@ std::string HYBRIDPlugin_Hypothesis::CommandToRun(const HYBRIDPlugin_Hypothesis* SMESH_Mesh& mesh) { SMESH_Comment cmd = GetExeName(); - // check if any option is overridden by hyp->myTextOption - bool p_h = ( hyp && hyp->myTextOption.find("-h") != std::string::npos ); - bool p_v = ( hyp && hyp->myTextOption.find("-v") != std::string::npos ); - bool p_i = ( hyp && hyp->myTextOption.find("-i") != std::string::npos ); - bool p_o = ( hyp && hyp->myTextOption.find("-o") != std::string::npos ); - bool p_mnot = ( hyp && hyp->myTextOption.find("--max_number_of_threads ") != std::string::npos ); - bool p_blsi = ( hyp && hyp->myTextOption.find("--boundary_layer_surface_tags ") != std::string::npos ); - bool p_blii = ( hyp && hyp->myTextOption.find("--boundary_layer_imprint_tags ") != std::string::npos ); - bool p_blsd = ( hyp && hyp->myTextOption.find("--normal_direction ") != std::string::npos ); - bool p_hotfl = ( hyp && hyp->myTextOption.find("--boundary_layer_global_initial_height ") != std::string::npos ); - bool p_nobl = ( hyp && hyp->myTextOption.find("--number_of_boundary_layers ") != std::string::npos ); - bool p_blgp = ( hyp && hyp->myTextOption.find("--boundary_layer_geometric_progression ") != std::string::npos ); - bool p_eg = ( hyp && hyp->myTextOption.find("--element_generation ") != std::string::npos ); - bool p_cm = ( hyp && hyp->myTextOption.find("--collision_mode ") != std::string::npos ); - bool p_am = ( hyp && hyp->myTextOption.find("--add_multinormals ") != std::string::npos ); - bool p_cs = ( hyp && hyp->myTextOption.find("--global_physical_size ") != std::string::npos ); - bool p_mat = ( hyp && hyp->myTextOption.find("--multinormal_angle_threshold ") != std::string::npos ); - bool p_sn = ( hyp && hyp->myTextOption.find("--smooth_normals ") != std::string::npos ); - - //missing options : - //- boundary_layer_max_element_angle + // check if any option is overridden by hyp->_option2value + bool p_h = ( hyp && hyp->HasOptionDefined("-h")); + bool p_v = ( hyp && hyp->HasOptionDefined("-v")); + bool p_blsd = ( hyp && hyp->HasOptionDefined("--normal_direction ")); + bool p_hotfl = ( hyp && hyp->HasOptionDefined("--boundary_layer_global_initial_height ")); + bool p_nobl = ( hyp && hyp->HasOptionDefined("--number_of_boundary_layers ")); + bool p_blgp = ( hyp && hyp->HasOptionDefined("--boundary_layer_geometric_progression ")); + bool p_eg = ( hyp && hyp->HasOptionDefined("--element_generation ")); + bool p_cs = ( hyp && hyp->HasOptionDefined("--global_physical_size ")); bool nolayers = false; bool layersOnAllWrap = hyp ? hyp->myLayersOnAllWrap : DefaultLayersOnAllWrap(); @@ -1915,9 +2026,6 @@ std::string HYBRIDPlugin_Hypothesis::CommandToRun(const HYBRIDPlugin_Hypothesis* if ( !p_v && hyp ) cmd << " --verbose " << hyp->myVerboseLevel; - if ( !p_mnot && hyp ) - cmd << " --max_number_of_threads " << 8; //TODO getenv NB CPU - //no layers? if ( !p_nobl && hyp ) { if ( hyp->myNbOfBoundaryLayers < 1 ) nolayers = true; @@ -1925,18 +2033,20 @@ std::string HYBRIDPlugin_Hypothesis::CommandToRun(const HYBRIDPlugin_Hypothesis* if ( !p_hotfl && hyp ) { if ( hyp->myHeightFirstLayer < 1e-50 ) nolayers = true; } - + if ( !p_blsd && hyp ) { if ( hyp->myBoundaryLayersGrowth >= 0 && hyp->myBoundaryLayersGrowth <= 1 ) { const char* value[] = { "-1" , "1" }; // -1 == inside cmd << " --normal_direction " << value[ hyp->myBoundaryLayersGrowth ]; } } - + if ( !p_hotfl && hyp ) { cmd << " --boundary_layer_global_initial_height " << hyp->myHeightFirstLayer; } - + if ( hyp && hyp->GetHeightIsRelative() ) + cmd << " --boundary_layer_height_relative_to_local_surface_size yes"; + if ( !p_nobl && hyp ) { cmd << " --number_of_boundary_layers " << ( nolayers ? 0 : hyp->myNbOfBoundaryLayers ); } @@ -1948,7 +2058,11 @@ std::string HYBRIDPlugin_Hypothesis::CommandToRun(const HYBRIDPlugin_Hypothesis* if ( !nolayers && hyp ) { cmd << " --boundary_layer_size_mode " << ( layersOnAllWrap ? "global" : "local" ); - + + if ( hyp->GetBoundaryLayersMaxElemAngle() != hyp->DefaultBoundaryLayersMaxElemAngle() ) + cmd << " --boundary_layer_max_element_angle " + << SMESH_Comment( hyp->GetBoundaryLayersMaxElemAngle() ); + if ( !layersOnAllWrap ) { // faces with layers @@ -1979,50 +2093,53 @@ std::string HYBRIDPlugin_Hypothesis::CommandToRun(const HYBRIDPlugin_Hypothesis* } if ( !p_eg && hyp ) { - if ( hyp->myElementGeneration >= 0 && hyp->myElementGeneration <= 2 ) { - const char* value[] = { "tetra-dominant" , "hexa-dominant", "cartesian_core" }; + if ( hyp->myElementGeneration >= 0 && hyp->myElementGeneration <= 3 ) { + const char* value[] = { "tetra_dominant" , "hexa_dominant", "cartesian_core", "extrusion_only" }; cmd << " --element_generation " << value[ hyp->myElementGeneration ]; } } if ( !p_cs && hyp ) { - if ( hyp->myCoreSize >= 0 ) { + if ( hyp->myCoreSize > 0 ) { cmd << " --global_physical_size " << hyp->myCoreSize; } } - if ( !p_cm && hyp ) { - if ( hyp->myCollisionMode >= 0 && hyp->myCollisionMode <= 1 ) { - const char* value[] = { "decrease" , "stop" }; - cmd << " --collision_mode " << value[ hyp->myCollisionMode ]; + if ( hyp ) + { + // options as text + std::string option, value; + bool isDefault; + const TOptionValues* options[] = { & hyp->_option2value, & hyp->_customOption2value }; + for ( int iOp = 0; iOp < 2; ++iOp ) + { + TOptionValues::const_iterator o2v = options[iOp]->begin(); + for ( ; o2v != options[iOp]->end(); ++o2v ) + { + option = o2v->first; + value = hyp->GetOptionValue( option, &isDefault ); + + if ( isDefault ) + continue; + if ( value.empty() ) + { + if ( hyp->_defaultOptionValues.count( option )) + continue; // non-custom option with no value + } + if ( option[0] != '-' ) + cmd << " --"; + else + cmd << " "; + cmd << option << " " << value; + } } } - - if ( !p_am && hyp ) { - int res = hyp->myAddMultinormals ? 0 : 1 ; - const char* value[] = { "yes" , "no" }; - cmd << " --add_multinormals " << value[ res ]; - } - - if ( !p_mat && hyp ) { - cmd << " --multinormal_angle_threshold " << hyp->myMultinormalsAngle; - } - - if ( !p_sn && hyp ) { - int res = hyp->mySmoothNormals ? 0 : 1 ; - const char* value[] = { "yes" , "no" }; - cmd << " --smooth_normals " << value[ res ]; - } - // options as text - if ( hyp && !hyp->myTextOption.empty() ) { - cmd += " " + hyp->myTextOption; - } #ifdef WIN32 cmd << " < NUL"; #endif //std::cout << "!!!!!CommandToRun end " << cmd << std::endl; - + return cmd; } @@ -2067,58 +2184,265 @@ std::string HYBRIDPlugin_Hypothesis::GetExeName() #endif } +//============================================================================= +void HYBRIDPlugin_Hypothesis::SetOptionValue(const std::string& optionName, + const std::string& optionValue) + throw (std::invalid_argument) +{ + TOptionValues::iterator op_val = _option2value.find(optionName); + if (op_val == _option2value.end()) + { + op_val = _customOption2value.find( optionName ); + if ( op_val != _customOption2value.end() && op_val->second != optionValue ) + NotifySubMeshesHypothesisModification(); + _customOption2value[ optionName ] = optionValue; + return; + } + + if (op_val->second != optionValue) + { + const char* ptr = optionValue.c_str(); + // strip white spaces + while (ptr[0] == ' ') + ptr++; + int i = strlen(ptr); + while (i != 0 && ptr[i - 1] == ' ') + i--; + // check value type + bool typeOk = true; + std::string typeName; + if (i == 0) { + // empty string + } else if (_charOptions.count(optionName)) { + // do not check strings + } else if (_doubleOptions.count(optionName)) { + // check if value is double + ToDbl(ptr, &typeOk); + typeName = "real"; + } else if (_boolOptions.count(optionName)) { + // check if value is bool + ToBool(ptr, &typeOk); + typeName = "bool"; + } else { + // check if value is int + ToInt(ptr, &typeOk); + typeName = "integer"; + } + if ( typeOk ) // check some specific values ? + { + } + if ( !typeOk ) + { + std::string msg = "Advanced option '" + optionName + "' = '" + optionValue + "' but must be " + typeName; + throw std::invalid_argument(msg); + } + std::string value( ptr, i ); + if ( _defaultOptionValues[ optionName ] == value ) + value.clear(); + + op_val->second = value; + + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +//! Return option value. If isDefault provided, it can be a default value, +// then *isDefault == true. If isDefault is not provided, the value will be +// empty if it equals a default one. +std::string HYBRIDPlugin_Hypothesis::GetOptionValue(const std::string& optionName, + bool* isDefault) const + throw (std::invalid_argument) +{ + TOptionValues::const_iterator op_val = _option2value.find(optionName); + if (op_val == _option2value.end()) + { + op_val = _customOption2value.find(optionName); + if (op_val == _customOption2value.end()) + { + std::string msg = "Unknown MG-Tetra option: <" + optionName + ">"; + throw std::invalid_argument(msg); + } + } + std::string val = op_val->second; + if ( isDefault ) *isDefault = ( val.empty() ); + + if ( val.empty() && isDefault ) + { + op_val = _defaultOptionValues.find( optionName ); + if (op_val != _defaultOptionValues.end()) + val = op_val->second; + } + return val; +} + + +//============================================================================= +bool HYBRIDPlugin_Hypothesis::HasOptionDefined( const std::string& optionName ) const +{ + bool isDefault = false; + try + { + GetOptionValue( optionName, &isDefault ); + } + catch ( std::invalid_argument ) + { + return false; + } + return !isDefault; +} + +//============================================================================= +void HYBRIDPlugin_Hypothesis::ClearOption(const std::string& optionName) +{ + TOptionValues::iterator op_val = _customOption2value.find(optionName); + if (op_val != _customOption2value.end()) + _customOption2value.erase(op_val); + else { + op_val = _option2value.find(optionName); + if (op_val != _option2value.end()) + op_val->second.clear(); + } +} + +//============================================================================= +HYBRIDPlugin_Hypothesis::TOptionValues HYBRIDPlugin_Hypothesis::GetOptionValues() const +{ + TOptionValues vals; + TOptionValues::const_iterator op_val = _option2value.begin(); + for ( ; op_val != _option2value.end(); ++op_val ) + vals.insert( make_pair( op_val->first, GetOptionValue( op_val->first, GET_DEFAULT() ))); + + return vals; +} + +//================================================================================ +/*! + * \brief Converts a string to a bool + */ +//================================================================================ + +bool HYBRIDPlugin_Hypothesis::ToBool(const std::string& str, bool* isOk ) + throw (std::invalid_argument) +{ + std::string s = str; + if ( isOk ) *isOk = true; + + for ( size_t i = 0; i <= s.size(); ++i ) + s[i] = tolower( s[i] ); + + if ( s == "1" || s == "true" || s == "active" || s == "yes" ) + return true; + + if ( s == "0" || s == "false" || s == "inactive" || s == "no" ) + return false; + + if ( isOk ) + *isOk = false; + else { + std::string msg = "Not a Boolean value:'" + str + "'"; + throw std::invalid_argument(msg); + } + return false; +} + +//================================================================================ +/*! + * \brief Converts a string to a real value + */ +//================================================================================ + +double HYBRIDPlugin_Hypothesis::ToDbl(const std::string& str, bool* isOk ) + throw (std::invalid_argument) +{ + if ( str.empty() ) throw std::invalid_argument("Empty value provided"); + + char * endPtr; + double val = strtod(&str[0], &endPtr); + bool ok = (&str[0] != endPtr); + + if ( isOk ) *isOk = ok; + + if ( !ok ) + { + std::string msg = "Not a real value:'" + str + "'"; + throw std::invalid_argument(msg); + } + return val; +} + //================================================================================ /*! -* \brief Return the enforced vertices -*/ + * \brief Converts a string to a integer value + */ //================================================================================ +int HYBRIDPlugin_Hypothesis::ToInt(const std::string& str, bool* isOk ) + throw (std::invalid_argument) +{ + if ( str.empty() ) throw std::invalid_argument("Empty value provided"); + + char * endPtr; + int val = (int)strtol( &str[0], &endPtr, 10); + bool ok = (&str[0] != endPtr); + + if ( isOk ) *isOk = ok; + + if ( !ok ) + { + std::string msg = "Not an integer value:'" + str + "'"; + throw std::invalid_argument(msg); + } + return val; +} + + HYBRIDPlugin_Hypothesis::THYBRIDEnforcedVertexList HYBRIDPlugin_Hypothesis::GetEnforcedVertices(const HYBRIDPlugin_Hypothesis* hyp) { - return hyp ? hyp->_GetEnforcedVertices():DefaultHYBRIDEnforcedVertexList(); + return hyp ? hyp->_GetEnforcedVertices():THYBRIDEnforcedVertexList(); } HYBRIDPlugin_Hypothesis::THYBRIDEnforcedVertexCoordsValues HYBRIDPlugin_Hypothesis::GetEnforcedVerticesCoordsSize (const HYBRIDPlugin_Hypothesis* hyp) { - return hyp ? hyp->_GetEnforcedVerticesCoordsSize(): DefaultHYBRIDEnforcedVertexCoordsValues(); + return hyp ? hyp->_GetEnforcedVerticesCoordsSize(): THYBRIDEnforcedVertexCoordsValues(); } HYBRIDPlugin_Hypothesis::THYBRIDEnforcedVertexEntryValues HYBRIDPlugin_Hypothesis::GetEnforcedVerticesEntrySize (const HYBRIDPlugin_Hypothesis* hyp) { - return hyp ? hyp->_GetEnforcedVerticesEntrySize(): DefaultHYBRIDEnforcedVertexEntryValues(); + return hyp ? hyp->_GetEnforcedVerticesEntrySize():THYBRIDEnforcedVertexEntryValues(); } HYBRIDPlugin_Hypothesis::TCoordsHYBRIDEnforcedVertexMap HYBRIDPlugin_Hypothesis::GetEnforcedVerticesByCoords (const HYBRIDPlugin_Hypothesis* hyp) { - return hyp ? hyp->_GetEnforcedVerticesByCoords(): DefaultCoordsHYBRIDEnforcedVertexMap(); + return hyp ? hyp->_GetEnforcedVerticesByCoords():TCoordsHYBRIDEnforcedVertexMap(); } HYBRIDPlugin_Hypothesis::TGeomEntryHYBRIDEnforcedVertexMap HYBRIDPlugin_Hypothesis::GetEnforcedVerticesByEntry (const HYBRIDPlugin_Hypothesis* hyp) { - return hyp ? hyp->_GetEnforcedVerticesByEntry(): DefaultGeomEntryHYBRIDEnforcedVertexMap(); + return hyp ? hyp->_GetEnforcedVerticesByEntry():TGeomEntryHYBRIDEnforcedVertexMap(); } HYBRIDPlugin_Hypothesis::TIDSortedNodeGroupMap HYBRIDPlugin_Hypothesis::GetEnforcedNodes(const HYBRIDPlugin_Hypothesis* hyp) { - return hyp ? hyp->_GetEnforcedNodes():DefaultIDSortedNodeGroupMap(); + return hyp ? hyp->_GetEnforcedNodes():TIDSortedNodeGroupMap(); } HYBRIDPlugin_Hypothesis::TIDSortedElemGroupMap HYBRIDPlugin_Hypothesis::GetEnforcedEdges(const HYBRIDPlugin_Hypothesis* hyp) { - return hyp ? hyp->_GetEnforcedEdges():DefaultIDSortedElemGroupMap(); + return hyp ? hyp->_GetEnforcedEdges():TIDSortedElemGroupMap(); } HYBRIDPlugin_Hypothesis::TIDSortedElemGroupMap HYBRIDPlugin_Hypothesis::GetEnforcedTriangles(const HYBRIDPlugin_Hypothesis* hyp) { - return hyp ? hyp->_GetEnforcedTriangles():DefaultIDSortedElemGroupMap(); + return hyp ? hyp->_GetEnforcedTriangles():TIDSortedElemGroupMap(); } HYBRIDPlugin_Hypothesis::TID2SizeMap HYBRIDPlugin_Hypothesis::GetNodeIDToSizeMap(const HYBRIDPlugin_Hypothesis* hyp) { - return hyp ? hyp->_GetNodeIDToSizeMap(): DefaultID2SizeMap(); + return hyp ? hyp->_GetNodeIDToSizeMap():TID2SizeMap(); } HYBRIDPlugin_Hypothesis::TSetStrings HYBRIDPlugin_Hypothesis::GetGroupsToRemove(const HYBRIDPlugin_Hypothesis* hyp) { - return hyp ? hyp->_GetGroupsToRemove(): DefaultGroupsToRemove(); + return hyp ? hyp->_GetGroupsToRemove():TSetStrings(); } diff --git a/src/HYBRIDPlugin/HYBRIDPlugin_Hypothesis.hxx b/src/HYBRIDPlugin/HYBRIDPlugin_Hypothesis.hxx index e365af8..93832c6 100644 --- a/src/HYBRIDPlugin/HYBRIDPlugin_Hypothesis.hxx +++ b/src/HYBRIDPlugin/HYBRIDPlugin_Hypothesis.hxx @@ -119,11 +119,18 @@ public: typedef std::set TSetStrings; static const char* GetHypType() { return "HYBRID_Parameters"; } + + /*! - * To mesh "holes" in a solid or not. Default is to mesh. + * Sizes of boundary layers are relative to the surface size. Default no */ - void SetToMeshHoles(bool toMesh); - bool GetToMeshHoles(bool checkFreeOption = false) const; + void SetHeightIsRelative( bool isRelative ); + bool GetHeightIsRelative() const { return myHeightIsRelative; } + /*! + * Maximum internal angles of boundary elements (in degree) + */ + void SetBoundaryLayersMaxElemAngle( double angle ); + double GetBoundaryLayersMaxElemAngle() const { return myBoundaryLayersMaxElemAngle; } /*! * To mesh layers on all wrap. Default is yes. */ @@ -173,7 +180,7 @@ public: * Collision Mode: 0-decrease, 1-stop. Default is decrease */ enum CollisionMode { Decrease = 0, Stop }; - void SetCollisionMode(CollisionMode level); + void SetCollisionMode(CollisionMode mode); CollisionMode GetCollisionMode() const; /*! * BoundaryLayersGrowth: 0-Layer_Growth_Inward, 1-Layer_Growth_Outward. Default is Layer_Growth_Inward @@ -184,7 +191,7 @@ public: /*! * ElementGeneration: 0-Generation_Tetra_Dominant, 1-Generation_Hexa_Dominant, 2-Generation_Cartesian_Core. Default is Generation_Tetra_Dominant */ - enum ElementGeneration { Generation_Tetra_Dominant = 0, Generation_Hexa_Dominant, Generation_Cartesian_Core }; + enum ElementGeneration { Generation_Tetra_Dominant = 0, Generation_Hexa_Dominant, Generation_Cartesian_Core, Generation_Extrusion_Only }; void SetElementGeneration(ElementGeneration level); ElementGeneration GetElementGeneration() const; /*! @@ -282,29 +289,38 @@ public: void SetAdvancedOption(const std::string& option); std::string GetAdvancedOption() const; /*! - * To define the volumic gradation - */ + * To define the volumic gradation + */ void SetGradation(double gradation); double GetGradation() const ; /*! - * Print log in standard output - */ + * Print log in standard output + */ void SetStandardOutputLog(bool logInStandardOutput); bool GetStandardOutputLog() const ; /*! - * Remove log file on success - */ + * Remove log file on success + */ void SetRemoveLogOnSuccess(bool removeLogOnSuccess); bool GetRemoveLogOnSuccess() const ; - - -// struct TEnforcedEdge { -// long ID; -// long node1; -// long node2; -// std::string groupName; -// }; - + + + typedef std::map< std::string, std::string > TOptionValues; + typedef std::set< std::string > TOptionNames; + + void SetOptionValue(const std::string& optionName, + const std::string& optionValue) throw (std::invalid_argument); + std::string GetOptionValue(const std::string& optionName, + bool* isDefault=0) const throw (std::invalid_argument); + bool HasOptionDefined( const std::string& optionName ) const; + void ClearOption(const std::string& optionName); + TOptionValues GetOptionValues() const; + const TOptionValues& GetCustomOptionValues() const { return _customOption2value; } + + static bool ToBool(const std::string& str, bool* isOk=0) throw (std::invalid_argument); + static double ToDbl(const std::string& str, bool* isOk=0) throw (std::invalid_argument); + static int ToInt(const std::string& str, bool* isOk=0) throw (std::invalid_argument); + /*! * \brief Return command to run hybrid mesher excluding file prefix (-f) @@ -372,6 +388,8 @@ public: static bool GetToMakeGroupsOfDomains(const HYBRIDPlugin_Hypothesis* hyp); void ClearGroupsToRemove(); + static bool DefaultHeightIsRelative() { return false; } + static double DefaultBoundaryLayersMaxElemAngle() { return 165.0; } static bool DefaultMeshHoles(); static bool DefaultLayersOnAllWrap(); static bool DefaultToMakeGroupsOfDomains(); @@ -398,28 +416,16 @@ public: static double DefaultBoundaryLayersProgression(); static double DefaultCoreSize(); static double DefaultMultinormalsAngle(); - - static THYBRIDEnforcedVertex DefaultHYBRIDEnforcedVertex() {return THYBRIDEnforcedVertex();} - static THYBRIDEnforcedVertexList DefaultHYBRIDEnforcedVertexList() {return THYBRIDEnforcedVertexList();} - static THYBRIDEnforcedVertexCoordsValues DefaultHYBRIDEnforcedVertexCoordsValues() {return THYBRIDEnforcedVertexCoordsValues();} - static THYBRIDEnforcedVertexEntryValues DefaultHYBRIDEnforcedVertexEntryValues() {return THYBRIDEnforcedVertexEntryValues();} - static TCoordsHYBRIDEnforcedVertexMap DefaultCoordsHYBRIDEnforcedVertexMap() {return TCoordsHYBRIDEnforcedVertexMap();} - static TGeomEntryHYBRIDEnforcedVertexMap DefaultGeomEntryHYBRIDEnforcedVertexMap() {return TGeomEntryHYBRIDEnforcedVertexMap();} - static TGroupNameHYBRIDEnforcedVertexMap DefaultGroupNameHYBRIDEnforcedVertexMap() {return TGroupNameHYBRIDEnforcedVertexMap();} - - static THYBRIDEnforcedMesh DefaultHYBRIDEnforcedMesh() {return THYBRIDEnforcedMesh();} - static THYBRIDEnforcedMeshList DefaultHYBRIDEnforcedMeshList() {return THYBRIDEnforcedMeshList();} - static TEntryHYBRIDEnforcedMeshListMap DefaultEntryHYBRIDEnforcedMeshListMap() {return TEntryHYBRIDEnforcedMeshListMap();} - static TIDSortedNodeGroupMap DefaultIDSortedNodeGroupMap() {return TIDSortedNodeGroupMap();} - static TIDSortedElemGroupMap DefaultIDSortedElemGroupMap() {return TIDSortedElemGroupMap();} - static TID2SizeMap DefaultID2SizeMap() {return TID2SizeMap();} - static TSetStrings DefaultGroupsToRemove() {return TSetStrings();} - + + /*! + * To mesh "holes" in a solid or not. Default is to mesh. + */ + void SetToMeshHoles(bool toMesh); + bool GetToMeshHoles(bool checkFreeOption = false) const; + // Persistence virtual std::ostream & SaveTo(std::ostream & save); virtual std::istream & LoadFrom(std::istream & load); - friend HYBRIDPLUGIN_EXPORT std::ostream & operator <<(std::ostream & save, HYBRIDPlugin_Hypothesis & hyp); - friend HYBRIDPLUGIN_EXPORT std::istream & operator >>(std::istream & load, HYBRIDPlugin_Hypothesis & hyp); /*! * \brief Does nothing @@ -433,38 +439,50 @@ public: private: - bool myToMeshHoles; + short myNbOfBoundaryLayers; + double myHeightFirstLayer; + bool myHeightIsRelative; + short myBoundaryLayersGrowth; + double myBoundaryLayersMaxElemAngle; + double myBoundaryLayersProgression; + + short myElementGeneration; + double myCoreSize; + bool myLayersOnAllWrap; - std::vector myFacesWithLayers; std::vector myFacesWithImprinting; std::vector myFacesWithSnapping; - bool myToMakeGroupsOfDomains; - double myMaximumMemory; - double myInitialMemory; - short myOptimizationLevel; + std::vector myFacesWithLayers; + + // advanced (main params before redesign for 9.6.2) short myCollisionMode; - short myBoundaryLayersGrowth; - short myElementGeneration; - bool myKeepFiles; + bool myAddMultinormals; + bool mySmoothNormals; + double myMultinormalsAngle; + double myGradation; + std::string myWorkingDirectory; short myVerboseLevel; - bool myToCreateNewNodes; - bool myToUseBoundaryRecoveryVersion; - bool myToUseFemCorrection; - bool myToRemoveCentralPoint; bool myLogInStandardOutput; bool myRemoveLogOnSuccess; - std::string myTextOption; - double myGradation; + bool myKeepFiles; + + TOptionValues _option2value, _customOption2value; // user defined values + TOptionValues _defaultOptionValues; // default values + TOptionNames _doubleOptions, _charOptions, _boolOptions; // to find a type of option + + short myOptimizationLevel; // missing from plugin + bool myToMakeGroupsOfDomains; // missing from plugin + + bool myToMeshHoles; // missing from hybrid + double myMaximumMemory; // missing from hybrid + double myInitialMemory; // missing from hybrid + bool myToCreateNewNodes; // missing from hybrid + bool myToUseBoundaryRecoveryVersion; // missing from hybrid + bool myToUseFemCorrection; // missing from hybrid + bool myToRemoveCentralPoint; // missing from hybrid + - bool myAddMultinormals; - bool mySmoothNormals; - double myHeightFirstLayer; - double myBoundaryLayersProgression; - double myCoreSize; - double myMultinormalsAngle; - short myNbOfBoundaryLayers; - THYBRIDEnforcedVertexList _enfVertexList; THYBRIDEnforcedVertexCoordsValues _enfVertexCoordsSizeList; THYBRIDEnforcedVertexEntryValues _enfVertexEntrySizeList; diff --git a/src/HYBRIDPlugin/HYBRIDPlugin_Hypothesis_i.cxx b/src/HYBRIDPlugin/HYBRIDPlugin_Hypothesis_i.cxx index 3643e22..c1755cd 100644 --- a/src/HYBRIDPlugin/HYBRIDPlugin_Hypothesis_i.cxx +++ b/src/HYBRIDPlugin/HYBRIDPlugin_Hypothesis_i.cxx @@ -64,6 +64,47 @@ HYBRIDPlugin_Hypothesis_i::~HYBRIDPlugin_Hypothesis_i() { } +//======================================================================= +/*! + * Sizes of boundary layers are relative to the surface size. Default no + */ +//======================================================================= + +void HYBRIDPlugin_Hypothesis_i::SetHeightIsRelative( CORBA::Boolean isRelative ) +{ + ASSERT(myBaseImpl); + if ( GetImpl()->GetHeightIsRelative() != isRelative ) + { + this->GetImpl()->SetHeightIsRelative( isRelative ); + SMESH::TPythonDump() << _this() << ".SetHeightIsRelative( " << isRelative << " )"; + } +} + +CORBA::Boolean HYBRIDPlugin_Hypothesis_i::GetHeightIsRelative() +{ + return this->GetImpl()->GetHeightIsRelative(); +} + +//======================================================================= +/*! + * Maximum internal angles of boundary elements (in degree) + */ +//======================================================================= + +void HYBRIDPlugin_Hypothesis_i::SetBoundaryLayersMaxElemAngle( CORBA::Double angle ) +{ + if ( GetImpl()->GetBoundaryLayersMaxElemAngle() != angle ) + { + this->GetImpl()->SetBoundaryLayersMaxElemAngle( angle ); + SMESH::TPythonDump() << _this() << ".SetBoundaryLayersMaxElemAngle( " << angle << " )"; + } +} + +CORBA::Double HYBRIDPlugin_Hypothesis_i::GetBoundaryLayersMaxElemAngle() +{ + return this->GetImpl()->GetBoundaryLayersMaxElemAngle(); +} + //======================================================================= //function : SetLayersOnAllWrap //======================================================================= @@ -475,6 +516,289 @@ CORBA::Boolean HYBRIDPlugin_Hypothesis_i::GetToRemoveCentralPoint() return this->GetImpl()->GetToRemoveCentralPoint(); } +//============================================================================= + +void HYBRIDPlugin_Hypothesis_i::SetOptionValue(const char* optionName, const char* optionValue) + throw (SALOME::SALOME_Exception) +{ + ASSERT(myBaseImpl); + try { + std::string name( optionName ); + while ( !name.empty() && name[0] == '-' ) + name = name.substr(1); + + if ( !optionValue || !optionValue[0] ) + UnsetOption( optionName ); + + // basic options (visible in Advanced table) + + else if ( name == "number_of_boundary_layers" ) + SetNbOfBoundaryLayers( GetImpl()->ToInt( optionValue )); + + else if ( name == "boundary_layer_global_initial_height" ) + SetHeightFirstLayer( GetImpl()->ToDbl( optionValue )); + + else if ( name == "boundary_layer_geometric_progression" ) + SetBoundaryLayersProgression( GetImpl()->ToDbl( optionValue )); + + else if ( name == "boundary_layer_max_element_angle" ) + SetBoundaryLayersMaxElemAngle( GetImpl()->ToDbl( optionValue )); + + else if ( name == "gradation" ) + SetGradation( GetImpl()->ToDbl( optionValue )); + + else if ( name == "element_generation" ) + switch ( optionValue[0] ) { + case 't': SetElementGeneration( 0 ); break; + case 'h': SetElementGeneration( 1 ); break; + case 'c': SetElementGeneration( 2 ); break; + case 'e': SetElementGeneration( 3 ); break; + default:; + } + else if ( name == "collision_mode" ) // decrease|stop + SetCollisionMode( optionValue[0] != 'd' ); + + else if ( name == "add_multinormals" ) + SetAddMultinormals( GetImpl()->ToBool( optionValue )); + + else if ( name == "multinormal_angle_threshold" ) + SetMultinormalsAngle( GetImpl()->ToDbl( optionValue )); + + else if ( name == "verbose" ) + SetVerboseLevel( GetImpl()->ToInt( optionValue )); + + else if ( name == "max_memory" ) + SetMaximumMemory( GetImpl()->ToInt( optionValue )); + + else if ( name == "automatic_memory" ) + SetInitialMemory( GetImpl()->ToInt( optionValue )); + + else if ( name == "smooth_normals" ) + SetSmoothNormals( GetImpl()->ToBool( optionValue )); + + else if ( name == "optimisation" ) + switch ( optionValue[0] ) { + case 'n': SetOptimizationLevel( 0 ); break; + case 'y': SetOptimizationLevel( 1 ); break; + case 'o': SetOptimizationLevel( 2 ); break; + default:; + } + + // advanced options (for backward compatibility) + // else if ( name == "create_tag_on_collision" || + // name == "tiny_edge_respect_geometry" ) + // AddOption( optionName, optionValue ); + + else { + bool valueChanged = true; + try { + valueChanged = ( this->GetImpl()->GetOptionValue( name ) != optionValue ); + } + catch ( std::invalid_argument ) { + } + if ( valueChanged ) + { + this->GetImpl()->SetOptionValue(optionName, optionValue); + SMESH::TPythonDump() << _this() << ".SetOptionValue( '" << optionName << "', '" << optionValue << "' )"; + } + } + } catch (const std::invalid_argument& ex) { + THROW_SALOME_CORBA_EXCEPTION( ex.what() ,SALOME::BAD_PARAM ); + } catch (SALOME_Exception& ex) { + THROW_SALOME_CORBA_EXCEPTION( ex.what() ,SALOME::BAD_PARAM ); + } +} + +//============================================================================= + +char* HYBRIDPlugin_Hypothesis_i::GetOptionValue(const char* optionName) + throw (SALOME::SALOME_Exception) +{ + ASSERT(myBaseImpl); + try { + bool isDefault; + return CORBA::string_dup(this->GetImpl()->GetOptionValue(optionName,&isDefault).c_str()); + } catch (const std::invalid_argument& ex) { + THROW_SALOME_CORBA_EXCEPTION( ex.what() ,SALOME::BAD_PARAM ); + } catch (SALOME_Exception& ex) { + THROW_SALOME_CORBA_EXCEPTION( ex.what() ,SALOME::BAD_PARAM ); + } + return 0; +} + +//============================================================================= + +void HYBRIDPlugin_Hypothesis_i::UnsetOption(const char* optionName) { + ASSERT(myBaseImpl); + if ( !GetImpl()->GetOptionValue( optionName ).empty() ) + { + this->GetImpl()->ClearOption(optionName); + SMESH::TPythonDump() << _this() << ".UnsetOption( '" << optionName << "' )"; + } +} + +//============================================================================= + +HYBRIDPlugin::string_array* HYBRIDPlugin_Hypothesis_i::GetOptionValues() +{ + HYBRIDPlugin::string_array_var result = new HYBRIDPlugin::string_array(); + + const ::HYBRIDPlugin_Hypothesis::TOptionValues & opts = this->GetImpl()->GetOptionValues(); + result->length(opts.size()); + int i=0; + + bool isDefault; + ::HYBRIDPlugin_Hypothesis::TOptionValues::const_iterator opIt = opts.begin(); + for (; opIt != opts.end(); ++opIt, ++i) + { + std::string name_value_type = opIt->first; + //if (!opIt->second.empty()) + { + name_value_type += ":"; + name_value_type += GetImpl()->GetOptionValue( opIt->first, &isDefault ); + name_value_type += isDefault ? ":0" : ":1"; + } + result[i] = CORBA::string_dup(name_value_type.c_str()); + } + + return result._retn(); +} + +//============================================================================= + +HYBRIDPlugin::string_array* HYBRIDPlugin_Hypothesis_i::GetAdvancedOptionValues() +{ + HYBRIDPlugin::string_array_var result = new HYBRIDPlugin::string_array(); + + const ::HYBRIDPlugin_Hypothesis::TOptionValues & custom_opts = this->GetImpl()->GetCustomOptionValues(); + result->length(custom_opts.size()); + int i=0; + + ::HYBRIDPlugin_Hypothesis::TOptionValues::const_iterator opIt = custom_opts.begin(); + for (; opIt != custom_opts.end(); ++opIt, ++i) { + std::string name_value_type = opIt->first; + if (!opIt->second.empty()) { + name_value_type += ":"; + name_value_type += opIt->second; + name_value_type += ":1"; // user defined + } + result[i] = CORBA::string_dup(name_value_type.c_str()); + } + return result._retn(); +} + +//============================================================================= + +void HYBRIDPlugin_Hypothesis_i::SetOptionValues(const HYBRIDPlugin::string_array& options) + throw (SALOME::SALOME_Exception) +{ + for (CORBA::ULong i = 0; i < options.length(); ++i) + { + std::string name_value_type = options[i].in(); + if(name_value_type.empty()) + continue; + size_t colonPos = name_value_type.find(':'); + std::string name, value; + if (colonPos == std::string::npos) // ':' not found + name = name_value_type; + else { + name = name_value_type.substr(0, colonPos); + if (colonPos < name_value_type.size() - 1 && name_value_type[colonPos] != ' ') { + std::string value_type = name_value_type.substr(colonPos + 1); + colonPos = value_type.find(':'); + value = value_type.substr(0, colonPos); + if (colonPos < value_type.size() - 1 && value_type[colonPos] != ' ') + if ( value_type.substr(colonPos + 1) == "0" ) // is default + value.clear(); + } + } + SetOptionValue(name.c_str(), value.c_str()); + } +} + +//============================================================================= + +void HYBRIDPlugin_Hypothesis_i::SetAdvancedOptionValues(const HYBRIDPlugin::string_array& options) +{ + SMESH::TPythonDump dump; + + std::string optionsAndValues; + for ( CORBA::ULong i = 0; i < options.length(); ++i) { + std::string name_value_type = options[i].in(); + if(name_value_type.empty()) + continue; + size_t colonPos = name_value_type.find(':'); + std::string name, value; + if (colonPos == std::string::npos) // ':' not found + name = name_value_type; + else { + name = name_value_type.substr(0, colonPos); + if (colonPos < name_value_type.size() - 1 && name_value_type[colonPos] != ' ') { + std::string value_type = name_value_type.substr(colonPos + 1); + colonPos = value_type.find(':'); + value = value_type.substr(0, colonPos); + } + } + AddOption(name.c_str(), value.c_str()); + + optionsAndValues += name + " " + value + " "; + } + + if ( !optionsAndValues.empty() ) + dump << _this() << ".SetAdvancedOptions( '" << optionsAndValues.c_str() << "' )"; +} + +//============================================================================= + +void HYBRIDPlugin_Hypothesis_i::SetAdvancedOption(const char* optionsAndValues) + throw (SALOME::SALOME_Exception) +{ + if ( !optionsAndValues ) return; + + SMESH::TPythonDump dump; + + std::istringstream strm( optionsAndValues ); + std::istream_iterator sIt( strm ), sEnd; + for ( int nbPairs = 0; sIt != sEnd; ++nbPairs ) + { + std::string option = *sIt; + if ( ++sIt != sEnd ) + { + std::string value = *sIt; + ++sIt; + AddOption( option.c_str(), value.c_str() ); + } + else + { + if ( nbPairs > 0 ) + THROW_SALOME_CORBA_EXCEPTION( "Uneven number of options and values" ,SALOME::BAD_PARAM ); + AddOption( option.c_str(), "" ); + } + } + dump << _this() << ".SetAdvancedOption( '" << optionsAndValues << "' )"; +} + +//============================================================================= + +void HYBRIDPlugin_Hypothesis_i::AddOption(const char* optionName, const char* optionValue) +{ + ASSERT(myBaseImpl); + bool valueChanged = ( !this->GetImpl()->HasOptionDefined(optionName) || + this->GetImpl()->GetOptionValue(optionName) != optionValue ); + if (valueChanged) { + this->GetImpl()->SetOptionValue(optionName, optionValue); + SMESH::TPythonDump() << _this() << ".SetOptionValue( '" << optionName << "', '" << optionValue << "' )"; + } +} + +//============================================================================= + +char* HYBRIDPlugin_Hypothesis_i::GetOption(const char* optionName) +{ + ASSERT(myBaseImpl); + return CORBA::string_dup(this->GetImpl()->GetOptionValue(optionName).c_str()); +} + //======================================================================= //function : SetTextOption //======================================================================= @@ -494,18 +818,6 @@ char* HYBRIDPlugin_Hypothesis_i::GetTextOption() return CORBA::string_dup( this->GetImpl()->GetAdvancedOption().c_str() ); } -//======================================================================= -//function : SetAdvancedOption -//======================================================================= -void HYBRIDPlugin_Hypothesis_i::SetAdvancedOption(const char* theOptAndVals ) -{ - if ( theOptAndVals && GetImpl()->GetAdvancedOption() != theOptAndVals ) - { - GetImpl()->SetAdvancedOption( theOptAndVals ); - SMESH::TPythonDump() << _this() << ".SetAdvancedOption( '" << theOptAndVals << "' )"; - } -} - //======================================================================= //function : GetAdvancedOption //======================================================================= @@ -612,7 +924,7 @@ void HYBRIDPlugin_Hypothesis_i::SetElementGeneration(CORBA::Short level) ::HYBRIDPlugin_Hypothesis::ElementGeneration l = (::HYBRIDPlugin_Hypothesis::ElementGeneration) level; if ( l < ::HYBRIDPlugin_Hypothesis::Generation_Tetra_Dominant || - l > ::HYBRIDPlugin_Hypothesis::Generation_Cartesian_Core ) + l > ::HYBRIDPlugin_Hypothesis::Generation_Extrusion_Only ) THROW_SALOME_CORBA_EXCEPTION( "Invalid ElementGeneration mode",SALOME::BAD_PARAM ); ASSERT(myBaseImpl); diff --git a/src/HYBRIDPlugin/HYBRIDPlugin_Hypothesis_i.hxx b/src/HYBRIDPlugin/HYBRIDPlugin_Hypothesis_i.hxx index 9fb85a6..ea4bc7b 100644 --- a/src/HYBRIDPlugin/HYBRIDPlugin_Hypothesis_i.hxx +++ b/src/HYBRIDPlugin/HYBRIDPlugin_Hypothesis_i.hxx @@ -49,12 +49,22 @@ class HYBRIDPLUGIN_EXPORT HYBRIDPlugin_Hypothesis_i: // Destructor virtual ~HYBRIDPlugin_Hypothesis_i(); + /*! + * Sizes of boundary layers are relative to the surface size. Default no + */ + void SetHeightIsRelative( CORBA::Boolean isRelative ); + CORBA::Boolean GetHeightIsRelative(); + /*! + * Maximum internal angles of boundary elements (in degree) + */ + void SetBoundaryLayersMaxElemAngle( CORBA::Double angle ); + CORBA::Double GetBoundaryLayersMaxElemAngle(); /*! * To mesh "holes" in a solid or not. Default is to mesh. */ void SetToMeshHoles(CORBA::Boolean toMesh); CORBA::Boolean GetToMeshHoles(); - /*! + /*! * IDs of faces to grow the layers on */ void SetFacesWithLayers(const SMESH::long_array& faceIDs); @@ -148,10 +158,23 @@ class HYBRIDPLUGIN_EXPORT HYBRIDPlugin_Hypothesis_i: */ void SetToRemoveCentralPoint(CORBA::Boolean toRemove); CORBA::Boolean GetToRemoveCentralPoint(); + + void SetOptionValue(const char* optionName, const char* optionValue) throw (SALOME::SALOME_Exception); + char* GetOptionValue(const char* optionName) throw (SALOME::SALOME_Exception); + void UnsetOption(const char* optionName); + + HYBRIDPlugin::string_array* GetOptionValues(); + HYBRIDPlugin::string_array* GetAdvancedOptionValues(); + + void SetOptionValues(const HYBRIDPlugin::string_array& options) throw (SALOME::SALOME_Exception); + void SetAdvancedOptionValues(const HYBRIDPlugin::string_array& options); + + void AddOption(const char* optionName, const char* optionValue); + char* GetOption(const char* optionName); /*! * To set hiden/undocumented/advanced options */ - void SetAdvancedOption(const char* theOptAndVals ); + void SetAdvancedOption(const char* theOptAndVals ) throw (SALOME::SALOME_Exception); char* GetAdvancedOption(); void SetTextOption(const char* option); char* GetTextOption(); -- 2.39.2