From f899b6e4b56e76e17e2d9341298341e9680e8eec Mon Sep 17 00:00:00 2001 From: eap Date: Wed, 9 Oct 2019 15:45:33 +0300 Subject: [PATCH] #17784 [EDF] MESH-GEMS-2.9.6 Meshers options --- .../images/ghs3d_parameters_advanced.png | Bin 38584 -> 37953 bytes .../images/ghs3d_parameters_basic.png | Bin 17114 -> 34799 bytes .../gui/GHS3DPLUGIN/input/ghs3d_hypo.doc | 213 ++++-- .../GHS3DPLUGIN/input/optimization_hypo.doc | 8 +- idl/GHS3DPlugin_Algorithm.idl | 67 +- src/GHS3DPlugin/GHS3DPluginBuilder.py | 41 +- src/GHS3DPlugin/GHS3DPlugin_Hypothesis.cxx | 608 +++++++++++++++--- src/GHS3DPlugin/GHS3DPlugin_Hypothesis.hxx | 67 +- src/GHS3DPlugin/GHS3DPlugin_Hypothesis_i.cxx | 383 ++++++++++- src/GHS3DPlugin/GHS3DPlugin_Hypothesis_i.hxx | 36 +- .../GHS3DPlugin_OptimizerHypothesis.cxx | 2 +- src/GUI/CMakeLists.txt | 3 + src/GUI/GHS3DPluginGUI_AdvWidget.cxx | 93 ++- src/GUI/GHS3DPluginGUI_AdvWidget_QTD.ui | 128 ++-- src/GUI/GHS3DPluginGUI_Dlg.h | 15 + src/GUI/GHS3DPluginGUI_HypothesisCreator.cxx | 485 +++++++++----- src/GUI/GHS3DPluginGUI_HypothesisCreator.h | 33 +- src/GUI/GHS3DPluginGUI_TreeWidget.cxx | 91 +++ src/GUI/GHS3DPluginGUI_TreeWidget.h | 36 ++ src/GUI/GHS3DPlugin_msg_en.ts | 104 +++ 20 files changed, 1973 insertions(+), 440 deletions(-) create mode 100644 src/GUI/GHS3DPluginGUI_TreeWidget.cxx create mode 100644 src/GUI/GHS3DPluginGUI_TreeWidget.h diff --git a/doc/salome/gui/GHS3DPLUGIN/images/ghs3d_parameters_advanced.png b/doc/salome/gui/GHS3DPLUGIN/images/ghs3d_parameters_advanced.png index 4372e3cc5458cec803efcd51ff0416d00d4778b6..a0bca6ada0636b84e2c24f4269055c1850a58092 100644 GIT binary patch literal 37953 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 diff --git a/doc/salome/gui/GHS3DPLUGIN/images/ghs3d_parameters_basic.png b/doc/salome/gui/GHS3DPLUGIN/images/ghs3d_parameters_basic.png index 8963bd09e7a266281b0d835cf4397b971a8728bc..3ecb4f2c4c8321af4e8d2c9c8342e8ad5ac848c3 100644 GIT binary patch literal 34799 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 A6#xJL literal 17114 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 diff --git a/doc/salome/gui/GHS3DPLUGIN/input/ghs3d_hypo.doc b/doc/salome/gui/GHS3DPLUGIN/input/ghs3d_hypo.doc index 9e29026..af2ab19 100644 --- a/doc/salome/gui/GHS3DPLUGIN/input/ghs3d_hypo.doc +++ b/doc/salome/gui/GHS3DPLUGIN/input/ghs3d_hypo.doc @@ -17,15 +17,6 @@ To get a license, visit http://www.meshgems.com/meshgems-products.html - Name - allows to define the name of the hypothesis (MG-Tetra Parameters by default). -- Mesh holes - if checked, the algorithm will -create mesh in the holes inside a solid shape, else only the outermost -shape will be meshed. Volumic elements created within holes are bound -to the solid. - -- Make groups of domains - if checked, the algorithm will -create groups of just generated elements corresponding to each mesh -domain.
- - Optimization level - allows choosing the required optimization level (higher level of optimization provides better mesh, but can be time-consuming): @@ -40,12 +31,168 @@ but can be time-consuming): - strong +- Minimal size - sets the minimum edge size in the generated mesh. + +- Maximal size - sets the maximum edge size in the generated mesh. + +- Volumic gradation - Defines the volumic ratio between 2 consecutive elements. +WARNING: Changing the default value of this parameter may dramatically +decrease the quality of the resulting mesh. + +- Use volume proximity - activates consideration of distance between opposite surfaces. + + - Number of layers - asks for at least given number of layers of tets between opposite surfaces. + +- Mesh holes - if checked, the algorithm will +create mesh in the holes inside a solid shape, else only the outermost +shape will be meshed. Volumic elements created within holes are bound +to the solid. + +- Make groups of domains - if checked, the algorithm will +create groups of just generated elements corresponding to each mesh +domain.
+ \ref ghs3d_top "Back to top" \section ghs3d_advanced_parameters Advanced parameters \image html ghs3d_parameters_advanced.png +\subsection advanced_meshing_options Advanced meshing options + +Advanced page tab expose mostly useful advanced options. Initially, +default values of the options are displayed and they are not +modifiable. If an option is activated using a check-box, its value +becomes modifiable. + +Add option button 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. + +- Gradation on skin - This option set or not the gradation + value on the initial size of the skin vertices. + + - no the gradation is not applied on the skin vertices. + In this case the initial size of a vertex is the average edges + lenght which belong the vertex. + + - yes the gradation is applied on the skin vertices. In + this case the initial size of a vertex is the average edges + lenght which belong the vertex multiplied by the gradation. + + +- Boundary regeneration - defines the boundary regeneration mode. + MeshGems-Tetra uses alternative strategies for boundary regeneration. + + - standard means that the standard boundary regeneration algorithm is used. + + - safe means that various methods are tried as long as + the regeneration phase fails (including the alternate boundary + recovery mode), can be time consuming and can fail in very + difficult cases. + + - recovery means that the alternate boundary recovery + version is activated. Check Using MeshGems-Tetra with the + boundary recovery module chapter of MG-Tetra User Manual. + +- Force maximum edge size - This option can be used to force + the desired maximum edge size in the generated mesh given by + the Max Size parameter. The default value is no, meaning that + the maximum edge length can be greater than the given value of + the Max Size parameter. + +- Force quadratic mesh - This option permits to write or not an + output mesh file in case of negative Jacobians when generating a + quadratic mesh. Refer to section 4.6.3 for more details. + + - no means that no output is written (this is the default); + + - yes means that an output is written even in case of negative Jacobians. + +- Respect surface mesh - This option forbids or not the + correction of input triangles and enforced edges mid-nodes to make + the element Jacobian strictly positive when generating a quadratic + mesh. + + - yes means that the input triangles and edges mid-nodes + are unchanged, the correction of nodes is only applied in the volume. + + - no means that the input triangles and edges mid-nodes + can be moved. The correction of nodes is applied in the volume + and the mid-nodes correction can be applied on the input + triangles and edges mid-nodes. The corrected surface mid-nodes + are approximated on the surface first, or put on the linear + edges; The corrected edges mid-nodes can be put on the linear + edges. + +- Max number of errors - the error messages will be printed up + to a given maximum number of errors. At least 1 error is printed and + at most 100 errors are printed to prevent infinite loops. + +- Maximal number of threads - This allows to set the maximal + number of threads the software can use in parallel for the + multi-threading optimization mode. + +- No central point - yes prevents adding an internal point at the + centre of gravity of the bounding box that MeshGems-Tetra uses by + default in order to speed up and to simplify the meshing + process. This option can be particularly useful to: + + - generate a volume mesh without internal points at all; + + - in some rare cases, help the boundary regeneration phase when + it failed with the standard options (for example when one + dimension of the domain is large compared to the other two with + a ratio of 20 or more). Use this option when the boundary + regeneration failed with the standard parameters and before + using the recovery version. + +- Optimise worst elements - Applies an optimization processing + to improve the worst quality elements whenever possible. + +- Mode of pthreads - This option sets the optimization mode + when using multithread capabilities. By default, this option is not + activated which means that only a sequential optimization is + performed. + + - safe is slower than the sequential mode, but the + quality of the mesh can only improve; + + - aggressive - is faster than the sequential mode, but + the quality of the resulting mesh may altered compared to the sequential mode. + +- Rectify jacobian - This option activates correction of some + nodes so as to make the Jacobian of element strictly positive when + generating a quadratic mesh. + +- Sliver angle - This options can be used to specify to + MeshGems-Tetra what is considered as a sliver and what is not. The + user has the possibility to specify an angle (in degrees), which + caracterizes a sliver : any tetrahedron which has at least an angle + below this value will be considered as a sliver. + +- Remove overconstrained tetrahedra - This option can be used + to only split the tetrahadra which have at least two facets that + belong to the surface mesh. It will not split the overconstrained + edges in the mesh. The overconstrained tetrahedra are splitting, + whenever possible, which ensures that no tetrahedron has no more + than one boundary facet. + + - no means that no correction is applied; + + - yes means that the correction is applied after mesh generation; + + - only means only correction is applied to an existing mesh. + +- Target quality - Sets the desired maximum target of worst + quality acceptable for the volume mesh used during optimisation + phase. When defined, an optimization processing is applied to + improve the quality until the given target is reached whenever + possible. By default, this option is not activated which means that + only the standard optimisations are performed (the quality target is + the target quality computed by the program). + \subsection memory_settings Memory settings - Maximum memory size - launches MG-Tetra software with @@ -86,54 +233,6 @@ is enabled (there must be a log file to delete it) and Keep all working files of MG-Tetra 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 - -- Create new nodes - if this option is checked off, MG-Tetra -tries to create tetrahedrons using only the nodes of the 2D mesh. - -- Remove the initial central point MG-Tetra adds an internal point -at the gravity center of the bounding box to speed up and to simplify -the meshing process. However, it is possible to refrain from creating -this point by using the command line option -no initial central point. This can be -particularly useful to generate a volume mesh without internal points at all and in some rare cases -at the boundary regeneration phase when it is impossible to proceed -with the standard options -(for example, when one dimension of the domain is more than 20 times greater than the other two). -Use this option if the boundary regeneration has failed with the standard parameters and before using -the recovery version (command line option -C). -Note: when using this option, the speed of the meshing process may -decrease, and the quality may change. -Note: the boundary regeneration may fail with this option, in some rare cases. - -- Use boundary recovery version - enables using a -boundary recovery module which tries to -create volume meshes starting from very poor quality surface meshes -(almost flat triangles on the surface, high density propagation, -extreme aspect ratios, etc.) which fails with the standard version. The -resulting volume mesh will however most likely have a very poor -quality (poor aspect ratio of elements, tetrahedra with a very small -positive volume). - -- Use FEM correction - Applies finite-element correction by -replacing overconstrained elements where it is possible. At first the process -slices the overconstrained edges and at second the overconstrained -facets. This ensures that there are no edges with two boundary -vertices and that there are no facets with three boundary vertices. MG-Tetra gives the initial -and final overconstrained edges and facets. It also gives the facets -which have three edges on the boundary. -Note: when using this option, the speed of the meshing process may -decrease, quality may change, and the smallest volume may be smaller. -By default, the FEM correction is not used. - -- Volumic gradation - Defines the volumic ratio between 2 consecutive elements. -WARNING: Changing the default value of this parameter may dramatically decrease the quality of the resulting mesh. - -- A table at the page bottom allows to input in the command line any text -for MG-Tetra, for example, 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 ghs3d_top "Back to top" \section ghs3d_enforced_vertices Enforced vertices diff --git a/doc/salome/gui/GHS3DPLUGIN/input/optimization_hypo.doc b/doc/salome/gui/GHS3DPLUGIN/input/optimization_hypo.doc index e1868b5..a87bc55 100644 --- a/doc/salome/gui/GHS3DPLUGIN/input/optimization_hypo.doc +++ b/doc/salome/gui/GHS3DPLUGIN/input/optimization_hypo.doc @@ -57,11 +57,11 @@ elements as much as possible. \ref optimization_top "Back to top" -\section ghs3d_advanced_parameters Advanced parameters +\section mgtetra_optim_advanced_parameters Advanced parameters \image html mgtetra_optim_adv_params.png -\subsection memory_settings Memory settings +\subsection mgtetra_optim_memory_settings Memory settings - Initial memory size - starts MG-Tetra software with the specified amount of work space, in Mbytes. If this option is checked off, the @@ -71,7 +71,7 @@ software will be started with 100 Megabytes of working space. work space limited to the specified amount of RAM, in Mbytes. If this option is checked off, the software will be launched with 7O% of the total RAM space. -\subsection log Logs and debug +\subsection mgtetra_optim_log Logs and debug - Working directory - allows defining the folder for input and output files of MG-Tetra software, which are the files starting with "GHS3D_" prefix. @@ -104,7 +104,7 @@ files of MG-Tetra 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 +\subsection mgtetra_optim_advanced_meshing_options Advanced meshing options - A table allows to input in the command line any text for MG-Tetra, for example, advanced options.
diff --git a/idl/GHS3DPlugin_Algorithm.idl b/idl/GHS3DPlugin_Algorithm.idl index bae1d03..752f9e6 100644 --- a/idl/GHS3DPlugin_Algorithm.idl +++ b/idl/GHS3DPlugin_Algorithm.idl @@ -32,6 +32,8 @@ */ module GHS3DPlugin { + typedef sequence string_array; + typedef sequence TCoords; struct GHS3DEnforcedVertex { string name; @@ -71,6 +73,26 @@ module GHS3DPlugin */ void SetToMeshHoles(in boolean toMesh); boolean GetToMeshHoles(); + /*! + *Set lower boundary of mesh element size + */ + void SetMinSize(in double theMinSize); + double GetMinSize(); + /*! + *Set upper boundary of mesh element size + */ + void SetMaxSize(in double theMaxSize); + double GetMaxSize(); + /*! + * Activate/deactivate volume proximity computation + */ + void SetVolumeProximity( in boolean toUse ); + boolean GetVolumeProximity(); + /*! + * Set number of surface element layers to be generated due to volume proximity + */ + void SetNbVolumeProximityLayers( in short nbLayers ); + short GetNbVolumeProximityLayers(); /*! * To make groups of volumes of different domains when mesh is generated from skin. * Default is to make groups. @@ -142,13 +164,6 @@ module GHS3DPlugin */ void SetToRemoveCentralPoint(in boolean toRemove); boolean GetToRemoveCentralPoint(); - /*! - * To set hiden/undocumented/advanced options - */ - void SetAdvancedOption(in string option); - string GetAdvancedOption(); - void SetTextOption(in string option); // obsolete - string GetTextOption(); /*! * To define the volumic gradation */ @@ -164,6 +179,39 @@ module GHS3DPlugin */ void SetRemoveLogOnSuccess(in boolean removeLogOnSuccess); boolean GetRemoveLogOnSuccess(); + /*! + * 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 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(); // 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 set an enforced vertex */ @@ -201,6 +249,11 @@ module GHS3DPlugin * Set/get/unset an enforced vertex (private method for GUI) */ boolean p_SetEnforcedMesh(in SMESH::SMESH_IDSource theSource, in SMESH::ElementType elementType, in string name, in string groupName) raises (SALOME::SALOME_Exception); + + // GUI methods + double GetMaxSizeDefault(); + double GetMinSizeDefault(); + void SetMinMaxSizeDefault( in double theMinSize, in double theMaxSize ); }; /*! diff --git a/src/GHS3DPlugin/GHS3DPluginBuilder.py b/src/GHS3DPlugin/GHS3DPluginBuilder.py index c1b710f..1c58b89 100644 --- a/src/GHS3DPlugin/GHS3DPluginBuilder.py +++ b/src/GHS3DPlugin/GHS3DPluginBuilder.py @@ -88,6 +88,30 @@ class GHS3D_Algorithm(Mesh_Algorithm): pass return self.params + ## Set lower boundary of mesh element size + # Set it to zero to deactivate this option + def SetMinSize(self, theMinSize): + self.Parameters().SetMinSize(theMinSize) + return + + ## Set upper boundary of mesh element size + # Set it to zero to deactivate this option + def SetMaxSize(self, theMaxSize): + self.Parameters().SetMaxSize(theMaxSize) + return + + ## Activate/deactivate volume proximity computation + # + def SetVolumeProximity(self, toUse ): + self.Parameters().SetVolumeProximity(toUse) + return + + ## Set number of surface element layers to be generated due to volume proximity + # + def SetNbVolumeProximityLayers(self, nbLayers ): + self.Parameters().SetNbVolumeProximityLayers(nbLayers) + return + ## To mesh "holes" in a solid or not. Default is to mesh. # @param toMesh "mesh holes" flag value def SetToMeshHoles(self, toMesh): @@ -264,15 +288,22 @@ class GHS3D_Algorithm(Mesh_Algorithm): pass pass - ## Sets command line option as text. - # @param option command line option - def SetTextOption(self, option): - self.Parameters().SetAdvancedOption(option) + ## 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. + # @param optionAndValue command line option in a form "option value" + def SetAdvancedOption(self, optionAndValue): + self.Parameters().SetAdvancedOption(optionAndValue) + pass + + ## OBSOLETE Sets command line option as text. # @param option command line option - def SetAdvancedOption(self, option): + def SetTextOption(self, option): self.Parameters().SetAdvancedOption(option) pass diff --git a/src/GHS3DPlugin/GHS3DPlugin_Hypothesis.cxx b/src/GHS3DPlugin/GHS3DPlugin_Hypothesis.cxx index 892aa70..705c3e4 100644 --- a/src/GHS3DPlugin/GHS3DPlugin_Hypothesis.cxx +++ b/src/GHS3DPlugin/GHS3DPlugin_Hypothesis.cxx @@ -36,6 +36,15 @@ using namespace std; +namespace +{ + struct GET_DEFAULT // struct used to get default value from GetOptionValue() + { + bool isDefault; + operator bool* () { return &isDefault; } + }; +} + //======================================================================= //function : GHS3DPlugin_Hypothesis //======================================================================= @@ -57,21 +66,84 @@ GHS3DPlugin_Hypothesis::GHS3DPlugin_Hypothesis(int hypId, SMESH_Gen * gen) myLogInStandardOutput(DefaultStandardOutputLog()), myRemoveLogOnSuccess( DefaultRemoveLogOnSuccess() ), myGradation(DefaultGradation()), - _enfVertexList(DefaultGHS3DEnforcedVertexList()), - _enfVertexCoordsSizeList(DefaultGHS3DEnforcedVertexCoordsValues()), - _enfVertexEntrySizeList(DefaultGHS3DEnforcedVertexEntryValues()), - _coordsEnfVertexMap(DefaultCoordsGHS3DEnforcedVertexMap()), - _geomEntryEnfVertexMap(DefaultGeomEntryGHS3DEnforcedVertexMap()), - _enfMeshList(DefaultGHS3DEnforcedMeshList()), - _entryEnfMeshMap(DefaultEntryGHS3DEnforcedMeshListMap()), - _enfNodes(TIDSortedNodeGroupMap()), - _enfEdges(TIDSortedElemGroupMap()), - _enfTriangles(TIDSortedElemGroupMap()), - _nodeIDToSizeMap(DefaultID2SizeMap()), - _groupsToRemove(DefaultGroupsToRemove()) + myUseVolumeProximity(DefaultUseVolumeProximity()), + myNbVolumeProximityLayers(DefaultNbVolumeProximityLayers()), + myMinSize(0), + myMinSizeDefault(0), + myMaxSize(0), + myMaxSizeDefault(0) { _name = GetHypType(); _param_algo_dim = 3; + + const char* boolOptionNames[] = { "no_initial_central_point", // no + "force_max_size", // no + "apply_gradation_on_skin_vertex_sizes", // yes + "optimise_worst_elements", // no + "force_output_quadratic_mesh", // no + "rectify_jacobian", // yes + "jacobian_rectification_respect_input_surface_mesh", // yes + "" // mark of end + }; + const char* intOptionNames[] = { "max_number_of_errors_printed", // 1 + "max_number_of_threads", // 4 + "" // mark of end + }; + const char* doubleOptionNames[] = { "target_quality", // 0 + "sliver_angle", // 5 + "" // mark of end + }; + const char* charOptionNames[] = { "pthreads_mode", // "" + "boundary_regeneration", // standard + "split_overconstrained_tetrahedra", // no + "" // 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["no_initial_central_point" ] = "no"; + _defaultOptionValues["force_max_size" ] = "no"; + _defaultOptionValues["apply_gradation_on_skin_vertex_sizes" ] = "yes"; + _defaultOptionValues["optimise_worst_elements" ] = "no"; + _defaultOptionValues["force_output_quadratic_mesh" ] = "no"; + _defaultOptionValues["rectify_jacobian" ] = "yes"; + _defaultOptionValues["jacobian_rectification_respect_input_surface_mesh"] = "yes"; + _defaultOptionValues["max_number_of_errors_printed" ] = "1"; + _defaultOptionValues["max_number_of_threads" ] = "4"; + _defaultOptionValues["target_quality" ] = "";//NoValue(); + _defaultOptionValues["sliver_angle" ] = "5"; + _defaultOptionValues["pthreads_mode" ] = "";//NoValue(); + _defaultOptionValues["boundary_regeneration" ] = "standard"; + _defaultOptionValues["split_overconstrained_tetrahedra" ] = "no"; + +#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 } //======================================================================= @@ -92,11 +164,17 @@ void GHS3DPlugin_Hypothesis::SetToMeshHoles(bool toMesh) bool GHS3DPlugin_Hypothesis::GetToMeshHoles(bool checkFreeOption) const { - if (checkFreeOption && !myTextOption.empty()) { - if ( myTextOption.find("--components all")) - return true; - if ( myTextOption.find("--components outside_components")) - return false; + if ( checkFreeOption ) + { + std::string optionName = "components"; + TOptionValues::const_iterator op_val = _customOption2value.find(optionName); + if ( op_val != _customOption2value.end()) + { + if ( op_val->second.find("all")) + return true; + if ( op_val->second.find("outside_components")) + return false; + } } return myToMeshHoles; } @@ -330,10 +408,8 @@ bool GHS3DPlugin_Hypothesis::GetFEMCorrection() const void GHS3DPlugin_Hypothesis::SetToRemoveCentralPoint(bool toRemove) { - if ( myToRemoveCentralPoint != toRemove ) { - myToRemoveCentralPoint = toRemove; - NotifySubMeshesHypothesisModification(); - } + SetOptionValue( "no_initial_central_point", toRemove ? "yes" : "no" ); + myToRemoveCentralPoint = toRemove; } //======================================================================= @@ -351,9 +427,16 @@ bool GHS3DPlugin_Hypothesis::GetToRemoveCentralPoint() const void GHS3DPlugin_Hypothesis::SetAdvancedOption(const std::string& option) { - if ( myTextOption != option ) { - myTextOption = option; - NotifySubMeshesHypothesisModification(); + size_t wsPos = option.find(' '); + if ( wsPos == string::npos ) + { + SetOptionValue( option, "" ); + } + else + { + std::string opt( option, 0, wsPos ); + std::string val( option, wsPos + 1 ); + SetOptionValue( opt, val ); } } @@ -363,7 +446,23 @@ void GHS3DPlugin_Hypothesis::SetAdvancedOption(const std::string& option) std::string GHS3DPlugin_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; } //======================================================================= @@ -387,6 +486,46 @@ double GHS3DPlugin_Hypothesis::GetGradation() const return myGradation; } +//============================================================================= +void GHS3DPlugin_Hypothesis::SetMinSize(double theMinSize) +{ + if ( theMinSize != myMinSize ) + { + myMinSize = theMinSize; + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +void GHS3DPlugin_Hypothesis::SetMaxSize(double theMaxSize) +{ + if ( theMaxSize != myMaxSize ) + { + myMaxSize = theMaxSize; + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +void GHS3DPlugin_Hypothesis::SetUseVolumeProximity( bool toUse ) +{ + if ( myUseVolumeProximity != toUse ) + { + myUseVolumeProximity = toUse; + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +void GHS3DPlugin_Hypothesis::SetNbVolumeProximityLayers( int nbLayers ) +{ + if ( myNbVolumeProximityLayers != nbLayers ) + { + myNbVolumeProximityLayers = nbLayers; + NotifySubMeshesHypothesisModification(); + } +} + //======================================================================= //function : SetStandardOutputLog //======================================================================= @@ -983,15 +1122,6 @@ bool GHS3DPlugin_Hypothesis::DefaultToRemoveCentralPoint() return false; } -//======================================================================= -//function : DefaultGradation -//======================================================================= - -double GHS3DPlugin_Hypothesis::DefaultGradation() -{ - return 1.05; -} - //======================================================================= //function : DefaultStandardOutputLog //======================================================================= @@ -1030,11 +1160,11 @@ std::ostream & GHS3DPlugin_Hypothesis::SaveTo(std::ostream & save) save << (int)myToRemoveCentralPoint << " "; save << myGradation << " "; save << myToMakeGroupsOfDomains << " "; - if (!myTextOption.empty()) { - save << "__OPTIONS_BEGIN__ "; - save << myTextOption << " "; - save << "__OPTIONS_END__ "; - } + // if (!myTextOption.empty()) { + // save << "__OPTIONS_BEGIN__ "; + // save << myTextOption << " "; + // save << "__OPTIONS_END__ "; + // } TGHS3DEnforcedVertexList::iterator it = _enfVertexList.begin(); @@ -1104,6 +1234,25 @@ std::ostream & GHS3DPlugin_Hypothesis::SaveTo(std::ostream & save) } save << " " << "__ENFORCED_MESHES_END__ "; } + + // New options in 2.9.6 (issue #17784) + + save << " " << myUseVolumeProximity; + save << " " << myNbVolumeProximityLayers; + save << " " << myMinSize; + save << " " << myMaxSize; + save << " " << myMinSizeDefault; + save << " " << myMaxSizeDefault; + + 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; } @@ -1226,15 +1375,15 @@ std::istream & GHS3DPlugin_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); - } + // if (!myTextOption.empty()) { + // // Remove last space + // myTextOption.erase(myTextOption.end()-1); + // } isOK = false; break; } - myTextOption += txt; - myTextOption += " "; + // myTextOption += txt; + // myTextOption += " "; } } } @@ -1427,6 +1576,39 @@ std::istream & GHS3DPlugin_Hypothesis::LoadFrom(std::istream & load) } // while } // if + // New options in 2.9.6 (issue #17784) + + if ( ! hasOptions && ! hasEnforcedVertices && ! hasEnforcedMeshes ) + myUseVolumeProximity = ( separator == "1" ); + else if ( static_cast( load >> i )) + myUseVolumeProximity = (bool) i; + + if ( static_cast( load >> myNbVolumeProximityLayers )) + { + load >> myMinSize; + load >> myMaxSize; + load >> myMinSizeDefault; + load >> myMaxSizeDefault; + + 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; } @@ -1450,6 +1632,11 @@ bool GHS3DPlugin_Hypothesis::SetParametersByDefaults(const TDefaults& dflts, const SMESH_Mesh* /*theMesh*/) { myToMakeGroupsOfDomains = ( !dflts._shape || dflts._shape->IsNull() ); + + double diagonal = dflts._elemLength * _gen->GetBoundaryBoxSegmentation(); + myMinSizeDefault = 1e-3 * diagonal; + myMaxSizeDefault = diagonal / 5.; + return true; } @@ -1465,16 +1652,16 @@ std::string GHS3DPlugin_Hypothesis::CommandToRun(const GHS3DPlugin_Hypothesis* h { std::string cmd = GetExeName(); // check if any option is overridden by hyp->myTextOption - bool max_memory = hyp ? ( hyp->myTextOption.find("--max_memory") == std::string::npos ) : true; - bool auto_memory = hyp ? ( hyp->myTextOption.find("--automatic_memory") == std::string::npos ) : true; - bool comp = hyp ? ( hyp->myTextOption.find("--components") == std::string::npos ) : true; - bool optim_level = hyp ? ( hyp->myTextOption.find("--optimisation_level") == std::string::npos ) : true; - bool no_int_points = hyp ? ( hyp->myTextOption.find("--no_internal_points") == std::string::npos ) : true; - bool C = hyp ? ( hyp->myTextOption.find("-C") == std::string::npos ) : true; - bool verbose = hyp ? ( hyp->myTextOption.find("--verbose") == std::string::npos ) : true; - bool fem = hyp ? ( hyp->myTextOption.find("-FEM")== std::string::npos ) : true; - bool rem = hyp ? ( hyp->myTextOption.find("--no_initial_central_point")== std::string::npos ) : true; - bool gra = hyp ? ( hyp->myTextOption.find("-Dcpropa")== std::string::npos ) : true; + bool max_memory = hyp ? !hyp->HasOptionDefined("max_memory") : true; + bool auto_memory = hyp ? !hyp->HasOptionDefined("automatic_memory") : true; + bool comp = hyp ? !hyp->HasOptionDefined("components") : true; + bool optim_level = hyp ? !hyp->HasOptionDefined("optimisation_level") : true; + bool no_int_points = hyp ? !hyp->HasOptionDefined("no_internal_points") : true; + bool C = hyp ? !hyp->HasOptionDefined("-C") : true; + bool verbose = hyp ? !hyp->HasOptionDefined("verbose") : true; + bool gra = hyp ? !hyp->HasOptionDefined("-Dcpropa") : true; + bool rem = hyp ? !hyp->HasOptionDefined("no_initial_central_point") : true; + //bool fem = hyp ? !hyp->HasOptionDefined("-FEM") : true; // if use boundary recovery version, few options are allowed bool useBndRecovery = !C; @@ -1535,17 +1722,17 @@ std::string GHS3DPlugin_Hypothesis::CommandToRun(const GHS3DPlugin_Hypothesis* h } // boundary recovery version - if ( useBndRecovery ) { - cmd += " -C"; - } + // if ( useBndRecovery ) { + // cmd += " -C"; + // } // to use FEM correction - if ( fem && hyp && hyp->myToUseFemCorrection) { - cmd += " -FEM"; - } + // if ( fem && hyp && hyp->myToUseFemCorrection) { + // cmd += " -FEM"; + // } // to remove initial central point. - if ( rem && hyp && hyp->myToRemoveCentralPoint) { + if ( rem && hyp && hyp->myToRemoveCentralPoint ) { if ( forExecutable ) cmd += " --no_initial_central_point"; else @@ -1553,16 +1740,65 @@ std::string GHS3DPlugin_Hypothesis::CommandToRun(const GHS3DPlugin_Hypothesis* h } // options as text - if ( hyp && !hyp->myTextOption.empty() ) { - cmd += " " + hyp->myTextOption; + // if ( hyp && !hyp->myTextOption.empty() ) { + // cmd += " " + hyp->myTextOption; + // } + + // min/max size + if ( hyp ) + { + if ( hyp->GetMinSize() > 0 ) + cmd += " --min_size " + SMESH_Comment( hyp->GetMinSize() ); + if ( hyp->GetMaxSize() > 0 ) + cmd += " --max_size " + SMESH_Comment( hyp->GetMaxSize() ); } // to define volumic gradation. - if ( gra && hyp ) { - if ( forExecutable ) - cmd += " -Dcpropa=" + SMESH_Comment( hyp->myGradation ); - else - cmd += " --gradation " + SMESH_Comment( hyp->myGradation ); + if ( gra && hyp ) + { + cmd += " --gradation " + SMESH_Comment( hyp->myGradation ); + } + + if ( hyp ) + { + // proximity + if ( hyp->GetUseVolumeProximity() ) + { + cmd += " --volume_proximity_layers " + SMESH_Comment( hyp->GetNbVolumeProximityLayers() ); + } + + 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() )//value == NoValue() ) + { + if ( hyp->_defaultOptionValues.count( option )) + continue; // non-custom option with no value + //value.clear(); + } + if ( strncmp( "no", option.c_str(), 2 ) == 0 ) // options w/o values: --no_* + { + if ( !value.empty() && ToBool( value ) == false ) + continue; + value.clear(); + } + if ( option[0] != '-' ) + cmd += " --"; + else + cmd += " "; + cmd += option + " " + value; + } + } } #ifdef WIN32 @@ -1616,50 +1852,264 @@ std::string GHS3DPlugin_Hypothesis::GetExeName() GHS3DPlugin_Hypothesis::TGHS3DEnforcedVertexList GHS3DPlugin_Hypothesis::GetEnforcedVertices(const GHS3DPlugin_Hypothesis* hyp) { - return hyp ? hyp->_GetEnforcedVertices():DefaultGHS3DEnforcedVertexList(); + return hyp ? hyp->_GetEnforcedVertices(): TGHS3DEnforcedVertexList(); } GHS3DPlugin_Hypothesis::TGHS3DEnforcedVertexCoordsValues GHS3DPlugin_Hypothesis::GetEnforcedVerticesCoordsSize (const GHS3DPlugin_Hypothesis* hyp) { - return hyp ? hyp->_GetEnforcedVerticesCoordsSize(): DefaultGHS3DEnforcedVertexCoordsValues(); + return hyp ? hyp->_GetEnforcedVerticesCoordsSize(): TGHS3DEnforcedVertexCoordsValues(); } GHS3DPlugin_Hypothesis::TGHS3DEnforcedVertexEntryValues GHS3DPlugin_Hypothesis::GetEnforcedVerticesEntrySize (const GHS3DPlugin_Hypothesis* hyp) { - return hyp ? hyp->_GetEnforcedVerticesEntrySize(): DefaultGHS3DEnforcedVertexEntryValues(); + return hyp ? hyp->_GetEnforcedVerticesEntrySize(): TGHS3DEnforcedVertexEntryValues(); } GHS3DPlugin_Hypothesis::TCoordsGHS3DEnforcedVertexMap GHS3DPlugin_Hypothesis::GetEnforcedVerticesByCoords (const GHS3DPlugin_Hypothesis* hyp) { - return hyp ? hyp->_GetEnforcedVerticesByCoords(): DefaultCoordsGHS3DEnforcedVertexMap(); + return hyp ? hyp->_GetEnforcedVerticesByCoords(): TCoordsGHS3DEnforcedVertexMap(); } GHS3DPlugin_Hypothesis::TGeomEntryGHS3DEnforcedVertexMap GHS3DPlugin_Hypothesis::GetEnforcedVerticesByEntry (const GHS3DPlugin_Hypothesis* hyp) { - return hyp ? hyp->_GetEnforcedVerticesByEntry(): DefaultGeomEntryGHS3DEnforcedVertexMap(); + return hyp ? hyp->_GetEnforcedVerticesByEntry(): TGeomEntryGHS3DEnforcedVertexMap(); } GHS3DPlugin_Hypothesis::TIDSortedNodeGroupMap GHS3DPlugin_Hypothesis::GetEnforcedNodes(const GHS3DPlugin_Hypothesis* hyp) { - return hyp ? hyp->_GetEnforcedNodes():DefaultIDSortedNodeGroupMap(); + return hyp ? hyp->_GetEnforcedNodes():TIDSortedNodeGroupMap(); } GHS3DPlugin_Hypothesis::TIDSortedElemGroupMap GHS3DPlugin_Hypothesis::GetEnforcedEdges(const GHS3DPlugin_Hypothesis* hyp) { - return hyp ? hyp->_GetEnforcedEdges():DefaultIDSortedElemGroupMap(); + return hyp ? hyp->_GetEnforcedEdges():TIDSortedElemGroupMap(); } GHS3DPlugin_Hypothesis::TIDSortedElemGroupMap GHS3DPlugin_Hypothesis::GetEnforcedTriangles(const GHS3DPlugin_Hypothesis* hyp) { - return hyp ? hyp->_GetEnforcedTriangles():DefaultIDSortedElemGroupMap(); + return hyp ? hyp->_GetEnforcedTriangles():TIDSortedElemGroupMap(); } GHS3DPlugin_Hypothesis::TID2SizeMap GHS3DPlugin_Hypothesis::GetNodeIDToSizeMap(const GHS3DPlugin_Hypothesis* hyp) { - return hyp ? hyp->_GetNodeIDToSizeMap(): DefaultID2SizeMap(); + return hyp ? hyp->_GetNodeIDToSizeMap(): TID2SizeMap(); } GHS3DPlugin_Hypothesis::TSetStrings GHS3DPlugin_Hypothesis::GetGroupsToRemove(const GHS3DPlugin_Hypothesis* hyp) { - return hyp ? hyp->_GetGroupsToRemove(): DefaultGroupsToRemove(); + return hyp ? hyp->_GetGroupsToRemove(): TSetStrings(); } + + +//============================================================================= +void GHS3DPlugin_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 GHS3DPlugin_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 GHS3DPlugin_Hypothesis::HasOptionDefined( const std::string& optionName ) const +{ + bool isDefault = false; + try + { + GetOptionValue( optionName, &isDefault ); + } + catch ( std::invalid_argument ) + { + return false; + } + return !isDefault; +} + +//============================================================================= +void GHS3DPlugin_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(); + } +} + +//============================================================================= +GHS3DPlugin_Hypothesis::TOptionValues GHS3DPlugin_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 GHS3DPlugin_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 GHS3DPlugin_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 Converts a string to a integer value + */ +//================================================================================ + +int GHS3DPlugin_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; +} + diff --git a/src/GHS3DPlugin/GHS3DPlugin_Hypothesis.hxx b/src/GHS3DPlugin/GHS3DPlugin_Hypothesis.hxx index 77cde27..667c8eb 100644 --- a/src/GHS3DPlugin/GHS3DPlugin_Hypothesis.hxx +++ b/src/GHS3DPlugin/GHS3DPlugin_Hypothesis.hxx @@ -119,6 +119,19 @@ public: typedef std::set TSetStrings; static const char* GetHypType() { return "MG-Tetra Parameters"; } + + void SetMinSize(double theMinSize); + double GetMinSize() const { return myMinSize; } + + void SetMaxSize(double theMaxSize); + double GetMaxSize() const { return myMaxSize; } + + void SetUseVolumeProximity( bool toUse ); + bool GetUseVolumeProximity() const { return myUseVolumeProximity; } + + void SetNbVolumeProximityLayers( int nbLayers ); + int GetNbVolumeProximityLayers() const { return myNbVolumeProximityLayers; } + /*! * To mesh "holes" in a solid or not. Default is to mesh. */ @@ -215,6 +228,19 @@ public: void SetRemoveLogOnSuccess(bool removeLogOnSuccess); bool GetRemoveLogOnSuccess() const ; + + 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 inline const char* NoValue() { return "_"; } // struct TEnforcedEdge { // long ID; @@ -302,24 +328,15 @@ public: static bool DefaultToRemoveCentralPoint(); static bool DefaultStandardOutputLog(); static bool DefaultRemoveLogOnSuccess(); - static double DefaultGradation(); - - static TGHS3DEnforcedVertex DefaultGHS3DEnforcedVertex() {return TGHS3DEnforcedVertex();} - static TGHS3DEnforcedVertexList DefaultGHS3DEnforcedVertexList() {return TGHS3DEnforcedVertexList();} - static TGHS3DEnforcedVertexCoordsValues DefaultGHS3DEnforcedVertexCoordsValues() {return TGHS3DEnforcedVertexCoordsValues();} - static TGHS3DEnforcedVertexEntryValues DefaultGHS3DEnforcedVertexEntryValues() {return TGHS3DEnforcedVertexEntryValues();} - static TCoordsGHS3DEnforcedVertexMap DefaultCoordsGHS3DEnforcedVertexMap() {return TCoordsGHS3DEnforcedVertexMap();} - static TGeomEntryGHS3DEnforcedVertexMap DefaultGeomEntryGHS3DEnforcedVertexMap() {return TGeomEntryGHS3DEnforcedVertexMap();} - static TGroupNameGHS3DEnforcedVertexMap DefaultGroupNameGHS3DEnforcedVertexMap() {return TGroupNameGHS3DEnforcedVertexMap();} - - static TGHS3DEnforcedMesh DefaultGHS3DEnforcedMesh() {return TGHS3DEnforcedMesh();} - static TGHS3DEnforcedMeshList DefaultGHS3DEnforcedMeshList() {return TGHS3DEnforcedMeshList();} - static TEntryGHS3DEnforcedMeshListMap DefaultEntryGHS3DEnforcedMeshListMap() {return TEntryGHS3DEnforcedMeshListMap();} - static TIDSortedNodeGroupMap DefaultIDSortedNodeGroupMap() {return TIDSortedNodeGroupMap();} - static TIDSortedElemGroupMap DefaultIDSortedElemGroupMap() {return TIDSortedElemGroupMap();} - static TID2SizeMap DefaultID2SizeMap() {return TID2SizeMap();} - static TSetStrings DefaultGroupsToRemove() {return TSetStrings();} - + static inline double DefaultGradation() { return 1.05; } + static bool DefaultUseVolumeProximity() { return false; } + static int DefaultNbVolumeProximityLayers() { return 2; } + + void SetMinMaxSizeDefault( double theMinSize, double theMaxSize ) + { myMinSizeDefault = theMinSize; myMaxSizeDefault = theMaxSize; } + double GetMinSizeDefault() const { return myMinSizeDefault; } + double GetMaxSizeDefault() const { return myMaxSizeDefault; } + // Persistence virtual std::ostream & SaveTo(std::ostream & save); virtual std::istream & LoadFrom(std::istream & load); @@ -334,6 +351,10 @@ public: */ virtual bool SetParametersByDefaults(const TDefaults& dflts, const SMESH_Mesh* theMesh=0); + 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); + protected: bool myToMeshHoles; @@ -350,9 +371,17 @@ protected: bool myToRemoveCentralPoint; bool myLogInStandardOutput; bool myRemoveLogOnSuccess; - std::string myTextOption; double myGradation; + bool myUseVolumeProximity; + int myNbVolumeProximityLayers; + double myMinSize, myMinSizeDefault; + double myMaxSize, myMaxSizeDefault; + //std::string myTextOption; + TOptionValues _option2value, _customOption2value; // user defined values + TOptionValues _defaultOptionValues; // default values + TOptionNames _doubleOptions, _charOptions, _boolOptions; // to find a type of option + TGHS3DEnforcedVertexList _enfVertexList; TGHS3DEnforcedVertexCoordsValues _enfVertexCoordsSizeList; TGHS3DEnforcedVertexEntryValues _enfVertexEntrySizeList; diff --git a/src/GHS3DPlugin/GHS3DPlugin_Hypothesis_i.cxx b/src/GHS3DPlugin/GHS3DPlugin_Hypothesis_i.cxx index b686ff5..38babcd 100644 --- a/src/GHS3DPlugin/GHS3DPlugin_Hypothesis_i.cxx +++ b/src/GHS3DPlugin/GHS3DPlugin_Hypothesis_i.cxx @@ -31,12 +31,8 @@ #include #include #include -//#include #include -// SALOME KERNEL includes -// #include -// #include using namespace std; @@ -82,6 +78,92 @@ CORBA::Boolean GHS3DPlugin_Hypothesis_i::GetToMeshHoles() return this->GetImpl()->GetToMeshHoles(); } +//============================================================================= +void GHS3DPlugin_Hypothesis_i::SetMinSize(CORBA::Double theMinSize) +{ + if ( GetMinSize() != theMinSize ) { + this->GetImpl()->SetMinSize( theMinSize ); + SMESH::TPythonDump() << _this() << ".SetMinSize( " << theMinSize << " )"; + } +} + +//============================================================================= +CORBA::Double GHS3DPlugin_Hypothesis_i::GetMinSize() +{ + return this->GetImpl()->GetMinSize(); +} + +//============================================================================= +CORBA::Double GHS3DPlugin_Hypothesis_i::GetMinSizeDefault() +{ + return this->GetImpl()->GetMinSizeDefault(); +} + +//============================================================================= +void GHS3DPlugin_Hypothesis_i::SetMaxSize(CORBA::Double theMaxSize) +{ + if ( GetMaxSize() != theMaxSize ) { + this->GetImpl()->SetMaxSize( theMaxSize ); + SMESH::TPythonDump() << _this() << ".SetMaxSize( " << theMaxSize << " )"; + } +} + +//============================================================================= +CORBA::Double GHS3DPlugin_Hypothesis_i::GetMaxSize() +{ + return this->GetImpl()->GetMaxSize(); +} + +//============================================================================= +CORBA::Double GHS3DPlugin_Hypothesis_i::GetMaxSizeDefault() +{ + return this->GetImpl()->GetMaxSizeDefault(); +} + +//============================================================================= +void GHS3DPlugin_Hypothesis_i::SetMinMaxSizeDefault( CORBA::Double theMinSize, + CORBA::Double theMaxSize ) +{ + this->GetImpl()->SetMinMaxSizeDefault( theMinSize, theMaxSize ); +} + +//============================================================================= +/*! + * Activate/deactivate volume proximity computation + */ +void GHS3DPlugin_Hypothesis_i::SetVolumeProximity( CORBA::Boolean toUse ) +{ + if ( GetVolumeProximity() != toUse ) + { + this->GetImpl()->SetUseVolumeProximity( toUse ); + SMESH::TPythonDump() << _this() << ".SetVolumeProximity( " << toUse << " )"; + } +} + +CORBA::Boolean GHS3DPlugin_Hypothesis_i::GetVolumeProximity() +{ + return this->GetImpl()->GetUseVolumeProximity(); +} + + +//============================================================================= +/*! + * Set number of surface element layers to be generated due to volume proximity + */ +void GHS3DPlugin_Hypothesis_i::SetNbVolumeProximityLayers( CORBA::Short nbLayers ) +{ + if ( GetNbVolumeProximityLayers() != nbLayers ) + { + this->GetImpl()->SetNbVolumeProximityLayers( nbLayers ); + SMESH::TPythonDump() << _this() << ".SetNbVolumeProximityLayers( " << nbLayers << " )"; + } +} + +CORBA::Short GHS3DPlugin_Hypothesis_i::GetNbVolumeProximityLayers() +{ + return this->GetImpl()->GetNbVolumeProximityLayers(); +} + //======================================================================= //function : SetToMakeGroupsOfDomains //======================================================================= @@ -349,9 +431,7 @@ CORBA::Boolean GHS3DPlugin_Hypothesis_i::GetToRemoveCentralPoint() void GHS3DPlugin_Hypothesis_i::SetTextOption(const char* option) { - ASSERT(myBaseImpl); - this->GetImpl()->SetAdvancedOption(option); - SMESH::TPythonDump() << _this() << ".SetAdvancedOption( '" << option << "' )"; + SetAdvancedOption(option); } //======================================================================= @@ -360,20 +440,19 @@ void GHS3DPlugin_Hypothesis_i::SetTextOption(const char* option) char* GHS3DPlugin_Hypothesis_i::GetTextOption() { - ASSERT(myBaseImpl); - return CORBA::string_dup( this->GetImpl()->GetAdvancedOption().c_str() ); + return GetAdvancedOption(); } //======================================================================= //function : SetAdvancedOption //======================================================================= -void GHS3DPlugin_Hypothesis_i::SetAdvancedOption(const char* option) -{ - ASSERT(myBaseImpl); - this->GetImpl()->SetAdvancedOption(option); - SMESH::TPythonDump() << _this() << ".SetAdvancedOption( '" << option << "' )"; -} +// void GHS3DPlugin_Hypothesis_i::SetAdvancedOption(const char* option) +// { +// ASSERT(myBaseImpl); +// this->GetImpl()->SetAdvancedOption(option); +// SMESH::TPythonDump() << _this() << ".SetAdvancedOption( '" << option << "' )"; +// } //======================================================================= //function : GetAdvancedOption @@ -385,8 +464,278 @@ char* GHS3DPlugin_Hypothesis_i::GetAdvancedOption() return CORBA::string_dup( this->GetImpl()->GetAdvancedOption().c_str() ); } +//============================================================================= + +void GHS3DPlugin_Hypothesis_i::SetOptionValue(const char* optionName, const char* optionValue) + throw (SALOME::SALOME_Exception) +{ + ASSERT(myBaseImpl); + try { + std::string name( optionName ); + if ( !optionValue || !optionValue[0] ) + UnsetOption( optionName ); + + // basic options (visible in Advanced table) + + 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 == "no_initial_central_point" && // optimizer + strcmp( GetImpl()->GetName(), ::GHS3DPlugin_Hypothesis::GetHypType() ) != 0 ) + { + //if ( strcmp( optionValue, ::GHS3DPlugin_Hypothesis::NoValue() ) == 0 ) + if ( !optionValue[0] ) + SetToRemoveCentralPoint( true ); + else + SetToRemoveCentralPoint( GetImpl()->ToBool( optionValue )); + } + else if ( name == "no_internal_points" && // optimizer + strcmp( GetImpl()->GetName(), ::GHS3DPlugin_Hypothesis::GetHypType() ) != 0) + { + //if ( strcmp( optionValue, ::GHS3DPlugin_Hypothesis::NoValue() ) == 0 ) + if ( !optionValue[0] ) + SetToRemoveCentralPoint( true ); + else + SetToCreateNewNodes( GetImpl()->ToBool( optionValue )); + } + else if ( name == "min_size" ) + SetMinSize( GetImpl()->ToDbl( optionValue )); + + else if ( name == "max_size" ) + SetMaxSize( GetImpl()->ToDbl( optionValue )); + + else if ( name == "gradation" ) + SetGradation( GetImpl()->ToDbl( optionValue )); + + else if ( name == "volume_proximity_layers" ) + SetNbVolumeProximityLayers( GetImpl()->ToInt( optionValue )); + + else if ( name == "components" ) + SetToMeshHoles( strncmp( "all", optionValue, 3 ) == 0 ); + + // 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* GHS3DPlugin_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 GHS3DPlugin_Hypothesis_i::UnsetOption(const char* optionName) { + ASSERT(myBaseImpl); + if ( !GetImpl()->GetOptionValue( optionName ).empty() ) + { + this->GetImpl()->ClearOption(optionName); + SMESH::TPythonDump() << _this() << ".UnsetOption( '" << optionName << "' )"; + } +} + +//============================================================================= + +GHS3DPlugin::string_array* GHS3DPlugin_Hypothesis_i::GetOptionValues() +{ + GHS3DPlugin::string_array_var result = new GHS3DPlugin::string_array(); + + const ::GHS3DPlugin_Hypothesis::TOptionValues & opts = this->GetImpl()->GetOptionValues(); + result->length(opts.size()); + int i=0; + + bool isDefault; + ::GHS3DPlugin_Hypothesis::TOptionValues::const_iterator opIt = opts.begin(); + for (; opIt != opts.end(); ++opIt, ++i) + { + 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(); +} + +//============================================================================= + +GHS3DPlugin::string_array* GHS3DPlugin_Hypothesis_i::GetAdvancedOptionValues() +{ + GHS3DPlugin::string_array_var result = new GHS3DPlugin::string_array(); + + const ::GHS3DPlugin_Hypothesis::TOptionValues & custom_opts = this->GetImpl()->GetCustomOptionValues(); + result->length(custom_opts.size()); + int i=0; + + ::GHS3DPlugin_Hypothesis::TOptionValues::const_iterator opIt = custom_opts.begin(); + for (; opIt != custom_opts.end(); ++opIt, ++i) { + 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 GHS3DPlugin_Hypothesis_i::SetOptionValues(const GHS3DPlugin::string_array& options) + throw (SALOME::SALOME_Exception) +{ + for (CORBA::ULong i = 0; i < options.length(); ++i) + { + string name_value_type = options[i].in(); + if(name_value_type.empty()) + continue; + size_t colonPos = name_value_type.find(':'); + string name, value; + if (colonPos == 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] != ' ') { + 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 GHS3DPlugin_Hypothesis_i::SetAdvancedOptionValues(const GHS3DPlugin::string_array& options) +{ + SMESH::TPythonDump dump; + + string optionsAndValues; + for ( CORBA::ULong i = 0; i < options.length(); ++i) { + string name_value_type = options[i].in(); + if(name_value_type.empty()) + continue; + size_t colonPos = name_value_type.find(':'); + string name, value; + if (colonPos == 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] != ' ') { + 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 GHS3DPlugin_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 GHS3DPlugin_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* GHS3DPlugin_Hypothesis_i::GetOption(const char* optionName) +{ + ASSERT(myBaseImpl); + return CORBA::string_dup(this->GetImpl()->GetOptionValue(optionName).c_str()); +} + //======================================================================= -//function : SetToRemoveCentralPoint +//function : SetGradation //======================================================================= void GHS3DPlugin_Hypothesis_i::SetGradation(CORBA::Double gradation) @@ -399,7 +748,7 @@ void GHS3DPlugin_Hypothesis_i::SetGradation(CORBA::Double gradation) } //======================================================================= -//function : GetToRemoveCentralPoint +//function : GetGradation //======================================================================= CORBA::Double GHS3DPlugin_Hypothesis_i::GetGradation() diff --git a/src/GHS3DPlugin/GHS3DPlugin_Hypothesis_i.hxx b/src/GHS3DPlugin/GHS3DPlugin_Hypothesis_i.hxx index 2860543..37f1a86 100644 --- a/src/GHS3DPlugin/GHS3DPlugin_Hypothesis_i.hxx +++ b/src/GHS3DPlugin/GHS3DPlugin_Hypothesis_i.hxx @@ -54,6 +54,22 @@ class GHS3DPLUGIN_EXPORT GHS3DPlugin_Hypothesis_i: */ void SetToMeshHoles(CORBA::Boolean toMesh); CORBA::Boolean GetToMeshHoles(); + /*! + * Activate/deactivate volume proximity computation + */ + void SetVolumeProximity( CORBA::Boolean toUse ); + CORBA::Boolean GetVolumeProximity(); + /*! + * Set number of surface element layers to be generated due to volume proximity + */ + void SetNbVolumeProximityLayers( CORBA::Short nbLayers ); + CORBA::Short GetNbVolumeProximityLayers(); + + void SetMaxSize(CORBA::Double theMaxSize); + CORBA::Double GetMaxSize(); + + void SetMinSize(CORBA::Double theMinSize); + CORBA::Double GetMinSize(); /*! * To make groups of volumes of different domains when mesh is generated from skin. * Default is to make groups. @@ -126,10 +142,23 @@ class GHS3DPLUGIN_EXPORT GHS3DPlugin_Hypothesis_i: /*! * To set hiden/undocumented/advanced options */ - void SetAdvancedOption(const char* option); + void SetAdvancedOption(const char* option) throw (SALOME::SALOME_Exception); char* GetAdvancedOption(); void SetTextOption(const char* option); // obsolete char* GetTextOption(); + + 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); + + GHS3DPlugin::string_array* GetOptionValues(); + GHS3DPlugin::string_array* GetAdvancedOptionValues(); + + void SetOptionValues(const GHS3DPlugin::string_array& options) throw (SALOME::SALOME_Exception); + void SetAdvancedOptionValues(const GHS3DPlugin::string_array& options); + + void AddOption(const char* optionName, const char* optionValue); + char* GetOption(const char* optionName); /*! * To define the volumic gradation */ @@ -179,6 +208,11 @@ class GHS3DPLUGIN_EXPORT GHS3DPlugin_Hypothesis_i: GHS3DPlugin::GHS3DEnforcedMeshList* GetEnforcedMeshes(); void ClearEnforcedMeshes(); + // 3 GUI methods + CORBA::Double GetMaxSizeDefault(); + CORBA::Double GetMinSizeDefault(); + void SetMinMaxSizeDefault( CORBA::Double theMinSize, CORBA::Double theMaxSize ); + // Get implementation ::GHS3DPlugin_Hypothesis* GetImpl(); diff --git a/src/GHS3DPlugin/GHS3DPlugin_OptimizerHypothesis.cxx b/src/GHS3DPlugin/GHS3DPlugin_OptimizerHypothesis.cxx index 1ad894f..d4b2961 100644 --- a/src/GHS3DPlugin/GHS3DPlugin_OptimizerHypothesis.cxx +++ b/src/GHS3DPlugin/GHS3DPlugin_OptimizerHypothesis.cxx @@ -195,7 +195,7 @@ std::string GHS3DPlugin_OptimizerHypothesis::CommandToRun(const GHS3DPlugin_Opti cmd << " --verbose " << hyp->myVerboseLevel; - cmd << " " << hyp->myTextOption; + //cmd << " " << hyp->myTextOption; } return cmd; diff --git a/src/GUI/CMakeLists.txt b/src/GUI/CMakeLists.txt index 1665d35..e381f5f 100644 --- a/src/GUI/CMakeLists.txt +++ b/src/GUI/CMakeLists.txt @@ -33,6 +33,7 @@ INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR} ${PROJECT_BINARY_DIR}/idl ${PROJECT_SOURCE_DIR}/src/GHS3DPlugin + ${PROJECT_SOURCE_DIR}/src/GUI ) # additional preprocessor / compiler flags @@ -65,6 +66,7 @@ SET(_link_LIBRARIES SET(_moc_HEADERS GHS3DPluginGUI_HypothesisCreator.h GHS3DPluginGUI_Dlg.h + GHS3DPluginGUI_TreeWidget.h ) # header files / no moc processed @@ -84,6 +86,7 @@ SET(_other_SOURCES GHS3DPluginGUI.cxx GHS3DPluginGUI_HypothesisCreator.cxx GHS3DPluginGUI_AdvWidget.cxx + GHS3DPluginGUI_TreeWidget.cxx ) # --- resources --- diff --git a/src/GUI/GHS3DPluginGUI_AdvWidget.cxx b/src/GUI/GHS3DPluginGUI_AdvWidget.cxx index 18a79bf..a29f5eb 100644 --- a/src/GUI/GHS3DPluginGUI_AdvWidget.cxx +++ b/src/GUI/GHS3DPluginGUI_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; + } + }; +} ////////////////////////////////////////// // GHS3DPluginGUI_AdvWidget @@ -38,9 +54,84 @@ GHS3DPluginGUI_AdvWidget::GHS3DPluginGUI_AdvWidget( QWidget* parent, Qt::WindowF : QWidget( parent, f ) { setupUi( this ); - advOptionTable->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 ))); } GHS3DPluginGUI_AdvWidget::~GHS3DPluginGUI_AdvWidget() { } + +void GHS3DPluginGUI_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 == GHS3DPlugin_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 GHS3DPluginGUI_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 = GHS3DPlugin_Hypothesis::NoValue(); +} + + +void GHS3DPluginGUI_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/GHS3DPluginGUI_AdvWidget_QTD.ui b/src/GUI/GHS3DPluginGUI_AdvWidget_QTD.ui index e589dc5..dea16fe 100644 --- a/src/GUI/GHS3DPluginGUI_AdvWidget_QTD.ui +++ b/src/GUI/GHS3DPluginGUI_AdvWidget_QTD.ui @@ -6,24 +6,67 @@ 0 0 - 485 - 477 + 337 + 369 Form - - - 0 - - - 0 - - - 0 - - + + + + + QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed + + + true + + + + OPTION_NAME_COLUMN + + + + 50 + false + + + + + + OPTION_VALUE_COLUMN + + + + 50 + false + + + + + + + + + GHS3D_ADD_OPTION + + + + + + + Qt::Horizontal + + + + 188 + 20 + + + + + Memory settings @@ -104,7 +147,7 @@ - + Logs and debug @@ -178,56 +221,6 @@ - - - - Advanced meshing options - - - - - - Use FEM correction - - - - - - - Remove initial central point - - - - - - - - - - Volumic gradation - - - - - - - Create new nodes - - - - - - - Use boundary recovery version - - - - - - - - - @@ -237,10 +230,9 @@

SMESHGUI_SpinBox.h
- SMESH_AdvOptionsWdg - QWidget -
SMESH_AdvOptionsWdg.h
- 1 + GHS3DPluginGUI_TreeWidget + QTreeWidget +
GHS3DPluginGUI_TreeWidget.h
diff --git a/src/GUI/GHS3DPluginGUI_Dlg.h b/src/GUI/GHS3DPluginGUI_Dlg.h index a647e3d..dbd491d 100644 --- a/src/GUI/GHS3DPluginGUI_Dlg.h +++ b/src/GUI/GHS3DPluginGUI_Dlg.h @@ -23,6 +23,14 @@ #ifndef GHS3DPLUGINGUI_H #define GHS3DPLUGINGUI_H +enum { + OPTION_ID_COLUMN = 0, + OPTION_TYPE_COLUMN, + OPTION_NAME_COLUMN = 0, + OPTION_VALUE_COLUMN, + NB_COLUMNS, +}; + ////////////////////////////////////////// // GHS3DPluginGUI_AdvWidget ////////////////////////////////////////// @@ -38,6 +46,13 @@ class GHS3DPLUGINGUI_EXPORT GHS3DPluginGUI_AdvWidget : public QWidget, public: GHS3DPluginGUI_AdvWidget( QWidget* = 0, Qt::WindowFlags = 0 ); ~GHS3DPluginGUI_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/GHS3DPluginGUI_HypothesisCreator.cxx b/src/GUI/GHS3DPluginGUI_HypothesisCreator.cxx index 452397b..2183f96 100644 --- a/src/GUI/GHS3DPluginGUI_HypothesisCreator.cxx +++ b/src/GUI/GHS3DPluginGUI_HypothesisCreator.cxx @@ -294,7 +294,25 @@ void EnforcedMeshTableWidgetDelegate::updateEditorGeometry(QWidget *editor, GHS3DPluginGUI_HypothesisCreator::GHS3DPluginGUI_HypothesisCreator( const QString& theHypType ) - : SMESHGUI_GenericHypothesisCreator( theHypType ) + : SMESHGUI_GenericHypothesisCreator( theHypType ), + myName(0), + myOptimizationLevelCombo(0), + myMinSizeCheck(0), + myMaxSizeCheck(0), + myMinSizeSpin(0), + myMaxSizeSpin(0), + myGradationCheck(0), + myGradationSpin(0), + myUseProximityGroup(0), + myNbProximityLayers(0), + myToMakeGroupsOfDomains(0), + myToMeshHolesCheck(0), + myOptimizationCombo(0), + mySplitOverConstrainedCombo(0), + myPThreadsModeCombo(0), + myNumberOfThreadsSpin(0), + mySmoothOffSliversCheck(0), + myCreateNewNodesCheck(0) { GeomToolSelected = NULL; GeomToolSelected = getGeomSelectionTool(); @@ -354,73 +372,127 @@ QFrame* GHS3DPluginGUI_HypothesisCreator::buildFrame() aStdLayout->setMargin( 11 ); int row = 0; - myName = 0; if ( isCreation() ) { aStdLayout->addWidget( new QLabel( tr( "SMESH_NAME" ), myStdGroup ), row, 0, 1, 1 ); myName = new QLineEdit( myStdGroup ); aStdLayout->addWidget( myName, row++, 1, 1, 1 ); } - - myToMeshHolesCheck = new QCheckBox( tr( "GHS3D_TO_MESH_HOLES" ), myStdGroup ); - aStdLayout->addWidget( myToMeshHolesCheck, row, 0, 1, 1 ); - myToMakeGroupsOfDomains = new QCheckBox( tr( "GHS3D_TO_MAKE_DOMAIN_GROUPS" ), myStdGroup ); - aStdLayout->addWidget( myToMakeGroupsOfDomains, row++, 1, 1, 1 ); - - QLabel* optimizationLbl = new QLabel( tr( "GHS3D_OPTIMIZATION" ), myStdGroup ); - aStdLayout->addWidget( optimizationLbl, row, 0, 1, 1 ); - myOptimizationCombo = getModeCombo( myStdGroup, false ); - aStdLayout->addWidget( myOptimizationCombo, row++, 1, 1, 1 ); - - QLabel* optimizatiolLevelLbl = new QLabel( tr( "GHS3D_OPTIMIZATIOL_LEVEL" ), myStdGroup ); - aStdLayout->addWidget( optimizatiolLevelLbl, row, 0, 1, 1 ); - myOptimizationLevelCombo = new QComboBox( myStdGroup ); - aStdLayout->addWidget( myOptimizationLevelCombo, row++, 1, 1, 1 ); - - QLabel* splitOverconstrainedLbl = new QLabel( tr("GHS3D_SPLIT_OVERCONSTRAINED"), myStdGroup ); - aStdLayout->addWidget( splitOverconstrainedLbl, row, 0, 1, 1 ); - mySplitOverConstrainedCombo = getModeCombo( myStdGroup, false ); - aStdLayout->addWidget( mySplitOverConstrainedCombo, row++, 1, 1, 1 ); - - QLabel* pthreadsModeLbl = new QLabel( tr( "GHS3D_PTHREADS_MODE" ), myStdGroup); - aStdLayout->addWidget( pthreadsModeLbl, row, 0, 1, 1 ); - myPThreadsModeCombo = getModeCombo( myStdGroup, true ); - aStdLayout->addWidget( myPThreadsModeCombo, row++, 1, 1, 1 ); - - QLabel* nbThreadsLbl = new QLabel( tr( "GHS3D_NB_THREADS" ), myStdGroup); - aStdLayout->addWidget( nbThreadsLbl, row, 0, 1, 1 ); - myNumberOfThreadsSpin = new SalomeApp_IntSpinBox( 0, 1000, 1, myStdGroup ); - aStdLayout->addWidget( myNumberOfThreadsSpin, row++, 1, 1, 1 ); - - mySmoothOffSliversCheck = new QCheckBox( tr( "GHS3D_SMOOTH_OFF_SLIVERS" ), myStdGroup ); - aStdLayout->addWidget( mySmoothOffSliversCheck, row, 0, 1, 1 ); - myCreateNewNodesCheck = new QCheckBox( tr( "TO_ADD_NODES" ), myStdGroup ); - aStdLayout->addWidget( myCreateNewNodesCheck, row++, 1, 1, 1 ); - - myOptimizationLevelCombo->addItems( QStringList() - << tr( "LEVEL_NONE" ) << tr( "LEVEL_LIGHT" ) - << tr( "LEVEL_MEDIUM" ) << tr( "LEVEL_STANDARDPLUS" ) - << tr( "LEVEL_STRONG" )); - aStdLayout->setRowStretch( row, 10 ); - if ( isOptimization() ) { - myToMeshHolesCheck->hide(); - myToMakeGroupsOfDomains->hide(); + myToMeshHolesCheck = new QCheckBox( tr( "GHS3D_TO_MESH_HOLES" ), myStdGroup ); + aStdLayout->addWidget( myToMeshHolesCheck, row, 0, 1, 1 ); + myToMakeGroupsOfDomains = new QCheckBox( tr( "GHS3D_TO_MAKE_DOMAIN_GROUPS" ), myStdGroup ); + aStdLayout->addWidget( myToMakeGroupsOfDomains, row++, 1, 1, 1 ); + + QLabel* optimizationLbl = new QLabel( tr( "GHS3D_OPTIMIZATION" ), myStdGroup ); + aStdLayout->addWidget( optimizationLbl, row, 0, 1, 1 ); + myOptimizationCombo = getModeCombo( myStdGroup, false ); + aStdLayout->addWidget( myOptimizationCombo, row++, 1, 1, 1 ); + + QLabel* optimizatiolLevelLbl = new QLabel( tr( "GHS3D_OPTIMIZATIOL_LEVEL" ), myStdGroup ); + aStdLayout->addWidget( optimizatiolLevelLbl, row, 0, 1, 1 ); + myOptimizationLevelCombo = new QComboBox( myStdGroup ); + aStdLayout->addWidget( myOptimizationLevelCombo, row++, 1, 1, 1 ); + + QLabel* splitOverconstrainedLbl = new QLabel( tr("GHS3D_SPLIT_OVERCONSTRAINED"), myStdGroup ); + aStdLayout->addWidget( splitOverconstrainedLbl, row, 0, 1, 1 ); + mySplitOverConstrainedCombo = getModeCombo( myStdGroup, false ); + aStdLayout->addWidget( mySplitOverConstrainedCombo, row++, 1, 1, 1 ); + + QLabel* pthreadsModeLbl = new QLabel( tr( "GHS3D_PTHREADS_MODE" ), myStdGroup); + aStdLayout->addWidget( pthreadsModeLbl, row, 0, 1, 1 ); + myPThreadsModeCombo = getModeCombo( myStdGroup, true ); + aStdLayout->addWidget( myPThreadsModeCombo, row++, 1, 1, 1 ); + + QLabel* nbThreadsLbl = new QLabel( tr( "GHS3D_NB_THREADS" ), myStdGroup); + aStdLayout->addWidget( nbThreadsLbl, row, 0, 1, 1 ); + myNumberOfThreadsSpin = new SalomeApp_IntSpinBox( 0, 1000, 1, myStdGroup ); + aStdLayout->addWidget( myNumberOfThreadsSpin, row++, 1, 1, 1 ); + + mySmoothOffSliversCheck = new QCheckBox( tr( "GHS3D_SMOOTH_OFF_SLIVERS" ), myStdGroup ); + aStdLayout->addWidget( mySmoothOffSliversCheck, row, 0, 1, 1 ); + myCreateNewNodesCheck = new QCheckBox( tr( "TO_ADD_NODES" ), myStdGroup ); + aStdLayout->addWidget( myCreateNewNodesCheck, row++, 1, 1, 1 ); } else { - optimizationLbl->hide(); - myOptimizationCombo->hide(); - splitOverconstrainedLbl->hide(); - mySplitOverConstrainedCombo->hide(); - pthreadsModeLbl->hide(); - myPThreadsModeCombo->hide(); - nbThreadsLbl->hide(); - myNumberOfThreadsSpin->hide(); - mySmoothOffSliversCheck->hide(); - myCreateNewNodesCheck->hide(); + // Main parameters + + QGroupBox* mainGroup = new QGroupBox( tr("GHS3D_MAIN_PARAMS"), myStdGroup ); + QLabel* optimizatiolLevelLbl = new QLabel( tr( "GHS3D_OPTIMIZATIOL_LEVEL" ), mainGroup ); + myOptimizationLevelCombo = new QComboBox( mainGroup ); + myMinSizeCheck = new QCheckBox( tr("GHS3D_MIN_SIZE"), mainGroup ); + myMaxSizeCheck = new QCheckBox( tr("GHS3D_MAX_SIZE"), mainGroup ); + myMinSizeSpin = new SMESHGUI_SpinBox( mainGroup ); + myMaxSizeSpin = new SMESHGUI_SpinBox( mainGroup ); + myMinSizeCheck->setChecked( false ); + myMaxSizeCheck->setChecked( false ); + myMinSizeSpin->RangeStepAndValidator(0, COORD_MAX, 10.0, "length_precision"); + myMaxSizeSpin->RangeStepAndValidator(0, COORD_MAX, 10.0, "length_precision"); + myMinSizeSpin->setEnabled( false ); + myMaxSizeSpin->setEnabled( false ); + connect( myMinSizeCheck, SIGNAL( toggled(bool)), myMinSizeSpin, SLOT( setEnabled(bool))); + connect( myMaxSizeCheck, SIGNAL( toggled(bool)), myMaxSizeSpin, SLOT( setEnabled(bool))); + + QGridLayout* mainLayout = new QGridLayout( mainGroup ); + mainLayout->setSpacing( 6 ); + mainLayout->setMargin( 11 ); + mainLayout->addWidget( optimizatiolLevelLbl, 0, 0, 1, 1 ); + mainLayout->addWidget( myOptimizationLevelCombo, 0, 1, 1, 1 ); + mainLayout->addWidget( myMinSizeCheck, 1, 0, 1, 1 ); + mainLayout->addWidget( myMinSizeSpin, 1, 1, 1, 1 ); + mainLayout->addWidget( myMaxSizeCheck, 2, 0, 1, 1 ); + mainLayout->addWidget( myMaxSizeSpin, 2, 1, 1, 1 ); + + // Volume proximity + + QGroupBox* proxyGroup = new QGroupBox( tr("GHS3D_VOLUME_PROXIMITY"), myStdGroup ); + myGradationCheck = new QCheckBox( tr("GHS3D_GRADATION"), proxyGroup ); + myGradationSpin = new SMESHGUI_SpinBox( proxyGroup ); + myGradationSpin->RangeStepAndValidator(1, COORD_MAX, 0.1, "length_precision"); + myGradationSpin->setEnabled( false ); + connect( myGradationCheck, SIGNAL( toggled(bool)), myGradationSpin, SLOT( setEnabled(bool))); + myUseProximityGroup = new QGroupBox( tr("GHS3D_USE_VOLUME_PROXIMITY"), proxyGroup ); + myUseProximityGroup->setCheckable( true ); + //myUseProximityGroup->setChecked( false ); + QLabel* nbProximityLayersLabel = new QLabel( tr("GHS3D_NB_LAYERS")); + myNbProximityLayers = new SalomeApp_IntSpinBox( 2, 1e6, 1, proxyGroup ); + + QHBoxLayout* useProxyLayout = new QHBoxLayout( myUseProximityGroup ); + useProxyLayout->addWidget( nbProximityLayersLabel ); + useProxyLayout->addWidget( myNbProximityLayers ); + + QGridLayout* proxyLayout = new QGridLayout( proxyGroup ); + proxyLayout->setSpacing( 6 ); + proxyLayout->setMargin( 11 ); + proxyLayout->addWidget( myGradationCheck, 0, 0, 1, 1 ); + proxyLayout->addWidget( myGradationSpin, 0, 1, 1, 1 ); + proxyLayout->addWidget( myUseProximityGroup, 1, 0, 1, 2 ); + + // Other parameters + + QGroupBox* otherGroup = new QGroupBox( tr("GHS3D_OTHER_PARAMETERS"), myStdGroup ); + myToMeshHolesCheck = new QCheckBox( tr( "GHS3D_TO_MESH_HOLES" ), otherGroup ); + myToMakeGroupsOfDomains = new QCheckBox( tr( "GHS3D_TO_MAKE_DOMAIN_GROUPS" ), otherGroup ); + + QGridLayout* otherLayout = new QGridLayout( otherGroup ); + otherLayout->setSpacing( 6 ); + otherLayout->setMargin( 11 ); + otherLayout->addWidget( myToMeshHolesCheck, 0, 0 ); + otherLayout->addWidget( myToMakeGroupsOfDomains, 1, 0 ); + + + aStdLayout->addWidget( mainGroup, row++, 0, 1, 2 ); + aStdLayout->addWidget( proxyGroup, row++, 0, 1, 2 ); + aStdLayout->addWidget( otherGroup, row++, 0, 1, 2 ); } + aStdLayout->setRowStretch( row, 10 ); + + myOptimizationLevelCombo->addItems( QStringList() + << tr( "LEVEL_NONE" ) << tr( "LEVEL_LIGHT" ) + << tr( "LEVEL_MEDIUM" ) << tr( "LEVEL_STANDARDPLUS" ) + << tr( "LEVEL_STRONG" )); // advanced parameters myAdvGroup = new QWidget(); @@ -451,24 +523,24 @@ QFrame* GHS3DPluginGUI_HypothesisCreator::buildFrame() myAdvWidget->memoryGroupBox ->setTitle(tr( "MEMORY_GROUP_TITLE" )); myAdvWidget->logGroupBox ->setTitle(tr( "LOG_GROUP_TITLE" )); - myAdvWidget->advancedMeshingGroupBox ->setTitle(tr( "ADVANCED_MESHING_GROUP_TITLE" )); + //myAdvWidget->advancedMeshingGroupBox ->setTitle(tr( "ADVANCED_MESHING_GROUP_TITLE" )); - 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( "GHS3D_GRADATION" )); - myAdvWidget->gradationSpinBox->RangeStepAndValidator(0.0, 5.0, 0.05, "length_precision"); - - if ( isOptimization() ) - { - myAdvWidget->createNewNodesCheck->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( "GHS3D_GRADATION" )); + // myAdvWidget->gradationSpinBox->RangeStepAndValidator(0.0, 5.0, 0.05, "length_precision"); + + // if ( isOptimization() ) + // { + // myAdvWidget->createNewNodesCheck->hide(); + // myAdvWidget->removeInitialCentralPointCheck->hide(); + // myAdvWidget->boundaryRecoveryCheck->hide(); + // myAdvWidget->FEMCorrectionCheck->hide(); + // myAdvWidget->gradationLabel->hide(); + // myAdvWidget->gradationSpinBox->hide(); + // } // Enforced vertices parameters myEnfGroup = new QWidget(); @@ -619,10 +691,10 @@ QFrame* GHS3DPluginGUI_HypothesisCreator::buildFrame() 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( 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() ) ); + connect( myAdvWidget->addBtn, SIGNAL( clicked() ), this, SLOT( onAddOption() ) ); connect( myEnforcedTableWidget, SIGNAL( itemClicked(QTableWidgetItem *)), this, SLOT( synchronizeCoords() ) ); connect( myEnforcedTableWidget, SIGNAL( itemChanged(QTableWidgetItem *)), this, SLOT( updateEnforcedVertexValues(QTableWidgetItem *) ) ); @@ -769,12 +841,12 @@ void GHS3DPluginGUI_HypothesisCreator::onSelectEnforcedVertex() myEnfVertex = myEnfVertexWdg->GetObject< GEOM::GEOM_Object >(nbSelEnfVertex-1); if (myEnfVertex == GEOM::GEOM_Object::_nil()) return; - if (myEnfVertex->GetShapeType() == GEOM::VERTEX) { - GHS3DPluginGUI_HypothesisCreator* that = (GHS3DPluginGUI_HypothesisCreator*)this; + if (myEnfVertex->GetShapeType() == GEOM::VERTEX) + { GEOM::GEOM_IMeasureOperations_var measureOp = getGeomEngine()->GetIMeasureOperations( ); if (CORBA::is_nil(measureOp)) return; - + CORBA::Double x,y,z; measureOp->PointCoordinates (myEnfVertex, x, y, z); if ( measureOp->IsDone() ) @@ -1309,15 +1381,14 @@ void GHS3DPluginGUI_HypothesisCreator::updateWidgets() { //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() ); + //myAdvWidget->initialMemoryCheck->setEnabled( !myAdvWidget->boundaryRecoveryCheck->isChecked() ); + myAdvWidget->initialMemorySpin->setEnabled( myAdvWidget->initialMemoryCheck->isChecked() /*&& !myAdvWidget->boundaryRecoveryCheck->isChecked()*/ ); + //myOptimizationLevelCombo->setEnabled( !myAdvWidget->boundaryRecoveryCheck->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 ); } } @@ -1331,7 +1402,43 @@ bool GHS3DPluginGUI_HypothesisCreator::checkParams(QString& msg) const return false; } - return true; + GHS3DPlugin::GHS3DPlugin_Hypothesis_var h = + GHS3DPlugin::GHS3DPlugin_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 GHS3DPluginGUI_HypothesisCreator::retrieveParams() const @@ -1351,31 +1458,49 @@ void GHS3DPluginGUI_HypothesisCreator::retrieveParams() const myToMeshHolesCheck ->setChecked ( data.myToMeshHoles ); myToMakeGroupsOfDomains ->setChecked ( data.myToMakeGroupsOfDomains ); myOptimizationLevelCombo ->setCurrentIndex( data.myOptimizationLevel ); - myOptimizationCombo ->setCurrentIndex( data.myOptimization ); - mySplitOverConstrainedCombo ->setCurrentIndex( data.mySplitOverConstrained ); - myPThreadsModeCombo ->setCurrentIndex( data.myPThreadsMode ); - myNumberOfThreadsSpin ->setValue ( data.myNumberOfThreads ); - mySmoothOffSliversCheck ->setChecked ( data.mySmoothOffSlivers ); - myCreateNewNodesCheck ->setChecked ( data.myToCreateNewNodes ); - + if ( myOptimizationCombo ) // optimizer + { + myOptimizationCombo ->setCurrentIndex( data.myOptimization ); + mySplitOverConstrainedCombo ->setCurrentIndex( data.mySplitOverConstrained ); + myPThreadsModeCombo ->setCurrentIndex( data.myPThreadsMode ); + myNumberOfThreadsSpin ->setValue ( data.myNumberOfThreads ); + mySmoothOffSliversCheck ->setChecked ( data.mySmoothOffSlivers ); + myCreateNewNodesCheck ->setChecked ( data.myToCreateNewNodes ); + } + else + { + myMinSizeSpin->setValue( data.myMinSize ); + myMinSizeCheck->setChecked( data.myUseMinSize ); + myMaxSizeSpin->setValue( data.myMaxSize ); + myMaxSizeCheck->setChecked( data.myUseMaxSize ); + myGradationCheck->setChecked( data.myUseGradation ); + myGradationSpin->setValue( data.myUseGradation ? data.myGradation : GHS3DPlugin_Hypothesis::DefaultGradation() ); + myUseProximityGroup->setChecked( data.myUseProximity ); + myNbProximityLayers->setValue( data.myNbProximityLayers ); + } myAdvWidget->maxMemoryCheck ->setChecked ( data.myMaximumMemory > 0 ); - myAdvWidget->maxMemorySpin ->setValue ( qMax( data.myMaximumMemory, - (float)myAdvWidget->maxMemorySpin->minimum() )); + myAdvWidget->maxMemorySpin ->setValue + ( qMax( data.myMaximumMemory, (float)myAdvWidget->maxMemorySpin->minimum() )); myAdvWidget->initialMemoryCheck ->setChecked ( data.myInitialMemory > 0 ); - myAdvWidget->initialMemorySpin ->setValue ( qMax( data.myInitialMemory, - (float)myAdvWidget->initialMemorySpin->minimum() )); + myAdvWidget->initialMemorySpin ->setValue + ( qMax( data.myInitialMemory, (float)myAdvWidget->initialMemorySpin->minimum() )); 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->advOptionTable ->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(); @@ -1535,20 +1660,17 @@ QString GHS3DPluginGUI_HypothesisCreator::storeParams() const if ( data.myRemoveInitialCentralPoint ) valStr += " --no_initial_central_point"; - if ( data.myBoundaryRecovery ) - valStr += " -C"; + // if ( data.myBoundaryRecovery ) + // valStr += " -C"; - if ( data.myFEMCorrection ) - valStr += " -FEM"; + // if ( data.myFEMCorrection ) + // valStr += " -FEM"; if ( data.myGradation != 1.05 ) { valStr += " -Dcpropa="; valStr += QString::number( data.myGradation ); } - valStr += " "; - valStr += data.myTextOption; - return valStr; } @@ -1570,31 +1692,47 @@ bool GHS3DPluginGUI_HypothesisCreator::readParamsFromHypo( GHS3DHypothesisData& h_data.myNumberOfThreads = opt->GetMaximalNumberOfThreads(); h_data.mySmoothOffSlivers = opt->GetSmoothOffSlivers(); } - else // avoid "Conditional jump or move depends on uninitialised value" error + else { + // avoid "Conditional jump or move depends on uninitialised value" error h_data.myOptimization = 1; h_data.mySplitOverConstrained = 1; h_data.myPThreadsMode = 1; h_data.myNumberOfThreads = 1; h_data.mySmoothOffSlivers = 1; } + h_data.myOptimizationLevel = h->GetOptimizationLevel(); + h_data.myMinSize = h->GetMinSize(); + h_data.myMaxSize = h->GetMaxSize(); + this->myMinSizeDefault = h->GetMinSizeDefault(); + this->myMaxSizeDefault = h->GetMaxSizeDefault(); + if ( ! ( h_data.myUseMinSize = h_data.myMinSize > 0 )) + h_data.myMinSize = this->myMinSizeDefault; + if ( ! ( h_data.myUseMaxSize = h_data.myMaxSize > 0 )) + h_data.myMaxSize = this->myMaxSizeDefault; + h_data.myNbProximityLayers = h->GetNbVolumeProximityLayers(); + h_data.myUseGradation = h->GetGradation() != GHS3DPlugin_Hypothesis::DefaultGradation(); + h_data.myUseProximity = h->GetVolumeProximity(); h_data.myToMeshHoles = h->GetToMeshHoles(); h_data.myToMakeGroupsOfDomains = h->GetToMakeGroupsOfDomains(); h_data.myMaximumMemory = h->GetMaximumMemory(); h_data.myInitialMemory = h->GetInitialMemory(); h_data.myInitialMemory = h->GetInitialMemory(); - 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.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.myTextOption = h->GetAdvancedOption(); h_data.myLogInStandardOutput = h->GetStandardOutputLog(); h_data.myRemoveLogOnSuccess = h->GetRemoveLogOnSuccess(); + + GHS3DPluginGUI_HypothesisCreator* that = (GHS3DPluginGUI_HypothesisCreator*)this; + that->myOptions = h->GetOptionValues(); + that->myCustomOptions = h->GetAdvancedOptionValues(); GHS3DPlugin::GHS3DEnforcedVertexList_var vertices = h->GetEnforcedVertices(); h_data.myEnforcedVertices.clear(); @@ -1651,43 +1789,31 @@ bool GHS3DPluginGUI_HypothesisCreator::storeParamsToHypo( const GHS3DHypothesisD if( isCreation() ) SMESH::SetName( SMESH::FindSObject( h ), h_data.myName.toLatin1().constData() ); - 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->GetKeepFiles() != h_data.myKeepFiles ) - h->SetKeepFiles ( h_data.myKeepFiles ); - if ( h->GetWorkingDirectory() != h_data.myWorkingDir ) - 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->GetAdvancedOption() != 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 ) - h->SetRemoveLogOnSuccess( h_data.myRemoveLogOnSuccess ); + h->SetOptimizationLevel ( h_data.myOptimizationLevel ); + h->SetMinSize ( h_data.myUseMinSize ? h_data.myMinSize : 0 ); + h->SetMaxSize ( h_data.myUseMaxSize ? h_data.myMaxSize : 0 ); + h->SetMinMaxSizeDefault ( this->myMinSizeDefault, this->myMaxSizeDefault ); + h->SetGradation ( h_data.myGradation ); + h->SetVolumeProximity ( h_data.myUseProximity ); + h->SetNbVolumeProximityLayers ( h_data.myNbProximityLayers ); + h->SetToMeshHoles ( h_data.myToMeshHoles ); + h->SetToMakeGroupsOfDomains ( h_data.myToMakeGroupsOfDomains ); + + h->SetMaximumMemory ( h_data.myMaximumMemory ); + h->SetInitialMemory ( h_data.myInitialMemory ); + h->SetInitialMemory ( h_data.myInitialMemory ); + h->SetKeepFiles ( h_data.myKeepFiles ); + h->SetWorkingDirectory ( h_data.myWorkingDir.toLatin1().constData() ); + h->SetVerboseLevel ( h_data.myVerboseLevel ); + //h->SetToRemoveCentralPoint ( h_data.myRemoveInitialCentralPoint ); + //h->SetToUseBoundaryRecoveryVersion( h_data.myBoundaryRecovery ); + //h->SetFEMCorrection ( h_data.myFEMCorrection ); + h->SetStandardOutputLog ( h_data.myLogInStandardOutput ); + h->SetRemoveLogOnSuccess ( h_data.myRemoveLogOnSuccess ); if ( !opt->_is_nil() ) { + opt->SetToCreateNewNodes ( h_data.myToCreateNewNodes ); opt->SetOptimization ( (GHS3DPlugin::Mode) h_data.myOptimization ); opt->SetSplitOverConstrained ( (GHS3DPlugin::Mode) h_data.mySplitOverConstrained ); opt->SetPThreadsMode ( (GHS3DPlugin::PThreadsMode) h_data.myPThreadsMode ); @@ -1750,7 +1876,7 @@ bool GHS3DPluginGUI_HypothesisCreator::storeParamsToHypo( const GHS3DHypothesisD default: break; } - + ok = h->p_SetEnforcedMesh(theSource, elementType, enfMesh->name.c_str(), enfMesh->groupName.c_str()); } // for } // try @@ -1764,32 +1890,38 @@ bool GHS3DPluginGUI_HypothesisCreator::storeParamsToHypo( const GHS3DHypothesisD bool GHS3DPluginGUI_HypothesisCreator::readParamsFromWidgets( GHS3DHypothesisData& h_data ) const { - h_data.myName = myName ? myName->text() : ""; - h_data.myToMeshHoles = myToMeshHolesCheck->isChecked(); - h_data.myToMakeGroupsOfDomains = myToMakeGroupsOfDomains->isChecked(); - h_data.myOptimization = myOptimizationCombo->currentIndex(); - h_data.myOptimizationLevel = myOptimizationLevelCombo->currentIndex(); - h_data.mySplitOverConstrained = mySplitOverConstrainedCombo->currentIndex(); - h_data.myPThreadsMode = myPThreadsModeCombo->currentIndex(); - h_data.myNumberOfThreads = myNumberOfThreadsSpin->value(); - h_data.mySmoothOffSlivers = mySmoothOffSliversCheck->isChecked(); - h_data.myMaximumMemory = myAdvWidget->maxMemoryCheck->isChecked() ? myAdvWidget->maxMemorySpin->value() : -1; - h_data.myInitialMemory = myAdvWidget->initialMemoryCheck->isChecked() ? myAdvWidget->initialMemorySpin->value() : -1; - h_data.myKeepFiles = myAdvWidget->keepWorkingFilesCheck->isChecked(); - h_data.myWorkingDir = myAdvWidget->workingDirectoryLineEdit->text().trimmed(); - h_data.myVerboseLevel = myAdvWidget->verboseLevelSpin->value(); - 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->advOptionTable->GetCustomOptions(); - h_data.myLogInStandardOutput = !myAdvWidget->logInFileCheck->isChecked(); - h_data.myRemoveLogOnSuccess = myAdvWidget->removeLogOnSuccessCheck->isChecked(); - if ( isOptimization() ) - h_data.myToCreateNewNodes = myCreateNewNodesCheck->isChecked(); + h_data.myName = myName ? myName->text() : ""; + h_data.myOptimizationLevel = myOptimizationLevelCombo->currentIndex(); + if ( mySplitOverConstrainedCombo ) // optimizer + { + h_data.myToCreateNewNodes = myCreateNewNodesCheck->isChecked(); + h_data.myOptimization = myOptimizationCombo->currentIndex(); + h_data.mySplitOverConstrained = mySplitOverConstrainedCombo->currentIndex(); + h_data.myPThreadsMode = myPThreadsModeCombo->currentIndex(); + h_data.myNumberOfThreads = myNumberOfThreadsSpin->value(); + h_data.mySmoothOffSlivers = mySmoothOffSliversCheck->isChecked(); + } else - h_data.myToCreateNewNodes = myAdvWidget->createNewNodesCheck->isChecked(); - + { + h_data.myMinSize = myMinSizeSpin->value(); + h_data.myMaxSize = myMaxSizeSpin->value(); + h_data.myUseMinSize = myMinSizeCheck->isChecked(); + h_data.myUseMaxSize = myMaxSizeCheck->isChecked(); + h_data.myGradation = myGradationSpin->value(); + h_data.myUseGradation = myGradationCheck->isChecked(); + h_data.myUseProximity = myUseProximityGroup->isChecked(); + h_data.myNbProximityLayers = myNbProximityLayers->value(); + 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.myKeepFiles = myAdvWidget->keepWorkingFilesCheck->isChecked(); + h_data.myWorkingDir = myAdvWidget->workingDirectoryLineEdit->text().trimmed(); + h_data.myVerboseLevel = myAdvWidget->verboseLevelSpin->value(); + h_data.myLogInStandardOutput = !myAdvWidget->logInFileCheck->isChecked(); + h_data.myRemoveLogOnSuccess = myAdvWidget->removeLogOnSuccessCheck->isChecked(); + // Enforced vertices h_data.myEnforcedVertices.clear(); QVariant valueX, valueY, valueZ; @@ -1848,3 +1980,8 @@ QString GHS3DPluginGUI_HypothesisCreator::helpPage() const { return isOptimization() ? "optimization_page.html" : "ghs3d_hypo_page.html"; } + +void GHS3DPluginGUI_HypothesisCreator::onAddOption() +{ + myAdvWidget->AddOption( NULL, true ); +} diff --git a/src/GUI/GHS3DPluginGUI_HypothesisCreator.h b/src/GUI/GHS3DPluginGUI_HypothesisCreator.h index 4f979dc..6437f41 100644 --- a/src/GUI/GHS3DPluginGUI_HypothesisCreator.h +++ b/src/GUI/GHS3DPluginGUI_HypothesisCreator.h @@ -56,6 +56,7 @@ class QSpinBox; class QTableWidget; class QTableWidgetItem; class QHeaderView; +class QGroupBox; class GHS3DPluginGUI_AdvWidget; class LightApp_SelectionMgr; @@ -142,13 +143,16 @@ typedef std::set< TEnfMesh*, CompareEnfMeshes > TEnfMeshList; typedef struct { - bool myToMeshHoles,myToMakeGroupsOfDomains,myKeepFiles,myToCreateNewNodes,myBoundaryRecovery,myFEMCorrection,myRemoveInitialCentralPoint, - myLogInStandardOutput, myRemoveLogOnSuccess; - float myMaximumMemory; - float myInitialMemory; int myOptimizationLevel; - QString myName,myWorkingDir,myTextOption; + double myMinSize, myMaxSize, myMinSizeDefault, myMaxSizeDefault; double myGradation; + int myNbProximityLayers; + bool myUseMinSize, myUseMaxSize, myUseGradation, myUseProximity; + bool myToMeshHoles, myToMakeGroupsOfDomains; + bool myToCreateNewNodes,myBoundaryRecovery,myFEMCorrection,myRemoveInitialCentralPoint, + myKeepFiles,myLogInStandardOutput, myRemoveLogOnSuccess; + float myInitialMemory, myMaximumMemory; + QString myName,myWorkingDir; short myVerboseLevel; TEnfVertexList myEnforcedVertices; TEnfMeshList myEnforcedMeshes; @@ -182,6 +186,7 @@ protected: virtual QString type() const; protected slots: + void onAddOption(); void onToMeshHoles(bool); void onDirBtnClicked(); void updateWidgets(); @@ -219,9 +224,21 @@ private: private: QWidget* myStdGroup; QLineEdit* myName; - QCheckBox* myToMeshHolesCheck; - QCheckBox* myToMakeGroupsOfDomains; + // main QComboBox* myOptimizationLevelCombo; + QCheckBox* myMinSizeCheck; + QCheckBox* myMaxSizeCheck; + SMESHGUI_SpinBox* myMinSizeSpin; + SMESHGUI_SpinBox* myMaxSizeSpin; + mutable double myMinSizeDefault, myMaxSizeDefault; + // proximity + QCheckBox* myGradationCheck; + SMESHGUI_SpinBox* myGradationSpin; + QGroupBox* myUseProximityGroup; + SalomeApp_IntSpinBox* myNbProximityLayers; + // other + QCheckBox* myToMakeGroupsOfDomains; + QCheckBox* myToMeshHolesCheck; QComboBox* myOptimizationCombo; QComboBox* mySplitOverConstrainedCombo; @@ -232,6 +249,8 @@ private: QWidget* myAdvGroup; GHS3DPluginGUI_AdvWidget* myAdvWidget; + mutable GHS3DPlugin::string_array_var myOptions, myCustomOptions; + QWidget* myEnfGroup; QPixmap iconVertex, iconCompound; diff --git a/src/GUI/GHS3DPluginGUI_TreeWidget.cxx b/src/GUI/GHS3DPluginGUI_TreeWidget.cxx new file mode 100644 index 0000000..8511275 --- /dev/null +++ b/src/GUI/GHS3DPluginGUI_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 "GHS3DPluginGUI_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 ); + } +} + +GHS3DPluginGUI_TreeWidget::GHS3DPluginGUI_TreeWidget( QWidget* parent ) + : QTreeWidget( parent ) +{ +} + +QModelIndex GHS3DPluginGUI_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 GHS3DPluginGUI_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/GHS3DPluginGUI_TreeWidget.h b/src/GUI/GHS3DPluginGUI_TreeWidget.h new file mode 100644 index 0000000..e80b3e2 --- /dev/null +++ b/src/GUI/GHS3DPluginGUI_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(GHS3DPluginGUI_TreeWidget_H) +#define GHS3DPluginGUI_TreeWidget_H + +#include + +class GHS3DPluginGUI_TreeWidget : public QTreeWidget +{ + Q_OBJECT +public: + GHS3DPluginGUI_TreeWidget( QWidget* ); + +protected: + QModelIndex moveCursor( CursorAction, Qt::KeyboardModifiers ); + void keyPressEvent( QKeyEvent* ); +}; + +#endif // GHS3DPluginGUI_TreeWidget_H diff --git a/src/GUI/GHS3DPlugin_msg_en.ts b/src/GUI/GHS3DPlugin_msg_en.ts index b90dc6d..5271493 100644 --- a/src/GUI/GHS3DPlugin_msg_en.ts +++ b/src/GUI/GHS3DPlugin_msg_en.ts @@ -279,5 +279,109 @@ GHS3D_SMOOTH_OFF_SLIVERS Smooth off sliver elements + + OPTION_TYPE_COLUMN + Type + + + OPTION_NAME_COLUMN + Option + + + OPTION_VALUE_COLUMN + Value + + + GHS3D_ADD_OPTION + Add option + + + GHS3D_MAIN_PARAMS + Main parameters + + + GHS3D_MIN_SIZE + Minimal size + + + GHS3D_MAX_SIZE + Maximal size + + + GHS3D_VOLUME_PROXIMITY + Volume proximity + + + GHS3D_USE_VOLUME_PROXIMITY + Use volume proximity + + + GHS3D_NB_LAYERS + Number of layers + + + GHS3D_OTHER_PARAMETERS + Other parameters + + + no_initial_central_point + No central point + + + force_max_size + Force maximum edge size + + + apply_gradation_on_skin_vertex_sizes + Gradation on skin + + + optimise_worst_elements + Optimise worst elements + + + force_output_quadratic_mesh + Force quadratic mesh + + + rectify_jacobian + Rectify jacobian + + + jacobian_rectification_respect_input_surface_mesh + Respect surface mesh + + + max_number_of_errors_printed + Max number of errors + + + max_number_of_threads + Maximal number of threads + + + target_quality + Target quality + + + sliver_angle + Sliver angle + + + pthreads_mode + Mode of pthreads + + + boundary_regeneration + Boundary regeneration + + + split_overconstrained_tetrahedra + Remove overconstrained tetrahedra + + + _ + + -- 2.39.2