From 7ff943acaaab8240d6406feb33a05ba0b9a38d6e Mon Sep 17 00:00:00 2001 From: eap Date: Tue, 9 Aug 2016 19:30:07 +0300 Subject: [PATCH] 23307: [EDF 7315] Improvement of DISTENE meshing plugins --- .../BLSURFPLUGIN/images/blsurf_parameters.png | Bin 43431 -> 44891 bytes .../images/blsurf_parameters_advanced.png | Bin 34740 -> 39219 bytes .../gui/BLSURFPLUGIN/input/blsurf_hypo.doc | 243 ++--- idl/BLSURFPlugin_Algorithm.idl | 164 ++++ src/BLSURFPlugin/BLSURFPluginBuilder.py | 155 +++- src/BLSURFPlugin/BLSURFPlugin_BLSURF.cxx | 85 +- src/BLSURFPlugin/BLSURFPlugin_Hypothesis.cxx | 864 ++++++++++++++---- src/BLSURFPlugin/BLSURFPlugin_Hypothesis.hxx | 102 ++- .../BLSURFPlugin_Hypothesis_i.cxx | 749 +++++++++++++-- .../BLSURFPlugin_Hypothesis_i.hxx | 76 +- src/GUI/BLSURFPluginGUI_AdvWidget.cxx | 94 +- src/GUI/BLSURFPluginGUI_AdvWidget_QTD.ui | 283 +++--- src/GUI/BLSURFPluginGUI_Dlg.h | 8 +- src/GUI/BLSURFPluginGUI_HypothesisCreator.cxx | 436 +++------ src/GUI/BLSURFPluginGUI_HypothesisCreator.h | 12 +- src/GUI/BLSURFPluginGUI_StdWidget.cxx | 34 +- src/GUI/BLSURFPluginGUI_StdWidget_QTD.ui | 494 +++++++--- src/GUI/BLSURFPlugin_msg_en.ts | 123 ++- src/GUI/BLSURFPlugin_msg_fr.ts | 123 ++- src/GUI/CMakeLists.txt | 2 +- 20 files changed, 2876 insertions(+), 1171 deletions(-) diff --git a/doc/salome/gui/BLSURFPLUGIN/images/blsurf_parameters.png b/doc/salome/gui/BLSURFPLUGIN/images/blsurf_parameters.png index fb2365c09e751b1e2a6fa93cf5180e58d0e7787d..8b743fa1f7d380baad12e84a1e1486e3757ce265 100644 GIT binary patch literal 44891 zcmaI71yohhw>OFjqJ)CdAc%BGHz?g5(n@!CE7ILv(w&D6>F(}4bT=I0E%bliz2E!Z zxQxMov(GtuueJ7EbN*s(KWRxJBt&dPI5;>Y5n+B=IJn1^aBz=K5uSr1UCw6jz@Mkq zydv@l;Kv0)#}~YQVIiz+4L&~!e*GTlq3-;KgL@Ar!v96yA#r!!UJdO6=g*PUn=D_C zoTWS*R0}DK;#x>ye&s~v4Ah7+N5S%)(EOQ_JznAXgu1>lUUi|$PC>evWty+YOC91S zo>1ZUFTRruZQMFRpVb^V?K^kRN32?r_1NJRd_f@mh05#8Ie?hDlPa(*i6j+tdYcTic3Cz`5qvf*)lOvk)hbjoU7i$`fy@G{sEah`KhVcXnCXQ8AI!b zb4nawsj~3Oq<%>o`sVdqRhLL|;s{+%P^;LnL*3SLpR0UjSq>?Fsxy-25@ zD5HQ)%^k5{RxmP|-RMBCwcZy;h6rKIHFFMWu{ojU&E;k0bV>dblD&Td%j}{GN|Ci2 zP~L8&FH3$1mJ(EwH52a{a&-S!kjd`b5yPfN2p5-KTgkPp^Xi_QqiqLs`_^0ng}HqE z(*iUCwA;03=Tb#-{I|b&?e@u}PcFY;qL^u{Z)rPdlyI^{LPf->y5u-WrAhP`i=SWB zD9B15>;|TtPhY`3efrcO=A#^0q0P!rnz^H-T4iYMAXV^D{>cu>_|C3EEPitEO{p=w z)V`0FddVlG+k|6Sl!->?ZelsQYh3NW(c

R|Zy$#+-Z^=`I=zKWSX6^`2=eXAn$a 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 VC06T{Vh|ibT+uhtE7x_p`ycU*xuyUB diff --git a/doc/salome/gui/BLSURFPLUGIN/images/blsurf_parameters_advanced.png b/doc/salome/gui/BLSURFPLUGIN/images/blsurf_parameters_advanced.png index 7f5757c5d9758027ec440919ac71bd4a421d543e..cb8d6577768ed05bbbc2249c073d8342a8ca7d21 100644 GIT binary patch literal 39219 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

    )4jO^)?E3eBgmSuTLV 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�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 diff --git a/doc/salome/gui/BLSURFPLUGIN/input/blsurf_hypo.doc b/doc/salome/gui/BLSURFPLUGIN/input/blsurf_hypo.doc index aa88bed..55ab057 100644 --- a/doc/salome/gui/BLSURFPLUGIN/input/blsurf_hypo.doc +++ b/doc/salome/gui/BLSURFPLUGIN/input/blsurf_hypo.doc @@ -13,7 +13,9 @@ - Name - allows defining the name of the hypothesis (MG-CADSurf Parameters_n by default). -- Physical Mesh - can be set to None, Global size +- Physical Size group defines a \a physical sizemap. + +- \b Type of the physical sizemap can be set to None, Global size or Local size - if set to Global size, only the User size, @@ -23,7 +25,9 @@ Parameters_n by default). account the "Gradation" parameter and the custom elements sizes given in the "Local size" tab. -- Geometrical mesh - can be set to None, Global size +- Geometrical Size group defines a \a geometrical sizemap. + +- \b Type of the geometrical sizemap can be set to None, Global size - if set to Global size, allows user input in Mesh angle, Mesh distance and Gradation fields. These fields control @@ -41,28 +45,39 @@ is checked, the value is relative to the diagonal of the shape. - Min Size - defines the lower limit of mesh element size. If "Relative value" is checked, the value is relative to the diagonal of the shape. -- Gradation - maximum ratio between the lengths of two adjacent edges. - -- Quadratic mesh - if checked, quadratic elements will be generated. - - Mesh angle - Limiting angle (in degree) between the plane of a triangle of the mesh and each of the tangent planes at the three vertices. The smaller this angle is, the closer the mesh is to the exact surface, and the denser the resulting mesh is. - Mesh distance - Maximum desired distance between a triangle and its supporting CAD surface. The smaller this distance is, the closer the mesh is to the exact surface (only available in isotropic meshing). +- Quadratic mesh - if checked, quadratic elements will be generated. + +- Gradation - maximum ratio between the lengths of two adjacent edges. + +- Mesh optimisation - if checked, the mesh will be optimized in order to get better shaped elements. + +- Allow Quadrangles - if checked, allows the creation of quadrilateral elements. + - Anisotropic - if checked, this parameter defines the maximum anisotropic ratio of the metric governing the anisotropic meshing process. The default value (0) means that the metric (and thus the generated elements) can be arbitrarily stretched. +- Optimize tiny edges - if checked, the tiny (nano) edges are removed from the generated mesh during local mesh optimization. +The tiny edge value defines the minimal length under which an edge is considered to be a tiny one. + - Remove tiny edges - if checked, the tiny (nano) edges are removed from the generated mesh. The tiny edge value defines the minimal length under which an edge is considered to be a tiny one. - Remove bad elements - if checked, the bad elements (slivers) are removed from the generated mesh. The bad element value defines the aspect ratio triggering the "bad element” classification. -- Mesh optimisation - if checked, the mesh will be optimized in order to get better shaped elements. +- Correct surface intersections - if checked, the mesher will try to prevent all surface intersections, which is useful for future volume mesh generation. The value defines the time that will be spent in the intersection prevention process. For example, the value 3 means that the time of the intersection removal process won't be more than 3 times the time required to mesh without processing the intersections. + +- Volume Gradation - maximum ratio between the lengths of two adjacent edges affecting quality of a future volume mesh, specially in thin volume areas. The volume gradation parameter must be greater than 1, and should be greater or equal to the value of the classic +surface gradation (at the risk of increasing the time of convergence of the gradation process). +The closer it is to 1, the smoother the final volume mesh you will build should be. + -- Allow Quadrangles - if checked, allows the creation of quadrilateral elements. \ref blsurf_top "Back to top" @@ -72,206 +87,100 @@ The notion of diag used in the descriptions means the diagonal of the bou \image html blsurf_parameters_advanced.png -- CAD preprocessor options. The CAD preprocessor (formerly known as PreCAD) has two main goals: - - - Complete missing or inadequate CAD descriptions. - - - Perform topology reconstruction and specific geometry - enhancement for mesh generation. - - \n The following preprocessor options are the most significant and important ones. - All options are unchecked by default. No cleanup is made by default so that the mesh matches the shape. - If the user has a bad shape (e.g. imported shape), he can activate some options to improve the mesh. - - - Merge Edges - optimize the geometry by merging some - edges. This option is unchecked by default. - - - Remove tiny UV edges - optimize the geometry by removing small - tiny edges on the UV face. This option is unchecked by default. - - - Process 3D topology - perform the cleanup processing. - This option is unchecked by default. - - - Discard input topology - compute the CAD topology from scratch, - without considering the topological information contained in the original CAD - (useful for iges files). This option is unchecked by default. - - - Remove duplicate CAD faces - optimize the geometry by merging the - duplicate CAD faces. This option is unchecked by default. - -- Verbosity level - defines the percentage of "verbosity" of -MeshGems-CADSurf [0-10]. - -- ExportGMF - saves the computed mesh into a GMF file (.mesh or .meshb). - -- Add option - provides the choice of multiple PreCAD and MG-CADSurf -advanced options, which appear, if selected, in a table where it is -possible to input the value of the option and edit it later. - -- Clear option - removes the option selected in the table. - -The following advanced MG-CADSurf options can be used: - -- \b volume_gradation (real) - Controls the mesh volume gradation, which can improve the shape quality of a -volume mesh built afterward, specially in thin volume areas. -The volume gradation parameter must be greater than 1, and should be greater or equal to the value of the classic -surface gradation (at the risk of increasing the time of convergence of the gradation process). -The closer it is to 1, the smoother the final volume mesh you will build should be. - -- \b correct_surface_intersections (bool) - If this option is deactivated, MeshGems-CADSurf will not correct -surface intersections. This particularly useful if you don't want volume filling in a later stage, or if you want to fix the -intersections in an other way (using MeshGems Cleaner for instance). -By default this option is 1. +\b 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. -- \b surface_intersections_processing_max_cost (real) - If correct_surface_intersections = 1, this -parameter gives the time the user is ready to spend in the intersection prevention process. For example, -if set to 3, MeshGems-CADSurf will not spend more time in the intersection removal process than -3 times the time required to mesh without processing the intersections. +- \b Meshing options -- \b create_tag_on_collision (bool) - If this option is activated, MeshGems-CADSurf will create new tags to -describe tag collisions (when it locally changes the topology, depending on the patch independent -options). When this option is not activated, only one tag is preserved while the other one is dropped. -By default this option is 1. + - Enforce CAD edge sizes - Relaxes the given sizemap constraint around CAD edges to allow a better +element quality and a better geometric approximation. It is only useful in combination with the +gradation option. -- \b debug (bool) - If debug = 1, MeshGems-CADSurf will be very verbose and will output some intermediate files -in the working directory. This option is meant to communicate with Distene support mainly. -By default this option is 0. + - Priority of geometry over Jacobian - This parameter determines whether or not the geometry accuracy +is more important than the negative Jacobian correction. When this parameter is set to 0, +MeshGems-CADSurf is allowed to lose the CAD-mesh associativity in order to correct the last negative Jacobians. -- \b enforce_cad_edge_sizes (bool) - Relaxes the given sizemap constraint around CAD edges to allow a better -element quality and a better geometric approximation. It is only useful in combination with the gradation option. -By default this option is 0. + - Maximal number of points per patch - This parameter controls the maximum amount of points MeshGems-CADSurf +is allowed to generate on a single CAD patch. For an automatic gestion of the memory, you can set this parameter to ”0”. -- \b rectify_jacobian (bool) - The quadratic elements generation is a processing of the MeshGems-CADSurf + - Rectify Jacobian - The quadratic elements generation is a processing of the MeshGems-CADSurf meshing process which inserts the extra nodes on the CAD. This parameter determines whether MeshGems-CADSurf will try to correct or not all the elements of the surface mesh with negative Jacobians by moving the internal nodes of the mesh. -By default this option is 1. -- \b jacobian_rectification_respect_geometry (bool) - This parameter determines whether or not the geometry accuracy -is more important than the negative Jacobian correction. When this parameter is set to 0, -MeshGems-CADSurf is allowed to lose the CAD-mesh associativity in order to correct the last negative Jacobians. -By default this option is 1. - -- \b respect_geometry (bool) - This patch independent option can be deactivated to allow MeshGems-CADSurf + - Respect geometry - This patch independent option can be deactivated to allow MeshGems-CADSurf to lower the geometry accuracy in its patch independent process. -By default this option is 1. -- \b optimise_tiny_edges (bool) - This patch-independent correction option can be activated to remove the tiny -edges (defined by the option tiny edge optimisation length) from the generated mesh when it improves -the local mesh quality, without taking into account the tags (attributes) specifications. -By default this option is 0. - -- \b tiny_edge_avoid_surface_intersections (bool) - This option defines the priority between the tiny feature + - Tiny edges avoid surface intersections - This option defines the priority between the tiny feature suppression and the surface intersection prevention. By default, MeshGems-CADSurf gives the priority to the surface intersection prevention rather than to tiny edge or bad surface element removal. These mesh features are then removed only if it does not lead to surface intersections. This behaviour can be deactivated by setting this parameter to 0, giving priority to the tiny edge or bad surface element removal. -By default this option is 1. - -- \b tiny_edge_optimisation_length (double) - This parameter defines the minimal length under which an edge is -considered to be a tiny one to be optimised out by the optimise tiny edges option. -By default this option is \f$\mathrm{diag} \times 10^{-6}\f$. -- \b tiny_edge_respect_geometry (bool) - This option defines the behaviour of the tiny edge removal algorithm -regarding volume collapse. By default, all tiny edges will be removed, regardless of any potential -volume collapse. When this option is activated, it will prevent volume from being collapsed during the -tiny edge removal process. -By default this option is 0. -- \b max_number_of_points_per_patch (int) - This parameter controls the maximum amount of points MeshGems-CADSurf -is allowed to generate on a single CAD patch. For an automatic gestion of the memory, one can set this parameter to ”0”. -By default this option is 100000. +- CAD preprocessor options. The CAD preprocessor (formerly known as PreCAD) has two main goals: -- \b periodic_tolerance (double) - This parameter defines the maximum size difference between two periodic edges -and also the maximum distance error between two periodic entities. -By default this option is diag/100. - -- \b required_entities (char) - The required entities control the correction operations. Accepted values for this parameter are: - - - respect : MeshGems-CADSurf is not allowed to alter any required entity, even for correction purposes, - - ignore : MeshGems-CADSurf will ignore the required entities in its processing, - - clear : MeshGems-CADSurf will clear any required status for the entities. There will not be any entity marked as required in the generated mesh. - - \n By default this option is "respect". - -- \b tags (char) - The tag (attribute) system controls the optimisation process. Accepted values for this parameter are: - - - respect : the CAD tags will be preserved and unaltered by the optimisation operations, - - ignore : the CAD tags will be ignored by the optimisation operations but they will still be present inthe output mesh, - - clear : MeshGems-CADSurf will clear any tag on any entity and optimise accordingly. There will not be any tag in the generated mesh. - - \n By default this option is "respect". - - -\b Remark: To set boolean options, you have to type 0 or 1. - - - -The following MG-CADSurf options are deprecated (since MeshGems 1.3) and will be removed in the next version of Salome: + - Complete missing or inadequate CAD descriptions. -- frontal -- hinterpol_flag -- hmean_flag -- prox_nb_layer -- prox_ratio -- proximity. + - Perform topology reconstruction and specific geometry + enhancement for mesh generation. + \n All options are unchecked by default. No cleanup is made by default so that the mesh matches the shape. If the user has a bad shape (e.g. imported shape), he can activate some options to improve the mesh. -The following PreCAD options are commonly usable. + - Closed geometry - describes whether the working geometry should be closed or not. + When activated, this option helps PreCAD to process the dirtiest geometries. -- \b closed_geometry (boolean) - describes whether the working geometry -should be closed or not. When activated, this option helps PreCAD to process -the dirtiest geometries. By default this option is 0. + - \b Debug - If debug = yes PreCAD will be very verbose and will output some intermediate files in the working directory. -- \b create_tag_collision (boolean) - creates new tags from original ones in case -of collision (entity merge or association for example). By default -this option is 1. + - Discard input topology - compute the CAD topology from scratch, + without considering the topological information contained in the original CAD + (useful for iges files). This option is unchecked by default. -- \b debug (bool) - If debug = 1 PreCAD will be very verbose and will output -some intermediate files in the working directory. By default this -option is 0. + - Merge Edges - optimize the geometry by merging some + edges. -- \b manifold_geometry (int) - describes whether the working geometry should be manifold or not. -When activated, this option helps PreCAD to process the dirtiest -geometries. By default this option is 0. + - Periodic tolerance - This parameter defines the maximum size difference between two periodic edges and also the maximum distance error between two periodic entities. -- \b periodic_tolerance (real) - defines the maximum distance error accepted between -two sets of periodic entities. By default this option is \f$\mathrm{diag} \times 10^{-5}\f$. + - Remove duplicate CAD faces - optimize the geometry by merging the + duplicate CAD faces. This option is unchecked by default. -- \b remove_tiny_edges (boolean) -optimize the geometry by removing the nano edges whenever possible. -By default this option is 0. + - Required entities - The required entities control the correction operations. Accepted values for this parameter are: + - respect : MeshGems-CADSurf is not allowed to alter any required entity, even for correction purposes, + - ignore : MeshGems-CADSurf will ignore the required entities in its processing, + - clear : MeshGems-CADSurf will clear any required status for the entities. There will not be any entity marked as required in the generated mesh. -- \b required_entities (char) -controls the correction operations. Possible values are: + - Sewing tolerance - tolerance of the assembly. It rarely requires to be tuned. - - "respect" - PreCAD is not allowed to correct or optimize a required edge. + - \b Tags - controls the optimisation process. Possible values are: + - "respect" - PreCAD is not allowed to cross the CAD attributes boundaries for optimisation purpose. + - "ignore" - PreCAD is allowed to cross the CAD attributes boundaries for optimisation. + - "clear" - PreCAD will erase each tgas of each entities, and will thus be allowed to cross the CAD attributes boundaries in its optimisation purpose. - - "ignore" - PreCAD is allowed to correct a required edge. - - "clear" - PreCAD will erase "required" status of each required entities, and will thus - be allowed to correct a required edge. +- Add option - adds a new line in Other options section where you can type an option name and value. The following advanced MG-CADSurf options can be used: - \n By default this option is "respect". + - \b create_tag_on_collision (bool) - If this option is activated, MeshGems-CADSurf will create new tags to + describe tag collisions (when it locally changes the topology, depending on the patch independent + options). When this option is not activated, only one tag is preserved while the other one is dropped. + By default this option is 1. -- \b sewing_tolerance (real) - tolerance of the assembly. It rarely requires to be tuned. -By default this option is \f$\mathrm{diag} \times 5 \cdot 10^{-4}\f$. + - \b tiny_edge_respect_geometry (bool) - This option defines the behaviour of the tiny edge removal algorithm + regarding volume collapse. By default, all tiny edges will be removed, regardless of any potential + volume collapse. When this option is activated, it will prevent volume from being collapsed during the tiny edge removal process. + By default this option is 0. -- \b tags (char) -controls the optimisation process. Possible values are: + - \b manifold_geometry (int) - describes whether the working geometry should be manifold or not. + When activated, this option helps PreCAD to process the dirtiest + geometries. By default this option is 0. - - "respect" - PreCAD is not allowed to cross the CAD attributes boundaries for optimisation purpose. - - "ignore" - PreCAD is allowed to cross the CAD attributes boundaries for optimisation. - - "clear" - PreCAD will erase each tgas of each entities, and will thus - be allowed to cross the CAD attributes boundaries in its optimisation purpose. +- Verbosity level - defines the percentage of "verbosity" of +MeshGems-CADSurf [0-10]. - \n By default this option is "respect". +- ExportGMF - saves the computed mesh into a GMF file (.mesh or .meshb). -- \b tiny_edge_length (real) - the length below which en edge is considered as nano for the topology processing. -By default this option is \f$10^{-5}\f$. -\note Moreover, user can choose "" item in these two pop-up menus -(MG-CADSurf and PreCAD) to be able to specify both the option name and the option value. \ref blsurf_top "Back to top" diff --git a/idl/BLSURFPlugin_Algorithm.idl b/idl/BLSURFPlugin_Algorithm.idl index e865c2f..d7f9c11 100644 --- a/idl/BLSURFPlugin_Algorithm.idl +++ b/idl/BLSURFPlugin_Algorithm.idl @@ -178,9 +178,19 @@ module BLSURFPlugin /*! * Sets maximal allowed ratio between the lengths of two adjacent edges */ + void SetUseGradation(in boolean toUse); + boolean GetUseGradation(); void SetGradation(in double ratio); double GetGradation(); + /*! + * Sets maximal allowed ratio between the lengths of two adjacent edges in 3D mesh + */ + void SetUseVolumeGradation(in boolean toUse); + boolean GetUseVolumeGradation(); + void SetVolumeGradation(in double ratio); + double GetVolumeGradation(); + /*! * Sets to create quadrilateral elements or not */ @@ -227,6 +237,37 @@ module BLSURFPlugin void SetTinyEdgeLength(in double length); double GetTinyEdgeLength(); + /*! + * This patch-independent correction option can be activated to remove the tiny + * edges (defined by the option tiny edge optimisation length) from the generated + * mesh when it improves the local mesh quality, without taking into account the + * tags (attributes) specifications. + */ + void SetOptimiseTinyEdges(in boolean toOptimise); + boolean GetOptimiseTinyEdges(); + + /*! + * Defines the minimal length under which an edge is considered to be a tiny one + * to be optimised out by the optimise tiny edges option + */ + void SetTinyEdgeOptimisationLength(in double length); + double GetTinyEdgeOptimisationLength(); + + /*! + * Activate correction of all surface intersections + */ + void SetCorrectSurfaceIntersection(in boolean toCorrect); + boolean GetCorrectSurfaceIntersection(); + + /*! + * Defines the time the user is ready to spend in the intersection prevention process. + * For example, maxCost = 3 means that MeshGems-CADSurf will not spend more time + * in the intersection removal process than 3 times the time required to mesh + * without processing the intersections. + */ + void SetCorrectSurfaceIntersectionMaxCost(in double maxCost); + double GetCorrectSurfaceIntersectionMaxCost(); + /*! * This patch independent correction option can be activated to remove the bad * elements (often called slivers) from the generated mesh, without taking into account @@ -271,6 +312,124 @@ module BLSURFPlugin void SetVerbosity(in short theVal) raises (SALOME::SALOME_Exception); short GetVerbosity(); + /*! + * Set enforce_cad_edge_sizes parameter + * + * Relaxes the given sizemap constraint around CAD edges to allow a better + * element quality and a better geometric approximation. It is only useful in + * combination with the gradation option. + */ + void SetEnforceCadEdgesSize( in boolean toEnforce ); + boolean GetEnforceCadEdgesSize(); + + /*! + * Set jacobian_rectification_respect_geometry parameter + * + * While making the mesh quadratic, allows to lose the CAD-mesh associativity in order + * to correct elements with nagative Jacobian + */ + void SetJacobianRectificationRespectGeometry( in boolean allowRectification ); + boolean GetJacobianRectificationRespectGeometry(); + + /*! + * Set rectify_jacobian parameter + * + * While making the mesh quadratic, allow to fix nagative Jacobian surface elements + */ + void SetJacobianRectification( in boolean allowRectification ); + boolean GetJacobianRectification(); + + /*! + * Set max_number_of_points_per_patch parameter + * + * This parameter controls the maximum amount of points MeshGems-CADSurf is allowed + * to generate on a single CAD patch. For an automatic gestion of the memory, one + * can set this parameter to 0 + */ + void SetMaxNumberOfPointsPerPatch( in long nb ) raises (SALOME::SALOME_Exception); + long GetMaxNumberOfPointsPerPatch(); + + /*! + * Set respect_geometry parameter + * + * This patch independent option can be deactivated to allow MeshGems-CADSurf + * to lower the geometry accuracy in its patch independent process. + */ + void SetRespectGeometry( in boolean toRespect ); + boolean GetRespectGeometry(); + + /*! + * Set tiny_edges_avoid_surface_intersections parameter + * + * This option defines the priority between the tiny feature + * suppression and the surface intersection prevention. + */ + void SetTinyEdgesAvoidSurfaceIntersections( in boolean toAvoidIntersection ); + boolean GetTinyEdgesAvoidSurfaceIntersections(); + + /*! + * Set closed_geometry parameter parameter + * + * Describes whether the geometry is expected to be closed or not. + * When activated, this option helps MeshGems-PreCAD to treat the dirtiest geometries. + */ + void SetClosedGeometry( in boolean isClosed ); + boolean GetClosedGeometry(); + + /*! + * Set debug parameter + * + * Make MeshGems-CADSurf will be very verbose and will output some intermediate + * files in the working directory. This option is mainly meant for Distene support issues. + */ + void SetDebug( in boolean isDebug ); + boolean GetDebug(); + + /*! + * Set periodic_tolerance parameter + * + * This parameter defines the maximum size difference between two periodic edges + * and also the maximum distance error between two periodic entities. + */ + void SetPeriodicTolerance( in double tol ) raises (SALOME::SALOME_Exception); + double GetPeriodicTolerance() raises (SALOME::SALOME_Exception); + + /*! + * Set required_entities parameter + * + * The required entities control the correction operations. + * Accepted values for this parameter are : + * - "respect" : MeshGems-CADSurf is not allowed to alter any required entity, + * even for correction purposes, + * - "ignore" : MeshGems-CADSurf will ignore the required entities in its processing, + * - "clear" : MeshGems-CADSurf will clear any required status for the entities. + * There will not be any entity marked as required in the generated mesh. + */ + void SetRequiredEntities( in string howToTreat ) raises (SALOME::SALOME_Exception); + string GetRequiredEntities(); + + /*! + * Set sewing_tolerance parameter + * + * This parameter is the tolerance of the assembly. + */ + void SetSewingTolerance( in double tol ) raises (SALOME::SALOME_Exception); + double GetSewingTolerance() raises (SALOME::SALOME_Exception); + + /*! + * Set tags parameter + * + * The tag (attribute) system controls the optimisation process. + * Accepted values for this parameter are : + * - "respect" : the CAD tags will be preserved and unaltered by the optimisation operations, + * - "ignore" : the CAD tags will be ignored by the optimisation operations + * but they will still be present in the output mesh, + * - "clear" : MeshGems-CADSurf will clear any tag on any entity and optimise accordingly. + * There will not be any tag in the generated mesh. + */ + void SetTags( in string howToTreat ) raises (SALOME::SALOME_Exception); + string GetTags(); + /*! * To merges edges. */ @@ -320,6 +479,8 @@ module BLSURFPlugin /*! * 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); void AddOption(in string optionName, in string optionValue); void AddPreCADOption(in string optionName, in string optionValue); string GetOption(in string optionName); @@ -329,10 +490,12 @@ module BLSURFPlugin * 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 GetPreCADOptionValues(); + string_array GetAdvancedOptionValues(); /*! * Set option values each in the form "option_name[:option_value][:option_type]". @@ -340,6 +503,7 @@ module BLSURFPlugin */ void SetOptionValues(in string_array options) raises (SALOME::SALOME_Exception); void SetPreCADOptionValues(in string_array options) raises (SALOME::SALOME_Exception); + void SetAdvancedOptionValues(in string_array options); /*! * SizeMap diff --git a/src/BLSURFPlugin/BLSURFPluginBuilder.py b/src/BLSURFPlugin/BLSURFPluginBuilder.py index 3b443a9..084b8c7 100644 --- a/src/BLSURFPlugin/BLSURFPluginBuilder.py +++ b/src/BLSURFPlugin/BLSURFPluginBuilder.py @@ -74,6 +74,7 @@ class BLSURF_Algorithm(Mesh_Algorithm): _bad_surface_element_aspect_ratio = 1000 _geometric_approximation = 22 _gradation = 1.3 + _volume_gradation = 2 _metric = "isotropic" _remove_tiny_edges = 0 @@ -159,11 +160,22 @@ class BLSURF_Algorithm(Mesh_Algorithm): ## Sets maximal allowed ratio between the lengths of two adjacent edges. # @param theVal value of maximal length ratio - def SetGradation(self, theVal=_gradation): + def SetGradation(self, toUseGradation=True, theVal=_gradation): + if isinstance( toUseGradation, float ): ## backward compatibility + toUseGradation, theVal = True, toUseGradation if self.Parameters().GetGeometricMesh() == 0: theVal = self._gradation + self.Parameters().SetUseGradation(toUseGradation) self.Parameters().SetGradation(theVal) pass + ## Sets maximal allowed ratio between the lengths of two adjacent edges in 3D mesh. + # @param theVal value of maximal length ratio + def SetVolumeGradation(self, toUseGradation=True, theVal=_gradation): + if self.Parameters().GetGeometricMesh() == 0: theVal = self._volume_gradation + self.Parameters().SetUseVolumeGradation(toUseGradation) + self.Parameters().SetVolumeGradation(theVal) + pass + ## Sets topology usage way. # @param way defines how mesh conformity is assured
      #
    • FromCAD - mesh conformity is assured by conformity of a shape
    • @@ -191,6 +203,141 @@ class BLSURF_Algorithm(Mesh_Algorithm): self.Parameters().SetVerbosity(level) pass + ## Set enforce_cad_edge_sizes parameter + # + # Relaxes the given sizemap constraint around CAD edges to allow a better + # element quality and a better geometric approximation. It is only useful in + # combination with the gradation option. + # + def SetEnforceCadEdgesSize( self, toEnforce ): + self.Parameters().SetEnforceCadEdgesSize( toEnforce ) + + ## Set jacobian_rectification_respect_geometry parameter + # + # While making the mesh quadratic, allows to lose the CAD-mesh associativity in order + # to correct elements with nagative Jacobian + # + def SetJacobianRectificationRespectGeometry( self, allowRectification ): + self.Parameters().SetJacobianRectificationRespectGeometry( allowRectification ) + + ## Set rectify_jacobian parameter + # + # While making the mesh quadratic, allow to fix nagative Jacobian surface elements + # + def SetJacobianRectification( self, allowRectification ): + self.Parameters().SetJacobianRectification( allowRectification ) + + ## Set respect_geometry parameter + # + # This patch independent option can be deactivated to allow MeshGems-CADSurf + # to lower the geometry accuracy in its patch independent process. + # + def SetRespectGeometry( self, toRespect ): + self.Parameters().SetRespectGeometry( toRespect ) + + ## Set max_number_of_points_per_patch parameter + # + # This parameter controls the maximum amount of points MeshGems-CADSurf is allowed + # to generate on a single CAD patch. For an automatic gestion of the memory, one + # can set this parameter to 0 + # + def SetMaxNumberOfPointsPerPatch( self, nb ): + self.Parameters().SetMaxNumberOfPointsPerPatch( nb ) + + ## Set respect_geometry parameter + # + # This patch independent option can be deactivated to allow MeshGems-CADSurf + # to lower the geometry accuracy in its patch independent process. + # + def SetRespectGeometry( self, toRespect ): + self.Parameters().SetRespectGeometry( toRespect ) + + ## Set tiny_edges_avoid_surface_intersections parameter + # + # This option defines the priority between the tiny feature + # suppression and the surface intersection prevention. + # + def SetTinyEdgesAvoidSurfaceIntersections( self, toAvoidIntersection ): + self.Parameters().SetTinyEdgesAvoidSurfaceIntersections( toAvoidIntersection ) + + ## Set closed_geometry parameter parameter + # + # Describes whether the geometry is expected to be closed or not. + # When activated, this option helps MeshGems-PreCAD to treat the dirtiest geometries. + # + def SetClosedGeometry( self, isClosed ): + self.Parameters().SetClosedGeometry( isClosed ) + + ## Set debug parameter + # + # Make MeshGems-CADSurf will be very verbose and will output some intermediate + # files in the working directory. This option is mainly meant for Distene support issues. + # + def SetDebug( self, isDebug ): + self.Parameters().SetDebug( isDebug ) + + ## Set periodic_tolerance parameter + # + # This parameter defines the maximum size difference between two periodic edges + # and also the maximum distance error between two periodic entities. + # + def SetPeriodicTolerance( self, tol ): + self.Parameters().SetPeriodicTolerance( tol ) + + ## Set required_entities parameter + # + # The required entities control the correction operations. + # Accepted values for this parameter are : + # - "respect" : MeshGems-CADSurf is not allowed to alter any required entity, + # even for correction purposes, + # - "ignore" : MeshGems-CADSurf will ignore the required entities in its processing, + # - "clear" : MeshGems-CADSurf will clear any required status for the entities. + # There will not be any entity marked as required in the generated mesh. + # + def SetRequiredEntities( self, howToTreat ): + self.Parameters().SetRequiredEntities( howToTreat ) + + ## Set sewing_tolerance parameter + # + # This parameter is the tolerance of the assembly. + # + def SetSewingTolerance( self, tol ): + self.Parameters().SetSewingTolerance( tol ) + + ## Set tags parameter + # + # The tag (attribute) system controls the optimisation process. + # Accepted values for this parameter are : + # - "respect" : the CAD tags will be preserved and unaltered by the optimisation operations, + # - "ignore" : the CAD tags will be ignored by the optimisation operations + # but they will still be present in the output mesh, + # - "clear" : MeshGems-CADSurf will clear any tag on any entity and optimise accordingly. + # There will not be any tag in the generated mesh. + # + def SetTags( self, howToTreat ): + self.Parameters().SetTags( howToTreat ) + + ## Activate removal of the tiny edges from the generated + # mesh when it improves the local mesh quality, without taking into account the + # tags (attributes) specifications. + # @param toOptimise "to optimize" flag value + # @param length minimal length under which an edge is considered to be a tiny + def SetOptimiseTinyEdges(self, toOptimise, length=-1): + self.Parameters().SetOptimiseTinyEdges( toOptimise ) + if toOptimise: + self.Parameters().SetTinyEdgeOptimisationLength( length ) + + ## Activate correction of all surface intersections + # @param toCorrect "to correct" flag value + # @param maxCost the time the user is ready to spend in the intersection prevention process + # For example, maxCost = 3 means that MeshGems-CADSurf will not spend more time + # in the intersection removal process than 3 times the time required to mesh + # without processing the intersections. + def SetCorrectSurfaceIntersection(self, toCorrect, maxCost ): + self.Parameters().SetCorrectSurfaceIntersection( toCorrect ) + if toCorrect: + self.Parameters().SetCorrectSurfaceIntersectionMaxCost( maxCost ) + ## To optimize merges edges. # @param toMergeEdges "merge edges" flag value def SetPreCADMergeEdges(self, toMergeEdges=False): @@ -251,6 +398,12 @@ class BLSURF_Algorithm(Mesh_Algorithm): self.Parameters().SetPreCADOptionValue(optionName,optionValue) pass + ## Adds custom advanced option values + # @param optionsAndValues options and values in a form "option_1 v1 option_2 v2'" + def SetAdvancedOption(self, optionsAndValues): + self.Parameters().SetAdvancedOption(optionsAndValues) + pass + ## Adds custom advanced option value. # @param optionName custom advanced option name # @param level custom advanced option value diff --git a/src/BLSURFPlugin/BLSURFPlugin_BLSURF.cxx b/src/BLSURFPlugin/BLSURFPlugin_BLSURF.cxx index bc6ba82..ca54cf3 100644 --- a/src/BLSURFPlugin/BLSURFPlugin_BLSURF.cxx +++ b/src/BLSURFPlugin/BLSURFPlugin_BLSURF.cxx @@ -840,7 +840,10 @@ void BLSURFPlugin_BLSURF::SetParameters(const BLSURFPlugin_Hypothesis* hyp, bool _minSizeRel = BLSURFPlugin_Hypothesis::GetDefaultMinSizeRel(); double _maxSize = BLSURFPlugin_Hypothesis::GetDefaultMaxSize(diagonal); bool _maxSizeRel = BLSURFPlugin_Hypothesis::GetDefaultMaxSizeRel(); + double _use_gradation = BLSURFPlugin_Hypothesis::GetDefaultUseGradation(); double _gradation = BLSURFPlugin_Hypothesis::GetDefaultGradation(); + double _use_volume_gradation = BLSURFPlugin_Hypothesis::GetDefaultUseVolumeGradation(); + double _volume_gradation = BLSURFPlugin_Hypothesis::GetDefaultVolumeGradation(); bool _quadAllowed = BLSURFPlugin_Hypothesis::GetDefaultQuadAllowed(); double _angleMesh = BLSURFPlugin_Hypothesis::GetDefaultAngleMesh(); double _chordalError = BLSURFPlugin_Hypothesis::GetDefaultChordalError(diagonal); @@ -848,19 +851,23 @@ void BLSURFPlugin_BLSURF::SetParameters(const BLSURFPlugin_Hypothesis* hyp, double _anisotropicRatio = BLSURFPlugin_Hypothesis::GetDefaultAnisotropicRatio(); bool _removeTinyEdges = BLSURFPlugin_Hypothesis::GetDefaultRemoveTinyEdges(); double _tinyEdgeLength = BLSURFPlugin_Hypothesis::GetDefaultTinyEdgeLength(diagonal); + bool _optimiseTinyEdges = BLSURFPlugin_Hypothesis::GetDefaultOptimiseTinyEdges(); + double _tinyEdgeOptimisLength = BLSURFPlugin_Hypothesis::GetDefaultTinyEdgeOptimisationLength(diagonal); + bool _correctSurfaceIntersec= BLSURFPlugin_Hypothesis::GetDefaultCorrectSurfaceIntersection(); + double _corrSurfaceIntersCost = BLSURFPlugin_Hypothesis::GetDefaultCorrectSurfaceIntersectionMaxCost(); bool _badElementRemoval = BLSURFPlugin_Hypothesis::GetDefaultBadElementRemoval(); double _badElementAspectRatio = BLSURFPlugin_Hypothesis::GetDefaultBadElementAspectRatio(); bool _optimizeMesh = BLSURFPlugin_Hypothesis::GetDefaultOptimizeMesh(); bool _quadraticMesh = BLSURFPlugin_Hypothesis::GetDefaultQuadraticMesh(); int _verb = BLSURFPlugin_Hypothesis::GetDefaultVerbosity(); - int _topology = BLSURFPlugin_Hypothesis::GetDefaultTopology(); + //int _topology = BLSURFPlugin_Hypothesis::GetDefaultTopology(); // PreCAD - int _precadMergeEdges = BLSURFPlugin_Hypothesis::GetDefaultPreCADMergeEdges(); + //int _precadMergeEdges = BLSURFPlugin_Hypothesis::GetDefaultPreCADMergeEdges(); int _precadRemoveTinyUVEdges = BLSURFPlugin_Hypothesis::GetDefaultPreCADRemoveTinyUVEdges(); - int _precadRemoveDuplicateCADFaces = BLSURFPlugin_Hypothesis::GetDefaultPreCADRemoveDuplicateCADFaces(); + //int _precadRemoveDuplicateCADFaces = BLSURFPlugin_Hypothesis::GetDefaultPreCADRemoveDuplicateCADFaces(); int _precadProcess3DTopology = BLSURFPlugin_Hypothesis::GetDefaultPreCADProcess3DTopology(); - int _precadDiscardInput = BLSURFPlugin_Hypothesis::GetDefaultPreCADDiscardInput(); + //int _precadDiscardInput = BLSURFPlugin_Hypothesis::GetDefaultPreCADDiscardInput(); if (hyp) { @@ -882,8 +889,12 @@ void BLSURFPlugin_BLSURF::SetParameters(const BLSURFPlugin_Hypothesis* hyp, // if max size is not explicitly specified, "relative" flag is ignored _maxSizeRel = hyp->IsMaxSizeRel(); } - if (hyp->GetGradation() > 0) + _use_gradation = hyp->GetUseGradation(); + if (hyp->GetGradation() > 0 && _use_gradation) _gradation = hyp->GetGradation(); + _use_volume_gradation = hyp->GetUseVolumeGradation(); + if (hyp->GetVolumeGradation() > 0 && _use_volume_gradation ) + _volume_gradation = hyp->GetVolumeGradation(); _quadAllowed = hyp->GetQuadAllowed(); if (hyp->GetAngleMesh() > 0) _angleMesh = hyp->GetAngleMesh(); @@ -895,19 +906,25 @@ void BLSURFPlugin_BLSURF::SetParameters(const BLSURFPlugin_Hypothesis* hyp, _removeTinyEdges = hyp->GetRemoveTinyEdges(); if (hyp->GetTinyEdgeLength() > 0) _tinyEdgeLength = hyp->GetTinyEdgeLength(); + _optimiseTinyEdges = hyp->GetOptimiseTinyEdges(); + if (hyp->GetTinyEdgeOptimisationLength() > 0) + _tinyEdgeOptimisLength = hyp->GetTinyEdgeOptimisationLength(); + _correctSurfaceIntersec = hyp->GetCorrectSurfaceIntersection(); + if (hyp->GetCorrectSurfaceIntersectionMaxCost() > 0) + _corrSurfaceIntersCost = hyp->GetCorrectSurfaceIntersectionMaxCost(); _badElementRemoval = hyp->GetBadElementRemoval(); if (hyp->GetBadElementAspectRatio() >= 0) _badElementAspectRatio = hyp->GetBadElementAspectRatio(); _optimizeMesh = hyp->GetOptimizeMesh(); _quadraticMesh = hyp->GetQuadraticMesh(); _verb = hyp->GetVerbosity(); - _topology = (int) hyp->GetTopology(); + //_topology = (int) hyp->GetTopology(); // PreCAD - _precadMergeEdges = hyp->GetPreCADMergeEdges(); + //_precadMergeEdges = hyp->GetPreCADMergeEdges(); _precadRemoveTinyUVEdges = hyp->GetPreCADRemoveTinyUVEdges(); - _precadRemoveDuplicateCADFaces = hyp->GetPreCADRemoveDuplicateCADFaces(); + //_precadRemoveDuplicateCADFaces = hyp->GetPreCADRemoveDuplicateCADFaces(); _precadProcess3DTopology = hyp->GetPreCADProcess3DTopology(); - _precadDiscardInput = hyp->GetPreCADDiscardInput(); + //_precadDiscardInput = hyp->GetPreCADDiscardInput(); const BLSURFPlugin_Hypothesis::TOptionValues& opts = hyp->GetOptionValues(); BLSURFPlugin_Hypothesis::TOptionValues::const_iterator opIt; @@ -930,35 +947,15 @@ void BLSURFPlugin_BLSURF::SetParameters(const BLSURFPlugin_Hypothesis* hyp, MESSAGE("cadsurf_set_param(): " << opIt->first << " = " << opIt->second); set_param(css, opIt->first.c_str(), opIt->second.c_str()); } - - const BLSURFPlugin_Hypothesis::TOptionValues& custom_preCADopts = hyp->GetCustomPreCADOptionValues(); - for ( opIt = custom_preCADopts.begin(); opIt != custom_preCADopts.end(); ++opIt ) - if ( !opIt->second.empty() ) { - MESSAGE("cadsurf_set_param(): " << opIt->first << " = " << opIt->second); - set_param(css, opIt->first.c_str(), opIt->second.c_str()); - } } -// else { -// //0020968: EDF1545 SMESH: Problem in the creation of a mesh group on geometry -// // GetDefaultPhySize() sometimes leads to computation failure -// // GDD 26/07/2012 From Distene documentation, global physical size default value = diag/100 -// _phySize = BLSURFPlugin_Hypothesis::GetDefaultPhySize(diagonal); -// _minSize = BLSURFPlugin_Hypothesis::GetDefaultMinSize(diagonal); -// _maxSize = BLSURFPlugin_Hypothesis::GetDefaultMaxSize(diagonal); -// _chordalError = BLSURFPlugin_Hypothesis::GetDefaultChordalError(diagonal); -// _tinyEdgeLength = BLSURFPlugin_Hypothesis::GetDefaultTinyEdgeLength(diagonal); -// MESSAGE("BLSURFPlugin_BLSURF::SetParameters using defaults"); -// } - // PreProcessor (formerly PreCAD) - set_param(css, "merge_edges", _precadMergeEdges ? "yes" : "no"); + // PreProcessor (formerly PreCAD) -- commented params are preCADoptions (since 0023307) + //set_param(css, "merge_edges", _precadMergeEdges ? "yes" : "no"); set_param(css, "remove_tiny_uv_edges", _precadRemoveTinyUVEdges ? "yes" : "no"); - set_param(css, "remove_duplicate_cad_faces", _precadRemoveDuplicateCADFaces ? "yes" : "no"); + //set_param(css, "remove_duplicate_cad_faces", _precadRemoveDuplicateCADFaces ? "yes" : "no"); set_param(css, "process_3d_topology", _precadProcess3DTopology ? "1" : "0"); - set_param(css, "discard_input_topology", _precadDiscardInput ? "1" : "0"); - - // unlimit mesh size (issue 0022266) - set_param(css, "max_number_of_points_per_patch", "1000000"); + //set_param(css, "discard_input_topology", _precadDiscardInput ? "1" : "0"); + //set_param(css, "max_number_of_points_per_patch", "1000000"); bool useGradation = false; switch (_physicalMesh) @@ -1022,8 +1019,10 @@ void BLSURFPlugin_BLSURF::SetParameters(const BLSURFPlugin_Hypothesis* hyp, // anisotropic and quadrangle mesh requires disabling gradation if ( _anisotropic && _quadAllowed ) useGradation = false; // limitation of V1.3 - if ( useGradation ) - set_param(css, "gradation", val_to_string(_gradation).c_str()); + if ( useGradation && _use_gradation ) + set_param(css, "gradation", val_to_string(_gradation).c_str()); + if ( useGradation && _use_volume_gradation ) + set_param(css, "volume_gradation", val_to_string(_volume_gradation).c_str()); set_param(css, "element_generation", _quadAllowed ? "quad_dominant" : "triangle"); @@ -1033,6 +1032,12 @@ void BLSURFPlugin_BLSURF::SetParameters(const BLSURFPlugin_Hypothesis* hyp, set_param(css, "remove_tiny_edges", _removeTinyEdges ? "1" : "0"); if ( _removeTinyEdges ) set_param(css, "tiny_edge_length", val_to_string(_tinyEdgeLength).c_str()); + set_param(css, "optimise_tiny_edges", _optimiseTinyEdges ? "1" : "0"); + if ( _optimiseTinyEdges ) + set_param(css, "tiny_edge_optimisation_length", val_to_string(_tinyEdgeOptimisLength).c_str()); + set_param(css, "correct_surface_intersections", _correctSurfaceIntersec ? "1" : "0"); + if ( _correctSurfaceIntersec ) + set_param(css, "surface_intersections_processing_max_cost", val_to_string(_corrSurfaceIntersCost ).c_str()); set_param(css, "force_bad_surface_element_removal", _badElementRemoval ? "1" : "0"); if ( _badElementRemoval ) set_param(css, "bad_surface_element_aspect_ratio", val_to_string(_badElementAspectRatio).c_str()); @@ -1849,9 +1854,6 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, */ // PreCAD - // If user requests it, send the CAD through Distene preprocessor : PreCAD - cad_t *cleanc = NULL; // preprocessed cad - dcad_t *cleandc = NULL; // preprocessed dcad cadsurf_session_t *css = cadsurf_session_new(ctx); @@ -1859,7 +1861,6 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, BLSURF_Cleaner cleaner( ctx,css,c,dcad ); MESSAGE("BEGIN SetParameters"); - bool use_precad = false; SetParameters(_hypothesis, css, aShape); MESSAGE("END SetParameters"); @@ -2628,10 +2629,10 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, mesh_get_composite_tag_definition(msh, tag, &nb_tag, tags_buff); if(nb_tag > 1) tag=tags_buff[nb_tag-1]; - if ( tag > emap.Extent() ) + if ( tag < 1 || tag > emap.Extent() ) { std::cerr << "MG-CADSurf BUG:::: Edge tag " << tag - << " more than nb CAD egdes (" << emap.Extent() << ")" << std::endl; + << " does not point to a CAD edge (nb edges " << emap.Extent() << ")" << std::endl; continue; } if (tags[vtx[0]]) { diff --git a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.cxx b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.cxx index 1d59f69..cda6029 100644 --- a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.cxx +++ b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.cxx @@ -39,6 +39,15 @@ #include CORBA_CLIENT_HEADER(SALOMEDS) #include CORBA_CLIENT_HEADER(GEOM_Gen) +namespace +{ + struct GET_DEFAULT // struct used to get default value from GetOptionValue() + { + bool isDefault; + operator bool* () { return &isDefault; } + }; +} + //============================================================================= BLSURFPlugin_Hypothesis::BLSURFPlugin_Hypothesis(int hypId, int studyId, SMESH_Gen * gen) : SMESH_Hypothesis(hypId, studyId, gen), @@ -50,7 +59,10 @@ BLSURFPlugin_Hypothesis::BLSURFPlugin_Hypothesis(int hypId, int studyId, SMESH_G _maxSize(GetDefaultMaxSize()), _minSizeRel(GetDefaultMinSizeRel()), _maxSizeRel(GetDefaultMaxSizeRel()), + _useGradation(GetDefaultUseGradation()), _gradation(GetDefaultGradation()), + _useVolumeGradation(GetDefaultUseVolumeGradation()), + _volumeGradation(GetDefaultVolumeGradation()), _quadAllowed(GetDefaultQuadAllowed()), _angleMesh(GetDefaultAngleMesh()), _chordalError(GetDefaultChordalError()), @@ -58,6 +70,10 @@ BLSURFPlugin_Hypothesis::BLSURFPlugin_Hypothesis(int hypId, int studyId, SMESH_G _anisotropicRatio(GetDefaultAnisotropicRatio()), _removeTinyEdges(GetDefaultRemoveTinyEdges()), _tinyEdgeLength(GetDefaultTinyEdgeLength()), + _optimiseTinyEdges(GetDefaultOptimiseTinyEdges()), + _tinyEdgeOptimisationLength(GetDefaultTinyEdgeOptimisationLength()), + _correctSurfaceIntersec(GetDefaultCorrectSurfaceIntersection()), + _corrSurfaceIntersCost(GetDefaultCorrectSurfaceIntersectionMaxCost()), _badElementRemoval(GetDefaultBadElementRemoval()), _badElementAspectRatio(GetDefaultBadElementAspectRatio()), _optimizeMesh(GetDefaultOptimizeMesh()), @@ -89,52 +105,51 @@ BLSURFPlugin_Hypothesis::BLSURFPlugin_Hypothesis(int hypId, int studyId, SMESH_G // _GMFFileMode = false; // GMF ascii mode - const char* boolOptionNames[] = { "correct_surface_intersections", // default = 1 - "create_tag_on_collision", // default = 1 - "debug", // default = 0 - "enforce_cad_edge_sizes", // default = 0 - "frontal", // ok default = 1 + // Advanced options with their defaults according to MG User Manual + + const char* boolOptionNames[] = { "enforce_cad_edge_sizes", // default = 0 + // "correct_surface_intersections", // default = 1 + // "create_tag_on_collision", // default = 1 "jacobian_rectification_respect_geometry", // default = 1 - "proximity", // default = 0 "rectify_jacobian", // default = 1 "respect_geometry", // default = 1 - "optimise_tiny_edges", // default = 0 + // "optimise_tiny_edges", // default = 0 + // "remove_duplicate_cad_faces", // default = 1 "tiny_edge_avoid_surface_intersections", // default = 1 - "tiny_edge_respect_geometry", // default = 0 + // "tiny_edge_respect_geometry", // default = 0 "" // mark of end }; - const char* intOptionNames[] = { "hinterpol_flag", // ok default = 0 - "hmean_flag", // ok default = 0 - "max_number_of_points_per_patch", // default = 100000 - "prox_nb_layer", // detects the volumic proximity of surfaces + const char* intOptionNames[] = { "max_number_of_points_per_patch", // default = 100000 "" // mark of end }; - const char* doubleOptionNames[] = { "surface_intersections_processing_max_cost",// default = 15 - "periodic_tolerance", // default = diag/100 - "prox_ratio", - "volume_gradation", - "tiny_edge_optimisation_length", // default = diag * 1e-6 + const char* doubleOptionNames[] = { // "surface_intersections_processing_max_cost",// default = 15 + // "periodic_tolerance", // default = diag/100 + // "volume_gradation", + // "tiny_edge_optimisation_length", // default = diag * 1e-6 "" // mark of end }; - const char* charOptionNames[] = { "required_entities", // default = "respect" - "tags", // default = "respect" + const char* charOptionNames[] = { // "required_entities", // default = "respect" + // "tags", // default = "respect" "" // mark of end }; // PreCAD advanced options const char* preCADboolOptionNames[] = { "closed_geometry", // default = 0 - "create_tag_on_collision", // default = 1 + "discard_input_topology", // default = 0 + "merge_edges", // default = = 1 + "remove_duplicate_cad_faces", // default = 1 + // "create_tag_on_collision", // default = 1 "debug", // default = 0 - "remove_tiny_edges", // default = 0 + // "remove_tiny_edges", // default = 0 "" // mark of end }; - const char* preCADintOptionNames[] = { "manifold_geometry", // default = 0 + const char* preCADintOptionNames[] = { // "manifold_geometry", // default = 0 "" // mark of end }; const char* preCADdoubleOptionNames[] = { "periodic_tolerance", // default = diag * 1e-5 "sewing_tolerance", // default = diag * 5e-4 - "tiny_edge_length", // default = diag * 1e-5 + // "tiny_edge_length", // default = diag * 1e-5 "" // mark of end }; const char* preCADcharOptionNames[] = { "required_entities", // default = "respect" @@ -144,12 +159,16 @@ BLSURFPlugin_Hypothesis::BLSURFPlugin_Hypothesis(int hypId, int studyId, SMESH_G int i = 0; while (boolOptionNames[i][0]) + { + _boolOptions.insert( boolOptionNames[i] ); _option2value[boolOptionNames[i++]].clear(); - + } i = 0; while (preCADboolOptionNames[i][0]) + { + _boolOptions.insert( preCADboolOptionNames[i] ); _preCADoption2value[preCADboolOptionNames[i++]].clear(); - + } i = 0; while (intOptionNames[i][0]) _option2value[intOptionNames[i++]].clear(); @@ -178,8 +197,32 @@ BLSURFPlugin_Hypothesis::BLSURFPlugin_Hypothesis(int hypId, int studyId, SMESH_G _preCADcharOptions.insert(preCADcharOptionNames[i]); _preCADoption2value[preCADcharOptionNames[i++]].clear(); } - + // default values to be used while MG meshing + + _defaultOptionValues["enforce_cad_edge_sizes" ] = "no"; + _defaultOptionValues["jacobian_rectification_respect_geometry"] = "yes"; + _defaultOptionValues["max_number_of_points_per_patch" ] = "0"; + _defaultOptionValues["rectify_jacobian" ] = "yes"; + _defaultOptionValues["respect_geometry" ] = "yes"; + _defaultOptionValues["tiny_edge_avoid_surface_intersections" ] = "yes"; + _defaultOptionValues["closed_geometry" ] = "no"; + _defaultOptionValues["debug" ] = "no"; + _defaultOptionValues["discard_input_topology" ] = "no"; + _defaultOptionValues["merge_edges" ] = "no"; + _defaultOptionValues["periodic_tolerance" ] = "1e-5*D"; + _defaultOptionValues["remove_duplicate_cad_faces" ] = "no"; + _defaultOptionValues["required_entities" ] = "respect"; + _defaultOptionValues["sewing_tolerance" ] = "5e-4*D"; + _defaultOptionValues["tags" ] = "respect"; + +#ifdef _DEBUG_ + // check validity of option names of _defaultOptionValues + TOptionValues::iterator n2v = _defaultOptionValues.begin(); + for ( ; n2v != _defaultOptionValues.end(); ++n2v ) + ASSERT( _option2value.count( n2v->first ) || _preCADoption2value.count( n2v->first )); + ASSERT( _option2value.size() + _preCADoption2value.size() == _defaultOptionValues.size() ); +#endif _sizeMap.clear(); _attractors.clear(); @@ -271,6 +314,14 @@ void BLSURFPlugin_Hypothesis::SetMaxSize(double theMaxSize, bool isRelative) { } } +//============================================================================= +void BLSURFPlugin_Hypothesis::SetUseGradation(bool theVal) { + if (theVal != _useGradation) { + _useGradation = theVal; + NotifySubMeshesHypothesisModification(); + } +} + //============================================================================= void BLSURFPlugin_Hypothesis::SetGradation(double theVal) { if (theVal != _gradation) { @@ -279,6 +330,22 @@ void BLSURFPlugin_Hypothesis::SetGradation(double theVal) { } } +//============================================================================= +void BLSURFPlugin_Hypothesis::SetUseVolumeGradation(bool theVal) { + if (theVal != _useVolumeGradation) { + _useVolumeGradation = theVal; + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +void BLSURFPlugin_Hypothesis::SetVolumeGradation(double theVal) { + if (theVal != _volumeGradation) { + _volumeGradation = theVal; + NotifySubMeshesHypothesisModification(); + } +} + //============================================================================= void BLSURFPlugin_Hypothesis::SetQuadAllowed(bool theVal) { if (theVal != _quadAllowed) { @@ -335,6 +402,38 @@ void BLSURFPlugin_Hypothesis::SetTinyEdgeLength(double theVal) { } } +//============================================================================= +void BLSURFPlugin_Hypothesis::SetOptimiseTinyEdges(bool theVal) { + if (theVal != _optimiseTinyEdges) { + _optimiseTinyEdges = theVal; + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +void BLSURFPlugin_Hypothesis::SetTinyEdgeOptimisationLength(double theVal) { + if (theVal != _tinyEdgeOptimisationLength) { + _tinyEdgeOptimisationLength = theVal; + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +void BLSURFPlugin_Hypothesis::SetCorrectSurfaceIntersection(bool theVal) { + if (theVal != _correctSurfaceIntersec) { + _correctSurfaceIntersec = theVal; + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +void BLSURFPlugin_Hypothesis::SetCorrectSurfaceIntersectionMaxCost(double theVal) { + if (theVal != _corrSurfaceIntersCost) { + _corrSurfaceIntersCost = theVal; + NotifySubMeshesHypothesisModification(); + } +} + //============================================================================= void BLSURFPlugin_Hypothesis::SetBadElementRemoval(bool theVal) { if (theVal != _badElementRemoval) { @@ -384,16 +483,218 @@ void BLSURFPlugin_Hypothesis::SetVerbosity(int theVal) { } //============================================================================= -void BLSURFPlugin_Hypothesis::SetPreCADMergeEdges(bool theVal) { +void BLSURFPlugin_Hypothesis::SetEnforceCadEdgesSize( bool toEnforce ) +{ + if ( GetEnforceCadEdgesSize() != toEnforce ) + { + SetOptionValue( "enforce_cad_edge_sizes", toEnforce ? "yes" : "no" ); + NotifySubMeshesHypothesisModification(); + } +} +//============================================================================= +bool BLSURFPlugin_Hypothesis::GetEnforceCadEdgesSize() +{ + return ToBool( GetOptionValue( "enforce_cad_edge_sizes" ), GET_DEFAULT() ); +} +//============================================================================= + +void BLSURFPlugin_Hypothesis::SetJacobianRectificationRespectGeometry( bool allowRectification ) +{ + if ( GetJacobianRectificationRespectGeometry() != allowRectification ) + { + SetOptionValue("jacobian_rectification_respect_geometry", allowRectification ? "yes" : "no" ); + NotifySubMeshesHypothesisModification(); + } +} +//============================================================================= +bool BLSURFPlugin_Hypothesis::GetJacobianRectificationRespectGeometry() +{ + return ToBool( GetOptionValue("jacobian_rectification_respect_geometry", GET_DEFAULT())); +} +//============================================================================= + +void BLSURFPlugin_Hypothesis::SetJacobianRectification( bool allowRectification ) +{ + if ( GetJacobianRectification() != allowRectification ) + { + SetOptionValue( "rectify_jacobian", allowRectification ? "yes" : "no" ); + NotifySubMeshesHypothesisModification(); + } +} +//============================================================================= +bool BLSURFPlugin_Hypothesis::GetJacobianRectification() +{ + return ToBool( GetOptionValue("rectify_jacobian", GET_DEFAULT())); +} +//============================================================================= + +void BLSURFPlugin_Hypothesis::SetMaxNumberOfPointsPerPatch( CORBA::Long nb ) + throw (std::invalid_argument) +{ + if ( nb < 0 ) + throw std::invalid_argument( SMESH_Comment("Invalid number of points: ") << nb ); + + if ( GetMaxNumberOfPointsPerPatch() != nb ) + { + SetOptionValue("max_number_of_points_per_patch", SMESH_Comment( nb )); + NotifySubMeshesHypothesisModification(); + } +} +//============================================================================= +int BLSURFPlugin_Hypothesis::GetMaxNumberOfPointsPerPatch() +{ + return ToInt( GetOptionValue("max_number_of_points_per_patch", GET_DEFAULT())); +} +//============================================================================= + +void BLSURFPlugin_Hypothesis::SetRespectGeometry( bool toRespect ) +{ + if ( GetRespectGeometry() != toRespect ) + { + SetOptionValue("respect_geometry", toRespect ? "yes" : "no" ); + NotifySubMeshesHypothesisModification(); + } +} +//============================================================================= +bool BLSURFPlugin_Hypothesis::GetRespectGeometry() +{ + return ToBool( GetOptionValue( "respect_geometry", GET_DEFAULT())); +} +//============================================================================= + +void BLSURFPlugin_Hypothesis::SetTinyEdgesAvoidSurfaceIntersections( bool toAvoidIntersection ) +{ + if ( GetTinyEdgesAvoidSurfaceIntersections() != toAvoidIntersection ) + { + SetOptionValue("tiny_edge_avoid_surface_intersections", toAvoidIntersection ? "yes" : "no" ); + NotifySubMeshesHypothesisModification(); + } +} +//============================================================================= +bool BLSURFPlugin_Hypothesis::GetTinyEdgesAvoidSurfaceIntersections() +{ + return ToBool( GetOptionValue("tiny_edge_avoid_surface_intersections", GET_DEFAULT())); +} +//============================================================================= + +void BLSURFPlugin_Hypothesis::SetClosedGeometry( bool isClosed ) +{ + if ( GetClosedGeometry() != isClosed ) + { + SetPreCADOptionValue("closed_geometry", isClosed ? "yes" : "no" ); + NotifySubMeshesHypothesisModification(); + } +} +//============================================================================= +bool BLSURFPlugin_Hypothesis::GetClosedGeometry() +{ + return ToBool( GetPreCADOptionValue( "closed_geometry", GET_DEFAULT())); +} +//============================================================================= + +void BLSURFPlugin_Hypothesis::SetDebug( bool isDebug ) +{ + if ( GetDebug() != isDebug ) + { + SetPreCADOptionValue("debug", isDebug ? "yes" : "no" ); + NotifySubMeshesHypothesisModification(); + } +} +//============================================================================= +bool BLSURFPlugin_Hypothesis::GetDebug() +{ + return ToBool( GetPreCADOptionValue("debug", GET_DEFAULT())); +} +//============================================================================= + +void BLSURFPlugin_Hypothesis::SetPeriodicTolerance( CORBA::Double tol ) + throw (std::invalid_argument) +{ + if ( tol <= 0 ) + throw std::invalid_argument( SMESH_Comment("Invalid tolerance: ") << tol ); + if ( GetPeriodicTolerance() != tol ) + { + SetPreCADOptionValue("periodic_tolerance", SMESH_Comment( tol ) ); + NotifySubMeshesHypothesisModification(); + } +} +//============================================================================= +double BLSURFPlugin_Hypothesis::GetPeriodicTolerance() +{ + return ToDbl( GetPreCADOptionValue( "periodic_tolerance", GET_DEFAULT())); +} +//============================================================================= + +void BLSURFPlugin_Hypothesis::SetRequiredEntities( const std::string& howToTreat ) + throw (std::invalid_argument) +{ + if ( howToTreat != "respect" && howToTreat != "ignore" && howToTreat != "clear" ) + throw std::invalid_argument + ( SMESH_Comment("required_entities must be in ['respect','ignore','clear'] ")); + + if ( GetRequiredEntities() != howToTreat ) + { + SetPreCADOptionValue("required_entities", howToTreat ); + NotifySubMeshesHypothesisModification(); + } +} +//============================================================================= +std::string BLSURFPlugin_Hypothesis::GetRequiredEntities() +{ + return GetPreCADOptionValue("required_entities", GET_DEFAULT()); +} +//============================================================================= + +void BLSURFPlugin_Hypothesis::SetSewingTolerance( CORBA::Double tol ) + throw (std::invalid_argument) +{ + if ( tol <= 0 ) + throw std::invalid_argument( SMESH_Comment("Invalid tolerance: ") << tol ); + if ( GetSewingTolerance() != tol ) + { + SetPreCADOptionValue("sewing_tolerance", SMESH_Comment( tol ) ); + NotifySubMeshesHypothesisModification(); + } +} +//============================================================================= +CORBA::Double BLSURFPlugin_Hypothesis::GetSewingTolerance() +{ + return ToDbl( GetPreCADOptionValue("sewing_tolerance", GET_DEFAULT())); +} +//============================================================================= + +void BLSURFPlugin_Hypothesis::SetTags( const std::string& howToTreat ) + throw (std::invalid_argument) +{ + if ( howToTreat != "respect" && howToTreat != "ignore" && howToTreat != "clear" ) + throw std::invalid_argument + ( SMESH_Comment("'tags' must be in ['respect','ignore','clear'] ")); + + if ( GetTags() != howToTreat ) + { + SetPreCADOptionValue("tags", howToTreat ); + NotifySubMeshesHypothesisModification(); + } +} +//============================================================================= +std::string BLSURFPlugin_Hypothesis::GetTags() +{ + return GetPreCADOptionValue("tags", GET_DEFAULT()); +} +//============================================================================= +void BLSURFPlugin_Hypothesis::SetPreCADMergeEdges(bool theVal) +{ if (theVal != _preCADMergeEdges) { // SetTopology(PreCAD); _preCADMergeEdges = theVal; + SetPreCADOptionValue("merge_edges", theVal ? "yes" : "no" ); NotifySubMeshesHypothesisModification(); } } //============================================================================= -void BLSURFPlugin_Hypothesis::SetPreCADRemoveTinyUVEdges(bool theVal) { +void BLSURFPlugin_Hypothesis::SetPreCADRemoveTinyUVEdges(bool theVal) +{ if (theVal != _preCADRemoveTinyUVEdges) { // SetTopology(PreCAD); _preCADRemoveTinyUVEdges = theVal; @@ -402,28 +703,33 @@ void BLSURFPlugin_Hypothesis::SetPreCADRemoveTinyUVEdges(bool theVal) { } //============================================================================= -void BLSURFPlugin_Hypothesis::SetPreCADRemoveDuplicateCADFaces(bool theVal) { +void BLSURFPlugin_Hypothesis::SetPreCADRemoveDuplicateCADFaces(bool theVal) +{ if (theVal != _preCADRemoveDuplicateCADFaces) { -// SetTopology(PreCAD); + // SetTopology(PreCAD); _preCADRemoveDuplicateCADFaces = theVal; + SetPreCADOptionValue("remove_duplicate_cad_faces", theVal ? "yes" : "no" ); NotifySubMeshesHypothesisModification(); } } //============================================================================= -void BLSURFPlugin_Hypothesis::SetPreCADProcess3DTopology(bool theVal) { +void BLSURFPlugin_Hypothesis::SetPreCADProcess3DTopology(bool theVal) +{ if (theVal != _preCADProcess3DTopology) { -// SetTopology(PreCAD); + // SetTopology(PreCAD); _preCADProcess3DTopology = theVal; NotifySubMeshesHypothesisModification(); } } //============================================================================= -void BLSURFPlugin_Hypothesis::SetPreCADDiscardInput(bool theVal) { +void BLSURFPlugin_Hypothesis::SetPreCADDiscardInput(bool theVal) +{ if (theVal != _preCADDiscardInput) { -// SetTopology(PreCAD); + // SetTopology(PreCAD); _preCADDiscardInput = theVal; + SetPreCADOptionValue("discard_input_topology", theVal ? "yes" : "no" ); NotifySubMeshesHypothesisModification(); } } @@ -433,19 +739,26 @@ void BLSURFPlugin_Hypothesis::SetPreCADDiscardInput(bool theVal) { void BLSURFPlugin_Hypothesis::SetGMFFile(const std::string& theFileName) { _GMFFileName = theFileName; -// _GMFFileMode = isBinary; + // _GMFFileMode = isBinary; NotifySubMeshesHypothesisModification(); } //============================================================================= void BLSURFPlugin_Hypothesis::SetOptionValue(const std::string& optionName, const std::string& optionValue) - throw (std::invalid_argument) { + throw (std::invalid_argument) { + TOptionValues::iterator op_val = _option2value.find(optionName); - if (op_val == _option2value.end()) { - std::string msg = "Unknown MG-CADSurf option: '" + optionName + "'"; - throw std::invalid_argument(msg); + if (op_val == _option2value.end()) + { + op_val = _preCADoption2value.find(optionName); + if (op_val == _preCADoption2value.end()) + { + std::string msg = "Unknown MG-CADSurf option: '" + optionName + "'. Try SetAdvancedOption()"; + throw std::invalid_argument(msg); + } } - if (op_val->second != optionValue) { + if (op_val->second != optionValue) + { const char* ptr = optionValue.c_str(); // strip white spaces while (ptr[0] == ' ') @@ -458,39 +771,49 @@ void BLSURFPlugin_Hypothesis::SetOptionValue(const std::string& optionName, cons std::string typeName; if (i == 0) { // empty string - } else if (_charOptions.find(optionName) != _charOptions.end()) { + } else if (_charOptions.count(optionName)) { // do not check strings - } else if (_doubleOptions.find(optionName) != _doubleOptions.end()) { + } else if (_doubleOptions.count(optionName)) { // check if value is double - char * endPtr; - strtod(ptr, &endPtr); - typeOk = (ptr != endPtr); + 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 - char * endPtr; - strtol(ptr, &endPtr, 10); - typeOk = (ptr != endPtr); + ToInt(ptr, &typeOk); typeName = "integer"; } if (!typeOk) { std::string msg = "Advanced option '" + optionName + "' = '" + optionValue + "' but must be " + typeName; throw std::invalid_argument(msg); } - op_val->second = optionValue; + std::string value( ptr, i ); + if ( _defaultOptionValues[ optionName ] == value ) + value.clear(); + + op_val->second = value; + NotifySubMeshesHypothesisModification(); } } //============================================================================= void BLSURFPlugin_Hypothesis::SetPreCADOptionValue(const std::string& optionName, const std::string& optionValue) - throw (std::invalid_argument) { + throw (std::invalid_argument) { + TOptionValues::iterator op_val = _preCADoption2value.find(optionName); if (op_val == _preCADoption2value.end()) { - std::string msg = "Unknown MG-CADSurf option: '" + optionName + "'"; - throw std::invalid_argument(msg); + op_val = _option2value.find(optionName); + if (op_val == _option2value.end()) { + std::string msg = "Unknown MG-PreCAD option: '" + optionName + "'. Try SetAdvancedOption()"; + throw std::invalid_argument(msg); + } } - if (op_val->second != optionValue) { + if (op_val->second != optionValue) + { const char* ptr = optionValue.c_str(); // strip white spaces while (ptr[0] == ' ') @@ -511,6 +834,10 @@ void BLSURFPlugin_Hypothesis::SetPreCADOptionValue(const std::string& optionName strtod(ptr, &endPtr); typeOk = (ptr != endPtr); typeName = "real"; + } else if (_boolOptions.count(optionName)) { + // check if value is bool + ToBool(ptr, &typeOk); + typeName = "bool"; } else { // check if value is int char * endPtr; @@ -522,35 +849,81 @@ void BLSURFPlugin_Hypothesis::SetPreCADOptionValue(const std::string& optionName std::string msg = "PreCAD advanced option '" + optionName + "' = '" + optionValue + "' but must be " + typeName; throw std::invalid_argument(msg); } - op_val->second = optionValue; + std::string value( ptr, i ); + if ( _defaultOptionValues[ optionName ] == value ) + value.clear(); + + op_val->second = value; + NotifySubMeshesHypothesisModification(); } } //============================================================================= -std::string BLSURFPlugin_Hypothesis::GetOptionValue(const std::string& optionName) throw (std::invalid_argument) { - TOptionValues::iterator op_val = _option2value.find(optionName); - if (op_val == _option2value.end()) { - std::string msg = "Unknown MG-CADSurf option: <"; - msg += optionName + ">"; - throw std::invalid_argument(msg); +std::string BLSURFPlugin_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 = _preCADoption2value.find(optionName); + if (op_val == _preCADoption2value.end()) + { + op_val = _customOption2value.find(optionName); + if (op_val == _customOption2value.end()) + { + std::string msg = "Unknown MG-CADSurf 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 op_val->second; + return val; } //============================================================================= -std::string BLSURFPlugin_Hypothesis::GetPreCADOptionValue(const std::string& optionName) throw (std::invalid_argument) { - TOptionValues::iterator op_val = _preCADoption2value.find(optionName); - if (op_val == _preCADoption2value.end()) { - std::string msg = "Unknown PRECAD option: <"; - msg += optionName + ">"; - throw std::invalid_argument(msg); +std::string BLSURFPlugin_Hypothesis::GetPreCADOptionValue(const std::string& optionName, + bool* isDefault) const + throw (std::invalid_argument) +{ + TOptionValues::const_iterator op_val = _preCADoption2value.find(optionName); + if (op_val == _preCADoption2value.end()) + { + 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-CADSurf option: <" + optionName + ">"; + throw std::invalid_argument(msg); + } + } } - return op_val->second; + std::string val = op_val->second; + if ( isDefault ) *isDefault = ( val.empty() ); + + if ( val.empty() && isDefault ) + { + op_val = _defaultOptionValues.find( optionName ); + if (op_val != _option2value.end()) + val = op_val->second; + } + return val; } //============================================================================= -void BLSURFPlugin_Hypothesis::ClearOption(const std::string& optionName) { +void BLSURFPlugin_Hypothesis::ClearOption(const std::string& optionName) +{ TOptionValues::iterator op_val = _customOption2value.find(optionName); if (op_val != _customOption2value.end()) _customOption2value.erase(op_val); @@ -558,55 +931,67 @@ void BLSURFPlugin_Hypothesis::ClearOption(const std::string& optionName) { op_val = _option2value.find(optionName); if (op_val != _option2value.end()) op_val->second.clear(); + else { + op_val = _preCADoption2value.find(optionName); + if (op_val != _preCADoption2value.end()) + op_val->second.clear(); + } } } //============================================================================= -void BLSURFPlugin_Hypothesis::ClearPreCADOption(const std::string& optionName) { - TOptionValues::iterator op_val = _customPreCADOption2value.find(optionName); - if (op_val != _customPreCADOption2value.end()) - _customPreCADOption2value.erase(op_val); - else { - op_val = _preCADoption2value.find(optionName); - if (op_val != _preCADoption2value.end()) - op_val->second.clear(); - } +void BLSURFPlugin_Hypothesis::ClearPreCADOption(const std::string& optionName) +{ + TOptionValues::iterator op_val = _preCADoption2value.find(optionName); + if (op_val != _preCADoption2value.end()) + op_val->second.clear(); } //============================================================================= void BLSURFPlugin_Hypothesis::AddOption(const std::string& optionName, const std::string& optionValue) { + bool modif = true; TOptionValues::iterator op_val = _option2value.find(optionName); - if (op_val != _option2value.end()) { + if (op_val != _option2value.end()) + { if (op_val->second != optionValue) op_val->second = optionValue; + else + modif = false; } - else { - op_val = _customOption2value.find(optionName); - if (op_val == _customOption2value.end()) - _customOption2value[optionName] = optionValue; - else if (op_val->second != optionValue) - op_val->second = optionValue; + else + { + op_val = _preCADoption2value.find(optionName); + if (op_val != _preCADoption2value.end()) + { + if (op_val->second != optionValue) + op_val->second = optionValue; + else + modif = false; + } + else if ( optionValue.empty() ) + { + _customOption2value.erase( optionName ); + } + else + { + op_val = _customOption2value.find(optionName); + if (op_val == _customOption2value.end()) + _customOption2value[optionName] = optionValue; + else if (op_val->second != optionValue) + op_val->second = optionValue; + else + modif = false; + } } - NotifySubMeshesHypothesisModification(); + if ( modif ) + NotifySubMeshesHypothesisModification(); } //============================================================================= void BLSURFPlugin_Hypothesis::AddPreCADOption(const std::string& optionName, const std::string& optionValue) { - TOptionValues::iterator op_val = _preCADoption2value.find(optionName); - if (op_val != _preCADoption2value.end()) { - if (op_val->second != optionValue) - op_val->second = optionValue; - } - else { - op_val = _customPreCADOption2value.find(optionName); - if (op_val == _customPreCADOption2value.end()) - _customPreCADOption2value[optionName] = optionValue; - else if (op_val->second != optionValue) - op_val->second = optionValue; - } - NotifySubMeshesHypothesisModification(); + AddOption( optionName, optionValue ); } //============================================================================= @@ -622,13 +1007,35 @@ std::string BLSURFPlugin_Hypothesis::GetOption(const std::string& optionName) //============================================================================= std::string BLSURFPlugin_Hypothesis::GetPreCADOption(const std::string& optionName) { - TOptionValues::iterator op_val = _customPreCADOption2value.find(optionName); - if (op_val != _customPreCADOption2value.end()) + TOptionValues::iterator op_val = _customOption2value.find(optionName); + if (op_val != _customOption2value.end()) return op_val->second; else return ""; } +//============================================================================= +BLSURFPlugin_Hypothesis::TOptionValues BLSURFPlugin_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; +} + +//============================================================================= +BLSURFPlugin_Hypothesis::TOptionValues BLSURFPlugin_Hypothesis::GetPreCADOptionValues() const +{ + TOptionValues vals; + TOptionValues::const_iterator op_val = _preCADoption2value.begin(); + for ( ; op_val != _preCADoption2value.end(); ++op_val ) + vals.insert( make_pair( op_val->first, GetPreCADOptionValue( op_val->first, GET_DEFAULT() ))); + + return vals; +} + //======================================================================= //function : SetSizeMapEntry //======================================================================= @@ -1417,6 +1824,9 @@ std::ostream & BLSURFPlugin_Hypothesis::SaveTo(std::ostream & save) { save << " " << (int) _anisotropic << " " << _anisotropicRatio << " " << (int) _removeTinyEdges << " " << _tinyEdgeLength ; save << " " << (int) _badElementRemoval << " " << _badElementAspectRatio << " " << (int) _optimizeMesh << " " << (int) _quadraticMesh ; save << " " << (int) _preCADProcess3DTopology << " " << (int) _preCADRemoveDuplicateCADFaces << " " << (int) _preCADRemoveTinyUVEdges; + save << " " << (int)_optimiseTinyEdges << " " << _tinyEdgeOptimisationLength; + save << " " << (int)_correctSurfaceIntersec << " " << _corrSurfaceIntersCost; + save << " " << (int)_useGradation << " " << (int)_useVolumeGradation << " " << _volumeGradation; op_val = _option2value.begin(); if (op_val != _option2value.end()) { @@ -1448,16 +1858,6 @@ std::ostream & BLSURFPlugin_Hypothesis::SaveTo(std::ostream & save) { save << " " << "__PRECAD_OPTIONS_END__"; } - op_val = _customPreCADOption2value.begin(); - if (op_val != _customPreCADOption2value.end()) { - save << " " << "__CUSTOM_PRECAD_OPTIONS_BEGIN__"; - for (; op_val != _customPreCADOption2value.end(); ++op_val) { - if (!op_val->second.empty()) - save << " " << op_val->first << " " << op_val->second << "%#"; // "%#" is a mark of value end - } - save << " " << "__CUSTOM_PRECAD_OPTIONS_END__"; - } - TSizeMap::iterator it_sm = _sizeMap.begin(); if (it_sm != _sizeMap.end()) { save << " " << "__SIZEMAP_BEGIN__"; @@ -1836,7 +2236,6 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) { bool hasOptions = false; bool hasCustomOptions = false; bool hasPreCADOptions = false; - bool hasCustomPreCADOptions = false; bool hasSizeMap = false; bool hasAttractor = false; bool hasNewAttractor = false; @@ -1860,8 +2259,6 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) { hasCustomOptions = true; else if (option_or_sm == "__PRECAD_OPTIONS_BEGIN__") hasPreCADOptions = true; - else if (option_or_sm == "__CUSTOM_PRECAD_OPTIONS_BEGIN__") - hasCustomPreCADOptions = true; else if (option_or_sm == "__SIZEMAP_BEGIN__") hasSizeMap = true; else if (option_or_sm == "__ATTRACTORS_BEGIN__") @@ -1954,20 +2351,64 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) { else load.clear(std::ios::badbit | load.rdstate()); - isOK = static_cast(load >> i); - if (isOK) - _preCADRemoveDuplicateCADFaces = (bool) i; - else - load.clear(std::ios::badbit | load.rdstate()); - - isOK = static_cast(load >> i); - if (isOK) - _preCADRemoveTinyUVEdges = (bool) i; - else - load.clear(std::ios::badbit | load.rdstate()); - + if (( load >> std::ws).peek() != '_' ) + { + isOK = static_cast(load >> i); + if (isOK) + _preCADRemoveDuplicateCADFaces = (bool) i; + else + load.clear(std::ios::badbit | load.rdstate()); + + isOK = static_cast(load >> i); + if (isOK) + _preCADRemoveTinyUVEdges = (bool) i; + else + load.clear(std::ios::badbit | load.rdstate()); + + isOK = static_cast(load >> i); + if (isOK) + _optimiseTinyEdges = (bool) i; + else + load.clear(std::ios::badbit | load.rdstate()); + + isOK = static_cast(load >> val); + if (isOK) + _tinyEdgeOptimisationLength = val; + else + load.clear(std::ios::badbit | load.rdstate()); + + isOK = static_cast(load >> i); + if (isOK) + _correctSurfaceIntersec = (bool) i; + else + load.clear(std::ios::badbit | load.rdstate()); + + isOK = static_cast(load >> val); + if (isOK) + _corrSurfaceIntersCost = val; + else + load.clear(std::ios::badbit | load.rdstate()); + + isOK = static_cast(load >> i); + if (isOK) + _useGradation = (bool) i; + else + load.clear(std::ios::badbit | load.rdstate()); + + isOK = static_cast(load >> i); + if (isOK) + _useVolumeGradation = (bool) i; + else + load.clear(std::ios::badbit | load.rdstate()); + + isOK = static_cast(load >> val); + if (isOK) + _volumeGradation = val; + else + load.clear(std::ios::badbit | load.rdstate()); + } } - + if (hasCADSurfOptions) { isOK = static_cast(load >> option_or_sm); @@ -1978,8 +2419,6 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) { hasCustomOptions = true; else if (option_or_sm == "__PRECAD_OPTIONS_BEGIN__") hasPreCADOptions = true; - else if (option_or_sm == "__CUSTOM_PRECAD_OPTIONS_BEGIN__") - hasCustomPreCADOptions = true; else if (option_or_sm == "__SIZEMAP_BEGIN__") hasSizeMap = true; else if (option_or_sm == "__ATTRACTORS_BEGIN__") @@ -2024,7 +2463,7 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) { break; } } - value[len - 2] = '\0'; //cut off "%#" + value.resize(len - 2); //cut off "%#" } } @@ -2035,8 +2474,6 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) { hasCustomOptions = true; else if (option_or_sm == "__PRECAD_OPTIONS_BEGIN__") hasPreCADOptions = true; - else if (option_or_sm == "__CUSTOM_PRECAD_OPTIONS_BEGIN__") - hasCustomPreCADOptions = true; else if (option_or_sm == "__SIZEMAP_BEGIN__") hasSizeMap = true; else if (option_or_sm == "__ATTRACTORS_BEGIN__") @@ -2079,8 +2516,8 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) { break; } } - _customOption2value[optName] = value.substr(0,len-2); - value[len - 2] = '\0'; //cut off "%#" + value.resize(len - 2); //cut off "%#" + _customOption2value[optName] = value; } } @@ -2089,8 +2526,6 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) { if (isOK) { if (option_or_sm == "__PRECAD_OPTIONS_BEGIN__") hasPreCADOptions = true; - else if (option_or_sm == "__CUSTOM_PRECAD_OPTIONS_BEGIN__") - hasCustomPreCADOptions = true; else if (option_or_sm == "__SIZEMAP_BEGIN__") hasSizeMap = true; else if (option_or_sm == "__ATTRACTORS_BEGIN__") @@ -2134,63 +2569,11 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) { break; } } - value[len - 2] = '\0'; //cut off "%#" + value.resize(len - 2); //cut off "%#" } } if (hasPreCADOptions) { - isOK = static_cast(load >> option_or_sm); - if (isOK) { - if (option_or_sm == "__CUSTOM_PRECAD_OPTIONS_BEGIN__") - hasCustomPreCADOptions = true; - else if (option_or_sm == "__SIZEMAP_BEGIN__") - hasSizeMap = true; - else if (option_or_sm == "__ATTRACTORS_BEGIN__") - hasAttractor = true; - else if (option_or_sm == "__NEW_ATTRACTORS_BEGIN__") - hasNewAttractor = true; - else if (option_or_sm == "__ENFORCED_VERTICES_BEGIN__") - hasEnforcedVertex = true; - else if (option_or_sm == "__PRECAD_FACES_PERIODICITY_BEGIN__") - hasPreCADFacesPeriodicity = true; - else if (option_or_sm == "__PRECAD_EDGES_PERIODICITY_BEGIN__") - hasPreCADEdgesPeriodicity = true; - else if (option_or_sm == "__FACES_PERIODICITY_BEGIN__") - hasFacesPeriodicity = true; - else if (option_or_sm == "__EDGES_PERIODICITY_BEGIN__") - hasEdgesPeriodicity = true; - else if (option_or_sm == "__VERTICES_PERIODICITY_BEGIN__") - hasVerticesPeriodicity = true; - } - } - - while (isOK && hasCustomPreCADOptions) { - isOK = static_cast(load >> optName); - if (isOK) { - if (optName == "__CUSTOM_PRECAD_OPTIONS_END__") - break; - isOK = static_cast(load >> optValue); - } - if (isOK) { - std::string& value = optValue; - int len = value.size(); - // continue reading until "%#" encountered - while (value[len - 1] != '#' || value[len - 2] != '%') { - isOK = static_cast(load >> optValue); - if (isOK) { - value += " "; - value += optValue; - len = value.size(); - } else { - break; - } - } - _customPreCADOption2value[optName] = value.substr(0,len-2); - value[len - 2] = '\0'; //cut off "%#" - } - } - - if (hasCustomPreCADOptions) { isOK = static_cast(load >> option_or_sm); if (isOK) { if (option_or_sm == "__SIZEMAP_BEGIN__") @@ -2213,7 +2596,7 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) { hasVerticesPeriodicity = true; } } - + std::string smEntry, smValue; while (isOK && hasSizeMap) { isOK = static_cast(load >> smEntry); @@ -2237,7 +2620,7 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) { break; } } - value2[len2 - 2] = '\0'; //cut off "%#" + value2.resize(len2 - 2); //cut off "%#" } } @@ -2285,7 +2668,7 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) { break; } } - value3[len3 - 2] = '\0'; //cut off "%#" + value3.resize(len3 - 2); //cut off "%#" } } @@ -2942,6 +3325,18 @@ double BLSURFPlugin_Hypothesis::GetDefaultTinyEdgeLength(double diagonal) { return undefinedDouble(); } +//================================================================================ +/*! + * \brief Returns default tiny edge optimisation length given a default value of element length ratio + */ +//================================================================================ + +double BLSURFPlugin_Hypothesis::GetDefaultTinyEdgeOptimisationLength(double diagonal) { + if (diagonal != 0) + return diagonal * 1e-6 ; + return undefinedDouble(); +} + //============================================================================= /*! * \brief Initialize my parameter values by default parameters. @@ -2954,9 +3349,90 @@ bool BLSURFPlugin_Hypothesis::SetParametersByDefaults(const TDefaults& dflts, co _phySize = GetDefaultPhySize(diagonal, _gen->GetBoundaryBoxSegmentation()); _minSize = GetDefaultMinSize(diagonal); _maxSize = GetDefaultMaxSize(diagonal); - _chordalError = GetDefaultChordalError(diagonal); + _chordalError = 0.5 * _phySize; //GetDefaultChordalError(diagonal); IMP 0023307 _tinyEdgeLength = GetDefaultTinyEdgeLength(diagonal); + _tinyEdgeOptimisationLength = GetDefaultTinyEdgeOptimisationLength(diagonal); return true; -// return bool(_phySize = dflts._elemLength); } + +//================================================================================ +/*! + * \brief Converts a string to a bool + */ +//================================================================================ + +bool BLSURFPlugin_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 BLSURFPlugin_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 BLSURFPlugin_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/BLSURFPlugin/BLSURFPlugin_Hypothesis.hxx b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.hxx index bee70c6..70a97ab 100644 --- a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.hxx +++ b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.hxx @@ -86,9 +86,16 @@ public: double GetMaxSize() const { return _maxSize; } bool IsMaxSizeRel() const { return _maxSizeRel; } + void SetUseGradation(bool toUse); + bool GetUseGradation() const { return _useGradation; } void SetGradation(double theGradation); double GetGradation() const { return _gradation; } + void SetUseVolumeGradation(bool toUse); + bool GetUseVolumeGradation() const { return _useVolumeGradation; } + void SetVolumeGradation(double theGradation); + double GetVolumeGradation() const { return _volumeGradation; } + void SetQuadAllowed(bool theVal); bool GetQuadAllowed() const { return _quadAllowed; } @@ -110,6 +117,18 @@ public: void SetTinyEdgeLength(double theVal); double GetTinyEdgeLength() const { return _tinyEdgeLength; } + void SetOptimiseTinyEdges(bool theVal); + bool GetOptimiseTinyEdges() const { return _optimiseTinyEdges; } + + void SetTinyEdgeOptimisationLength(double theVal); + double GetTinyEdgeOptimisationLength() const { return _tinyEdgeOptimisationLength; } + + void SetCorrectSurfaceIntersection(bool theVal); + bool GetCorrectSurfaceIntersection() const { return _correctSurfaceIntersec; } + + void SetCorrectSurfaceIntersectionMaxCost(double theVal); + double GetCorrectSurfaceIntersectionMaxCost() const { return _corrSurfaceIntersCost; } + void SetBadElementRemoval(bool theVal); bool GetBadElementRemoval() const { return _badElementRemoval; } @@ -131,6 +150,42 @@ public: void ClearEntry(const std::string& entry, const char * attEntry = 0); void ClearSizeMaps(); + void SetEnforceCadEdgesSize( bool toEnforce ); + bool GetEnforceCadEdgesSize(); + + void SetJacobianRectificationRespectGeometry( bool allowRectification ); + bool GetJacobianRectificationRespectGeometry(); + + void SetJacobianRectification( bool allowRectification ); + bool GetJacobianRectification(); + + void SetMaxNumberOfPointsPerPatch( int nb ) throw (std::invalid_argument); + int GetMaxNumberOfPointsPerPatch(); + + void SetRespectGeometry( bool toRespect ); + bool GetRespectGeometry(); + + void SetTinyEdgesAvoidSurfaceIntersections( bool toAvoidIntersection ); + bool GetTinyEdgesAvoidSurfaceIntersections(); + + void SetClosedGeometry( bool isClosed ); + bool GetClosedGeometry(); + + void SetDebug( bool isDebug ); + bool GetDebug(); + + void SetPeriodicTolerance( double tol ) throw (std::invalid_argument); + double GetPeriodicTolerance(); + + void SetRequiredEntities( const std::string& howToTreat ) throw (std::invalid_argument); + std::string GetRequiredEntities(); + + void SetSewingTolerance( double tol ) throw (std::invalid_argument); + double GetSewingTolerance(); + + void SetTags( const std::string& howToTreat ) throw (std::invalid_argument); + std::string GetTags(); + void SetPreCADMergeEdges(bool theVal); bool GetPreCADMergeEdges() const { return _preCADMergeEdges; } @@ -342,7 +397,7 @@ public: // bool GetInternalEnforcedVertex(const TEntry& theFaceEntry); static PhysicalMesh GetDefaultPhysicalMesh() { return PhysicalGlobalSize; } - static GeometricMesh GetDefaultGeometricMesh() { return DefaultGeom; } + static GeometricMesh GetDefaultGeometricMesh() { return GeometricalGlobalSize; } static double GetDefaultPhySize(double diagonal, double bbSegmentation); static double GetDefaultPhySize() { return undefinedDouble(); } static bool GetDefaultPhySizeRel() { return false; } @@ -352,9 +407,12 @@ public: static double GetDefaultMaxSize(double diagonal); static double GetDefaultMaxSize() { return undefinedDouble(); } static bool GetDefaultMaxSizeRel() { return false; } + static bool GetDefaultUseGradation() { return false; } static double GetDefaultGradation() { return 1.3; } + static bool GetDefaultUseVolumeGradation() { return false; } + static double GetDefaultVolumeGradation() { return 2; } static bool GetDefaultQuadAllowed() { return false; } - static double GetDefaultAngleMesh() { return 22.0; } + static double GetDefaultAngleMesh() { return 8.0; } static double GetDefaultChordalError(double diagonal); static double GetDefaultChordalError() { return undefinedDouble(); } @@ -363,6 +421,11 @@ public: static bool GetDefaultRemoveTinyEdges() { return false; } static double GetDefaultTinyEdgeLength(double diagonal); static double GetDefaultTinyEdgeLength() { return undefinedDouble(); } + static bool GetDefaultOptimiseTinyEdges() { return false; } + static double GetDefaultTinyEdgeOptimisationLength(double diagonal); + static double GetDefaultTinyEdgeOptimisationLength() { return undefinedDouble(); } + static bool GetDefaultCorrectSurfaceIntersection() { return true; } + static double GetDefaultCorrectSurfaceIntersectionMaxCost() { return 15.; } static bool GetDefaultBadElementRemoval() { return false; } static double GetDefaultBadElementAspectRatio() {return 1000.0; } static bool GetDefaultOptimizeMesh() { return true; } @@ -433,20 +496,23 @@ public: const std::string& optionValue) throw (std::invalid_argument); void SetPreCADOptionValue(const std::string& optionName, const std::string& optionValue) throw (std::invalid_argument); - std::string GetOptionValue(const std::string& optionName) throw (std::invalid_argument); - std::string GetPreCADOptionValue(const std::string& optionName) throw (std::invalid_argument); + std::string GetOptionValue(const std::string& optionName, bool* isDefault=0) const throw (std::invalid_argument); + std::string GetPreCADOptionValue(const std::string& optionName, bool* isDefault=0) const throw (std::invalid_argument); void ClearOption(const std::string& optionName); void ClearPreCADOption(const std::string& optionName); - const TOptionValues& GetOptionValues() const { return _option2value; } - const TOptionValues& GetPreCADOptionValues() const { return _preCADoption2value; } + TOptionValues GetOptionValues() const; + TOptionValues GetPreCADOptionValues() const; const TOptionValues& GetCustomOptionValues() const { return _customOption2value; } - const TOptionValues& GetCustomPreCADOptionValues() const { return _customPreCADOption2value; } void AddOption(const std::string& optionName, const std::string& optionValue); void AddPreCADOption(const std::string& optionName, const std::string& optionValue); std::string GetOption(const std::string& optionName); std::string GetPreCADOption(const std::string& optionName); + 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); + /*! * Sets the file for export resulting mesh in GMF format */ @@ -484,7 +550,10 @@ private: bool _phySizeRel; double _minSize, _maxSize; bool _minSizeRel, _maxSizeRel; + bool _useGradation; double _gradation; + bool _useVolumeGradation; + double _volumeGradation; bool _quadAllowed; double _angleMesh; double _chordalError; @@ -492,6 +561,10 @@ private: double _anisotropicRatio; bool _removeTinyEdges; double _tinyEdgeLength; + bool _optimiseTinyEdges; + double _tinyEdgeOptimisationLength; + bool _correctSurfaceIntersec; + double _corrSurfaceIntersCost; bool _badElementRemoval; double _badElementAspectRatio; bool _optimizeMesh; @@ -506,21 +579,22 @@ private: bool _preCADDiscardInput; double _preCADEpsNano; - TOptionValues _option2value, _preCADoption2value; - TOptionValues _customOption2value, _customPreCADOption2value; - TOptionNames _doubleOptions, _charOptions; + TOptionValues _option2value, _preCADoption2value, _customOption2value; // user defined values + TOptionValues _defaultOptionValues; // default values + TOptionNames _doubleOptions, _charOptions, _boolOptions; // to find a type of option TOptionNames _preCADdoubleOptions, _preCADcharOptions; + TSizeMap _sizeMap; TSizeMap _attractors; TAttractorMap _classAttractors; TSizeMap _attEntry; TParamsMap _attParams; - TFaceEntryEnfVertexListMap _faceEntryEnfVertexListMap; - TEnfVertexList _enfVertexList; + TFaceEntryEnfVertexListMap _faceEntryEnfVertexListMap; + TEnfVertexList _enfVertexList; // maps to get "manual" enf vertex (through their coordinates) - TFaceEntryCoordsListMap _faceEntryCoordsListMap; - TCoordsEnfVertexMap _coordsEnfVertexMap; + TFaceEntryCoordsListMap _faceEntryCoordsListMap; + TCoordsEnfVertexMap _coordsEnfVertexMap; // maps to get "geom" enf vertex (through their geom entries) TFaceEntryEnfVertexEntryListMap _faceEntryEnfVertexEntryListMap; TEnfVertexEntryEnfVertexMap _enfVertexEntryEnfVertexMap; diff --git a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.cxx b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.cxx index f335309..b39f733 100644 --- a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.cxx +++ b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.cxx @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -238,6 +239,35 @@ CORBA::Boolean BLSURFPlugin_Hypothesis_i::IsMaxSizeRel() { return this->GetImpl()->IsMaxSizeRel(); } + +//============================================================================= +/*! + * BLSURFPlugin_Hypothesis_i::SetUseGradation + * + * Set true or false + */ +//============================================================================= +void BLSURFPlugin_Hypothesis_i::SetUseGradation(CORBA::Boolean theValue) { + MESSAGE("BLSURFPlugin_Hypothesis_i::SetUseGradation"); + ASSERT(myBaseImpl); + this->GetImpl()->SetUseGradation(theValue); + std::string theValueStr = theValue ? "True" : "False"; + SMESH::TPythonDump() << _this() << ".SetUseGradation( " << theValueStr.c_str() << " )"; +} + +//============================================================================= +/*! + * BLSURFPlugin_Hypothesis_i::GetUseGradation + * + * Get true or false + */ +//============================================================================= +CORBA::Boolean BLSURFPlugin_Hypothesis_i::GetUseGradation() { + MESSAGE("BLSURFPlugin_Hypothesis_i::GetUseGradation"); + ASSERT(myBaseImpl); + return this->GetImpl()->GetUseGradation(); +} + //============================================================================= /*! * BLSURFPlugin_Hypothesis_i::SetGradation @@ -265,6 +295,61 @@ CORBA::Double BLSURFPlugin_Hypothesis_i::GetGradation() { return this->GetImpl()->GetGradation(); } +//============================================================================= +/*! + * BLSURFPlugin_Hypothesis_i::SetUseVolumeGradation + * + * Set true or false + */ +//============================================================================= +void BLSURFPlugin_Hypothesis_i::SetUseVolumeGradation(CORBA::Boolean theValue) { + MESSAGE("BLSURFPlugin_Hypothesis_i::SetUseVolumeGradation"); + ASSERT(myBaseImpl); + this->GetImpl()->SetUseVolumeGradation(theValue); + std::string theValueStr = theValue ? "True" : "False"; + SMESH::TPythonDump() << _this() << ".SetUseVolumeGradation( " << theValueStr.c_str() << " )"; +} + +//============================================================================= +/*! + * BLSURFPlugin_Hypothesis_i::GetUseVolumeGradation + * + * Get true or false + */ +//============================================================================= +CORBA::Boolean BLSURFPlugin_Hypothesis_i::GetUseVolumeGradation() { + MESSAGE("BLSURFPlugin_Hypothesis_i::GetUseVolumeGradation"); + ASSERT(myBaseImpl); + return this->GetImpl()->GetUseVolumeGradation(); +} + +//============================================================================= +/*! + * BLSURFPlugin_Hypothesis_i::SetVolumeGradation + * + * Set VolumeGradation + */ +//============================================================================= +void BLSURFPlugin_Hypothesis_i::SetVolumeGradation(CORBA::Double theValue) { + // MESSAGE("BLSURFPlugin_Hypothesis_i::SetVolumeGradation"); + ASSERT(myBaseImpl); + this->GetImpl()->SetVolumeGradation(theValue); + SMESH::TPythonDump() << _this() << ".SetVolumeGradation( " << theValue << " )"; +} + +//============================================================================= +/*! + * BLSURFPlugin_Hypothesis_i::GetVolumeGradation + * + * Get VolumeGradation + */ +//============================================================================= +CORBA::Double BLSURFPlugin_Hypothesis_i::GetVolumeGradation() { + // MESSAGE("BLSURFPlugin_Hypothesis_i::GetVolumeGradation"); + ASSERT(myBaseImpl); + return this->GetImpl()->GetVolumeGradation(); +} + //============================================================================= /*! * BLSURFPlugin_Hypothesis_i::SetQuadAllowed @@ -458,6 +543,116 @@ CORBA::Double BLSURFPlugin_Hypothesis_i::GetTinyEdgeLength() { return this->GetImpl()->GetTinyEdgeLength(); } +//============================================================================= +/*! + * BLSURFPlugin_Hypothesis_i::SetOptimiseTinyEdges + * + * Set true or false + */ +//============================================================================= +void BLSURFPlugin_Hypothesis_i::SetOptimiseTinyEdges(CORBA::Boolean theValue) { + // MESSAGE("BLSURFPlugin_Hypothesis_i::SetOptimiseTinyEdges"); + ASSERT(myBaseImpl); + this->GetImpl()->SetOptimiseTinyEdges(theValue); + std::string theValueStr = theValue ? "True" : "False"; + SMESH::TPythonDump() << _this() << ".SetOptimiseTinyEdges( " << theValueStr.c_str() << " )"; +} + +//============================================================================= +/*! + * BLSURFPlugin_Hypothesis_i::GetOptimiseTinyEdges + * + * Get true or false + */ +//============================================================================= +CORBA::Boolean BLSURFPlugin_Hypothesis_i::GetOptimiseTinyEdges() { + // MESSAGE("BLSURFPlugin_Hypothesis_i::GetOptimiseTinyEdges"); + ASSERT(myBaseImpl); + return this->GetImpl()->GetOptimiseTinyEdges(); +} + +//============================================================================= +/*! + * BLSURFPlugin_Hypothesis_i::SetTinyEdgeOptimisationLength + * + * Set Tiny Edge OptimisationLength + */ +//============================================================================= +void BLSURFPlugin_Hypothesis_i::SetTinyEdgeOptimisationLength(CORBA::Double theValue) { + // MESSAGE("BLSURFPlugin_Hypothesis_i::SetTinyEdgeOptimisationLength"); + ASSERT(myBaseImpl); + this->GetImpl()->SetTinyEdgeOptimisationLength(theValue); + SMESH::TPythonDump() << _this() << ".SetTinyEdgeOptimisationLength( " << theValue << " )"; +} + +//============================================================================= +/*! + * BLSURFPlugin_Hypothesis_i::GetTinyEdgeOptimisationLength + * + * Get Tiny Edge OptimisationLength + */ +//============================================================================= +CORBA::Double BLSURFPlugin_Hypothesis_i::GetTinyEdgeOptimisationLength() { + // MESSAGE("BLSURFPlugin_Hypothesis_i::GetTinyEdgeOptimisationLength"); + ASSERT(myBaseImpl); + return this->GetImpl()->GetTinyEdgeOptimisationLength(); +} + +//============================================================================= +/*! + * BLSURFPlugin_Hypothesis_i::SetCorrectSurfaceIntersection + * + * Set true or false + */ +//============================================================================= +void BLSURFPlugin_Hypothesis_i::SetCorrectSurfaceIntersection(CORBA::Boolean theValue) { + // MESSAGE("BLSURFPlugin_Hypothesis_i::SetCorrectSurfaceIntersection"); + ASSERT(myBaseImpl); + this->GetImpl()->SetCorrectSurfaceIntersection(theValue); + std::string theValueStr = theValue ? "True" : "False"; + SMESH::TPythonDump() << _this() << ".SetCorrectSurfaceIntersection( " << theValueStr.c_str() << " )"; +} + +//============================================================================= +/*! + * BLSURFPlugin_Hypothesis_i::GetCorrectSurfaceIntersection + * + * Get true or false + */ +//============================================================================= +CORBA::Boolean BLSURFPlugin_Hypothesis_i::GetCorrectSurfaceIntersection() { + // MESSAGE("BLSURFPlugin_Hypothesis_i::GetCorrectSurfaceIntersection"); + ASSERT(myBaseImpl); + return this->GetImpl()->GetCorrectSurfaceIntersection(); +} + +//============================================================================= +/*! + * BLSURFPlugin_Hypothesis_i::SetCorrectSurfaceIntersectionMaxCost + * + * Set Tiny Edge OptimisationLength + */ +//============================================================================= +void BLSURFPlugin_Hypothesis_i::SetCorrectSurfaceIntersectionMaxCost(CORBA::Double theValue) { + // MESSAGE("BLSURFPlugin_Hypothesis_i::SetCorrectSurfaceIntersectionMaxCost"); + ASSERT(myBaseImpl); + this->GetImpl()->SetCorrectSurfaceIntersectionMaxCost(theValue); + SMESH::TPythonDump() << _this() << ".SetCorrectSurfaceIntersectionMaxCost( " << theValue << " )"; +} + +//============================================================================= +/*! + * BLSURFPlugin_Hypothesis_i::GetCorrectSurfaceIntersectionMaxCost + * + * Get Tiny Edge OptimisationLength + */ +//============================================================================= +CORBA::Double BLSURFPlugin_Hypothesis_i::GetCorrectSurfaceIntersectionMaxCost() { + // MESSAGE("BLSURFPlugin_Hypothesis_i::GetCorrectSurfaceIntersectionMaxCost"); + ASSERT(myBaseImpl); + return this->GetImpl()->GetCorrectSurfaceIntersectionMaxCost(); +} + //============================================================================= /*! * BLSURFPlugin_Hypothesis_i::SetBadElementRemoval @@ -616,6 +811,240 @@ CORBA::Short BLSURFPlugin_Hypothesis_i::GetVerbosity() { return (CORBA::Short) this->GetImpl()->GetVerbosity(); } +//============================================================================= +void BLSURFPlugin_Hypothesis_i::SetEnforceCadEdgesSize( CORBA::Boolean toEnforce ) +{ + if ( GetEnforceCadEdgesSize() != toEnforce ) + { + this->GetImpl()->SetEnforceCadEdgesSize(toEnforce); + SMESH::TPythonDump() << _this() << ".SetEnforceCadEdgesSize( " << toEnforce << " )"; + } +} +//============================================================================= +CORBA::Boolean BLSURFPlugin_Hypothesis_i::GetEnforceCadEdgesSize() +{ + return this->GetImpl()->GetEnforceCadEdgesSize(); +} +//============================================================================= + +void BLSURFPlugin_Hypothesis_i::SetJacobianRectificationRespectGeometry( CORBA::Boolean allowRectification ) +{ + if ( GetJacobianRectificationRespectGeometry() != allowRectification ) + { + this->GetImpl()->SetJacobianRectificationRespectGeometry(allowRectification); + SMESH::TPythonDump() << _this() << ".SetJacobianRectificationRespectGeometry( " << allowRectification << " )"; + } +} +//============================================================================= +CORBA::Boolean BLSURFPlugin_Hypothesis_i::GetJacobianRectificationRespectGeometry() +{ + return this->GetImpl()->GetJacobianRectificationRespectGeometry(); +} +//============================================================================= + +void BLSURFPlugin_Hypothesis_i::SetJacobianRectification( CORBA::Boolean allowRectification ) +{ + if ( GetJacobianRectification() != allowRectification ) + { + this->GetImpl()->SetJacobianRectification(allowRectification); + SMESH::TPythonDump() << _this() << ".SetJacobianRectification( " << allowRectification << " )"; + } +} +//============================================================================= +CORBA::Boolean BLSURFPlugin_Hypothesis_i::GetJacobianRectification() +{ + return this->GetImpl()->GetJacobianRectification(); +} +//============================================================================= + +void BLSURFPlugin_Hypothesis_i::SetMaxNumberOfPointsPerPatch( CORBA::Long nb ) throw (SALOME::SALOME_Exception) +{ + if ( GetMaxNumberOfPointsPerPatch() != nb ) + { + try { + this->GetImpl()->SetMaxNumberOfPointsPerPatch(nb); + + } 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 ); + } + SMESH::TPythonDump() << _this() << ".SetMaxNumberOfPointsPerPatch( " << nb << " )"; + } +} +//============================================================================= +CORBA::Long BLSURFPlugin_Hypothesis_i::GetMaxNumberOfPointsPerPatch() +{ + return this->GetImpl()->GetMaxNumberOfPointsPerPatch(); +} +//============================================================================= + +void BLSURFPlugin_Hypothesis_i::SetRespectGeometry( CORBA::Boolean toRespect ) +{ + if ( GetRespectGeometry() != toRespect ) + { + this->GetImpl()->SetRespectGeometry(toRespect); + SMESH::TPythonDump() << _this() << ".SetRespectGeometry( " << toRespect << " )"; + } +} +//============================================================================= +CORBA::Boolean BLSURFPlugin_Hypothesis_i::GetRespectGeometry() +{ + return this->GetImpl()->GetRespectGeometry(); +} +//============================================================================= + +void BLSURFPlugin_Hypothesis_i::SetTinyEdgesAvoidSurfaceIntersections( CORBA::Boolean toAvoidIntersection ) +{ + if ( GetTinyEdgesAvoidSurfaceIntersections() != toAvoidIntersection ) + { + this->GetImpl()->SetTinyEdgesAvoidSurfaceIntersections(toAvoidIntersection); + SMESH::TPythonDump() << _this() << ".SetTinyEdgesAvoidSurfaceIntersections( " << toAvoidIntersection << " )"; + } +} +//============================================================================= +CORBA::Boolean BLSURFPlugin_Hypothesis_i::GetTinyEdgesAvoidSurfaceIntersections() +{ + return this->GetImpl()->GetTinyEdgesAvoidSurfaceIntersections(); +} +//============================================================================= + +void BLSURFPlugin_Hypothesis_i::SetClosedGeometry( CORBA::Boolean isClosed ) +{ + if ( GetClosedGeometry() != isClosed ) + { + this->GetImpl()->SetClosedGeometry(isClosed); + SMESH::TPythonDump() << _this() << ".SetClosedGeometry( " << isClosed << " )"; + } +} +//============================================================================= +CORBA::Boolean BLSURFPlugin_Hypothesis_i::GetClosedGeometry() +{ + return this->GetImpl()->GetClosedGeometry(); +} +//============================================================================= + +void BLSURFPlugin_Hypothesis_i::SetDebug( CORBA::Boolean isDebug ) +{ + if ( GetDebug() != isDebug ) + { + this->GetImpl()->SetDebug(isDebug); + SMESH::TPythonDump() << _this() << ".SetDebug( " << isDebug << " )"; + } +} +//============================================================================= +bool BLSURFPlugin_Hypothesis_i::GetDebug() +{ + return this->GetImpl()->GetDebug(); +} +//============================================================================= + +void BLSURFPlugin_Hypothesis_i::SetPeriodicTolerance( CORBA::Double tol ) throw (SALOME::SALOME_Exception) +{ + if ( SMESH::toStdStr( GetPreCADOptionValue("periodic_tolerance")) != SMESH_Comment( tol )) + { + try + { + this->GetImpl()->SetPeriodicTolerance(tol); + + } 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 ); + } + SMESH::TPythonDump() << _this() << ".SetPeriodicTolerance( " << tol << " )"; + } +} +//============================================================================= +double BLSURFPlugin_Hypothesis_i::GetPeriodicTolerance() throw (SALOME::SALOME_Exception) +{ + try{ + return this->GetImpl()->GetPeriodicTolerance(); + + } 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 -1; +} +//============================================================================= + +void BLSURFPlugin_Hypothesis_i::SetRequiredEntities( const char* howToTreat ) throw (SALOME::SALOME_Exception) +{ + if ( GetImpl()->GetRequiredEntities() != howToTreat ) + { + try { + this->GetImpl()->SetRequiredEntities(howToTreat); + + } 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 ); + } + SMESH::TPythonDump() << _this() << ".SetRequiredEntities( '" << howToTreat << "' )"; + } +} +//============================================================================= +char* BLSURFPlugin_Hypothesis_i::GetRequiredEntities() +{ + return CORBA::string_dup( this->GetImpl()->GetRequiredEntities().c_str() ); +} +//============================================================================= + +void BLSURFPlugin_Hypothesis_i::SetSewingTolerance( CORBA::Double tol ) throw (SALOME::SALOME_Exception) +{ + if ( SMESH::toStdStr( GetPreCADOptionValue("sewing_tolerance")) != SMESH_Comment( tol )) + { + try + { + this->GetImpl()->SetSewingTolerance(tol); + SMESH::TPythonDump() << _this() << ".SetSewingTolerance( " << tol << " )"; + + } 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 ); + } + } +} +//============================================================================= +CORBA::Double BLSURFPlugin_Hypothesis_i::GetSewingTolerance() throw (SALOME::SALOME_Exception) +{ + try + { + return this->GetImpl()->GetSewingTolerance(); + + } 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 -1; +} +//============================================================================= + +void BLSURFPlugin_Hypothesis_i::SetTags( const char* howToTreat ) throw (SALOME::SALOME_Exception) +{ + if ( GetImpl()->GetTags() != howToTreat ) + { + try { + this->GetImpl()->SetTags(howToTreat); + } + 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 ); + } + } + SMESH::TPythonDump() << _this() << ".SetTags( '" << howToTreat << "' )"; +} +//============================================================================= +char* BLSURFPlugin_Hypothesis_i::GetTags() +{ + return CORBA::string_dup( this->GetImpl()->GetTags().c_str() ); +} + //============================================================================= /*! * BLSURFPlugin_Hypothesis_i::SetPreCADMergeEdges @@ -760,44 +1189,168 @@ CORBA::Boolean BLSURFPlugin_Hypothesis_i::GetPreCADDiscardInput() { //============================================================================= void BLSURFPlugin_Hypothesis_i::SetOptionValue(const char* optionName, const char* optionValue) - throw (SALOME::SALOME_Exception) { + throw (SALOME::SALOME_Exception) { ASSERT(myBaseImpl); - bool valueChanged = false; try { - valueChanged = (this->GetImpl()->GetOptionValue(optionName) != optionValue); - if (valueChanged) - this->GetImpl()->SetOptionValue(optionName, optionValue); + std::string name( optionName ); + if ( !optionValue || !optionValue[0] ) + UnsetOption( optionName ); + + // basic options (visible in Advanced table) + + else if ( name == "enforce_cad_edge_sizes" ) + SetEnforceCadEdgesSize( GetImpl()->ToBool( optionValue )); + + else if ( name == "jacobian_rectification_respect_geometry" ) + SetJacobianRectificationRespectGeometry( GetImpl()->ToBool( optionValue )); + + else if ( name == "max_number_of_points_per_patch" ) + SetMaxNumberOfPointsPerPatch( GetImpl()->ToInt( optionValue )); + + else if ( name == "rectify_jacobian" ) + SetJacobianRectification( GetImpl()->ToBool( optionValue )); + + else if ( name == "respect_geometry" ) + SetRespectGeometry( GetImpl()->ToBool( optionValue )); + + else if ( name == "tiny_edge_avoid_surface_intersections" ) + SetTinyEdgesAvoidSurfaceIntersections( GetImpl()->ToBool( optionValue )); + + else if ( name == "closed_geometry" ) + SetClosedGeometry( GetImpl()->ToBool( optionValue )); + + else if ( name == "debug" ) + SetDebug( GetImpl()->ToBool( optionValue )); + + else if ( name == "discard_input_topology" ) + SetPreCADDiscardInput( GetImpl()->ToBool( optionValue )); + + else if ( name == "merge_edges" ) + SetPreCADMergeEdges( GetImpl()->ToBool( optionValue )); + + else if ( name == "periodic_tolerance" ) + SetPeriodicTolerance( GetImpl()->ToDbl( optionValue )); + + else if ( name == "remove_duplicate_cad_faces" ) + SetPreCADRemoveDuplicateCADFaces( GetImpl()->ToBool( optionValue )); + + else if ( name == "required_entities" ) + SetRequiredEntities( optionValue ); + + else if ( name == "sewing_tolerance" ) + SetSewingTolerance( GetImpl()->ToDbl( optionValue )); + + else if ( name == "tags" ) + SetTags( optionValue ); + + // other basic options with specific methods + + else if ( name == "correct_surface_intersections" ) + SetCorrectSurfaceIntersection( GetImpl()->ToBool( optionValue )); + + else if ( name == "optimise_tiny_edges" ) + SetOptimiseTinyEdges( GetImpl()->ToBool( optionValue )); + + else if ( name == "surface_intersections_processing_max_cost" ) + SetCorrectSurfaceIntersectionMaxCost( GetImpl()->ToDbl( optionValue )); + + else if ( name == "volume_gradation" ) + SetVolumeGradation( GetImpl()->ToDbl( optionValue )); + + else if ( name == "tiny_edge_optimisation_length" ) + SetTinyEdgeOptimisationLength( GetImpl()->ToDbl( optionValue )); + + // advanced options (for backward compatibility) + + else if ( name == "create_tag_on_collision" || + name == "tiny_edge_respect_geometry" ) + AddOption( optionName, optionValue ); + + else { + bool valueChanged; + valueChanged = ( this->GetImpl()->GetOptionValue( name ) != optionValue && + this->GetImpl()->GetOptionValue( name, &valueChanged ) != optionValue ); + if ( valueChanged ) + { + this->GetImpl()->SetOptionValue(optionName, optionValue); + SMESH::TPythonDump() << _this() << ".SetOptionValue( '" << optionName << "', '" << optionValue << "' )"; + } + } } catch (const std::invalid_argument& ex) { - SALOME::ExceptionStruct ExDescription; - ExDescription.text = ex.what(); - ExDescription.type = SALOME::BAD_PARAM; - ExDescription.sourceFile = "BLSURFPlugin_Hypothesis::SetOptionValue(name,value)"; - ExDescription.lineNumber = 0; - throw SALOME::SALOME_Exception(ExDescription); + THROW_SALOME_CORBA_EXCEPTION( ex.what() ,SALOME::BAD_PARAM ); } catch (SALOME_Exception& ex) { THROW_SALOME_CORBA_EXCEPTION( ex.what() ,SALOME::BAD_PARAM ); } - if (valueChanged) - SMESH::TPythonDump() << _this() << ".SetOptionValue( '" << optionName << "', '" << optionValue << "' )"; } //============================================================================= void BLSURFPlugin_Hypothesis_i::SetPreCADOptionValue(const char* optionName, const char* optionValue) - throw (SALOME::SALOME_Exception) { + throw (SALOME::SALOME_Exception) { ASSERT(myBaseImpl); bool valueChanged = false; try { - valueChanged = (this->GetImpl()->GetPreCADOptionValue(optionName) != optionValue); - if (valueChanged) - this->GetImpl()->SetPreCADOptionValue(optionName, optionValue); + std::string name( optionName ); + if ( !optionValue || !optionValue[0] ) + UnsetOption( optionName ); + + else if ( name == "closed_geometry" ) + SetClosedGeometry( GetImpl()->ToBool( optionValue )); + + else if ( name == "debug" ) + SetDebug( GetImpl()->ToBool( optionValue )); + + else if ( name == "discard_input_topology" ) + SetPreCADDiscardInput( GetImpl()->ToBool( optionValue )); + + else if ( name == "merge_edges" ) + SetPreCADMergeEdges( GetImpl()->ToBool( optionValue )); + + else if ( name == "periodic_tolerance" ) + SetPeriodicTolerance( GetImpl()->ToDbl( optionValue )); + + else if ( name == "remove_duplicate_cad_faces" ) + SetPreCADRemoveDuplicateCADFaces( GetImpl()->ToBool( optionValue )); + + else if ( name == "required_entities" ) + SetRequiredEntities( optionValue ); + + else if ( name == "sewing_tolerance" ) + SetSewingTolerance( GetImpl()->ToDbl( optionValue )); + + else if ( name == "tags" ) + SetTags( optionValue ); + + // other basic options with specific methods + + else if ( name == "correct_surface_intersections" ) + SetCorrectSurfaceIntersection( GetImpl()->ToBool( optionValue )); + + else if ( name == "optimise_tiny_edges" ) + SetOptimiseTinyEdges( GetImpl()->ToBool( optionValue )); + + else if ( name == "surface_intersections_processing_max_cost" ) + SetCorrectSurfaceIntersectionMaxCost( GetImpl()->ToDbl( optionValue )); + + else if ( name == "volume_gradation" ) + SetVolumeGradation( GetImpl()->ToDbl( optionValue )); + + else if ( name == "tiny_edge_optimisation_length" ) + SetTinyEdgeOptimisationLength( GetImpl()->ToDbl( optionValue )); + + // advanced options (for backward compatibility) + + else if ( name == "create_tag_on_collision" || + name == "tiny_edge_respect_geometry" ) + AddOption( optionName, optionValue ); + + else { + valueChanged = (this->GetImpl()->GetPreCADOptionValue(optionName) != optionValue); + if (valueChanged) + this->GetImpl()->SetPreCADOptionValue(optionName, optionValue); + } } catch (const std::invalid_argument& ex) { - SALOME::ExceptionStruct ExDescription; - ExDescription.text = ex.what(); - ExDescription.type = SALOME::BAD_PARAM; - ExDescription.sourceFile = "BLSURFPlugin_Hypothesis::SetPreCADOptionValue(name,value)"; - ExDescription.lineNumber = 0; - throw SALOME::SALOME_Exception(ExDescription); + THROW_SALOME_CORBA_EXCEPTION( ex.what() ,SALOME::BAD_PARAM ); } catch (SALOME_Exception& ex) { THROW_SALOME_CORBA_EXCEPTION( ex.what() ,SALOME::BAD_PARAM ); } @@ -810,14 +1363,10 @@ void BLSURFPlugin_Hypothesis_i::SetPreCADOptionValue(const char* optionName, con char* BLSURFPlugin_Hypothesis_i::GetOptionValue(const char* optionName) throw (SALOME::SALOME_Exception) { ASSERT(myBaseImpl); try { - return CORBA::string_dup(this->GetImpl()->GetOptionValue(optionName).c_str()); + bool isDefault; + return CORBA::string_dup(this->GetImpl()->GetOptionValue(optionName,&isDefault).c_str()); } catch (const std::invalid_argument& ex) { - SALOME::ExceptionStruct ExDescription; - ExDescription.text = ex.what(); - ExDescription.type = SALOME::BAD_PARAM; - ExDescription.sourceFile = "BLSURFPlugin_Hypothesis::GetOptionValue(name)"; - ExDescription.lineNumber = 0; - throw SALOME::SALOME_Exception(ExDescription); + THROW_SALOME_CORBA_EXCEPTION( ex.what() ,SALOME::BAD_PARAM ); } catch (SALOME_Exception& ex) { THROW_SALOME_CORBA_EXCEPTION( ex.what() ,SALOME::BAD_PARAM ); } @@ -829,14 +1378,10 @@ char* BLSURFPlugin_Hypothesis_i::GetOptionValue(const char* optionName) throw (S char* BLSURFPlugin_Hypothesis_i::GetPreCADOptionValue(const char* optionName) throw (SALOME::SALOME_Exception) { ASSERT(myBaseImpl); try { - return CORBA::string_dup(this->GetImpl()->GetPreCADOptionValue(optionName).c_str()); + bool isDefault; + return CORBA::string_dup(this->GetImpl()->GetPreCADOptionValue(optionName,&isDefault).c_str()); } catch (const std::invalid_argument& ex) { - SALOME::ExceptionStruct ExDescription; - ExDescription.text = ex.what(); - ExDescription.type = SALOME::BAD_PARAM; - ExDescription.sourceFile = "BLSURFPlugin_Hypothesis::GetPreCADOptionValue(name)"; - ExDescription.lineNumber = 0; - throw SALOME::SALOME_Exception(ExDescription); + THROW_SALOME_CORBA_EXCEPTION( ex.what() ,SALOME::BAD_PARAM ); } catch (SALOME_Exception& ex) { THROW_SALOME_CORBA_EXCEPTION( ex.what() ,SALOME::BAD_PARAM ); } @@ -847,16 +1392,22 @@ char* BLSURFPlugin_Hypothesis_i::GetPreCADOptionValue(const char* optionName) th void BLSURFPlugin_Hypothesis_i::UnsetOption(const char* optionName) { ASSERT(myBaseImpl); - this->GetImpl()->ClearOption(optionName); - SMESH::TPythonDump() << _this() << ".UnsetOption( '" << optionName << "' )"; + if ( !GetImpl()->GetOptionValue( optionName ).empty() ) + { + this->GetImpl()->ClearOption(optionName); + SMESH::TPythonDump() << _this() << ".UnsetOption( '" << optionName << "' )"; + } } //============================================================================= void BLSURFPlugin_Hypothesis_i::UnsetPreCADOption(const char* optionName) { ASSERT(myBaseImpl); - this->GetImpl()->ClearPreCADOption(optionName); - SMESH::TPythonDump() << _this() << ".UnsetPreCADOption( '" << optionName << "' )"; + if ( !GetImpl()->GetPreCADOptionValue( optionName ).empty() ) + { + this->GetImpl()->ClearPreCADOption(optionName); + SMESH::TPythonDump() << _this() << ".UnsetPreCADOption( '" << optionName << "' )"; + } } //============================================================================= @@ -866,31 +1417,21 @@ BLSURFPlugin::string_array* BLSURFPlugin_Hypothesis_i::GetOptionValues() { BLSURFPlugin::string_array_var result = new BLSURFPlugin::string_array(); const ::BLSURFPlugin_Hypothesis::TOptionValues & opts = this->GetImpl()->GetOptionValues(); - const ::BLSURFPlugin_Hypothesis::TOptionValues & custom_opts = this->GetImpl()->GetCustomOptionValues(); - result->length(opts.size()+custom_opts.size()); + result->length(opts.size()); int i=0; + bool isDefault; ::BLSURFPlugin_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 += opIt->second; - name_value_type += ":0"; + name_value_type += GetImpl()->GetOptionValue( opIt->first, &isDefault ); + name_value_type += isDefault ? ":0" : ":1"; } result[i] = CORBA::string_dup(name_value_type.c_str()); } - 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"; - } - result[i] = CORBA::string_dup(name_value_type.c_str()); - } return result._retn(); } @@ -901,28 +1442,40 @@ BLSURFPlugin::string_array* BLSURFPlugin_Hypothesis_i::GetPreCADOptionValues() { BLSURFPlugin::string_array_var result = new BLSURFPlugin::string_array(); const ::BLSURFPlugin_Hypothesis::TOptionValues & opts = this->GetImpl()->GetPreCADOptionValues(); - const ::BLSURFPlugin_Hypothesis::TOptionValues & custom_opts = this->GetImpl()->GetCustomPreCADOptionValues(); - result->length(opts.size()+custom_opts.size()); + result->length(opts.size()); int i=0; + bool isDefault; ::BLSURFPlugin_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 += opIt->second; - name_value_type += ":0"; + name_value_type += GetImpl()->GetPreCADOptionValue( opIt->first, &isDefault ); + name_value_type += isDefault ? ":0" : ":1"; } result[i] = CORBA::string_dup(name_value_type.c_str()); } + return result._retn(); +} + +//============================================================================= + +BLSURFPlugin::string_array* BLSURFPlugin_Hypothesis_i::GetAdvancedOptionValues() +{ + BLSURFPlugin::string_array_var result = new BLSURFPlugin::string_array(); - opIt = custom_opts.begin(); - for (; opIt != custom_opts.end(); ++opIt,++i) { + const ::BLSURFPlugin_Hypothesis::TOptionValues & custom_opts = this->GetImpl()->GetCustomOptionValues(); + result->length(custom_opts.size()); + int i=0; + + ::BLSURFPlugin_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"; + name_value_type += ":1"; // user defined } result[i] = CORBA::string_dup(name_value_type.c_str()); } @@ -940,7 +1493,6 @@ void BLSURFPlugin_Hypothesis_i::SetOptionValues(const BLSURFPlugin::string_array continue; size_t colonPos = name_value_type.find(':'); string name, value; - bool custom = false; if (colonPos == string::npos) // ':' not found name = name_value_type; else { @@ -950,10 +1502,11 @@ void BLSURFPlugin_Hypothesis_i::SetOptionValues(const BLSURFPlugin::string_array colonPos = value_type.find(':'); value = value_type.substr(0, colonPos); if (colonPos < value_type.size() - 1 && value_type[colonPos] != ' ') - custom = atoi((value_type.substr(colonPos + 1)).c_str()); + if ( value_type.substr(colonPos + 1) == "0" ) // is default + value.clear(); } } - custom ? AddOption(name.c_str(), value.c_str()) : SetOptionValue(name.c_str(), value.c_str()); + SetOptionValue(name.c_str(), value.c_str()); } } @@ -968,7 +1521,6 @@ void BLSURFPlugin_Hypothesis_i::SetPreCADOptionValues(const BLSURFPlugin::string continue; size_t colonPos = name_value_type.find(':'); string name, value; - bool custom = false; if (colonPos == string::npos) // ':' not found name = name_value_type; else { @@ -978,11 +1530,72 @@ void BLSURFPlugin_Hypothesis_i::SetPreCADOptionValues(const BLSURFPlugin::string colonPos = value_type.find(':'); value = value_type.substr(0, colonPos); if (colonPos < value_type.size() - 1 && value_type[colonPos] != ' ') - custom = atoi((value_type.substr(colonPos + 1)).c_str()); + if ( value_type.substr(colonPos + 1) == "0" ) // is default + value.clear(); } } - custom ? AddPreCADOption(name.c_str(), value.c_str()) : SetPreCADOptionValue(name.c_str(), value.c_str()); + SetPreCADOptionValue(name.c_str(), value.c_str()); + } +} + +//============================================================================= + +void BLSURFPlugin_Hypothesis_i::SetAdvancedOptionValues(const BLSURFPlugin::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 BLSURFPlugin_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; + while ( sIt != sEnd ) + { + std::string option = *sIt; + if ( ++sIt != sEnd ) + { + std::string value = *sIt; + ++sIt; + AddOption( option.c_str(), value.c_str() ); + } + else + { + THROW_SALOME_CORBA_EXCEPTION( "Uneven number of options and values" ,SALOME::BAD_PARAM ); + } } + dump << _this() << ".SetAdvancedOption( '" << optionsAndValues << "' )"; } //============================================================================= diff --git a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.hxx b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.hxx index 1994391..eeb20c3 100644 --- a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.hxx +++ b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.hxx @@ -66,39 +66,58 @@ public: CORBA::Double GetMaxSize(); CORBA::Boolean IsMaxSizeRel(); + void SetUseGradation(CORBA::Boolean theValue); + CORBA::Boolean GetUseGradation(); void SetGradation(CORBA::Double theValue); CORBA::Double GetGradation(); + void SetUseVolumeGradation(CORBA::Boolean theValue); + CORBA::Boolean GetUseVolumeGradation(); + void SetVolumeGradation(CORBA::Double theValue); + CORBA::Double GetVolumeGradation(); + void SetQuadAllowed(CORBA::Boolean theValue); CORBA::Boolean GetQuadAllowed(); void SetAngleMesh(CORBA::Double theValue); CORBA::Double GetAngleMesh(); - + void SetChordalError(CORBA::Double distance); CORBA::Double GetChordalError(); - + void SetAnisotropic(CORBA::Boolean anisotropic); CORBA::Boolean GetAnisotropic(); - + void SetAnisotropicRatio(CORBA::Double ratio); CORBA::Double GetAnisotropicRatio(); - + void SetRemoveTinyEdges(CORBA::Boolean remove); CORBA::Boolean GetRemoveTinyEdges(); - + void SetTinyEdgeLength(CORBA::Double length); CORBA::Double GetTinyEdgeLength(); - + + void SetOptimiseTinyEdges(CORBA::Boolean toOptimise); + CORBA::Boolean GetOptimiseTinyEdges(); + + void SetTinyEdgeOptimisationLength(CORBA::Double length); + CORBA::Double GetTinyEdgeOptimisationLength(); + + void SetCorrectSurfaceIntersection(CORBA::Boolean toOptimise); + CORBA::Boolean GetCorrectSurfaceIntersection(); + + void SetCorrectSurfaceIntersectionMaxCost(CORBA::Double maxCost); + CORBA::Double GetCorrectSurfaceIntersectionMaxCost(); + void SetBadElementRemoval(CORBA::Boolean remove); CORBA::Boolean GetBadElementRemoval(); - + void SetBadElementAspectRatio(CORBA::Double ratio); CORBA::Double GetBadElementAspectRatio(); - + void SetOptimizeMesh(CORBA::Boolean optimize); CORBA::Boolean GetOptimizeMesh(); - + void SetQuadraticMesh(CORBA::Boolean quadratic); CORBA::Boolean GetQuadraticMesh(); @@ -108,6 +127,42 @@ public: void SetVerbosity(CORBA::Short theVal) throw (SALOME::SALOME_Exception); CORBA::Short GetVerbosity(); + void SetEnforceCadEdgesSize( CORBA::Boolean toEnforce ); + CORBA::Boolean GetEnforceCadEdgesSize(); + + void SetJacobianRectificationRespectGeometry( CORBA::Boolean allowRectification ); + CORBA::Boolean GetJacobianRectificationRespectGeometry(); + + void SetJacobianRectification( CORBA::Boolean allowRectification ); + CORBA::Boolean GetJacobianRectification(); + + void SetMaxNumberOfPointsPerPatch( CORBA::Long nb ) throw (SALOME::SALOME_Exception); + CORBA::Long GetMaxNumberOfPointsPerPatch(); + + void SetRespectGeometry( CORBA::Boolean toRespect ); + CORBA::Boolean GetRespectGeometry(); + + void SetTinyEdgesAvoidSurfaceIntersections( CORBA::Boolean toAvoidIntersection ); + CORBA::Boolean GetTinyEdgesAvoidSurfaceIntersections(); + + void SetClosedGeometry( CORBA::Boolean isClosed ); + CORBA::Boolean GetClosedGeometry(); + + void SetDebug( CORBA::Boolean isDebug ); + bool GetDebug(); + + void SetPeriodicTolerance( CORBA::Double tol ) throw (SALOME::SALOME_Exception); + double GetPeriodicTolerance() throw (SALOME::SALOME_Exception); + + void SetRequiredEntities( const char* howToTreat ) throw (SALOME::SALOME_Exception); + char* GetRequiredEntities(); + + void SetSewingTolerance( CORBA::Double tol ) throw (SALOME::SALOME_Exception); + CORBA::Double GetSewingTolerance() throw (SALOME::SALOME_Exception); + + void SetTags( const char* howToTreat ) throw (SALOME::SALOME_Exception); + char* GetTags(); + void SetPreCADMergeEdges(CORBA::Boolean theValue); CORBA::Boolean GetPreCADMergeEdges(); @@ -133,9 +188,12 @@ public: BLSURFPlugin::string_array* GetOptionValues(); BLSURFPlugin::string_array* GetPreCADOptionValues(); + BLSURFPlugin::string_array* GetAdvancedOptionValues(); void SetOptionValues(const BLSURFPlugin::string_array& options) throw (SALOME::SALOME_Exception); void SetPreCADOptionValues(const BLSURFPlugin::string_array& options) throw (SALOME::SALOME_Exception); + void SetAdvancedOptionValues(const BLSURFPlugin::string_array& options); + void SetAdvancedOption(const char* optionsAndValues) throw (SALOME::SALOME_Exception); void AddOption(const char* optionName, const char* optionValue); void AddPreCADOption(const char* optionName, const char* optionValue); diff --git a/src/GUI/BLSURFPluginGUI_AdvWidget.cxx b/src/GUI/BLSURFPluginGUI_AdvWidget.cxx index 4f68841..8bd1296 100644 --- a/src/GUI/BLSURFPluginGUI_AdvWidget.cxx +++ b/src/GUI/BLSURFPluginGUI_AdvWidget.cxx @@ -29,23 +29,43 @@ #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; + } + }; +} ////////////////////////////////////////// // BLSURFPluginGUI_AdvWidget ////////////////////////////////////////// BLSURFPluginGUI_AdvWidget::BLSURFPluginGUI_AdvWidget( QWidget* parent, Qt::WindowFlags f ) -: QWidget( parent, f ) + : QWidget( parent, f ) { setupUi( this ); - myOptionTable->horizontalHeader()->hideSection( OPTION_ID_COLUMN ); + myOptionTable->topLevelItem( 2 )->setHidden( true ); // hide CUSTOM options + myOptionTable->header()->setSectionResizeMode( QHeaderView::ResizeToContents ); + myOptionTable->setItemDelegate( new ItemDelegate( myOptionTable ) ); + + connect( myOptionTable, SIGNAL( itemChanged(QTreeWidgetItem *, int)), SLOT( itemChanged(QTreeWidgetItem *, int ))); } BLSURFPluginGUI_AdvWidget::~BLSURFPluginGUI_AdvWidget() { } -void BLSURFPluginGUI_AdvWidget::onChooseGMFFile() { +void BLSURFPluginGUI_AdvWidget::onChooseGMFFile() +{ QString fileName = QFileDialog::getSaveFileName(0, tr("BLSURF_GMF_FILE_DIALOG"), myGMFFileName->text(), tr("BLSURF_GMF_FILE_FORMAT")); std::cout << "fileName: " << fileName.toStdString() << std::endl; if (!fileName.endsWith(".mesh") && !fileName.endsWith(".meshb")) @@ -53,4 +73,72 @@ void BLSURFPluginGUI_AdvWidget::onChooseGMFFile() { myGMFFileName->setText(fileName); } +void BLSURFPluginGUI_AdvWidget::AddOption( int iTable, const char* option ) +{ + if ( iTable < 0 || iTable > 2 ) return; + + QTreeWidgetItem * table = myOptionTable->topLevelItem( iTable ); + table->setExpanded( true ); + + QTreeWidgetItem * row = new QTreeWidgetItem( table ); + row->setData( NAME_COL, EDITABLE_ROLE, int( iTable == 2 && !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(); + } + 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 ( iTable == 2 ) + { + table->setHidden( false ); + if ( !option ) + { + myOptionTable->scrollToItem( row ); + myOptionTable->editItem( row, NAME_COL ); + } + } +} +void BLSURFPluginGUI_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 ); +} + + +void BLSURFPluginGUI_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/BLSURFPluginGUI_AdvWidget_QTD.ui b/src/GUI/BLSURFPluginGUI_AdvWidget_QTD.ui index c83d77d..c2f05df 100644 --- a/src/GUI/BLSURFPluginGUI_AdvWidget_QTD.ui +++ b/src/GUI/BLSURFPluginGUI_AdvWidget_QTD.ui @@ -6,193 +6,124 @@ 0 0 - 653 - 226 + 563 + 293 - - - + + + + + QAbstractItemView::DoubleClicked + + + + OPTION_NAME_COLUMN + + + + 50 + false + + + + + + OPTION_VALUE_COLUMN + + + + 50 + false + + + + + + BLSURF_MESHING_OPTIONS + + + + 75 + true + + + + + + BLSURF_PRECAD_OPTIONS + + + + 75 + true + + + + + + BLSURF_CUSTOM_OPTIONS + + + + 75 + true + + + + + + + + + BLSURF_ADD_OPTION + + + + + + + BLSURF_VERBOSITY + + + + + + + 10 + + + 5 + + + + + Qt::Horizontal - - - - - - true - - - true - - - true - - - false - - - - OPTION_ID_COLUMN - - - - - OPTION_TYPE_COLUMN - - - - - OPTION_NAME_COLUMN - - - - - OPTION_VALUE_COLUMN - - - - - - - - BLSURF_ADD_OPTION - - - - - - - BLSURF_REMOVE_OPTION - - - - - - - - - 0 - - - - - BLSURF_PRECAD_GROUP - - - false - - - false - - - - - - BLSURF_PRECAD_MERGE_EDGES - - - true - - - - - - - BLSURF_PRECAD_REMOVE_TINY_UV_EDGES - - - true - - - - - - - BLSURF_PRECAD_PROCESS_3D_TOPOLOGY - - - true - - - - - - - BLSURF_PRECAD_DISCARD_INPUT - - - - - - - BLSURF_PRECAD_REMOVE_DUPLICATE_CAD_FACES - - - true - - - - - - - - - - BLSURF_GMF_FILE - - - - - - - - - - Qt::Vertical - - - - 20 - 53 - - - - - - - - BLSURF_VERBOSITY - - - - - - - 10 - - - 5 - - - - - + + + 362 + 20 + + + + + + + + BLSURF_GMF_FILE + + + + - myOptionTable addBtn - rmBtn - myPreCADGroupBox - myPreCADMergeEdges - myPreCADRemoveTinyUVEdges - myPreCADRemoveDuplicateCADFaces - myPreCADProcess3DTopology - myPreCADDiscardInput myVerbosity chooseGMFBtn myGMFFileName diff --git a/src/GUI/BLSURFPluginGUI_Dlg.h b/src/GUI/BLSURFPluginGUI_Dlg.h index 878ee34..7c24426 100644 --- a/src/GUI/BLSURFPluginGUI_Dlg.h +++ b/src/GUI/BLSURFPluginGUI_Dlg.h @@ -90,8 +90,14 @@ public: BLSURFPluginGUI_AdvWidget( QWidget* = 0, Qt::WindowFlags = 0 ); ~BLSURFPluginGUI_AdvWidget(); + void AddOption( int iTable, const char* name_value_type ); + void GetOptionAndValue( QTreeWidgetItem * tblRow, QString& option, QString& value, bool& dflt ); + public slots: + void onChooseGMFFile(); + void itemChanged(QTreeWidgetItem * tblRow, int column); + }; -#endif \ No newline at end of file +#endif diff --git a/src/GUI/BLSURFPluginGUI_HypothesisCreator.cxx b/src/GUI/BLSURFPluginGUI_HypothesisCreator.cxx index 549ab62..aecdbe5 100644 --- a/src/GUI/BLSURFPluginGUI_HypothesisCreator.cxx +++ b/src/GUI/BLSURFPluginGUI_HypothesisCreator.cxx @@ -93,7 +93,11 @@ enum { SMP_ENTRY_COLUMN, // SMP_DIST_COLUMN, SMP_NB_COLUMNS, -// Enforced vertices array columns + + // Adv tables + TBL_MESHING = 0, TBL_PRECAD, TBL_CUSTOM, + + // Enforced vertices array columns ENF_VER_NAME_COLUMN = 0, ENF_VER_FACE_ENTRY_COLUMN, ENF_VER_X_COLUMN, @@ -525,24 +529,43 @@ bool BLSURFPluginGUI_HypothesisCreator::checkParams(QString& msg) const myAdvWidget->myOptionTable->setFocus(); QApplication::instance()->processEvents(); - int row = 0, nbRows = myAdvWidget->myOptionTable->rowCount(); - for ( ; row < nbRows; ++row ) + QString name, value; + bool isDefault; + int iTbl = 0, nbTbl = myAdvWidget->myOptionTable->topLevelItemCount(); + for ( ; iTbl < nbTbl; ++iTbl ) { - QString name = myAdvWidget->myOptionTable->item( row, OPTION_NAME_COLUMN )->text(); - QString value = myAdvWidget->myOptionTable->item( row, OPTION_VALUE_COLUMN )->text().trimmed(); - bool custom = myAdvWidget->myOptionTable->item( row, OPTION_NAME_COLUMN )->data(Qt::UserRole).toBool(); - if ( !value.isEmpty() && !custom ) { + QTreeWidgetItem* table = myAdvWidget->myOptionTable->topLevelItem( iTbl ); + int nbRows = table->childCount(); + for ( int iRow = 0; iRow < nbRows; ++iRow ) + { + QTreeWidgetItem* row = table->child( iRow ); + myAdvWidget->GetOptionAndValue( row, name, value, isDefault ); + + if ( name.simplified().isEmpty() ) + continue; // invalid custom option + + if ( isDefault ) // not selected option + value.clear(); + try { - QString optionType = myAdvWidget->myOptionTable->item( row, OPTION_TYPE_COLUMN )->text().trimmed(); - if (optionType == "PRECAD") - h->SetPreCADOptionValue( name.toLatin1().constData(), value.toLatin1().constData() ); - else if (optionType == "BLSURF") + switch ( iTbl ) + { + case TBL_MESHING: h->SetOptionValue( name.toLatin1().constData(), value.toLatin1().constData() ); + break; + case TBL_PRECAD: + h->SetPreCADOptionValue( name.toLatin1().constData(), value.toLatin1().constData() ); + break; + case TBL_CUSTOM: + h->AddOption( name.toLatin1().constData(), value.toLatin1().constData() ); + break; + } } catch ( const SALOME::SALOME_Exception& ex ) { msg = ex.details.text.in(); ok = false; + break; } } } @@ -551,6 +574,7 @@ bool BLSURFPluginGUI_HypothesisCreator::checkParams(QString& msg) const { h->SetOptionValues( myOptions ); // restore values h->SetPreCADOptionValues( myPreCADOptions ); // restore values + return ok; } // SizeMap and attractors @@ -668,14 +692,14 @@ QFrame* BLSURFPluginGUI_HypothesisCreator::buildFrame() } aStdLayout->addWidget( myStdWidget, row++, 0, 1, 4 ); - int maxrow = row; + //int maxrow = row; row = 0; if( isCreation() ) row = 1; // row = max(row,maxrow)+1; aStdLayout->setRowStretch(row,1); aStdLayout->setColumnStretch(1,1); - maxrow = row; + //maxrow = row; // advanced parameters @@ -684,8 +708,8 @@ QFrame* BLSURFPluginGUI_HypothesisCreator::buildFrame() anAdvLayout->setSpacing( 6 ); anAdvLayout->setMargin( 11 ); myAdvWidget = new BLSURFPluginGUI_AdvWidget(myAdvGroup); - myAdvWidget->addBtn->setMenu( new QMenu() ); - anAdvLayout->addWidget( myAdvWidget); + //myAdvWidget->addBtn->setMenu( new QMenu() ); + anAdvLayout->addWidget( myAdvWidget ); // Size Maps parameters @@ -1125,11 +1149,7 @@ QFrame* BLSURFPluginGUI_HypothesisCreator::buildFrame() myTabWidget->setCurrentIndex( STD_TAB ); - connect( myAdvWidget->addBtn->menu(), SIGNAL( aboutToShow() ), this, SLOT( onAddOption() ) ); - connect( myAdvWidget->addBtn->menu(), SIGNAL( triggered( QAction* ) ), this, SLOT( onOptionChosenInPopup( QAction* ) ) ); - connect( myAdvWidget->rmBtn, SIGNAL( clicked()), this, SLOT( onDeleteOption() ) ); - connect( myAdvWidget->myOptionTable, SIGNAL( cellPressed( int, int ) ), this, SLOT( onEditOption( int, int ) ) ); - connect( myAdvWidget->myOptionTable, SIGNAL( cellChanged( int, int ) ), this, SLOT( onChangeOptionName( int, int ) ) ); + connect( myAdvWidget->addBtn, SIGNAL( clicked() ), this, SLOT( onAddOption() ) ); connect( myStdWidget->myAllowQuadrangles, SIGNAL( stateChanged( int ) ), this, SLOT( onStateChange() )); // Size Maps @@ -1672,7 +1692,7 @@ void BLSURFPluginGUI_HypothesisCreator::onPeriodicityByVerticesChecked(bool chec { if (! checked) { - for (size_t k=2; kdeactivateSelection(); @@ -1744,7 +1764,7 @@ void BLSURFPluginGUI_HypothesisCreator::onPeriodicityContentModified() BLSURFPluginGUI_HypothesisCreator* that = (BLSURFPluginGUI_HypothesisCreator*)this; ListOfWidgets::const_iterator anIt = myPeriodicitySelectionWidgets.begin(); - size_t k=0; + int k=0; // find wich selection widget is activated for (; anIt != myPeriodicitySelectionWidgets.end(); anIt++, k++) { @@ -1798,10 +1818,16 @@ void BLSURFPluginGUI_HypothesisCreator::retrieveParams() const else myStdWidget->myMaxSize->SetValue( data.myMaxSize ); myStdWidget->myMaxSizeRel->setChecked( data.myMaxSizeRel ); - if (data.myGradation <= 0) + myStdWidget->myUseGradation->setChecked( data.myUseGradation ); + if (data.myGradation <= 0 || !data.myUseGradation ) myStdWidget->myGradation->setText(""); else myStdWidget->myGradation->SetValue( data.myGradation ); + myStdWidget->myUseVolumeGradation->setChecked( data.myUseVolumeGradation ); + if (data.myVolumeGradation <= 0 || !data.myUseVolumeGradation ) + myStdWidget->myVolumeGradation->setText(""); + else + myStdWidget->myVolumeGradation->SetValue( data.myVolumeGradation ); myStdWidget->myAllowQuadrangles->setChecked( data.myAllowQuadrangles ); if (data.myAngleMesh < 0) @@ -1822,6 +1848,16 @@ void BLSURFPluginGUI_HypothesisCreator::retrieveParams() const myStdWidget->myTinyEdgeLength->setText(""); else myStdWidget->myTinyEdgeLength->SetValue( data.myTinyEdgeLength ); + myStdWidget->myOptimiseTinyEdges->setChecked( data.myOptimiseTinyEdges ); + if (data.myTinyEdgeOptimisLength <= 0) + myStdWidget->myTinyEdgeOptimisLength->setText(""); + else + myStdWidget->myTinyEdgeOptimisLength->SetValue( data.myTinyEdgeOptimisLength ); + myStdWidget->myCorrectSurfaceIntersection->setChecked( data.myCorrectSurfaceIntersection ); + if (data.myCorrectSurfaceIntersectionMaxCost <= 0) + myStdWidget->myCorrectSurfaceIntersectionMaxCost->setText(""); + else + myStdWidget->myCorrectSurfaceIntersectionMaxCost->SetValue( data.myCorrectSurfaceIntersectionMaxCost ); myStdWidget->myForceBadElementRemoval->setChecked( data.myForceBadElementRemoval ); if (data.myBadElementAspectRatio <= 0) myStdWidget->myBadElementAspectRatio->setText(""); @@ -1833,72 +1869,18 @@ void BLSURFPluginGUI_HypothesisCreator::retrieveParams() const myStdWidget->resizeWidgets(); myAdvWidget->myVerbosity->setValue( data.myVerbosity ); - myAdvWidget->myPreCADGroupBox->setChecked(data.myTopology == PreCAD); - myAdvWidget->myPreCADMergeEdges->setChecked( data.myPreCADMergeEdges ); - myAdvWidget->myPreCADRemoveTinyUVEdges->setChecked( data.myPreCADRemoveTinyUVEdges ); - myAdvWidget->myPreCADRemoveDuplicateCADFaces->setChecked( data.myPreCADRemoveDuplicateCADFaces ); - myAdvWidget->myPreCADProcess3DTopology->setChecked( data.myPreCADProcess3DTopology ); - myAdvWidget->myPreCADDiscardInput->setChecked( data.myPreCADDiscardInput ); if ( myOptions.operator->() ) { -// MESSAGE("retrieveParams():myOptions->length() = " << myOptions->length()); - for ( int i = 0, nb = myOptions->length(); i < nb; ++i ) { - QString option = that->myOptions[i].in(); - QStringList name_value_type = option.split( ":", QString::KeepEmptyParts ); - bool custom = ( name_value_type.size() == 3 ) ? name_value_type[2].toInt() : false; - if ( name_value_type.count() > 1 ) { - QString idStr = QString("%1").arg( i ); - int row = myAdvWidget->myOptionTable->rowCount(); - myAdvWidget->myOptionTable->setRowCount( row+1 ); - myAdvWidget->myOptionTable->setItem( row, OPTION_ID_COLUMN, new QTableWidgetItem( idStr ) ); - myAdvWidget->myOptionTable->item( row, OPTION_ID_COLUMN )->setFlags( 0 ); - myAdvWidget->myOptionTable->setItem( row, OPTION_TYPE_COLUMN, new QTableWidgetItem( "BLSURF" ) ); - myAdvWidget->myOptionTable->item( row, OPTION_TYPE_COLUMN )->setFlags( 0 ); - myAdvWidget->myOptionTable->setItem( row, OPTION_NAME_COLUMN, new QTableWidgetItem( name_value_type[0] ) ); - if ( custom ) { - myAdvWidget->myOptionTable->item( row, OPTION_NAME_COLUMN )->setFlags( Qt::ItemIsSelectable | - Qt::ItemIsEditable | - Qt::ItemIsEnabled ); - myAdvWidget->myOptionTable->item( row, OPTION_NAME_COLUMN )->setData( Qt::UserRole, QVariant(true) ); - } - else - myAdvWidget->myOptionTable->item( row, OPTION_NAME_COLUMN )->setFlags( 0 ); - myAdvWidget->myOptionTable->setItem( row, OPTION_VALUE_COLUMN, new QTableWidgetItem( name_value_type[1] ) ); - myAdvWidget->myOptionTable->item( row, OPTION_VALUE_COLUMN )->setFlags( Qt::ItemIsSelectable | - Qt::ItemIsEditable | - Qt::ItemIsEnabled ); - } - } + for ( int i = 0, nb = myOptions->length(); i < nb; ++i ) + myAdvWidget->AddOption( TBL_MESHING, that->myOptions[i].in() ); } if ( myPreCADOptions.operator->() ) { -// MESSAGE("retrieveParams():myPreCADOptions->length() = " << myPreCADOptions->length()); - for ( int i = 0, nb = myPreCADOptions->length(); i < nb; ++i ) { - QString option = that->myPreCADOptions[i].in(); - QStringList name_value_type = option.split( ":", QString::KeepEmptyParts ); - bool custom = ( name_value_type.size() == 3 ) ? name_value_type[2].toInt() : false; - if ( name_value_type.count() > 1 ) { - QString idStr = QString("%1").arg( i ); - int row = myAdvWidget->myOptionTable->rowCount(); - myAdvWidget->myOptionTable->setRowCount( row+1 ); - myAdvWidget->myOptionTable->setItem( row, OPTION_ID_COLUMN, new QTableWidgetItem( idStr ) ); - myAdvWidget->myOptionTable->item( row, OPTION_ID_COLUMN )->setFlags( 0 ); - myAdvWidget->myOptionTable->setItem( row, OPTION_TYPE_COLUMN, new QTableWidgetItem( "PRECAD" ) ); - myAdvWidget->myOptionTable->item( row, OPTION_TYPE_COLUMN )->setFlags( 0 ); - myAdvWidget->myOptionTable->setItem( row, OPTION_NAME_COLUMN, new QTableWidgetItem( name_value_type[0] ) ); - if ( custom ) { - myAdvWidget->myOptionTable->item( row, OPTION_NAME_COLUMN )->setFlags( Qt::ItemIsSelectable | - Qt::ItemIsEditable | - Qt::ItemIsEnabled ); - myAdvWidget->myOptionTable->item( row, OPTION_NAME_COLUMN )->setData( Qt::UserRole, QVariant(true) ); - } - else - myAdvWidget->myOptionTable->item( row, OPTION_NAME_COLUMN )->setFlags( 0 ); - myAdvWidget->myOptionTable->setItem( row, OPTION_VALUE_COLUMN, new QTableWidgetItem( name_value_type[1] ) ); - myAdvWidget->myOptionTable->item( row, OPTION_VALUE_COLUMN )->setFlags( Qt::ItemIsSelectable | - Qt::ItemIsEditable | - Qt::ItemIsEnabled ); - } - } + for ( int i = 0, nb = myPreCADOptions->length(); i < nb; ++i ) + myAdvWidget->AddOption( TBL_PRECAD, that->myPreCADOptions[i].in() ); + } + if ( myCustomOptions.operator->() ) { + for ( int i = 0, nb = myCustomOptions->length(); i < nb; ++i ) + myAdvWidget->AddOption( TBL_CUSTOM, that->myCustomOptions[i].in() ); } myAdvWidget->myOptionTable->resizeColumnToContents( OPTION_NAME_COLUMN ); myAdvWidget->myGMFFileName->setText(QString(data.myGMFFileName.c_str())); @@ -2047,7 +2029,10 @@ bool BLSURFPluginGUI_HypothesisCreator::readParamsFromHypo( BlsurfHypothesisData h_data.myMinSizeRel = h->IsMinSizeRel(); h_data.myMaxSize = maxSize > 0 ? maxSize : -1.0; h_data.myMaxSizeRel = h->IsMaxSizeRel(); + h_data.myUseGradation = h->GetUseGradation(); h_data.myGradation = h->GetGradation(); + h_data.myUseVolumeGradation = h->GetUseVolumeGradation(); + h_data.myVolumeGradation = h->GetVolumeGradation(); h_data.myAllowQuadrangles = h->GetQuadAllowed(); double angle = h->GetAngleMesh(); h_data.myAngleMesh = angle > 0 ? angle : -1.0; @@ -2059,24 +2044,29 @@ bool BLSURFPluginGUI_HypothesisCreator::readParamsFromHypo( BlsurfHypothesisData h_data.myRemoveTinyEdges = h->GetRemoveTinyEdges(); double myTinyEdgeLength = h->GetTinyEdgeLength(); h_data.myTinyEdgeLength = myTinyEdgeLength > 0 ? myTinyEdgeLength : -1.0; + h_data.myOptimiseTinyEdges = h->GetOptimiseTinyEdges(); + double myTinyEdgeOptimisLength = h->GetTinyEdgeOptimisationLength(); + h_data.myTinyEdgeOptimisLength = myTinyEdgeOptimisLength > 0 ? myTinyEdgeOptimisLength : -1.0; + h_data.myCorrectSurfaceIntersection = h->GetCorrectSurfaceIntersection(); + double corrSurfaceIntersMaxCost = h->GetCorrectSurfaceIntersectionMaxCost(); + h_data.myCorrectSurfaceIntersectionMaxCost = corrSurfaceIntersMaxCost > 0 ? corrSurfaceIntersMaxCost : -1.0; h_data.myForceBadElementRemoval = h->GetBadElementRemoval(); double myBadElementAspectRatio = h->GetBadElementAspectRatio(); h_data.myBadElementAspectRatio = myBadElementAspectRatio > 0 ? myBadElementAspectRatio : -1.0; h_data.myOptimizeMesh = h->GetOptimizeMesh(); h_data.myQuadraticMesh = h->GetQuadraticMesh(); h_data.myVerbosity = h->GetVerbosity(); - h_data.myTopology = (int) h->GetTopology(); + //h_data.myTopology = (int) h->GetTopology(); h_data.myPreCADMergeEdges = h->GetPreCADMergeEdges(); - h_data.myPreCADRemoveTinyUVEdges = h->GetPreCADRemoveTinyUVEdges(); - h_data.myPreCADRemoveDuplicateCADFaces = h->GetPreCADRemoveDuplicateCADFaces(); h_data.myPreCADProcess3DTopology = h->GetPreCADProcess3DTopology(); h_data.myPreCADDiscardInput = h->GetPreCADDiscardInput(); BLSURFPluginGUI_HypothesisCreator* that = (BLSURFPluginGUI_HypothesisCreator*)this; - that->myOptions = h->GetOptionValues(); + that->myOptions = h->GetOptionValues(); that->myPreCADOptions = h->GetPreCADOptionValues(); - + that->myCustomOptions = h->GetAdvancedOptionValues(); + h_data.myGMFFileName = h->GetGMFFile(); // h_data.myGMFFileMode = h->GetGMFFileMode(); @@ -2133,7 +2123,7 @@ bool BLSURFPluginGUI_HypothesisCreator::readParamsFromHypo( BlsurfHypothesisData BLSURFPlugin::string_array_var allMyAttractors = h->GetAttractorEntries(); // MESSAGE("myAttractors->length() = " << allMyAttractors->length()); - for ( int i = 0;ilength(); ++i ) { + for ( CORBA::ULong i = 0;ilength(); ++i ) { QString myAttractors = allMyAttractors[i].in(); QStringList myAttractorList = myAttractors.split( "|", QString::KeepEmptyParts ); if ( myAttractorList.count() > 1 ) { @@ -2147,7 +2137,7 @@ bool BLSURFPluginGUI_HypothesisCreator::readParamsFromHypo( BlsurfHypothesisData // attractor new version MESSAGE("readParamsFromHypo, Attractors") BLSURFPlugin::TAttParamsMap_var allMyAttractorParams = h->GetAttractorParams(); - for ( int i = 0;ilength(); ++i ) { + for ( CORBA::ULong i = 0;ilength(); ++i ) { BLSURFPlugin::TAttractorParams myAttractorParams = allMyAttractorParams[i]; QString faceEntry = myAttractorParams.faceEntry.in(); QString attEntry = myAttractorParams.attEntry.in(); @@ -2170,7 +2160,7 @@ bool BLSURFPluginGUI_HypothesisCreator::readParamsFromHypo( BlsurfHypothesisData BLSURFPlugin::TFaceEntryEnfVertexListMap_var faceEntryEnfVertexListMap = h->GetAllEnforcedVerticesByFace(); MESSAGE("faceEntryEnfVertexListMap->length() = " << faceEntryEnfVertexListMap->length()); - for ( int i = 0;ilength(); ++i ) { + for ( CORBA::ULong i = 0;ilength(); ++i ) { std::string entry = faceEntryEnfVertexListMap[i].faceEntry.in(); // BLSURFPlugin::TEnfVertexList vertexList = faceEntryEnfVertexListMap[i].enfVertexList.in(); BLSURFPlugin::TEnfVertexList vertexList = faceEntryEnfVertexListMap[i].enfVertexList; @@ -2178,13 +2168,13 @@ bool BLSURFPluginGUI_HypothesisCreator::readParamsFromHypo( BlsurfHypothesisData // TEnfVertexList& enfVertexList = h_data.faceEntryEnfVertexListMap[entry]; - for (int j=0 ; jname = CORBA::string_dup(vertexList[j].name.in()); enfVertex->geomEntry = CORBA::string_dup(vertexList[j].geomEntry.in()); enfVertex->grpName = CORBA::string_dup(vertexList[j].grpName.in()); - for (int k=0 ; k< vertexList[j].coords.length();k++) + for (CORBA::ULong k=0 ; k< vertexList[j].coords.length();k++) enfVertex->coords.push_back(vertexList[j].coords[k]); h_data.faceEntryEnfVertexListMap[entry].insert(enfVertex); @@ -2297,8 +2287,15 @@ bool BLSURFPluginGUI_HypothesisCreator::storeParamsToHypo( const BlsurfHypothesi else h->SetMaxSize( h_data.myMaxSize <= 0 ? -1 : h_data.myMaxSize ); } + if ( h->GetUseGradation() != h_data.myUseGradation ) + h->SetUseGradation( h_data.myUseGradation ); if ( h->GetGradation() != h_data.myGradation ) h->SetGradation( h_data.myGradation <= 0 ? -1 : h_data.myGradation ); + if ( h->GetUseVolumeGradation() != h_data.myUseVolumeGradation ) + h->SetUseVolumeGradation( h_data.myUseVolumeGradation ); + if ( h->GetVolumeGradation() != h_data.myVolumeGradation ) + h->SetVolumeGradation( h_data.myVolumeGradation <= 0 ? -1 : h_data.myVolumeGradation ); + if ( h->GetQuadAllowed() != h_data.myAllowQuadrangles ) h->SetQuadAllowed( h_data.myAllowQuadrangles ); @@ -2319,6 +2316,15 @@ bool BLSURFPluginGUI_HypothesisCreator::storeParamsToHypo( const BlsurfHypothesi if ( h_data.myRemoveTinyEdges && ( h->GetTinyEdgeLength() != h_data.myTinyEdgeLength ) ) h->SetTinyEdgeLength( h_data.myTinyEdgeLength <= 0 ? -1 :h_data.myTinyEdgeLength ); + if ( h->GetOptimiseTinyEdges() != h_data.myOptimiseTinyEdges ) + h->SetOptimiseTinyEdges( h_data.myOptimiseTinyEdges ); + if ( h_data.myOptimiseTinyEdges && ( h->GetTinyEdgeOptimisationLength() != h_data.myTinyEdgeOptimisLength ) ) + h->SetTinyEdgeOptimisationLength( h_data.myTinyEdgeOptimisLength <= 0 ? -1 :h_data.myTinyEdgeOptimisLength ); + if ( h->GetCorrectSurfaceIntersection() != h_data.myCorrectSurfaceIntersection ) + h->SetCorrectSurfaceIntersection( h_data.myCorrectSurfaceIntersection ); + if ( h_data.myCorrectSurfaceIntersection && ( h->GetCorrectSurfaceIntersectionMaxCost() != h_data.myCorrectSurfaceIntersectionMaxCost ) ) + h->SetCorrectSurfaceIntersectionMaxCost( h_data.myCorrectSurfaceIntersectionMaxCost <= 0 ? -1 :h_data.myCorrectSurfaceIntersectionMaxCost ); + if ( h->GetBadElementRemoval() != h_data.myForceBadElementRemoval ) h->SetBadElementRemoval( h_data.myForceBadElementRemoval ); if ( h_data.myForceBadElementRemoval && ( h->GetBadElementAspectRatio() != h_data.myBadElementAspectRatio ) ) @@ -2332,21 +2338,18 @@ bool BLSURFPluginGUI_HypothesisCreator::storeParamsToHypo( const BlsurfHypothesi if ( h->GetVerbosity() != h_data.myVerbosity ) h->SetVerbosity( h_data.myVerbosity ); - if ( h->GetTopology() != h_data.myTopology ) - h->SetTopology( (int) h_data.myTopology ); + // if ( h->GetTopology() != h_data.myTopology ) + // h->SetTopology( (int) h_data.myTopology ); if ( h->GetPreCADMergeEdges() != h_data.myPreCADMergeEdges ) h->SetPreCADMergeEdges( h_data.myPreCADMergeEdges ); - if ( h->GetPreCADRemoveTinyUVEdges() != h_data.myPreCADRemoveTinyUVEdges ) - h->SetPreCADRemoveTinyUVEdges( h_data.myPreCADRemoveTinyUVEdges ); - if ( h->GetPreCADRemoveDuplicateCADFaces() != h_data.myPreCADRemoveDuplicateCADFaces ) - h->SetPreCADRemoveDuplicateCADFaces( h_data.myPreCADRemoveDuplicateCADFaces ); if ( h->GetPreCADProcess3DTopology() != h_data.myPreCADProcess3DTopology ) h->SetPreCADProcess3DTopology( h_data.myPreCADProcess3DTopology ); if ( h->GetPreCADDiscardInput() != h_data.myPreCADDiscardInput ) h->SetPreCADDiscardInput( h_data.myPreCADDiscardInput ); - h->SetOptionValues( myOptions ); // is set in checkParams() - h->SetPreCADOptionValues( myPreCADOptions ); // is set in checkParams() + // options are set in checkParams() + //h->SetOptionValues( myOptions ); // is set in readParamsFromWidgets() + //h->SetPreCADOptionValues( myPreCADOptions ); // is set in readParamsFromWidgets() if ( h->GetGMFFile() != h_data.myGMFFileName ) // || ( h->GetGMFFileMode() != h_data.myGMFFileMode ) ) @@ -2405,7 +2408,7 @@ bool BLSURFPluginGUI_HypothesisCreator::storeParamsToHypo( const BlsurfHypothesi } // Enforced vertices - bool ret; + //bool ret; double x, y, z = 0; std::string enfName; /* TODO GROUPS @@ -2435,7 +2438,8 @@ bool BLSURFPluginGUI_HypothesisCreator::storeParamsToHypo( const BlsurfHypothesi y = (*evsIt)->coords[1]; z = (*evsIt)->coords[2]; } - ret = h->SetEnforcedVertexEntry( faceEntry.c_str(), x, y, z, (*evsIt)->name.c_str(), (*evsIt)->geomEntry.c_str(), (*evsIt)->grpName.c_str()); + //ret = + h->SetEnforcedVertexEntry( faceEntry.c_str(), x, y, z, (*evsIt)->name.c_str(), (*evsIt)->geomEntry.c_str(), (*evsIt)->grpName.c_str()); } // for } // for @@ -2521,7 +2525,10 @@ QString BLSURFPluginGUI_HypothesisCreator::readParamsFromWidgets( BlsurfHypothes h_data.myMinSizeRel = myStdWidget->myMinSizeRel->isChecked(); h_data.myMaxSize = myStdWidget->myMaxSize->text().isEmpty() ? -1.0 : myStdWidget->myMaxSize->GetValue(); h_data.myMaxSizeRel = myStdWidget->myMaxSizeRel->isChecked(); + h_data.myUseGradation = myStdWidget->myUseGradation->isChecked(); h_data.myGradation = myStdWidget->myGradation->text().isEmpty() ? -1.0 : myStdWidget->myGradation->GetValue(); + h_data.myUseVolumeGradation = myStdWidget->myUseVolumeGradation->isChecked(); + h_data.myVolumeGradation = myStdWidget->myVolumeGradation->text().isEmpty() ? -1.0 : myStdWidget->myVolumeGradation->GetValue(); h_data.myAllowQuadrangles = myStdWidget->myAllowQuadrangles->isChecked(); h_data.myAngleMesh = myStdWidget->myAngleMesh->text().isEmpty() ? -1.0 : myStdWidget->myAngleMesh->GetValue(); h_data.myChordalError = myStdWidget->myChordalError->text().isEmpty() ? -1.0 : myStdWidget->myChordalError->GetValue(); @@ -2529,17 +2536,19 @@ QString BLSURFPluginGUI_HypothesisCreator::readParamsFromWidgets( BlsurfHypothes h_data.myAnisotropicRatio = myStdWidget->myAnisotropicRatio->text().isEmpty() ? -1.0 : myStdWidget->myAnisotropicRatio->GetValue(); h_data.myRemoveTinyEdges = myStdWidget->myRemoveTinyEdges->isChecked(); h_data.myTinyEdgeLength = myStdWidget->myTinyEdgeLength->text().isEmpty() ? -1.0 : myStdWidget->myTinyEdgeLength->GetValue(); + h_data.myOptimiseTinyEdges = myStdWidget->myOptimiseTinyEdges->isChecked(); + h_data.myTinyEdgeOptimisLength = myStdWidget->myTinyEdgeOptimisLength->text().isEmpty() ? -1.0 : myStdWidget->myTinyEdgeOptimisLength->GetValue(); + h_data.myCorrectSurfaceIntersection = myStdWidget->myCorrectSurfaceIntersection->isChecked(); + h_data.myCorrectSurfaceIntersectionMaxCost = myStdWidget->myCorrectSurfaceIntersectionMaxCost->text().isEmpty() ? -1.0 : myStdWidget->myCorrectSurfaceIntersectionMaxCost->GetValue(); h_data.myForceBadElementRemoval= myStdWidget->myForceBadElementRemoval->isChecked(); h_data.myBadElementAspectRatio = myStdWidget->myBadElementAspectRatio->text().isEmpty() ? -1.0 : myStdWidget->myBadElementAspectRatio->GetValue(); h_data.myOptimizeMesh = myStdWidget->myOptimizeMesh->isChecked(); h_data.myQuadraticMesh = myStdWidget->myQuadraticMesh->isChecked(); h_data.myVerbosity = myAdvWidget->myVerbosity->value(); - h_data.myTopology = myAdvWidget->myPreCADGroupBox->isChecked() ? PreCAD : FromCAD; - h_data.myPreCADMergeEdges = myAdvWidget->myPreCADMergeEdges->isChecked(); - h_data.myPreCADRemoveTinyUVEdges = myAdvWidget->myPreCADRemoveTinyUVEdges->isChecked(); - h_data.myPreCADRemoveDuplicateCADFaces = myAdvWidget->myPreCADRemoveDuplicateCADFaces->isChecked(); - h_data.myPreCADProcess3DTopology = myAdvWidget->myPreCADProcess3DTopology->isChecked(); - h_data.myPreCADDiscardInput = myAdvWidget->myPreCADDiscardInput->isChecked(); + //h_data.myTopology = myAdvWidget->myPreCADGroupBox->isChecked() ? PreCAD : FromCAD; + //h_data.myPreCADMergeEdges = myAdvWidget->myPreCADMergeEdges->isChecked(); + //h_data.myPreCADProcess3DTopology = myAdvWidget->myPreCADProcess3DTopology->isChecked(); + //h_data.myPreCADDiscardInput = myAdvWidget->myPreCADDiscardInput->isChecked(); QString guiHyp; guiHyp += tr("BLSURF_PHY_MESH") + " = " + QString::number( h_data.myPhysicalMesh ) + "; "; @@ -2568,50 +2577,15 @@ QString BLSURFPluginGUI_HypothesisCreator::readParamsFromWidgets( BlsurfHypothes guiHyp += tr("BLSURF_TOPOLOGY") + " = " + QString::number( h_data.myTopology ) + "; "; guiHyp += tr("BLSURF_PRECAD_MERGE_EDGES") + " = " + QString(h_data.myPreCADMergeEdges ? "yes" : "no") + "; "; - guiHyp += tr("BLSURF_PRECAD_REMOVE_TINY_UV_EDGES") + " = " + QString(h_data.myPreCADRemoveTinyUVEdges ? "yes" : "no") + "; "; - guiHyp += tr("BLSURF_PRECAD_REMOVE_DUPLICATE_CAD_FACES") + " = " + QString(h_data.myPreCADRemoveDuplicateCADFaces ? "yes" : "no") + "; "; guiHyp += tr("BLSURF_PRECAD_REMOVE_NANO_EDGES") + " = " + QString(h_data.myPreCADProcess3DTopology ? "yes" : "no") + "; "; guiHyp += tr("BLSURF_PRECAD_DISCARD_INPUT") + " = " + QString(h_data.myPreCADDiscardInput ? "yes" : "no") + "; "; - - BLSURFPluginGUI_HypothesisCreator* that = (BLSURFPluginGUI_HypothesisCreator*)this; - int row = 0, nbRows = myAdvWidget->myOptionTable->rowCount(); - for ( ; row < nbRows; ++row ) - { - int id = myAdvWidget->myOptionTable->item( row, OPTION_ID_COLUMN )->text().toInt(); - std::string optionType = myAdvWidget->myOptionTable->item( row, OPTION_TYPE_COLUMN )->text().toStdString(); - bool custom = myAdvWidget->myOptionTable->item( row, OPTION_NAME_COLUMN )->data(Qt::UserRole).toBool(); - if ( optionType == "BLSURF" && custom ) { - id = that->myOptions->length(); - that->myOptions->length( that->myOptions->length() + 1 ); - } - if ( optionType == "PRECAD" && custom ) { - id = that->myPreCADOptions->length(); - that->myPreCADOptions->length( that->myPreCADOptions->length() + 1 ); - } - if ( custom || ( id >= 0 && ( ( optionType == "BLSURF" && id < myOptions->length() ) || ( optionType == "PRECAD" && id < myPreCADOptions->length() ) ) ) ) - { - QString name = myAdvWidget->myOptionTable->item( row, OPTION_NAME_COLUMN )->text(); - QString value = myAdvWidget->myOptionTable->item( row, OPTION_VALUE_COLUMN )->text().trimmed(); - if ( value.isNull() ) - value = ""; - if (optionType == "PRECAD") - that->myPreCADOptions[ id ] = ( name + ":" + value + ":" + ( custom ? "1" : "0" ) ).toLatin1().constData(); - else - that->myOptions[ id ] = ( name + ":" + value + ":" + ( custom ? "1" : "0" ) ).toLatin1().constData(); - - if ( value != "" ) { - if (optionType == "PRECAD") - guiHyp += "PRECAD_"; - guiHyp += name + " = " + value + "; "; - } - } - } - + h_data.myGMFFileName = myAdvWidget->myGMFFileName->text().toStdString(); // h_data.myGMFFileMode = myGMFFileMode->isChecked(); // SizeMap - row = 0, nbRows = mySizeMapTable->topLevelItemCount(); + BLSURFPluginGUI_HypothesisCreator* that = (BLSURFPluginGUI_HypothesisCreator*)this; + int row = 0, nbRows = mySizeMapTable->topLevelItemCount(); for ( ; row < nbRows; ++row ) { QString entry = mySizeMapTable->topLevelItem(row)->data(SMP_ENTRY_COLUMN ,Qt::EditRole).toString(); @@ -2681,11 +2655,11 @@ QString BLSURFPluginGUI_HypothesisCreator::readParamsFromWidgets( BlsurfHypothes h_data.preCadPeriodicityVector.clear(); // For each tree item, store each value. Shapes are stored as entries. int nbPeriodicityDescriptions = myPeriodicityTreeWidget->topLevelItemCount(); - for (size_t i=0 ; itopLevelItem(i); TPreCadPeriodicity periodicity_i; if (item) { - for (size_t k=0; kcolumnCount(); ++k) + for (int k=0; kcolumnCount(); ++k) { MESSAGE(k); std::string entry = item->data(k, Qt::UserRole).toString().toStdString(); @@ -2703,166 +2677,16 @@ QString BLSURFPluginGUI_HypothesisCreator::readParamsFromWidgets( BlsurfHypothes void BLSURFPluginGUI_HypothesisCreator::onAddOption() { - QMenu* menu = (QMenu*)sender(); - // fill popup with option names - menu->clear(); - QStringList name_value_type; - if ( myOptions.operator->() ) { - QMenu* blsurfMenu = menu->addMenu(tr("OPTION_MENU_BLSURF")); - for ( int i = 0, nb = myOptions->length(); i < nb; ++i ) { - name_value_type = QString( myOptions[i].in() ).split( ":", QString::KeepEmptyParts ); - bool custom = ( name_value_type.size() == 3 ) ? name_value_type[2].toInt() : false; - if ( !custom && !name_value_type[0].isEmpty() ) - blsurfMenu->addAction( name_value_type[0] ); - } - // this user-customized action must be last in the menu - blsurfMenu->addAction( QString( "<" + tr("BLSURF_OTHER_OPTION") + ">" ) ); - } - if ( myPreCADOptions.operator->() ) { - QMenu* preCADmenu = menu->addMenu(tr("OPTION_MENU_PRECAD")); - for ( int i = 0, nb = myPreCADOptions->length(); i < nb; ++i ) { - name_value_type = QString( myPreCADOptions[i].in() ).split( ":", QString::KeepEmptyParts ); - bool custom = ( name_value_type.size() == 3 ) ? name_value_type[2].toInt() : false; - if ( !custom && !name_value_type[0].isEmpty() ) - preCADmenu->addAction( name_value_type[0] ); - } - // this user-customized action must be last in the menu - preCADmenu->addAction( QString( "<" + tr("BLSURF_OTHER_OPTION") + ">" ) ); - } -} - -void BLSURFPluginGUI_HypothesisCreator::onOptionChosenInPopup( QAction* a ) -{ - myAdvWidget->myOptionTable->setFocus(); - QMenu* menu = (QMenu*)( a->parent() ); - - int idx = menu->actions().indexOf( a ); - bool custom = menu->actions().last() == a; - - QString idStr = QString("%1").arg( idx ); - QString option, optionType; - if (menu->title() == tr("OPTION_MENU_BLSURF")) { - if (idx < myOptions->length()) - option = myOptions[idx].in(); - optionType = "BLSURF"; - } - else if (menu->title() == tr("OPTION_MENU_PRECAD")) { - if (idx < myPreCADOptions->length()) - option = myPreCADOptions[idx].in(); - optionType = "PRECAD"; - } - QString optionName = option.split( ":", QString::KeepEmptyParts )[0]; - - // look for a row with optionName - int row = 0, nbRows = myAdvWidget->myOptionTable->rowCount(); - for ( ; row < nbRows; ++row ) - if ( myAdvWidget->myOptionTable->item( row, OPTION_ID_COLUMN )->text() == idStr ) - if ( myAdvWidget->myOptionTable->item( row, OPTION_TYPE_COLUMN )->text() == optionType ) - break; - if (custom) - row = nbRows; - // add a row if not found - if ( row == nbRows ) { - myAdvWidget->myOptionTable->setRowCount( row+1 ); - myAdvWidget->myOptionTable->setItem( row, OPTION_ID_COLUMN, new QTableWidgetItem( idStr ) ); - myAdvWidget->myOptionTable->item( row, OPTION_ID_COLUMN )->setFlags( 0 ); - myAdvWidget->myOptionTable->setItem( row, OPTION_TYPE_COLUMN, new QTableWidgetItem( optionType ) ); - myAdvWidget->myOptionTable->item( row, OPTION_TYPE_COLUMN )->setFlags( 0 ); - if (custom) { - myAdvWidget->myOptionTable->setItem( row, OPTION_NAME_COLUMN, new QTableWidgetItem( "" ) ); - myAdvWidget->myOptionTable->item( row, OPTION_NAME_COLUMN )->setFlags( Qt::ItemIsSelectable | - Qt::ItemIsEditable | - Qt::ItemIsEnabled ); - myAdvWidget->myOptionTable->item( row, OPTION_NAME_COLUMN )->setData( Qt::UserRole, QVariant(true) ); - } - else { - myAdvWidget->myOptionTable->setItem( row, OPTION_NAME_COLUMN, new QTableWidgetItem( optionName ) ); - myAdvWidget->myOptionTable->item( row, OPTION_NAME_COLUMN )->setFlags( 0 ); - } - myAdvWidget->myOptionTable->setItem( row, OPTION_VALUE_COLUMN, new QTableWidgetItem( "" ) ); - myAdvWidget->myOptionTable->item( row, OPTION_VALUE_COLUMN )->setFlags( Qt::ItemIsSelectable | - Qt::ItemIsEditable | - Qt::ItemIsEnabled ); - myAdvWidget->myOptionTable->resizeColumnToContents( OPTION_NAME_COLUMN ); - } - myAdvWidget->myOptionTable->clearSelection(); - int activeColumn = custom ? OPTION_NAME_COLUMN : OPTION_VALUE_COLUMN; - myAdvWidget->myOptionTable->scrollToItem( myAdvWidget->myOptionTable->item( row, activeColumn ) ); - //myAdvWidget->myOptionTable->item( row, activeColumn )->setSelected( true ); - myAdvWidget->myOptionTable->setCurrentCell( row, activeColumn ); - //myAdvWidget->myOptionTable->openPersistentEditor( myOptionTable->item( row, activeColumn ) ); -} - -void BLSURFPluginGUI_HypothesisCreator::onDeleteOption() -{ - BLSURFPlugin::BLSURFPlugin_Hypothesis_var h = - BLSURFPlugin::BLSURFPlugin_Hypothesis::_narrow( hypothesis() ); - // clear option values and remember selected row - QList selectedRows; - QList selected = myAdvWidget->myOptionTable->selectedItems(); - QTableWidgetItem* item; - foreach( item, selected ) { - int row = item->row(); - if ( !selectedRows.contains( row ) ) { - selectedRows.append( row ); - int id = myAdvWidget->myOptionTable->item( row, OPTION_ID_COLUMN )->text().toInt(); - QString optionType = myAdvWidget->myOptionTable->item( row, OPTION_TYPE_COLUMN )->text(); - bool custom = myAdvWidget->myOptionTable->item( row, OPTION_NAME_COLUMN )->data(Qt::UserRole).toBool(); - QString name = myAdvWidget->myOptionTable->item( row, OPTION_NAME_COLUMN )->text(); - if ( id >= 0 ) - if ( optionType == "BLSURF" && id < myOptions->length() ) - if ( custom ) { - h->UnsetOption( name.toLatin1().constData() ); - myOptions[id] = ""; - } - else - myOptions[id] = name.toLatin1().constData(); - else if ( optionType == "PRECAD" && id < myPreCADOptions->length() ) - if ( custom ) { - h->UnsetPreCADOption( name.toLatin1().constData() ); - myPreCADOptions[id] = ""; - } - else - myPreCADOptions[id] = name.toLatin1().constData(); - } - } - qSort( selectedRows ); - QListIterator it( selectedRows ); - it.toBack(); - while ( it.hasPrevious() ) - myAdvWidget->myOptionTable->removeRow( it.previous() ); -} - -void BLSURFPluginGUI_HypothesisCreator::onEditOption( int row, int column ) -{ - if ( column != OPTION_NAME_COLUMN ) - return; - bool custom = myAdvWidget->myOptionTable->item( row, OPTION_NAME_COLUMN )->data(Qt::UserRole).toBool(); - if ( !custom ) - return; - - BLSURFPlugin::BLSURFPlugin_Hypothesis_var h = - BLSURFPlugin::BLSURFPlugin_Hypothesis::_narrow( hypothesis() ); - - int id = myAdvWidget->myOptionTable->item( row, OPTION_ID_COLUMN )->text().toInt(); - QString optionType = myAdvWidget->myOptionTable->item( row, OPTION_TYPE_COLUMN )->text().trimmed(); - QString name = myAdvWidget->myOptionTable->item( row, OPTION_NAME_COLUMN )->text(); - if ( optionType == "PRECAD" && id < myPreCADOptions->length() ) { - h->UnsetPreCADOption(name.toLatin1().constData()); - myPreCADOptions[id] = ""; - } - else if ( optionType == "BLSURF" && id < myOptions->length() ) { - h->UnsetOption(name.toLatin1().constData()); - myOptions[id] = ""; - } + myAdvWidget->AddOption( TBL_CUSTOM, NULL ); } void BLSURFPluginGUI_HypothesisCreator::onChangeOptionName( int row, int column ) { - if ( column != OPTION_NAME_COLUMN ) - return; - myAdvWidget->myOptionTable->resizeColumnToContents( OPTION_NAME_COLUMN ); + // if ( column != OPTION_NAME_COLUMN ) + // return; + // myAdvWidget->myOptionTable->resizeColumnToContents( OPTION_NAME_COLUMN ); } + // ********************** // *** BEGIN SIZE MAP *** // ********************** diff --git a/src/GUI/BLSURFPluginGUI_HypothesisCreator.h b/src/GUI/BLSURFPluginGUI_HypothesisCreator.h index b120ac9..811e225 100644 --- a/src/GUI/BLSURFPluginGUI_HypothesisCreator.h +++ b/src/GUI/BLSURFPluginGUI_HypothesisCreator.h @@ -163,13 +163,13 @@ typedef struct int myPhysicalMesh, myGeometricMesh; double myPhySize, myMinSize, myMaxSize; bool myPhySizeRel, myMinSizeRel, myMaxSizeRel; - bool myUseMinSize, myUseMaxSize; - double myGradation, myAngleMesh, myChordalError; - bool myAnisotropic, myRemoveTinyEdges, myForceBadElementRemoval; - double myAnisotropicRatio, myTinyEdgeLength, myBadElementAspectRatio; + bool myUseMinSize, myUseMaxSize, myUseGradation, myUseVolumeGradation; + double myGradation, myVolumeGradation, myAngleMesh, myChordalError; + bool myAnisotropic, myOptimiseTinyEdges, myRemoveTinyEdges, myForceBadElementRemoval, myCorrectSurfaceIntersection; + double myAnisotropicRatio, myTinyEdgeLength, myTinyEdgeOptimisLength, myBadElementAspectRatio, myCorrectSurfaceIntersectionMaxCost; bool myOptimizeMesh, myQuadraticMesh; bool myAllowQuadrangles, mySmpsurface,mySmpedge,mySmppoint,myEnforcedVertex,myInternalEnforcedVerticesAllFaces; - bool myPreCADMergeEdges, myPreCADRemoveTinyUVEdges, myPreCADRemoveDuplicateCADFaces, myPreCADProcess3DTopology, myPreCADDiscardInput; + bool myPreCADMergeEdges, myPreCADProcess3DTopology, myPreCADDiscardInput; // bool myGMFFileMode; std::string myGMFFileName, myInternalEnforcedVerticesAllFacesGroup; TEnfVertexList enfVertexList; @@ -376,7 +376,7 @@ private: QPushButton* myPeriodicityRemoveButton; QSpacerItem* myPeriodicityVerticalSpacer; - BLSURFPlugin::string_array_var myOptions, myPreCADOptions; + BLSURFPlugin::string_array_var myOptions, myPreCADOptions, myCustomOptions; PyObject * main_mod; PyObject * main_dict; diff --git a/src/GUI/BLSURFPluginGUI_StdWidget.cxx b/src/GUI/BLSURFPluginGUI_StdWidget.cxx index b17ad7d..35a60c4 100644 --- a/src/GUI/BLSURFPluginGUI_StdWidget.cxx +++ b/src/GUI/BLSURFPluginGUI_StdWidget.cxx @@ -44,10 +44,13 @@ BLSURFPluginGUI_StdWidget::BLSURFPluginGUI_StdWidget( QWidget* parent, Qt::Windo myMinSize->RangeStepAndValidator(0, COORD_MAX, 10.0, "length_precision"); myMaxSize->RangeStepAndValidator(0, COORD_MAX, 10.0, "length_precision"); myGradation->RangeStepAndValidator(1.0, COORD_MAX, 0.1, "length_precision"); + myVolumeGradation->RangeStepAndValidator(1.0, COORD_MAX, 0.1, "length_precision"); myAngleMesh->RangeStepAndValidator(0, 90, 0.5, "angular_precision"); myChordalError->RangeStepAndValidator(0, COORD_MAX, 0.1, "length_precision"); myAnisotropicRatio->RangeStepAndValidator(0, COORD_MAX, 0.1, "length_precision"); - myTinyEdgeLength->RangeStepAndValidator(COORD_MIN, COORD_MAX, 0.1, "length_precision"); + myTinyEdgeLength->RangeStepAndValidator(0, COORD_MAX, 0.1, "length_precision"); + myTinyEdgeOptimisLength->RangeStepAndValidator(0, COORD_MAX, 0.1, "length_precision"); + myCorrectSurfaceIntersectionMaxCost->RangeStepAndValidator(0, COORD_MAX, 1); myBadElementAspectRatio->RangeStepAndValidator(0, COORD_MAX, 1000, "length_precision"); myMinSize->setText(""); myMaxSize->setText(""); @@ -55,6 +58,8 @@ BLSURFPluginGUI_StdWidget::BLSURFPluginGUI_StdWidget( QWidget* parent, Qt::Windo myChordalError->setText(""); myAnisotropicRatio->setText(""); myTinyEdgeLength->setText(""); + myTinyEdgeOptimisLength->setText(""); + myCorrectSurfaceIntersectionMaxCost->setText(""); myBadElementAspectRatio->setText(""); } @@ -66,36 +71,17 @@ void BLSURFPluginGUI_StdWidget::onPhysicalMeshChanged() { bool isPhysicalGlobalSize = (myPhysicalMesh->currentIndex() == PhysicalGlobalSize); bool isPhysicalLocalSize = (myPhysicalMesh->currentIndex() == PhysicalLocalSize); bool isCustom = (isPhysicalGlobalSize || isPhysicalLocalSize) ; - bool geomIsCustom = (myGeometricMesh->currentIndex() != DefaultGeom); - bool isQuadAllowed = (myAllowQuadrangles->isChecked() ); - myGradation->setEnabled( !isQuadAllowed && ( !isPhysicalGlobalSize || geomIsCustom )); myPhySize->setEnabled(isCustom); myPhySizeRel->setEnabled(isCustom); - - if ( !isCustom ) { - if ( myGeometricMesh->currentIndex() == DefaultGeom ) { - myGeometricMesh->setCurrentIndex( GeometricalGlobalSize ); - onGeometricMeshChanged(); - } - } } void BLSURFPluginGUI_StdWidget::onGeometricMeshChanged() { bool isCustom = (myGeometricMesh->currentIndex() != DefaultGeom); - bool isPhysicalLocalSize = (myPhysicalMesh->currentIndex() == PhysicalLocalSize); - bool isQuadAllowed = (myAllowQuadrangles->isChecked() ); - - GeomParamsGroupBox->setEnabled(isCustom); - myGradation->setEnabled( !isQuadAllowed && ( isCustom || isPhysicalLocalSize )); - - if ( ! isCustom ) { - // hphy_flag = 0 and hgeo_flag = 0 is not allowed (spec) - if ( myPhysicalMesh->currentIndex() == DefaultSize ) { - myPhysicalMesh->setCurrentIndex( PhysicalGlobalSize ); - onPhysicalMeshChanged(); - } - } + + myAngleMesh->setEnabled( isCustom ); + myChordalError->setEnabled( isCustom ); + } void BLSURFPluginGUI_StdWidget::resizeWidgets() { diff --git a/src/GUI/BLSURFPluginGUI_StdWidget_QTD.ui b/src/GUI/BLSURFPluginGUI_StdWidget_QTD.ui index 9167973..53b0517 100644 --- a/src/GUI/BLSURFPluginGUI_StdWidget_QTD.ui +++ b/src/GUI/BLSURFPluginGUI_StdWidget_QTD.ui @@ -7,20 +7,29 @@ 0 0 - 588 - 244 + 667 + 342 - + + 0 + + + 0 + + + 0 + + 0 - BLSURF_MESH_TYPE + BLSURF_PHYSICAL_SIZE - + @@ -28,7 +37,7 @@ - + BLSURF_PHY_MESH_TOOLTIP @@ -54,17 +63,112 @@ + + + BLSURF_HPHYDEF_TOOLTIP + + + BLSURF_HPHYDEF + + + + + + + + + + BLSURF_SIZE_REL_TOOLTIP + + + BLSURF_SIZE_REL + + + + + + + BLSURF_MINSIZE + + + + + + + + + + BLSURF_SIZE_REL_TOOLTIP + + + BLSURF_SIZE_REL + + + + + + + BLSURF_MAXSIZE + + + + + + + 10.000000000000000 + + + + + + + BLSURF_SIZE_REL_TOOLTIP + + + BLSURF_SIZE_REL + + + + + + + Qt::Vertical + + + + 20 + 4 + + + + + + + + + + + true + + + BLSURF_GEOMETRICAL_SIZE + + + BLSURF_GEOM_MESH - + BLSURF_GEOM_MESH_TOOLTIP + + GLOBAL_SIZE + BLSURF_DEFAULT_USER @@ -77,25 +181,7 @@ - - - - - - - false - - - BLSURF_GEOMETRICAL_PARAMETERS - - - - - - - - - + BLSURF_ANGLE_MESH_TOOLTIP @@ -105,7 +191,17 @@ - + + + + true + + + 8.000000000000000 + + + + BLSURF_CHORDAL_TOOLTIP @@ -115,6 +211,35 @@ + + + + + + + Qt::Vertical + + + + 20 + 36 + + + + + + + + Qt::Vertical + + + + 20 + 23 + + + + @@ -123,62 +248,52 @@ BLSURF_MAIN_PARAMETERS - - - + + + - BLSURF_HPHYDEF_TOOLTIP + BLSURF_OPTIMISATION_TOOLTIP - BLSURF_HPHYDEF - - - - - - - - - - BLSURF_SIZE_REL_TOOLTIP + BLSURF_OPTIMISATION - - BLSURF_SIZE_REL + + true - - - - - + + - BLSURF_SIZE_REL_TOOLTIP + BLSURF_ELEMENT_ORDER_TOOLTIP - BLSURF_SIZE_REL + BLSURF_ELEMENT_ORDER - - - - 10.000000000000000 + + + + false - - - - BLSURF_SIZE_REL_TOOLTIP - - - BLSURF_SIZE_REL - - + + + + Qt::Vertical + + + + 20 + 55 + + + - - + + BLSURF_GRADATION_TOOLTIP @@ -187,31 +302,13 @@ - - - - false - - - - - - - BLSURF_MINSIZE - - - - - - - BLSURF_MAXSIZE + + + + BLSURF_ALLOW_QUADRANGLES_TOOLTIP - - - - - BLSURF_ELEMENT_ORDER + BLSURF_ALLOW_QUADRANGLES @@ -223,7 +320,7 @@ BLSURF_OTHER_PARAMETERS - + @@ -242,6 +339,23 @@ + + + BLSURF_OPTIMIZE_TINY_EDGES_TOOLTIP + + + BLSURF_OPTIMISE_TINY_EDGES + + + + + + + false + + + + BLSURF_REMOVE_TINY_EDGES_TOOLTIP @@ -251,14 +365,14 @@ - + false - + BLSURF_REMOVE_SLIVERS_TOOLTIP @@ -268,33 +382,60 @@ - + false - - + + - BLSURF_OPTIMISATION_TOOLTIP + BLSURF_SURFACE_INTERSECTIONS_TOOLTIP - BLSURF_OPTIMISATION + BLSURF_SURFACE_INTERSECTIONS - - true + + + + + + false - - + + + + BLSURF_VOLUME_GRADATION_TOOLTIP + - BLSURF_ALLOW_QUADRANGLES + BLSURF_VOLUME_GRADATION + + + + false + + + + + + + Qt::Vertical + + + + 20 + 3 + + + + @@ -309,25 +450,32 @@ myPhysicalMesh - myGeometricMesh myPhySize myPhySizeRel myMinSize myMinSizeRel myMaxSize myMaxSizeRel - myGradation - myQuadraticMesh + myGeometricMesh myAngleMesh myChordalError + myQuadraticMesh + myUseGradation + myGradation + myOptimizeMesh + myAllowQuadrangles myAnisotropic myAnisotropicRatio + myOptimiseTinyEdges + myTinyEdgeOptimisLength myRemoveTinyEdges myTinyEdgeLength myForceBadElementRemoval myBadElementAspectRatio - myOptimizeMesh - myAllowQuadrangles + myCorrectSurfaceIntersection + myCorrectSurfaceIntersectionMaxCost + myUseVolumeGradation + myVolumeGradation @@ -338,8 +486,8 @@ onGeometricMeshChanged() - 188 - 60 + 495 + 48 281 @@ -354,7 +502,7 @@ onPhysicalMeshChanged() - 188 + 226 37 @@ -370,12 +518,12 @@ setEnabled(bool) - 384 - 122 + 488 + 176 - 541 - 127 + 655 + 175 @@ -386,12 +534,12 @@ setEnabled(bool) - 414 - 151 + 488 + 228 - 547 - 152 + 655 + 227 @@ -402,12 +550,12 @@ setEnabled(bool) - 448 - 181 + 488 + 254 - 542 - 180 + 655 + 253 @@ -418,12 +566,12 @@ setDisabled(bool) - 441 - 119 + 488 + 176 - 525 - 60 + 495 + 100 @@ -434,12 +582,12 @@ setDisabled(bool) - 425 - 121 + 488 + 176 - 438 - 64 + 446 + 100 @@ -451,7 +599,7 @@ 159 - 119 + 74 220 @@ -466,8 +614,8 @@ onEditingFinished() - 144 - 150 + 159 + 100 205 @@ -482,8 +630,8 @@ onEditingFinished() - 128 - 176 + 159 + 126 135 @@ -498,8 +646,8 @@ onEditingFinished() - 170 - 201 + 316 + 199 315 @@ -514,8 +662,8 @@ onEditingFinished() - 548 - 34 + 495 + 74 566 @@ -530,8 +678,8 @@ onEditingFinished() - 542 - 56 + 495 + 100 537 @@ -539,6 +687,70 @@ + + myOptimiseTinyEdges + toggled(bool) + myTinyEdgeOptimisLength + setEnabled(bool) + + + 438 + 202 + + + 655 + 201 + + + + + myCorrectSurfaceIntersection + toggled(bool) + myCorrectSurfaceIntersectionMaxCost + setEnabled(bool) + + + 450 + 280 + + + 655 + 279 + + + + + myUseVolumeGradation + toggled(bool) + myVolumeGradation + setEnabled(bool) + + + 449 + 306 + + + 655 + 305 + + + + + myUseGradation + toggled(bool) + myGradation + setEnabled(bool) + + + 115 + 206 + + + 249 + 211 + + + onGeometricMeshChanged() diff --git a/src/GUI/BLSURFPlugin_msg_en.ts b/src/GUI/BLSURFPlugin_msg_en.ts index ebfa0fc..fda49de 100644 --- a/src/GUI/BLSURFPlugin_msg_en.ts +++ b/src/GUI/BLSURFPlugin_msg_en.ts @@ -9,7 +9,11 @@ BLSURF_PHY_MESH - Physical Mesh + Type + + + BLSURF_PHYSICAL_SIZE + Physical Size BLSURF_PHY_MESH_TOOLTIP @@ -20,7 +24,7 @@ BLSURF_GEOM_MESH - Geometrical Mesh + Type BLSURF_GEOM_MESH_TOOLTIP @@ -87,13 +91,25 @@ The default computed value is <em>diag</em>/5. BLSURF_GRADATION_TOOLTIP Maximum ratio between the lengths of two adjacent edges. + + BLSURF_VOLUME_GRADATION + Volume Gradation + + + BLSURF_VOLUME_GRADATION_TOOLTIP + Maximum ratio between the lengths of two adjacent edges in 3D mesh. + BLSURF_ALLOW_QUADRANGLES Allow Quadrangles - BLSURF_GEOMETRICAL_PARAMETERS - Geometrical parameters + BLSURF_ALLOW_QUADRANGLES_TOOLTIP + To generate quadrangle dominant mesh + + + BLSURF_GEOMETRICAL_SIZE + Geometrical size BLSURF_ANGLE_MESH @@ -134,6 +150,22 @@ The smaller this distance is, the closer the mesh is to the exact surface (only BLSURF_REMOVE_TINY_EDGES_TOOLTIP If checked, this parameter defines the minimal length under which an edge is considered to be a tiny one. + + BLSURF_OPTIMISE_TINY_EDGES + Optimize tiny edges + + + BLSURF_OPTIMIZE_TINY_EDGES_TOOLTIP + If checked, this parameter defines the minimal length under which an edge is considered to be a tiny one. + + + BLSURF_SURFACE_INTERSECTIONS + Correct surface intersections + + + BLSURF_SURFACE_INTERSECTIONS_TOOLTIP + If checked, this parameter defines the time that will be spent in the intersection prevention process. + BLSURF_REMOVE_SLIVERS Remove bad elements @@ -154,6 +186,10 @@ The smaller this distance is, the closer the mesh is to the exact surface (only BLSURF_ELEMENT_ORDER Quadratic mesh + + BLSURF_ELEMENT_ORDER_TOOLTIP + To generate quadratic mesh + BLSURF_HYPOTHESIS MG-CADSurf @@ -207,12 +243,12 @@ The smaller this distance is, the closer the mesh is to the exact surface (only Value - OPTION_MENU_BLSURF - MG-CADSurf + BLSURF_MESHING_OPTIONS + Meshing - OPTION_MENU_PRECAD - PreCAD + BLSURF_PRECAD_OPTIONS + CAD preprocessor BLSURF_ADD_OPTION @@ -223,8 +259,8 @@ The smaller this distance is, the closer the mesh is to the exact surface (only Clear option - BLSURF_OTHER_OPTION - Other option + BLSURF_CUSTOM_OPTIONS + Other options BLSURF_GMF_FILE @@ -559,4 +595,71 @@ The smaller this distance is, the closer the mesh is to the exact surface (only Edge + + BLSURFPluginGUI_AdvWidget + + enforce_cad_edge_sizes + Enforce CAD edge sizes + + + jacobian_rectification_respect_geometry + Priority of geometry over Jacobian + + + max_number_of_points_per_patch + Maximal number of points per patch + + + rectify_jacobian + Rectify Jacobian + + + respect_geometry + Respect geometry + + + tiny_edge_avoid_surface_intersections + Tiny edges avoid surface intersections + + + closed_geometry + Closed geometry + + + debug + Debug + + + discard_input_topology + Discard input topology + + + merge_edges + Merge edges + + + periodic_tolerance + Periodic tolerance + + + remove_duplicate_cad_faces + Remove duplicate CAD faces + + + required_entities + Required entities + + + sewing_tolerance + Sewing tolerance + + + tags + Tags + + + + + + diff --git a/src/GUI/BLSURFPlugin_msg_fr.ts b/src/GUI/BLSURFPlugin_msg_fr.ts index c7a535d..952ebec 100755 --- a/src/GUI/BLSURFPlugin_msg_fr.ts +++ b/src/GUI/BLSURFPlugin_msg_fr.ts @@ -13,7 +13,11 @@ BLSURF_PHY_MESH - Maillage physique + Type + + + BLSURF_PHYSICAL_SIZE + Taille physique BLSURF_PHY_MESH_TOOLTIP @@ -24,7 +28,7 @@ BLSURF_GEOM_MESH - Maillage géométrique + Type BLSURF_GEOM_MESH_TOOLTIP @@ -91,13 +95,25 @@ La valeur par défaut est calculée par <em>diag</em>/5.BLSURF_GRADATION_TOOLTIP Ratio maximum entre les longueurs de deux segments adjacents. + + BLSURF_VOLUME_GRADATION + Taux d'accroissement 3D + + + BLSURF_VOLUME_GRADATION_TOOLTIP + Ratio maximum entre les longueurs de deux segments adjacents. + BLSURF_ALLOW_QUADRANGLES Autoriser les quadrangles - BLSURF_GEOMETRICAL_PARAMETERS - Paramètres géometriques + BLSURF_ALLOW_QUADRANGLES_TOOLTIP + To generate quadrangle dominant mesh + + + BLSURF_GEOMETRICAL_SIZE + Taille géométrique BLSURF_ANGLE_MESH @@ -138,6 +154,22 @@ Plus la distance est petite, plus le maillage sera proche de la surface (disponi BLSURF_REMOVE_TINY_EDGES_TOOLTIP Si activé, ce paramètre défini la longueur minimale sous laquelle une arête est considérée comme toute petite. + + BLSURF_OPTIMISE_TINY_EDGES + Optimize tiny edges + + + BLSURF_OPTIMIZE_TINY_EDGES_TOOLTIP + If checked, this parameter defines the minimal length under which an edge is considered to be a tiny one. + + + BLSURF_SURFACE_INTERSECTIONS + Correct surface intersections + + + BLSURF_SURFACE_INTERSECTIONS_TOOLTIP + If checked, this parameter defines the time that will be spent in the intersection prevention process. + BLSURF_REMOVE_SLIVERS Enlever les mauvais éléments @@ -158,6 +190,10 @@ Plus la distance est petite, plus le maillage sera proche de la surface (disponi BLSURF_ELEMENT_ORDER Maillage quadratique + + BLSURF_ELEMENT_ORDER_TOOLTIP + To generate quadratic mesh + BLSURF_HYPOTHESIS MG-CADSurf 2D @@ -211,11 +247,11 @@ Plus la distance est petite, plus le maillage sera proche de la surface (disponi Valeur - OPTION_MENU_BLSURF - MG-CADSurf + BLSURF_MESHING_OPTIONS + Meshing - OPTION_MENU_PRECAD + BLSURF_PRECAD_OPTIONS PreCAD @@ -227,7 +263,7 @@ Plus la distance est petite, plus le maillage sera proche de la surface (disponi Effacer l'option - BLSURF_OTHER_OPTION + BLSURF_CUSTOM_OPTIONS L'autre option @@ -559,4 +595,75 @@ Plus la distance est petite, plus le maillage sera proche de la surface (disponi Arête + + BLSURFPluginGUI_AdvWidget + + enforce_cad_edge_sizes + enforce_cad_edge_sizes + + + jacobian_rectification_respect_geometry + Priorité de la géométrie sur le Jacobien + + + max_number_of_points_per_patch + Nombre de points maximal par patch + + + rectify_jacobian + Ajustement du Jacobien + + + respect_geometry + Respect de la géométrie + + + tiny_edge_avoid_surface_intersections + Priorité de l?intersection des surfaces sur le retrait des petites arêtes + + + closed_geometry + Géométrie fermée + + + debug + Deboggage + + + discard_input_topology + discard_input_topology + + + merge_edges + Fusion des arêtes + + + periodic_tolerance + Tolérance de périodicité + + + remove_duplicate_cad_faces + Suppression des faces doubles + + + required_entities + Entités requises + + + sewing_tolerance + Tolérance de fusion + + + tags + Etiquettes + + + yes + Actif + + + no + Inactif + + diff --git a/src/GUI/CMakeLists.txt b/src/GUI/CMakeLists.txt index 1172275..b42d57e 100644 --- a/src/GUI/CMakeLists.txt +++ b/src/GUI/CMakeLists.txt @@ -58,7 +58,7 @@ SET(_link_LIBRARIES ${GEOM_GEOM} ${SMESH_SMESH} ${SMESH_SMESHEngine} - ${SMESH_GeomSelectionTools} + ${SMESH_PluginUtils} ${SMESH_StdMeshersGUI} ${SMESH_SMESHFiltersSelection} ${CAS_KERNEL} -- 2.39.2