From 92893180990bccec5db0f74c6efb0500145a0687 Mon Sep 17 00:00:00 2001 From: vsr Date: Thu, 13 Dec 2012 12:19:49 +0000 Subject: [PATCH] Merge from V6_main 13/12/2012 --- adm_local/cmake_files/FindCADSURF.cmake | 46 + .../config_files/check_MESHGEMS_CADSURF.m4 | 129 ++ configure.ac | 18 +- doc/salome/gui/BLSURFPLUGIN/CMakeLists.txt | 75 + .../BLSURFPLUGIN/images/blsurf_parameters.png | Bin 37081 -> 53508 bytes .../images/blsurf_parameters_advanced.png | Bin 36675 -> 35575 bytes .../blsurf_parameters_enforced_vertices.png | Bin 30233 -> 34498 bytes .../gui/BLSURFPLUGIN/input/blsurf_hypo.doc | 263 +-- doc/salome/gui/BLSURFPLUGIN/input/index.doc | 2 +- idl/BLSURFPlugin_Algorithm.idl | 165 +- resources/BLSURFPlugin.xml | 3 +- src/BLSURFPlugin/BLSURFPluginDC.py | 769 ++++---- src/BLSURFPlugin/BLSURFPlugin_BLSURF.cxx | 1687 ++++++++++------- src/BLSURFPlugin/BLSURFPlugin_BLSURF.hxx | 22 +- src/BLSURFPlugin/BLSURFPlugin_Hypothesis.cxx | 560 ++++-- src/BLSURFPlugin/BLSURFPlugin_Hypothesis.hxx | 152 +- .../BLSURFPlugin_Hypothesis_i.cxx | 620 ++++-- .../BLSURFPlugin_Hypothesis_i.hxx | 105 +- src/BLSURFPlugin/Makefile.am | 30 +- src/GUI/BLSURFPluginGUI_AdvWidget.cxx | 56 + src/GUI/BLSURFPluginGUI_AdvWidget_QTD.ui | 202 ++ src/GUI/BLSURFPluginGUI_Dlg.h | 97 + src/GUI/BLSURFPluginGUI_HypothesisCreator.cxx | 835 +++----- src/GUI/BLSURFPluginGUI_HypothesisCreator.h | 122 +- src/GUI/BLSURFPluginGUI_StdWidget.cxx | 164 ++ src/GUI/BLSURFPluginGUI_StdWidget_QTD.ui | 548 ++++++ src/GUI/BLSURFPlugin_msg_en.ts | 171 +- src/GUI/BLSURFPlugin_msg_fr.ts | 169 +- src/GUI/Makefile.am | 21 +- 29 files changed, 4703 insertions(+), 2328 deletions(-) create mode 100644 adm_local/cmake_files/FindCADSURF.cmake create mode 100644 adm_local/unix/config_files/check_MESHGEMS_CADSURF.m4 create mode 100755 doc/salome/gui/BLSURFPLUGIN/CMakeLists.txt create mode 100644 src/GUI/BLSURFPluginGUI_AdvWidget.cxx create mode 100644 src/GUI/BLSURFPluginGUI_AdvWidget_QTD.ui create mode 100644 src/GUI/BLSURFPluginGUI_Dlg.h create mode 100644 src/GUI/BLSURFPluginGUI_StdWidget.cxx create mode 100644 src/GUI/BLSURFPluginGUI_StdWidget_QTD.ui diff --git a/adm_local/cmake_files/FindCADSURF.cmake b/adm_local/cmake_files/FindCADSURF.cmake new file mode 100644 index 0000000..6822a40 --- /dev/null +++ b/adm_local/cmake_files/FindCADSURF.cmake @@ -0,0 +1,46 @@ +# Copyright (C) 2007-2012 CEA/DEN, EDF R&D +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +SET(MESHGEMSHOME $ENV{MESHGEMSHOME}) +FIND_PATH(CADSURF_INCLUDES_DIR meshgems/cadsurf.h ${MESHGEMSHOME}/include) +SET(MESHGEMS_CADSURF_INCLUDES) +SET(MESHGEMS_CADSURF_INCLUDES ${MESHGEMS_CADSURF_INCLUDES} -I${CADSURF_INCLUDES_DIR}) + +SET(CADSURF_LIBS_PATHS) +SET(CADSURF_LIBS_PATHS ${CADSURF_LIBS_PATHS} ${MESHGEMSHOME}/lib) +IF(WINDOWS) + SET(CADSURF_LIBS_PATHS ${CADSURF_LIBS_PATHS} ${MESHGEMSHOME}/lib/WinXP_VC9) +ELSE(WINDOWS) + IF(CMAKE_SIZEOF_VOID_P STREQUAL 8) + SET(CADSURF_LIBS_PATHS ${CADSURF_LIBS_PATHS} ${MESHGEMSHOME}/lib/Linux_64) + ELSE() + SET(CADSURF_LIBS_PATHS ${CADSURF_LIBS_PATHS} ${MESHGEMSHOME}/lib/Linux) + ENDIF() +ENDIF(WINDOWS) + +FIND_LIBRARY(mg-cadsurf mg-cadsurf PATHS ${CADSURF_LIBS_PATHS}) +FIND_LIBRARY(mg-precad mg-precad PATHS ${CADSURF_LIBS_PATHS}) +FIND_LIBRARY(meshgems meshgems PATHS ${CADSURF_LIBS_PATHS}) + +SET(MESHGEMS_CADSURF_LIBS) +SET(MESHGEMS_CADSURF_LIBS ${MESHGEMS_CADSURF_LIBS} ${mg-cadsurf}) +SET(MESHGEMS_CADSURF_LIBS ${MESHGEMS_CADSURF_LIBS} ${mg-precad}) +IF(meshgems) + SET(MESHGEMS_CADSURF_LIBS ${MESHGEMS_CADSURF_LIBS} ${meshgems}) +ENDIF(meshgems) diff --git a/adm_local/unix/config_files/check_MESHGEMS_CADSURF.m4 b/adm_local/unix/config_files/check_MESHGEMS_CADSURF.m4 new file mode 100644 index 0000000..d2a0914 --- /dev/null +++ b/adm_local/unix/config_files/check_MESHGEMS_CADSURF.m4 @@ -0,0 +1,129 @@ +dnl Copyright (C) 2007-2012 CEA/DEN, EDF R&D +dnl +dnl This library is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Lesser General Public +dnl License as published by the Free Software Foundation; either +dnl version 2.1 of the License. +dnl +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Lesser General Public License for more details. +dnl +dnl You should have received a copy of the GNU Lesser General Public +dnl License along with this library; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +dnl +dnl See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +dnl + +dnl File : check_MESHGEMS_CADSURF.m4 +dnl Author : Gilles DAVID, Open CASCADE S.A.S (gilles.david@opencascade.com) +dnl +AC_DEFUN([CHECK_MESHGEMS_CADSURF],[ + +AC_REQUIRE([AC_PROG_CXX])dnl +AC_REQUIRE([AC_PROG_CXXCPP])dnl + +AC_CHECKING([for MeshGems-CADSurf commercial product]) + +AC_LANG_SAVE +AC_LANG_CPLUSPLUS + +MESHGEMS_CADSURF_INCLUDES="" +MESHGEMS_CADSURF_LIBS="" + +AC_ARG_WITH([meshgems], + [ --with_meshgems=DIR root directory path of MeshGems-CADSurf installation]) + +CADSURF_ok=no + +if test "$with_meshgems" != "no" ; then + if test "$with_meshgems" == "yes" || test "$with_meshgems" == "auto"; then + MESHGEMS_CADSURF_HOME="" + else + MESHGEMS_CADSURF_HOME="$with_meshgems" + fi + + if test "$MESHGEMS_CADSURF_HOME" == "" ; then + if test "x$MESHGEMS_CADSURFHOME" != "x" ; then + MESHGEMS_CADSURF_HOME=$MESHGEMS_CADSURFHOME + fi + if test "x$CADSURFHOME" != "x" ; then + MESHGEMS_CADSURF_HOME=$CADSURFHOME + fi + if test "x$MESHGEMSHOME" != "x" ; then + MESHGEMS_CADSURF_HOME=$MESHGEMSHOME + fi + fi + + if test "x$MESHGEMS_CADSURF_HOME" != "x"; then + + echo + echo ------------------------------------------------- + echo You are about to choose to use somehow the + echo MeshGems-CADSurf commercial product to generate 2D mesh. + echo + + LOCAL_INCLUDES="-I$MESHGEMS_CADSURF_HOME/include" + LOCAL_LIBS="-L$MESHGEMS_CADSURF_HOME/lib/Linux" + archtest="$(`which arch`)" + if test "x$archtest" = "x" ; then + archtest="`uname -m`" + fi + if test $archtest = "x86_64" ; then + LOCAL_LIBS="-L$MESHGEMS_CADSURF_HOME/lib/Linux_64" + fi + LOCAL_LIBS="${LOCAL_LIBS} -lmeshgems -lmg-cadsurf -lmg-precad" + + CPPFLAGS_old="$CPPFLAGS" + CXXFLAGS_old="$CXXFLAGS" + CPPFLAGS="$LOCAL_INCLUDES $CPPFLAGS" + CXXFLAGS="$LOCAL_INCLUDES $CXXFLAGS" + + AC_MSG_CHECKING([for MeshGems-CADSurf header file]) + + AC_CHECK_HEADER([meshgems/meshgems.h],[CADSURF_ok=yes],[CADSURF_ok=no]) + AC_CHECK_HEADER([meshgems/cadsurf.h],[CADSURF_ok=yes],[CADSURF_ok=no]) + + if test "x$CADSURF_ok" == "xyes"; then + + AC_MSG_CHECKING([for MeshGems-CADSurf library]) + + LIBS_old="$LIBS" + LIBS="-L. $LOCAL_LIBS $LIBS" + + AC_TRY_LINK( +extern "C" { +#include "meshgems/meshgems.h" +}, context_new(), + CADSURF_ok=yes,CADSURF_ok=no + ) + + LIBS="$LIBS_old" + + AC_MSG_RESULT([$CADSURF_ok]) + fi + + CPPFLAGS="$CPPFLAGS_old" + CXXFLAGS="$CXXFLAGS_old" + + fi +fi + +if test "x$CADSURF_ok" == xno ; then + AC_MSG_RESULT([for MeshGems-CADSurf: no]) + AC_MSG_WARN([MeshGems-CADSurf includes or libraries are not found or are not properly installed]) + AC_MSG_WARN([Cannot build without MeshGems-CADSurf. Use --with_meshgems option to define MeshGems installation.]) +else + MESHGEMS_CADSURF_INCLUDES=$LOCAL_INCLUDES + MESHGEMS_CADSURF_LIBS=$LOCAL_LIBS + AC_MSG_RESULT([for MeshGems-CADSurf: yes]) +fi + +AC_SUBST(MESHGEMS_CADSURF_INCLUDES) +AC_SUBST(MESHGEMS_CADSURF_LIBS) + +AC_LANG_RESTORE + +])dnl diff --git a/configure.ac b/configure.ac index 40768ae..a1f53a2 100644 --- a/configure.ac +++ b/configure.ac @@ -317,13 +317,21 @@ echo CHECK_HTML_GENERATORS +dnl echo +dnl echo --------------------------------------------- +dnl echo Testing BLSURF +dnl echo --------------------------------------------- +dnl echo +dnl +dnl CHECK_BLSURF + echo echo --------------------------------------------- -echo Testing BLSURF +echo Testing MeshGems-CADSurf echo --------------------------------------------- echo -CHECK_BLSURF +CHECK_MESHGEMS_CADSURF echo echo --------------------------------------------- @@ -368,11 +376,11 @@ echo echo Configure if test "${gui_ok}" = "yes"; then - variables="cc_ok boost_ok lex_yacc_ok python_ok swig_ok threads_ok OpenGL_ok qt_ok vtk_ok hdf5_ok omniORB_ok occ_ok doxygen_ok graphviz_ok Kernel_ok Geom_ok Med_ok SMesh_ok gui_ok BLSURF_ok" + variables="cc_ok boost_ok lex_yacc_ok python_ok swig_ok threads_ok OpenGL_ok qt_ok vtk_ok hdf5_ok omniORB_ok occ_ok doxygen_ok graphviz_ok Kernel_ok Geom_ok Med_ok SMesh_ok gui_ok CADSURF_ok" elif test "${SalomeGUI_need}" != "no"; then - variables="cc_ok boost_ok lex_yacc_ok python_ok swig_ok threads_ok vtk_ok hdf5_ok omniORB_ok occ_ok doxygen_ok graphviz_ok Kernel_ok Geom_ok Med_ok SMesh_ok gui_ok BLSURF_ok" + variables="cc_ok boost_ok lex_yacc_ok python_ok swig_ok threads_ok vtk_ok hdf5_ok omniORB_ok occ_ok doxygen_ok graphviz_ok Kernel_ok Geom_ok Med_ok SMesh_ok gui_ok CADSURF_ok" else - variables="cc_ok boost_ok lex_yacc_ok python_ok swig_ok threads_ok vtk_ok hdf5_ok omniORB_ok occ_ok doxygen_ok graphviz_ok Kernel_ok Geom_ok Med_ok SMesh_ok BLSURF_ok" + variables="cc_ok boost_ok lex_yacc_ok python_ok swig_ok threads_ok vtk_ok hdf5_ok omniORB_ok occ_ok doxygen_ok graphviz_ok Kernel_ok Geom_ok Med_ok SMesh_ok CADSURF_ok" fi for var in $variables diff --git a/doc/salome/gui/BLSURFPLUGIN/CMakeLists.txt b/doc/salome/gui/BLSURFPLUGIN/CMakeLists.txt new file mode 100755 index 0000000..ac96603 --- /dev/null +++ b/doc/salome/gui/BLSURFPLUGIN/CMakeLists.txt @@ -0,0 +1,75 @@ +# Copyright (C) 2012 CEA/DEN, EDF R&D, OPEN CASCADE +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +INCLUDE(${KERNEL_ROOT_DIR}/salome_adm/cmake_files/SalomeMacros.cmake) + +SET(top_builddir ${CMAKE_BINARY_DIR}) +SET(top_srcdir ${CMAKE_SOURCE_DIR}) +SET(srcdir ${CMAKE_CURRENT_SOURCE_DIR}) +SET(builddir ${CMAKE_CURRENT_BINARY_DIR}) +SET(datadir${CMAKE_INSTALL_PREFIX}/share) +SET(docdir ${datadir}/doc/salome) +SET(guidocdir ${docdir}/gui/BLSURFPLUGIN) + +SALOME_CONFIGURE_FILE(doxyfile.in doxyfile) +SALOME_CONFIGURE_FILE(doxyfile_py.in doxyfile_py) +SALOME_CONFIGURE_FILE(static/header.html.in ${builddir}/static/header.html) +SALOME_CONFIGURE_FILE(static/header_py.html.in ${builddir}/static/header_py.html) + +SET(DOC_SMESH_MeshersList BLSURFPlugin) +SET(f "$(SMESH_ROOT_DIR)/bin/salome/collect_mesh_methods.py") +IF(WINDOWS) + STRING(REPLACE "/" "\\" f ${f}) + STRING(REPLACE "/" "\\" SCR "@SET PYTHONPATH=${OMNIORB_ROOT_USER}/lib/x86_win32\;%PYTHONPATH% + @SET PYTHONPATH=${OMNIORB_ROOT_USER}/lib/python\;%PYTHONPATH% + @SET PATH=${OMNIORB_ROOT_USER}/lib/x86_win32\;%PATH% + @SET PATH=$ENV{KERNEL_ROOT_DIR}/lib/salome\;%PATH% + @SET PYTHONPATH=$ENV{KERNEL_ROOT_DIR}/bin/salome\;%PYTHONPATH% + @SET PYTHONPATH=$ENV{KERNEL_ROOT_DIR}/lib/python${PYTHON_VERSION}/site-packages/salome\;%PYTHONPATH% + @SET PYTHONPATH=$ENV{MED_ROOT_DIR}/lib/python${PYTHON_VERSION}/site-packages/salome\;%PYTHONPATH% + @SET PYTHONPATH=$ENV{MED_ROOT_DIR}/bin/salome\;%PYTHONPATH% + @SET PYTHONPATH=$ENV{GEOM_ROOT_DIR}/lib/python${PYTHON_VERSION}/site-packages/salome\;%PYTHONPATH% + @SET PYTHONPATH=$ENV{GEOM_ROOT_DIR}/bin/salome\;%PYTHONPATH% + @SET PYTHONPATH=$ENV{SMESH_ROOT_DIR}/lib/python${PYTHON_VERSION}/site-packages/salome\;%PYTHONPATH% + @SET PYTHONPATH=$ENV{SMESH_ROOT_DIR}/bin/salome\;%PYTHONPATH% + @SET PYTHONPATH=${CMAKE_INSTALL_PREFIX}/lib/python${PYTHON_VERSION}/site-packages/salome\;%PYTHONPATH% + @SET PYTHONPATH=${CMAKE_INSTALL_PREFIX}/bin/salome\;%PYTHONPATH% + @SET SMESH_MeshersList=${DOC_SMESH_MeshersList} + ") + SET(EXT "bat") + SET(CALL_STR "call") +ELSE(WINDOWS) + SET(DOC_PYTHONPATH ${CMAKE_INSTALL_PREFIX}/bin/salome:${SMESH_ROOT_DIR}/bin/salome:${SMESH_ROOT_DIR}/lib/python${PYTHON_VERSION}/site-packages/salome:${MED_ROOT_DIR}/lib/python${PYTHON_VERSION}/site-packages/salome:${GEOM_ROOT_DIR}/bin/salome:${GEOM_ROOT_DIR}/lib/python${PYTHON_VERSION}/site-packages/salome:${KERNEL_ROOT_DIR}/bin/salome:${KERNEL_ROOT_DIR}/lib/python${PYTHON_VERSION}/site-packages/salome:${OMNIORB_ROOT_USER}/lib/python${PYTHON_VERSION}/site-packages:${OMNIORB_ROOT_USER}/lib64/python${PYTHON_VERSION}/site-packages) + SET(SCR "export PYTHONPATH=${DOC_PYTHONPATH}:${PYTHONPATH} + export SMESH_MeshersList=${DOC_SMESH_MeshersList} + ") + SET(EXT "sh") + SET(CALL_STR ".") +ENDIF(WINDOWS) + +FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/tmp_env.${EXT} "${SCR}") + +ADD_CUSTOM_TARGET(usr_docs ${CALL_STR} ${CMAKE_CURRENT_BINARY_DIR}/tmp_env.${EXT} && ${PYTHON_EXECUTABLE} ${f} -d -o smesh.py BLSURFPlugin + COMMAND ${DOXYGEN_EXECUTABLE} doxyfile_py + COMMAND ${DOXYGEN_EXECUTABLE} doxyfile + COMMAND ${PYTHON_EXECUTABLE} -c "import os; os.remove(r'''smesh.py'''); os.remove(r'''tmp_env.${EXT}''')" + COMMAND ${PYTHON_EXECUTABLE} -c "import shutil, sys; shutil.rmtree(r'''${CMAKE_INSTALL_PREFIX}/share/doc/salome/gui/BLSURFPLUGIN''',True); shutil.copytree(r'''${CMAKE_CURRENT_BINARY_DIR}''',r'''${CMAKE_INSTALL_PREFIX}/share/doc/salome/gui/BLSURFPLUGIN''', ignore=shutil.ignore_patterns('*usr_docs*', '*CMakeFiles*', '*.cmake', 'doxyfile*', '*.vcproj', 'static', 'Makefile*')); shutil.copy(r'''${CMAKE_CURRENT_SOURCE_DIR}/images/head.png''',r'''${CMAKE_INSTALL_PREFIX}/share/doc/salome/gui/BLSURFPLUGIN'''); shutil.copy(r'''${CMAKE_CURRENT_SOURCE_DIR}/images/head.png''',r'''${CMAKE_INSTALL_PREFIX}/share/doc/salome/gui/BLSURFPLUGIN/blsurfpluginpy_doc''')" + VERBATIM + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} +) diff --git a/doc/salome/gui/BLSURFPLUGIN/images/blsurf_parameters.png b/doc/salome/gui/BLSURFPLUGIN/images/blsurf_parameters.png index 4da8a9e3a11d9e5f1c4b7c392fbaf2b406762a1d..82c7e90a83b55b84fb312e6f0fa19dfd2d368c77 100644 GIT binary patch literal 53508 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

h5h-To)RA{ku{_pja8 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

w6YKb{3bmH{|yrDpX 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 E0J3qxDF6Tf diff --git a/doc/salome/gui/BLSURFPLUGIN/images/blsurf_parameters_advanced.png b/doc/salome/gui/BLSURFPLUGIN/images/blsurf_parameters_advanced.png index 4fadb6b489bfadef4355128d9dc4014f9811c40e..1f2b0eebcdb1d7a016abcac6a3009bd47672760d 100644 GIT binary patch literal 35575 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 R0~IbP)fCj^3uTQ1{x6scAr1fl literal 36675 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 L)z4*}Q$iB}+#jCU diff --git a/doc/salome/gui/BLSURFPLUGIN/images/blsurf_parameters_enforced_vertices.png b/doc/salome/gui/BLSURFPLUGIN/images/blsurf_parameters_enforced_vertices.png index 4a76b1a73cd7269d0375e24bdf8dee40a8fd7822..33996a623ff5e9239418ca5442c9d5caa10f2672 100644 GIT binary patch literal 34498 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 literal 30233 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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 9bc028a..481510c 100644 --- a/doc/salome/gui/BLSURFPLUGIN/input/blsurf_hypo.doc +++ b/doc/salome/gui/BLSURFPLUGIN/input/blsurf_hypo.doc @@ -3,11 +3,8 @@ \page blsurf_hypo_page BLSURF Parameters hypothesis \anchor blsurf_top -BLSURF Parameters hypothesis works only with \b DISTENE \b BLSurf 2d -algorithm. This algorithm is a commercial software. To obtain a -licence, visit http://www.distene.com/en/corp/eval-distene.html -\tableofcontents +\tableofcontents \section blsurf_general_parameters General parameters @@ -16,96 +13,88 @@ licence, visit http://www.distene.com/en/corp/eval-distene.html - Name - allows defining the name of the hypothesis (BLSURF Parameters_n by default). -- Physical Mesh - can be set to None, Custom - or Size Map +- Physical Mesh - can be set to None, Global size + or Local size - - if set to Custom, allows user input in the in User size, - Max Physical Size and Min Physical Size fields. + - if set to Global size, only the User size, + Max Size and Min Size fields are taken into account. - - if set to Size Map, behaves like Custom mode and takes into - account the custom elements sizes given in the Size Map tab. + - if set to Local size, behaves like Custom mode and takes into + account the "Gradation" parameter and the custom elements sizes given in the + "Local size" tab. -- User size - defines the size of the generated mesh elements. +- Geometrical mesh - can be set to None, Global size -- Max Physical Size - defines the upper limit of mesh element size. + - if set to Global size, allows user input in Mesh angle, + Mesh distance and Gradation fields. These fields control + computation of the element size, so called geometrical size, conform + to the surface geometry considering local curvatures. If both the User size + and the geometrical parameters are defined, the eventual element size + corresponds to the least of the two. -- Min Physical Size - defines the lower limit of mesh element size. +- User size - defines the size of the generated mesh elements. If "Relative value" +is checked, the value is relative to the diagonal of the shape. -- Geometrical mesh - if set to Custom, allows user input in -Angle Mesh S, Angle Mesh C and Gradation -fields. These fields control computation of the element size, so -called geometrical size, conform to the surface geometry -considering local curvatures. If both the User size and the -geometrical size are defined, the eventual element size -corresponds to the least of the two. +- Max Size - defines the upper limit of mesh element size. If "Relative value" +is checked, the value is relative to the diagonal of the shape. -- Angle Mesh S - maximum angle between the mesh face and the -tangent to the geometrical surface at each mesh node, in degrees. +- 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. -- Angle Mesh C - maximum angle between the mesh edge and the -tangent to the geometrical curve at each mesh node, in degrees. +- Gradation - maximum ratio between the lengths of two adjacent edges. -- Max Geometrical Size - defines the upper limit of the - geometrical size. +- Quadratic mesh - if checked, quadratic elements will be generated. -- Min Geometrical Size - defines the lower limit of the - geometrical size. +- 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. -- Gradation - maximum ratio between the lengths of two adjacent - edges. +- 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). -- 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. -- Patch independent - if checked, geometrical edges are not -respected and all geometrical faces are meshed as one hyper-face. +- 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. -\ref blsurf_top "Back to top" +- 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. -\section blsurf_advanced_parameters Advanced parameters +- Mesh optimisation - if checked, the mesh will be optimized in order to get better shaped elements. -The notion of diag used in the descriptions means the diagonal -of the bounding box of the geometrical object to mesh. +- Allow Quadrangles - if checked, allows the creation of quadrilateral elements. -\image html blsurf_parameters_advanced.png - -- Verbosity level - defines the percentage of "verbosity" of -BLSURF [0-100]. +\ref blsurf_top "Back to top" -- Topology - allows creation of a conform mesh on a shell of -not sewed faces. The following choices are allowed: +\section blsurf_advanced_parameters Advanced parameters - - "From CAD" means that mesh conformity is assured by conformity - of a shape. +The notion of diag used in the descriptions means the diagonal of the bounding box of the geometrical object to mesh. - - "Pre-process" and "Pre-process++" allow the BLSURF software to - pre-process the geometrical model to eventually produce a conform - mesh. +\image html blsurf_parameters_advanced.png - - "PreCAD" is an auxiliary CAD pre-processing module which has - two main goals: +- PreCAD options -if checked, the PreCAD module will be used. This module has +two main goals: - - Complete missing or inadequate CAD descriptions. + - Complete missing or inadequate CAD descriptions. - - Perform topology reconstruction and specific geometry - enhancement for mesh generation. + - Perform topology reconstruction and specific geometry + enhancement for mesh generation. - \n This module requires a specific licence. The following PreCAD - options are the most significant and important ones: + \n This module requires a specific licence. The following PreCAD + options are the most significant and important ones: - Merge Edges - allows PreCAD to optimize the geometry by merging some - edges. This option is 0 by default. + edges. This option is checked by default. - - Remove nano edges - allows PreCAD to optimize the geometry by removing - the nano edges whenever possible. This option is 0 by default. - - - Nano edge length - gives the length below which an edge is considered as nano - for the topology processing. See also the \b remove_nano_edges option. If unset, PreCAD - default value is \f$\mathrm{diag} \times 10^{-5}\f$. + - Process 3D topology - allows PreCAD to perform the cleanup processing. + This option is checked by default. - Discard input topology - computes the CAD topology from scratch, without considering the topological information contained in the original CAD - (useful for iges files). This option is 0 by default. + (useful for iges files). This option is unchecked by default. + +- Verbosity level - defines the percentage of "verbosity" of +MeshGems-CADSurf and MeshGems-PreCAD [0-100]. - ExportGMF - saves the computed mesh into a GMF file (.mesh or .meshb). @@ -117,27 +106,14 @@ possible to input the value of the option and edit it later. The following BLSURF options are commonly usable: -- \b topo_eps1 (real) - is the tolerance level inside a CAD -patch. By default is equal to \f$\mathrm{diag} \times 10^{-4}\f$. This tolerance is used to -identify nodes to merge within one geometrical face when \b Topology -option is to pre-process. - -- \b topo_eps2 (real) - is the tolerance level between two CAD -patches. By default is equal to \f$\mathrm{diag} \times 10^{-4}\f$. This tolerance is used to -identify nodes to merge over different geometrical faces when -\b Topology option is to pre-process. - -- \b LSS (real) - is an abbreviation for "length of sub-segment". It is -a maximal allowed length of a mesh edge. Default is \f$0.5\f$. - - \b frontal (integer) - 1 - the mesh generator inserts points with an advancing front method. - - 0 - it inserts them with an algebraic method (on internal edges). This method is + - 0 - it inserts them with an algebraic method (on internal edges). This method is slightly faster but generates less regular meshes. - \n Default is 0. + \n Default is 1. - \anchor blsurf_hinterpol_flag \b hinterpol_flag (integer) - determines the computation of an interpolated value v between two points P1 and P2 on a @@ -164,115 +140,57 @@ values: \n Default is 0. -- \b CheckAdjacentEdges, \b CheckCloseEdges and \b CheckWellDefined -(integers) - give the number of calls of equally named subroutines the -purpose of which is to improve the mesh of domains having narrow -parts. At each iteration,\b CheckCloseEdges decreases the sizes of the -edges when two boundary curves are neighboring,\b CheckAdjacentEdges -balances the sizes of adjacent edges, and \b CheckWellDefined checks if -the parametric domain is well defined. Default values are 0. +The following PreCAD options are commonly usable. + +- \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 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. -- \b CoefRectangle (real)- defines the relative thickness of the rectangles -used by subroutine \b CheckCloseEdges (see above). Default is 0.25. +- \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. -- \b eps_collapse (real) - if more than 0.0, BLSURF removes -curves whose lengths are less than \b eps_collapse. To obtain an -approximate value of the length of a curve, it is arbitrarily -split into 20 edges. Default is 0.0. +- \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. -- \b eps_ends (real) - is used to detect the curves whose lengths are very -small, that sometimes constitutes an error. A message is printed -if \f$\left|P2-P1\right| < eps\_ends\f$, where P1 and P2 are the -extremities of a curve. Default is \f$\frac{\mathrm{diag}}{500.0}\f$. +- \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$. -- \b prefix (char) - is a prefix of the files generated by -BLSURF. Default is "x". +- \b remove_tiny_edges (boolean) -optimize the geometry by removing the nano edges whenever possible. +By default this option is 0. -- \b refs (integer) - reference of a surface, used when exporting -files. Default is 1. +- \b required_entities (char) -controls the correction operations. Possible values are: -The following PreCAD options are commonly usable. + - "respect" - PreCAD is not allowed to correct or optimize a required edge. -- \b closed_geometry (int) - 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. + - "ignore" - PreCAD is allowed to correct a required edge. -- \b debug (int) - If debug = 1 PreCAD will be very verbose and will output -some intermediate files in the working directory. By default this -option is 0. + - "clear" - PreCAD will erase "required" status of each required entities, and will thus + be allowed to correct a required edge. -- \b eps_nano_relative (real) - the same as \b eps_nano, but relatively to -the diagonal of the box bounding the geometry. By default this option is \f$10^{-5}\f$. + \n By default this option is "respect". -- \b eps_sewing (real) - tolerance of the assembly. It rarely requires to be tuned. +- \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 eps_sewing_relative (real) - the same as \b eps_nano but relatively to -the diagonal of the box bounding the geometry. By default this option -is \f$5 \cdot 10^{-4}\f$. +- \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. -- \b create_tag_collision (int) - creates new tags from original ones in case -of collision (entity merge or association for example). By default -this option is 0. + - "ignore" - PreCAD is allowed to cross the CAD attributes boundaries for optimisation. -- \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$. + - "clear" - PreCAD will erase each tgas of each entities, and will thus + be allowed to cross the CAD attributes boundaries in its optimisation purpose. -- \b periodic_tolerance_relative (real) - the same as \b periodic_tolerance but in a relative unit. -By default this option is \f$10^{-5}\f$. + \n By default this option is "respect". -- \b periodic_split_tolerance (real) - This periodicity processing related option defines -the minimum distance between a CAD point and an imprinted point. It allows to indirectly -control the number of created points and small edges. By default this -option is \f$\mathrm{diag} \times 10^{-4}\f$. - -- \b periodic_split_tolerance_relative (real - the same as \b -periodic_split_tolerance but in a relative unit. By default this -option is \f$10^{-4}\f$. - -The following advanced options are not documented and you can use them -at your own risk. - -- Integer variables: - - addsurf_ivertex - - anisotropic - - background - - coiter - - communication - - decim - - export_flag - - file_h - - gridnu - - gridnv - - intermedfile - - memory - - normals - - optim - - pardom_flag - - pinch - - rigid - - surforient - - tconf - - topo_collapse -- Real variables: - - addsurf_angle - - addsurf_R - - addsurf_H - - addsurf_FG - - addsurf_r - - addsurf_PA - - angle_compcurv - - angle_ridge - - anisotropic_ratio - - eps_pardom -- String variables: - - export_format - - export_option - - import_option +- \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$. \ref blsurf_top "Back to top" @@ -432,6 +350,9 @@ The enforced vertex is the projection of a point defined by its - If a group name is specified : If the group exists, the enforced nodes will be added in the existing group, if the group does not exist it will be created. +All the internal vertices of the faces can be considered as enforced vertices if the corresponding checkbox is checked. +A group can optionnaly be defined on those enforced vertices. + \sa Sample TUI Script of the \ref tui_blsurf "creation of a BLSurf hypothesis", including enforced vertices. \ref blsurf_top "Back to top" diff --git a/doc/salome/gui/BLSURFPLUGIN/input/index.doc b/doc/salome/gui/BLSURFPLUGIN/input/index.doc index 3a35d84..83ea929 100644 --- a/doc/salome/gui/BLSURFPLUGIN/input/index.doc +++ b/doc/salome/gui/BLSURFPLUGIN/input/index.doc @@ -7,7 +7,7 @@ used within the SALOME Mesh module for generation of 2D mesh. \note BLSURFPLUGIN plugin uses DISTENE BLSurf commercial meshing software and requires a license at the run time (to work within the -Mesh module). +Mesh module). To obtain a licence, visit http://www.distene.com/en/corp/eval-distene.html \b BLSURFPLUGIN plugin is destined for: - Meshing of the 2D geometric entities. diff --git a/idl/BLSURFPlugin_Algorithm.idl b/idl/BLSURFPlugin_Algorithm.idl index d26ce56..1cd1cd9 100644 --- a/idl/BLSURFPlugin_Algorithm.idl +++ b/idl/BLSURFPlugin_Algorithm.idl @@ -122,14 +122,6 @@ module BLSURFPlugin */ interface BLSURFPlugin_Hypothesis : SMESH::SMESH_Hypothesis { - /*! - * Sets topology usage way defining how mesh conformity is assured - * value=0 - mesh conformity is assured by conformity of a shape - * value=1,2 - mesh conformity is assured by pre-processing a CAD model - * value=3 - mesh conformity is assured by pre-processing a CAD model with Pre-CAD - */ - void SetTopology(in long way); - long GetTopology(); /*! * Sets a way to define size of mesh elements to generate @@ -140,73 +132,128 @@ module BLSURFPlugin void SetPhysicalMesh(in long isCustom); long GetPhysicalMesh(); + /*! + * Sets a way to define maximum angular deflection of mesh from CAD model + * 0 - deflection is defined automatically + * 1 - deflection is set by SetAngleMesh() method + * 2 - deflection is set by SetAngleMesh() method. A sizemap is defined (TODO). + */ + void SetGeometricMesh(in long isCustom); + long GetGeometricMesh(); + /*! * Sets size of mesh elements to generate */ void SetPhySize(in double size); + void SetPhySizeRel(in double size); double GetPhySize(); + boolean IsPhySizeRel(); /*! - * Sets lower boundary of mesh element size (PhySize) + * Sets lower boundary of mesh element size */ - void SetPhyMin(in double theMinSize); - double GetPhyMin(); + void SetMinSize(in double theMinSize); + void SetMinSizeRel(in double theMinSize); + double GetMinSize(); + boolean IsMinSizeRel(); /*! - * Sets upper boundary of mesh element size (PhySize) + * Sets upper boundary of mesh element size */ - void SetPhyMax(in double theMaxSize); - double GetPhyMax(); + void SetMaxSize(in double theMaxSize); + void SetMaxSizeRel(in double theMaxSize); + double GetMaxSize(); + boolean IsMaxSizeRel(); /*! - * Sets a way to define maximum angular deflection of mesh from CAD model - * 0 - deflection is defined automatically - * 1 - deflection is set by SetAngleMeshS() and SetAngleMeshC() methods + * Sets maximal allowed ratio between the lengths of two adjacent edges */ - void SetGeometricMesh(in long isCustom); - long GetGeometricMesh(); + void SetGradation(in double ratio); + double GetGradation(); /*! - * Sets angular deflection (in degrees) of a mesh face from CAD surface + * Sets to create quadrilateral elements or not */ - void SetAngleMeshS(in double angle); - double GetAngleMeshS(); + void SetQuadAllowed(in boolean allowed); + boolean GetQuadAllowed(); /*! - * Sets angular deflection (in degrees) of a mesh edge from CAD curve + * Sets angular deflection (in degrees) of a mesh face and edge from CAD surface */ - void SetAngleMeshC(in double angle); - double GetAngleMeshC(); + void SetAngleMesh(in double angle); + double GetAngleMesh(); /*! - * Sets lower boundary of mesh element size computed to respect angular deflection + * Sets the maximum desired distance between a triangle and its supporting CAD surface */ - void SetGeoMin(in double theMinSize); - double GetGeoMin(); + void SetChordalError(in double distance); + double GetChordalError(); /*! - * Sets upper boundary of mesh element size computed to respect angular deflection + * Determines whether the generated mesh will be isotropic or anisotropic */ - void SetGeoMax(in double theMaxSize); - double GetGeoMax(); + void SetAnisotropic(in boolean anisotropic); + boolean GetAnisotropic(); /*! - * Sets maximal allowed ratio between the lengths of two adjacent edges + * Defines the maximum anisotropic ratio of the metric governing the anisotropic process. + * The default value of 0 means that the metric (and thus the generated elements) + * can be arbitrarily stretched. */ - void SetGradation(in double ratio); - double GetGradation(); + void SetAnisotropicRatio(in double ratio); + double GetAnisotropicRatio(); /*! - * Sets to create quadrilateral elements or not + * This patch-independent correction option can be activated to remove the tiny + * (nano) edges from the generated mesh, without taking into account the tags + * (attributes) specifications. */ - void SetQuadAllowed(in boolean allowed); - boolean GetQuadAllowed(); + void SetRemoveTinyEdges(in boolean remove); + boolean GetRemoveTinyEdges(); /*! - * To respect geometrical edges or not + * Defines the minimal length under which an edge is considered to be a tiny one */ - void SetDecimesh(in boolean toIgnoreEdges); - boolean GetDecimesh(); + void SetTinyEdgeLength(in double length); + double GetTinyEdgeLength(); + + /*! + * This patch independent correction option can be activated to remove the bad + * elements (often called slivers) from the generated mesh, without taking into account + * the tags (attributes) specification. + */ + void SetBadElementRemoval(in boolean remove); + boolean GetBadElementRemoval(); + + /*! + * This parameter defines the aspect ratio triggering the "bad element" + * classification for the force bad surface element removal option. + */ + void SetBadElementAspectRatio(in double ratio); + double GetBadElementAspectRatio(); + + /*! + * If this option is activated, MeshGems-CADSurf will optimize the mesh in order to + * get better shaped elements, during a process which respects the patch independent options. + * This optimisation cannot be fully performed when correct_surface_intersections = 1. + */ + void SetOptimizeMesh(in boolean optimize); + boolean GetOptimizeMesh(); + + /*! + * Determines the order of mesh elements to be generated (linear or quadratic) + */ + void SetQuadraticMesh(in boolean quadratic); + boolean GetQuadraticMesh(); + + /*! + * Sets topology usage way defining how mesh conformity is assured + * value=0 - mesh conformity is assured by conformity of a shape + * value=1,2 - mesh conformity is assured by pre-processing a CAD model (OBSOLETE) + * value=3 - mesh conformity is assured by pre-processing a CAD model with Pre-CAD + */ + void SetTopology(in long way); + long GetTopology(); /*! * Sets verbosity level in the range 0 to 100. @@ -221,10 +268,11 @@ module BLSURFPlugin boolean GetPreCADMergeEdges(); /*! - * To remove nano edges. + * To process 3D topology. */ - void SetPreCADRemoveNanoEdges(in boolean toRemoveNanoEdges); - boolean GetPreCADRemoveNanoEdges(); + void SetPreCADProcess3DTopology(in boolean toProcess); + boolean GetPreCADProcess3DTopology(); + /*! * To compute topology from scratch @@ -232,13 +280,6 @@ module BLSURFPlugin void SetPreCADDiscardInput(in boolean toDiscardInput); boolean GetPreCADDiscardInput(); - /*! - * Sets the length below which an edge is considered as nano - * for the topology processing. - */ - void SetPreCADEpsNano(in double epsNano); - double GetPreCADEpsNano(); - /*! * Sets advanced option value */ @@ -282,12 +323,14 @@ module BLSURFPlugin * Set/unset a SizeMap on geom object */ void SetSizeMap(in GEOM::GEOM_Object GeomObj, in string sizeMap); + void SetConstantSizeMap(in GEOM::GEOM_Object GeomObj, in double sizeMap); void UnsetSizeMap(in GEOM::GEOM_Object GeomObj); /*! * Set a SizeMap on geom object given by entry */ void SetSizeMapEntry(in string entry, in string sizeMap); + void SetConstantSizeMapEntry(in string entry, in GEOM::shape_type shapeType, in double sizeMap); string GetSizeMapEntry(in string entry); string_array GetSizeMapEntries(); @@ -390,6 +433,28 @@ module BLSURFPlugin void SetGMFFile(in string theFileName); string GetGMFFile(); // boolean GetGMFFileMode(); + + // + // Obsolete methods - To be removed in V7 + // + void SetPhyMin(in double theMinSize); + double GetPhyMin(); + void SetPhyMax(in double theMaxSize); + double GetPhyMax(); + void SetGeoMin(in double theMinSize); + double GetGeoMin(); + void SetGeoMax(in double theMaxSize); + double GetGeoMax(); + void SetAngleMeshS(in double angle); + double GetAngleMeshS(); + void SetAngleMeshC(in double angle); + double GetAngleMeshC(); + void SetDecimesh(in boolean toIgnoreEdges); + boolean GetDecimesh(); + void SetPreCADRemoveNanoEdges(in boolean toRemoveNanoEdges); + boolean GetPreCADRemoveNanoEdges(); + void SetPreCADEpsNano(in double epsNano); + double GetPreCADEpsNano(); }; }; diff --git a/resources/BLSURFPlugin.xml b/resources/BLSURFPlugin.xml index 7eb2e41..93cbaf7 100644 --- a/resources/BLSURFPlugin.xml +++ b/resources/BLSURFPlugin.xml @@ -66,13 +66,14 @@ BLSURF=Triangle(algo=smesh.BLSURF) BLSURF_Parameters=Parameters() + ViscousLayers2D=ViscousLayers2D(SetTotalThickness(),SetNumberLayers(),SetStretchFactor(),SetIgnoreEdges()) diff --git a/src/BLSURFPlugin/BLSURFPluginDC.py b/src/BLSURFPlugin/BLSURFPluginDC.py index 791744e..c7b5568 100644 --- a/src/BLSURFPlugin/BLSURFPluginDC.py +++ b/src/BLSURFPlugin/BLSURFPluginDC.py @@ -28,16 +28,18 @@ from smesh import AssureGeomPublished FromCAD, PreProcess, PreProcessPlus, PreCAD = 0,1,2,3 # Element size flag of BLSURF -DefaultSize, DefaultGeom, BLSURF_Custom, SizeMap = 0,0,1,2 +DefaultSize, DefaultGeom, BLSURF_GlobalSize, BLSURF_LocalSize = 0,0,1,2 +# Retrocompatibility +BLSURF_Custom, SizeMap = BLSURF_GlobalSize, BLSURF_LocalSize # import BLSURFPlugin module if possible noBLSURFPlugin = 0 try: - import BLSURFPlugin + import BLSURFPlugin except ImportError: - noBLSURFPlugin = 1 - pass + noBLSURFPlugin = 1 + pass #---------------------------- # Mesh algo type identifiers @@ -56,333 +58,432 @@ BLSURF = "BLSURF" # class BLSURF_Algorithm(Mesh_Algorithm): - ## name of the dynamic method in smesh.Mesh class - # @internal - meshMethod = "Triangle" - ## type of algorithm used with helper function in smesh.Mesh class - # @internal - algoType = BLSURF - ## doc string of the method - # @internal - docHelper = "Creates triangle 2D algorithm for faces" - - _angleMeshS = 8 - _gradation = 1.1 - - ## Private constructor. - # @param mesh parent mesh object algorithm is assigned to - # @param geom geometry (shape/sub-shape) algorithm is assigned to; - # if it is @c 0 (default), the algorithm is assigned to the main shape - def __init__(self, mesh, geom=0): - Mesh_Algorithm.__init__(self) - if noBLSURFPlugin: - print "Warning: BLSURFPlugin module unavailable" - self.Create(mesh, geom, BLSURF, "libBLSURFEngine.so") - self.params=None - #self.SetPhysicalMesh() - PAL19680 - pass - - ## Sets a way to define size of mesh elements to generate. - # @param thePhysicalMesh is: DefaultSize, BLSURF_Custom or SizeMap. - def SetPhysicalMesh(self, thePhysicalMesh=DefaultSize): - self.Parameters().SetPhysicalMesh(thePhysicalMesh) - pass - - ## Sets size of mesh elements to generate. - # @param theVal value of mesh element size - def SetPhySize(self, theVal): - self.Parameters().SetPhySize(theVal) - pass - - ## Sets lower boundary of mesh element size (PhySize). - # @param theVal value of mesh element minimal size - def SetPhyMin(self, theVal=-1): - self.Parameters().SetPhyMin(theVal) - pass - - ## Sets upper boundary of mesh element size (PhySize). - # @param theVal value of mesh element maximal size - def SetPhyMax(self, theVal=-1): - self.Parameters().SetPhyMax(theVal) - pass - - ## Sets a way to define maximum angular deflection of mesh from CAD model. - # @param theGeometricMesh is: 0 (None) or 1 (Custom) - def SetGeometricMesh(self, theGeometricMesh=0): - if self.Parameters().GetPhysicalMesh() == 0: theGeometricMesh = 1 - self.Parameters().SetGeometricMesh(theGeometricMesh) - pass - - ## Sets angular deflection (in degrees) of a mesh face from CAD surface. - # @param theVal value of angular deflection for mesh face - def SetAngleMeshS(self, theVal=_angleMeshS): - if self.Parameters().GetGeometricMesh() == 0: theVal = self._angleMeshS - self.Parameters().SetAngleMeshS(theVal) - pass - - ## Sets angular deflection (in degrees) of a mesh edge from CAD curve. - # @param theVal value of angular deflection for mesh edge - def SetAngleMeshC(self, theVal=_angleMeshS): - if self.Parameters().GetGeometricMesh() == 0: theVal = self._angleMeshS - self.Parameters().SetAngleMeshC(theVal) - pass - - ## Sets lower boundary of mesh element size computed to respect angular deflection. - # @param theVal value of mesh element minimal size - def SetGeoMin(self, theVal=-1): - self.Parameters().SetGeoMin(theVal) - pass - - ## Sets upper boundary of mesh element size computed to respect angular deflection. - # @param theVal value of mesh element maximal size - def SetGeoMax(self, theVal=-1): - self.Parameters().SetGeoMax(theVal) - pass - - ## Sets maximal allowed ratio between the lengths of two adjacent edges. - # @param theVal value of maximal length ratio - def SetGradation(self, theVal=_gradation): - if self.Parameters().GetGeometricMesh() == 0: theVal = self._gradation - self.Parameters().SetGradation(theVal) - pass - - ## Sets topology usage way. - # @param way defines how mesh conformity is assured - # - FromCAD - mesh conformity is assured by conformity of a shape - # - PreProcess or PreProcessPlus - by pre-processing a CAD model - # - PreCAD - by pre-processing with PreCAD a CAD model - def SetTopology(self, way): - self.Parameters().SetTopology(way) - pass - - ## To respect geometrical edges or not. - # @param toIgnoreEdges "ignore edges" flag value - def SetDecimesh(self, toIgnoreEdges=False): - self.Parameters().SetDecimesh(toIgnoreEdges) - pass - - ## Sets verbosity level in the range 0 to 100. - # @param level verbosity level - def SetVerbosity(self, level): - self.Parameters().SetVerbosity(level) - pass - - ## To optimize merges edges. - # @param toMergeEdges "merge edges" flag value - def SetPreCADMergeEdges(self, toMergeEdges=False): - self.Parameters().SetPreCADMergeEdges(toMergeEdges) - pass - - ## To remove nano edges. - # @param toRemoveNanoEdges "remove nano edges" flag value - def SetPreCADRemoveNanoEdges(self, toRemoveNanoEdges=False): - self.Parameters().SetPreCADRemoveNanoEdges(toRemoveNanoEdges) - pass - - ## To compute topology from scratch - # @param toDiscardInput "discard input" flag value - def SetPreCADDiscardInput(self, toDiscardInput=False): - self.Parameters().SetPreCADDiscardInput(toDiscardInput) - pass - - ## Sets the length below which an edge is considered as nano - # for the topology processing. - # @param epsNano nano edge length threshold value - def SetPreCADEpsNano(self, epsNano): - self.Parameters().SetPreCADEpsNano(epsNano) - pass - - ## Sets advanced option value. - # @param optionName advanced option name - # @param level advanced option value - def SetOptionValue(self, optionName, level): - self.Parameters().SetOptionValue(optionName,level) - pass - - ## Sets advanced PreCAD option value. - # @param optionName name of the option - # @param optionValue value of the option - def SetPreCADOptionValue(self, optionName, optionValue): - self.Parameters().SetPreCADOptionValue(optionName,optionValue) - pass - - ## Sets GMF file for export at computation - # @param fileName GMF file name - def SetGMFFile(self, fileName): - self.Parameters().SetGMFFile(fileName) - pass - - #----------------------------------------- - # Enforced vertices (BLSURF) - #----------------------------------------- - - ## To get all the enforced vertices - def GetAllEnforcedVertices(self): - return self.Parameters().GetAllEnforcedVertices() - - ## To get all the enforced vertices sorted by face (or group, compound) - def GetAllEnforcedVerticesByFace(self): - return self.Parameters().GetAllEnforcedVerticesByFace() - - ## To get all the enforced vertices sorted by coords of input vertices - def GetAllEnforcedVerticesByCoords(self): - return self.Parameters().GetAllEnforcedVerticesByCoords() - - ## To get all the coords of input vertices sorted by face (or group, compound) - def GetAllCoordsByFace(self): - return self.Parameters().GetAllCoordsByFace() - - ## To get all the enforced vertices on a face (or group, compound) - # @param theFace : GEOM face (or group, compound) on which to define an enforced vertex - def GetEnforcedVertices(self, theFace): - AssureGeomPublished( self.mesh, theFace ) - return self.Parameters().GetEnforcedVertices(theFace) - - ## To clear all the enforced vertices - def ClearAllEnforcedVertices(self): - return self.Parameters().ClearAllEnforcedVertices() - - ## To set an enforced vertex on a face (or group, compound) given the coordinates of a point. If the point is not on the face, it will projected on it. If there is no projection, no enforced vertex is created. - # @param theFace : GEOM face (or group, compound) on which to define an enforced vertex - # @param x : x coordinate - # @param y : y coordinate - # @param z : z coordinate - # @param vertexName : name of the enforced vertex - # @param groupName : name of the group - def SetEnforcedVertex(self, theFace, x, y, z, vertexName = "", groupName = ""): - AssureGeomPublished( self.mesh, theFace ) - if vertexName == "": - if groupName == "": - return self.Parameters().SetEnforcedVertex(theFace, x, y, z) - else: - return self.Parameters().SetEnforcedVertexWithGroup(theFace, x, y, z, groupName) - pass - else: - if groupName == "": - return self.Parameters().SetEnforcedVertexNamed(theFace, x, y, z, vertexName) - else: - return self.Parameters().SetEnforcedVertexNamedWithGroup(theFace, x, y, z, vertexName, groupName) - pass - pass - - ## To set an enforced vertex on a face (or group, compound) given a GEOM vertex, group or compound. - # @param theFace : GEOM face (or group, compound) on which to define an enforced vertex - # @param theVertex : GEOM vertex (or group, compound) to be projected on theFace. - # @param groupName : name of the group - def SetEnforcedVertexGeom(self, theFace, theVertex, groupName = ""): - AssureGeomPublished( self.mesh, theFace ) - AssureGeomPublished( self.mesh, theVertex ) - if groupName == "": - return self.Parameters().SetEnforcedVertexGeom(theFace, theVertex) - else: - return self.Parameters().SetEnforcedVertexGeomWithGroup(theFace, theVertex,groupName) - pass - - ## To remove an enforced vertex on a given GEOM face (or group, compound) given the coordinates. - # @param theFace : GEOM face (or group, compound) on which to remove the enforced vertex - # @param x : x coordinate - # @param y : y coordinate - # @param z : z coordinate - def UnsetEnforcedVertex(self, theFace, x, y, z): - AssureGeomPublished( self.mesh, theFace ) - return self.Parameters().UnsetEnforcedVertex(theFace, x, y, z) - - ## To remove an enforced vertex on a given GEOM face (or group, compound) given a GEOM vertex, group or compound. - # @param theFace : GEOM face (or group, compound) on which to remove the enforced vertex - # @param theVertex : GEOM vertex (or group, compound) to remove. - def UnsetEnforcedVertexGeom(self, theFace, theVertex): - AssureGeomPublished( self.mesh, theFace ) - AssureGeomPublished( self.mesh, theVertex ) - return self.Parameters().UnsetEnforcedVertexGeom(theFace, theVertex) - - ## To remove all enforced vertices on a given face. - # @param theFace : face (or group/compound of faces) on which to remove all enforced vertices - def UnsetEnforcedVertices(self, theFace): - AssureGeomPublished( self.mesh, theFace ) - return self.Parameters().UnsetEnforcedVertices(theFace) - - ## To tell BLSURF to add a node on internal vertices - # @param toEnforceInternalVertices : boolean; if True the internal vertices are added as enforced vertices - def SetInternalEnforcedVertexAllFaces(self, toEnforceInternalVertices): - return self.Parameters().SetInternalEnforcedVertexAllFaces(toEnforceInternalVertices) - - ## To know if BLSURF will add a node on internal vertices - def GetInternalEnforcedVertexAllFaces(self): - return self.Parameters().GetInternalEnforcedVertexAllFaces() - - ## To define a group for the nodes of internal vertices - # @param groupName : string; name of the group - def SetInternalEnforcedVertexAllFacesGroup(self, groupName): - return self.Parameters().SetInternalEnforcedVertexAllFacesGroup(groupName) - - ## To get the group name of the nodes of internal vertices - def GetInternalEnforcedVertexAllFacesGroup(self): - return self.Parameters().GetInternalEnforcedVertexAllFacesGroup() - - #----------------------------------------- - # Attractors - #----------------------------------------- - - ## Sets an attractor on the chosen face. The mesh size will decrease exponentially with the distance from theAttractor, following the rule h(d) = theEndSize - (theEndSize - theStartSize) * exp [ - ( d / theInfluenceDistance ) ^ 2 ] - # @param theFace : face on which the attractor will be defined - # @param theAttractor : geometrical object from which the mesh size "h" decreases exponentially - # @param theStartSize : mesh size on theAttractor - # @param theEndSize : maximum size that will be reached on theFace - # @param theInfluenceDistance : influence of the attractor ( the size grow slower on theFace if it's high) - # @param theConstantSizeDistance : distance until which the mesh size will be kept constant on theFace - def SetAttractorGeom(self, theFace, theAttractor, theStartSize, theEndSize, theInfluenceDistance, theConstantSizeDistance): - AssureGeomPublished( self.mesh, theFace ) - AssureGeomPublished( self.mesh, theAttractor ) - self.Parameters().SetAttractorGeom(theFace, theAttractor, theStartSize, theEndSize, theInfluenceDistance, theConstantSizeDistance) - pass - - ## Unsets an attractor on the chosen face. - # @param theFace : face on which the attractor has to be removed - def UnsetAttractorGeom(self, theFace): - AssureGeomPublished( self.mesh, theFace ) - self.Parameters().SetAttractorGeom(theFace) - pass - - #----------------------------------------- - # Size maps (BLSURF) - #----------------------------------------- - - ## To set a size map on a face, edge or vertex (or group, compound) given Python function. - # If theObject is a face, the function can be: def f(u,v): return u+v - # If theObject is an edge, the function can be: def f(t): return t/2 - # If theObject is a vertex, the function can be: def f(): return 10 - # @param theObject : GEOM face, edge or vertex (or group, compound) on which to define a size map - # @param theSizeMap : Size map defined as a string - def SetSizeMap(self, theObject, theSizeMap): - AssureGeomPublished( self.mesh, theObject ) - self.Parameters().SetSizeMap(theObject, theSizeMap) - pass - - ## To remove a size map defined on a face, edge or vertex (or group, compound) - # @param theObject : GEOM face, edge or vertex (or group, compound) on which to define a size map - def UnsetSizeMap(self, theObject): - AssureGeomPublished( self.mesh, theObject ) - self.Parameters().UnsetSizeMap(theObject) - pass - - ## To remove all the size maps - def ClearSizeMaps(self): - self.Parameters().ClearSizeMaps() - pass - - ## Sets QuadAllowed flag. - # @param toAllow "allow quadrangles" flag value - def SetQuadAllowed(self, toAllow=True): - self.Parameters().SetQuadAllowed(toAllow) - pass - - ## Defines hypothesis having several parameters - # @return hypothesis object - def Parameters(self): - if not self.params: - self.params = self.Hypothesis("BLSURF_Parameters", [], - "libBLSURFEngine.so", UseExisting=0) - pass - return self.params - - pass # end of BLSURF_Algorithm class + ## name of the dynamic method in smesh.Mesh class + # @internal + meshMethod = "Triangle" + ## type of algorithm used with helper function in smesh.Mesh class + # @internal + algoType = BLSURF + ## doc string of the method + # @internal + docHelper = "Creates triangle 2D algorithm for faces" + + _anisotropic_ratio = 0 + _bad_surface_element_aspect_ratio = 1000 + _geometric_approximation = 22 + _gradation = 1.3 + _metric = "isotropic" + _remove_tiny_edges = 0 + + ## Private constructor. + # @param mesh parent mesh object algorithm is assigned to + # @param geom geometry (shape/sub-shape) algorithm is assigned to; + # if it is @c 0 (default), the algorithm is assigned to the main shape + def __init__(self, mesh, geom=0): + Mesh_Algorithm.__init__(self) + if noBLSURFPlugin: + print "Warning: BLSURFPlugin module unavailable" + self.Create(mesh, geom, BLSURF, "libBLSURFEngine.so") + self.params=None + #self.SetPhysicalMesh() - PAL19680 + pass + + ## Sets a way to define size of mesh elements to generate. + # @param thePhysicalMesh is: DefaultSize, BLSURF_Custom or SizeMap. + def SetPhysicalMesh(self, thePhysicalMesh=DefaultSize): + physical_size_mode = thePhysicalMesh + if self.Parameters().GetGeometricMesh() == DefaultGeom: + if physical_size_mode == DefaultSize: + physical_size_mode = BLSURF_GlobalSize + self.Parameters().SetPhysicalMesh(physical_size_mode) + pass + + ## Sets a way to define maximum angular deflection of mesh from CAD model. + # @param theGeometricMesh is: DefaultGeom (0)) or BLSURF_GlobalSize (1)) + def SetGeometricMesh(self, theGeometricMesh=DefaultGeom): + geometric_size_mode = theGeometricMesh + if self.Parameters().GetPhysicalMesh() == DefaultSize: + if geometric_size_mode == DefaultGeom: + geometric_size_mode = BLSURF_GlobalSize + self.Parameters().SetGeometricMesh(geometric_size_mode) + pass + + ## Sets size of mesh elements to generate. + # @param theVal : constant global size when using a global physical size. + # @param isRelative : if True, the value is relative to the length of the diagonal of the bounding box + def SetPhySize(self, theVal, isRelative = False): + if self.Parameters().GetPhysicalMesh() == DefaultSize: + self.SetPhysicalMesh(BLSURF_GlobalSize) + if isRelative: + self.Parameters().SetPhySizeRel(theVal) + else: + self.Parameters().SetPhySize(theVal) + pass + + ## Sets lower boundary of mesh element size. + # @param theVal : global minimal cell size desired. + # @param isRelative : if True, the value is relative to the length of the diagonal of the bounding box + def SetMinSize(self, theVal=-1, isRelative = False): + if isRelative: + self.Parameters().SetMinSizeRel(theVal) + else: + self.Parameters().SetMinSize(theVal) + pass + + ## Sets upper boundary of mesh element size. + # @param theVal : global maximal cell size desired. + # @param isRelative : if True, the value is relative to the length of the diagonal of the bounding box + def SetMaxSize(self, theVal=-1): + if isRelative: + self.Parameters().SetMaxSizeRel(theVal) + else: + self.Parameters().SetMaxSize(theVal) + pass + + ## Sets angular deflection (in degrees) from CAD surface. + # @param theVal value of angular deflection + def SetAngleMesh(self, theVal=_geometric_approximation): + if self.Parameters().GetGeometricMesh() == DefaultGeom: + self.SetGeometricMesh(BLSURF_GlobalSize) + self.Parameters().SetAngleMesh(theVal) + pass + + ## Sets maximal allowed ratio between the lengths of two adjacent edges. + # @param theVal value of maximal length ratio + def SetGradation(self, theVal=_gradation): + if self.Parameters().GetGeometricMesh() == 0: theVal = self._gradation + self.Parameters().SetGradation(theVal) + pass + + ## Sets topology usage way. + # @param way defines how mesh conformity is assured

    + #
  • FromCAD - mesh conformity is assured by conformity of a shape
  • + #
  • PreProcess or PreProcessPlus - by pre-processing a CAD model (OBSOLETE: FromCAD will be used)
  • + #
  • PreCAD - by pre-processing with PreCAD a CAD model
+ def SetTopology(self, way): + if way != PreCAD: + print "Warning: topology mode %d is no longer supported. Mode FromCAD is used."%way + way = FromCAD + self.Parameters().SetTopology(way) + pass + + ## To respect geometrical edges or not. + # @param toIgnoreEdges "ignore edges" flag value + def SetDecimesh(self, toIgnoreEdges=False): + if toIgnoreEdges: + self.SetOptionValue("respect_geometry","0") + else: + self.SetOptionValue("respect_geometry","1") + pass + + ## Sets verbosity level in the range 0 to 100. + # @param level verbosity level + def SetVerbosity(self, level): + self.Parameters().SetVerbosity(level) + pass + + ## To optimize merges edges. + # @param toMergeEdges "merge edges" flag value + def SetPreCADMergeEdges(self, toMergeEdges=False): + if self.Parameters().GetTopology() != PreCAD: + self.SetTopology(PreCAD) + self.Parameters().SetPreCADMergeEdges(toMergeEdges) + pass + + ## To process 3D topology. + # @param toProcess "PreCAD process 3D" flag value + def SetPreCADProcess3DTopology(self, toProcess=False): + if self.Parameters().GetTopology() != PreCAD: + self.SetTopology(PreCAD) + self.Parameters().SetPreCADProcess3DTopology(toProcess) + pass + + ## To remove nano edges. + # @param toRemoveNanoEdges "remove nano edges" flag value + def SetPreCADRemoveNanoEdges(self, toRemoveNanoEdges=False): + if toRemoveNanoEdges: + self.SetPreCADOptionValue("remove_tiny_edges","1") + else: + self.SetPreCADOptionValue("remove_tiny_edges","0") + pass + + ## To compute topology from scratch + # @param toDiscardInput "discard input" flag value + def SetPreCADDiscardInput(self, toDiscardInput=False): + if self.Parameters().GetTopology() != PreCAD: + self.SetTopology(PreCAD) + self.Parameters().SetPreCADDiscardInput(toDiscardInput) + pass + + ## Sets the length below which an edge is considered as nano + # for the topology processing. + # @param epsNano nano edge length threshold value + def SetPreCADEpsNano(self, epsNano): + self.SetPreCADOptionValue("tiny_edge_length","%f"%epsNano) + pass + + ## Sets advanced option value. + # @param optionName advanced option name + # @param level advanced option value + def SetOptionValue(self, optionName, level): + self.Parameters().SetOptionValue(optionName,level) + pass + + ## Sets advanced PreCAD option value. + # @param optionName name of the option + # @param optionValue value of the option + def SetPreCADOptionValue(self, optionName, optionValue): + if self.Parameters().GetTopology() != PreCAD: + self.SetTopology(PreCAD) + self.Parameters().SetPreCADOptionValue(optionName,optionValue) + pass + + ## Sets GMF file for export at computation + # @param fileName GMF file name + def SetGMFFile(self, fileName): + self.Parameters().SetGMFFile(fileName) + pass + + #----------------------------------------- + # Enforced vertices (BLSURF) + #----------------------------------------- + + ## To get all the enforced vertices + def GetAllEnforcedVertices(self): + return self.Parameters().GetAllEnforcedVertices() + + ## To get all the enforced vertices sorted by face (or group, compound) + def GetAllEnforcedVerticesByFace(self): + return self.Parameters().GetAllEnforcedVerticesByFace() + + ## To get all the enforced vertices sorted by coords of input vertices + def GetAllEnforcedVerticesByCoords(self): + return self.Parameters().GetAllEnforcedVerticesByCoords() + + ## To get all the coords of input vertices sorted by face (or group, compound) + def GetAllCoordsByFace(self): + return self.Parameters().GetAllCoordsByFace() + + ## To get all the enforced vertices on a face (or group, compound) + # @param theFace : GEOM face (or group, compound) on which to define an enforced vertex + def GetEnforcedVertices(self, theFace): + AssureGeomPublished( self.mesh, theFace ) + return self.Parameters().GetEnforcedVertices(theFace) + + ## To clear all the enforced vertices + def ClearAllEnforcedVertices(self): + return self.Parameters().ClearAllEnforcedVertices() + + ## To set an enforced vertex on a face (or group, compound) given the coordinates of a point. If the point is not on the face, it will projected on it. If there is no projection, no enforced vertex is created. + # @param theFace : GEOM face (or group, compound) on which to define an enforced vertex + # @param x : x coordinate + # @param y : y coordinate + # @param z : z coordinate + # @param vertexName : name of the enforced vertex + # @param groupName : name of the group + def SetEnforcedVertex(self, theFace, x, y, z, vertexName = "", groupName = ""): + AssureGeomPublished( self.mesh, theFace ) + if vertexName == "": + if groupName == "": + return self.Parameters().SetEnforcedVertex(theFace, x, y, z) + else: + return self.Parameters().SetEnforcedVertexWithGroup(theFace, x, y, z, groupName) + pass + else: + if groupName == "": + return self.Parameters().SetEnforcedVertexNamed(theFace, x, y, z, vertexName) + else: + return self.Parameters().SetEnforcedVertexNamedWithGroup(theFace, x, y, z, vertexName, groupName) + pass + pass + + ## To set an enforced vertex on a face (or group, compound) given a GEOM vertex, group or compound. + # @param theFace : GEOM face (or group, compound) on which to define an enforced vertex + # @param theVertex : GEOM vertex (or group, compound) to be projected on theFace. + # @param groupName : name of the group + def SetEnforcedVertexGeom(self, theFace, theVertex, groupName = ""): + AssureGeomPublished( self.mesh, theFace ) + AssureGeomPublished( self.mesh, theVertex ) + if groupName == "": + return self.Parameters().SetEnforcedVertexGeom(theFace, theVertex) + else: + return self.Parameters().SetEnforcedVertexGeomWithGroup(theFace, theVertex,groupName) + pass + + ## To remove an enforced vertex on a given GEOM face (or group, compound) given the coordinates. + # @param theFace : GEOM face (or group, compound) on which to remove the enforced vertex + # @param x : x coordinate + # @param y : y coordinate + # @param z : z coordinate + def UnsetEnforcedVertex(self, theFace, x, y, z): + AssureGeomPublished( self.mesh, theFace ) + return self.Parameters().UnsetEnforcedVertex(theFace, x, y, z) + + ## To remove an enforced vertex on a given GEOM face (or group, compound) given a GEOM vertex, group or compound. + # @param theFace : GEOM face (or group, compound) on which to remove the enforced vertex + # @param theVertex : GEOM vertex (or group, compound) to remove. + def UnsetEnforcedVertexGeom(self, theFace, theVertex): + AssureGeomPublished( self.mesh, theFace ) + AssureGeomPublished( self.mesh, theVertex ) + return self.Parameters().UnsetEnforcedVertexGeom(theFace, theVertex) + + ## To remove all enforced vertices on a given face. + # @param theFace : face (or group/compound of faces) on which to remove all enforced vertices + def UnsetEnforcedVertices(self, theFace): + AssureGeomPublished( self.mesh, theFace ) + return self.Parameters().UnsetEnforcedVertices(theFace) + + ## To tell BLSURF to add a node on internal vertices + # @param toEnforceInternalVertices : boolean; if True the internal vertices are added as enforced vertices + def SetInternalEnforcedVertexAllFaces(self, toEnforceInternalVertices): + return self.Parameters().SetInternalEnforcedVertexAllFaces(toEnforceInternalVertices) + + ## To know if BLSURF will add a node on internal vertices + def GetInternalEnforcedVertexAllFaces(self): + return self.Parameters().GetInternalEnforcedVertexAllFaces() + + ## To define a group for the nodes of internal vertices + # @param groupName : string; name of the group + def SetInternalEnforcedVertexAllFacesGroup(self, groupName): + return self.Parameters().SetInternalEnforcedVertexAllFacesGroup(groupName) + + ## To get the group name of the nodes of internal vertices + def GetInternalEnforcedVertexAllFacesGroup(self): + return self.Parameters().GetInternalEnforcedVertexAllFacesGroup() + + #----------------------------------------- + # Attractors + #----------------------------------------- + + ## Sets an attractor on the chosen face. The mesh size will decrease exponentially with the distance from theAttractor, following the rule h(d) = theEndSize - (theEndSize - theStartSize) * exp [ - ( d / theInfluenceDistance ) ^ 2 ] + # @param theFace : face on which the attractor will be defined + # @param theAttractor : geometrical object from which the mesh size "h" decreases exponentially + # @param theStartSize : mesh size on theAttractor + # @param theEndSize : maximum size that will be reached on theFace + # @param theInfluenceDistance : influence of the attractor ( the size grow slower on theFace if it's high) + # @param theConstantSizeDistance : distance until which the mesh size will be kept constant on theFace + def SetAttractorGeom(self, theFace, theAttractor, theStartSize, theEndSize, theInfluenceDistance, theConstantSizeDistance): + AssureGeomPublished( self.mesh, theFace ) + AssureGeomPublished( self.mesh, theAttractor ) + self.Parameters().SetAttractorGeom(theFace, theAttractor, theStartSize, theEndSize, theInfluenceDistance, theConstantSizeDistance) + pass + + ## Unsets an attractor on the chosen face. + # @param theFace : face on which the attractor has to be removed + def UnsetAttractorGeom(self, theFace): + AssureGeomPublished( self.mesh, theFace ) + self.Parameters().SetAttractorGeom(theFace) + pass + + #----------------------------------------- + # Size maps (BLSURF) + #----------------------------------------- + + ## To set a size map on a face, edge or vertex (or group, compound) given Python function. + # If theObject is a face, the function can be: def f(u,v): return u+v + # If theObject is an edge, the function can be: def f(t): return t/2 + # If theObject is a vertex, the function can be: def f(): return 10 + # @param theObject : GEOM face, edge or vertex (or group, compound) on which to define a size map + # @param theSizeMap : Size map defined as a string + def SetSizeMap(self, theObject, theSizeMap): + AssureGeomPublished( self.mesh, theObject ) + self.Parameters().SetSizeMap(theObject, theSizeMap) + pass + + ## To set a constant size map on a face, edge or vertex (or group, compound). + # @param theObject : GEOM face, edge or vertex (or group, compound) on which to define a size map + # @param theSizeMap : Size map defined as a double + def SetConstantSizeMap(self, theObject, theSizeMap): + AssureGeomPublished( self.mesh, theObject ) + self.Parameters().SetConstantSizeMap(theObject, theSizeMap) + + ## To remove a size map defined on a face, edge or vertex (or group, compound) + # @param theObject : GEOM face, edge or vertex (or group, compound) on which to define a size map + def UnsetSizeMap(self, theObject): + AssureGeomPublished( self.mesh, theObject ) + self.Parameters().UnsetSizeMap(theObject) + pass + + ## To remove all the size maps + def ClearSizeMaps(self): + self.Parameters().ClearSizeMaps() + pass + + ## Sets QuadAllowed flag. + # @param toAllow "allow quadrangles" flag value + def SetQuadAllowed(self, toAllow=True): + self.Parameters().SetQuadAllowed(toAllow) + pass + + ## Defines hypothesis having several parameters + # @return hypothesis object + def Parameters(self): + if not self.params: + self.params = self.Hypothesis("BLSURF_Parameters", [], + "libBLSURFEngine.so", UseExisting=0) + pass + return self.params + + #===================== + # Obsolete methods + #===================== + # + # SALOME 6.6.0 + # + + ## Sets lower boundary of mesh element size (PhySize). + def SetPhyMin(self, theVal=-1): + """ + Obsolete function. Use SetMinSize. + """ + print "Warning: SetPhyMin is obsolete. Please use SetMinSize" + self.SetMinSize(theVal) + pass + + ## Sets upper boundary of mesh element size (PhySize). + def SetPhyMax(self, theVal=-1): + """ + Obsolete function. Use SetMaxSize. + """ + print "Warning: SetPhyMax is obsolete. Please use SetMaxSize" + self.SetMaxSize(theVal) + pass + + ## Sets angular deflection (in degrees) of a mesh face from CAD surface. + def SetAngleMeshS(self, theVal=_geometric_approximation): + """ + Obsolete function. Use SetAngleMesh. + """ + print "Warning: SetAngleMeshS is obsolete. Please use SetAngleMesh" + self.SetAngleMesh(theVal) + pass + + ## Sets angular deflection (in degrees) of a mesh edge from CAD curve. + def SetAngleMeshC(self, theVal=_geometric_approximation): + """ + Obsolete function. Use SetAngleMesh. + """ + print "Warning: SetAngleMeshC is obsolete. Please use SetAngleMesh" + self.SetAngleMesh(theVal) + pass + + ## Sets lower boundary of mesh element size computed to respect angular deflection. + def SetGeoMin(self, theVal=-1): + """ + Obsolete function. Use SetMinSize. + """ + print "Warning: SetGeoMin is obsolete. Please use SetMinSize" + self.SetMinSize(theVal) + pass + + ## Sets upper boundary of mesh element size computed to respect angular deflection. + def SetGeoMax(self, theVal=-1): + """ + Obsolete function. Use SetMaxSize. + """ + print "Warning: SetGeoMax is obsolete. Please use SetMaxSize" + self.SetMaxSize(theVal) + pass + + + pass # end of BLSURF_Algorithm class \ No newline at end of file diff --git a/src/BLSURFPlugin/BLSURFPlugin_BLSURF.cxx b/src/BLSURFPlugin/BLSURFPlugin_BLSURF.cxx index e834c58..01cc508 100644 --- a/src/BLSURFPlugin/BLSURFPlugin_BLSURF.cxx +++ b/src/BLSURFPlugin/BLSURFPlugin_BLSURF.cxx @@ -28,9 +28,9 @@ #include "BLSURFPlugin_Attractor.hxx" extern "C"{ -#include -#include -#include +#include +#include +#include } #include @@ -39,6 +39,7 @@ extern "C"{ #include #include +#include #include #include #include @@ -46,6 +47,7 @@ extern "C"{ #include #include #include +#include #include @@ -56,48 +58,42 @@ extern "C"{ #include // OPENCASCADE includes +#include +#include +//#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include #include #include +#include +#include +#include #include -#include - -#include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include #include - -#include -#include -#include #include -#include -#include -#include - -#include -#include -#include +#include +#include +#include +#include +#include +#include #ifndef WNT #include #endif -#include -#include -#include -#include -#include -// #include -#include - /* ================================== * =========== PYTHON ============== * ==================================*/ @@ -244,6 +240,7 @@ BLSURFPlugin_BLSURF::BLSURFPlugin_BLSURF(int hypId, int studyId, _name = "BLSURF"; _shapeType = (1 << TopAbs_FACE); // 1 bit /shape type _compatibleHypothesis.push_back(BLSURFPlugin_Hypothesis::GetHypType()); + _compatibleHypothesis.push_back(StdMeshers_ViscousLayers2D::GetHypType()); _requireDiscreteBoundary = false; _onlyUnaryInput = false; _hypothesis = NULL; @@ -319,38 +316,42 @@ bool BLSURFPlugin_BLSURF::CheckHypothesis const TopoDS_Shape& aShape, SMESH_Hypothesis::Hypothesis_Status& aStatus) { - _hypothesis = NULL; + _hypothesis = NULL; + _haveViscousLayers = false; list::const_iterator itl; const SMESHDS_Hypothesis* theHyp; - const list& hyps = GetUsedHypothesis(aMesh, aShape); - int nbHyp = hyps.size(); - if (!nbHyp) + const list& hyps = GetUsedHypothesis(aMesh, aShape, + /*ignoreAuxiliary=*/false); + aStatus = SMESH_Hypothesis::HYP_OK; + if ( hyps.empty() ) { - aStatus = SMESH_Hypothesis::HYP_OK; return true; // can work with no hypothesis } - itl = hyps.begin(); - theHyp = (*itl); // use only the first hypothesis - - string hypName = theHyp->GetName(); - - if (hypName == "BLSURF_Parameters") + for ( itl = hyps.begin(); itl != hyps.end(); ++itl ) { - _hypothesis = static_cast (theHyp); - ASSERT(_hypothesis); - if ( _hypothesis->GetPhysicalMesh() == BLSURFPlugin_Hypothesis::DefaultSize && - _hypothesis->GetGeometricMesh() == BLSURFPlugin_Hypothesis::DefaultGeom ) - // hphy_flag = 0 and hgeo_flag = 0 is not allowed (spec) - aStatus = SMESH_Hypothesis::HYP_BAD_PARAMETER; + theHyp = *itl; + string hypName = theHyp->GetName(); + if ( hypName == BLSURFPlugin_Hypothesis::GetHypType() ) + { + _hypothesis = static_cast (theHyp); + ASSERT(_hypothesis); + if ( _hypothesis->GetPhysicalMesh() == BLSURFPlugin_Hypothesis::DefaultSize && + _hypothesis->GetGeometricMesh() == BLSURFPlugin_Hypothesis::DefaultGeom ) + // hphy_flag = 0 and hgeo_flag = 0 is not allowed (spec) + aStatus = SMESH_Hypothesis::HYP_BAD_PARAMETER; + } + else if ( hypName == StdMeshers_ViscousLayers2D::GetHypType() ) + { + _haveViscousLayers = true; + } else - aStatus = SMESH_Hypothesis::HYP_OK; + { + aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE; + } } - else - aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE; - return aStatus == SMESH_Hypothesis::HYP_OK; } @@ -367,6 +368,14 @@ inline std::string to_string(double d) return o.str(); } +inline std::string to_string_rel(double d) +{ + std::ostringstream o; + o << d; + o << 'r'; + return o.str(); +} + inline std::string to_string(int i) { std::ostringstream o; @@ -374,6 +383,14 @@ inline std::string to_string(int i) return o.str(); } +inline std::string to_string_rel(int i) +{ + std::ostringstream o; + o << i; + o << 'r'; + return o.str(); +} + double _smp_phy_size; // #if BLSURF_VERSION_LONG >= "3.1.1" // // sizemap_t *geo_sizemap_e, *geo_sizemap_f; @@ -385,8 +402,6 @@ status_t size_on_surface(integer face_id, real *uv, real *size, void *user_data) status_t size_on_edge(integer edge_id, real t, real *size, void *user_data); status_t size_on_vertex(integer vertex_id, real *size, void *user_data); -double my_u_min=1e6,my_v_min=1e6,my_u_max=-1e6,my_v_max=-1e6; - typedef struct { gp_XY uv; gp_XYZ xyz; @@ -557,7 +572,7 @@ void BLSURFPlugin_BLSURF::createEnforcedVertexOnFace(TopoDS_Shape faceShape, BLS } ///////////////////////////////////////////////////////// -void createAttractorOnFace(TopoDS_Shape GeomShape, std::string AttractorFunction) +void createAttractorOnFace(TopoDS_Shape GeomShape, std::string AttractorFunction, double defaultSize) { MESSAGE("Attractor function: "<< AttractorFunction); double xa, ya, za; // Coordinates of attractor point @@ -635,7 +650,7 @@ void createAttractorOnFace(TopoDS_Shape GeomShape, std::string AttractorFunction // We construct the python function ostringstream attractorFunctionStream; attractorFunctionStream << "def f(u,v): return "; - attractorFunctionStream << _smp_phy_size << "-(" << _smp_phy_size <<"-" << a << ")"; + attractorFunctionStream << defaultSize << "-(" << defaultSize <<"-" << a << ")"; //attractorFunctionStream << "*exp(-((u-("<GetBoundaryBoxSegmentation(); + int _physicalMesh = BLSURFPlugin_Hypothesis::GetDefaultPhysicalMesh(); + int _geometricMesh = BLSURFPlugin_Hypothesis::GetDefaultGeometricMesh(); + double _phySize = BLSURFPlugin_Hypothesis::GetDefaultPhySize(diagonal, bbSegmentation); + bool _phySizeRel = BLSURFPlugin_Hypothesis::GetDefaultPhySizeRel(); + double _minSize = BLSURFPlugin_Hypothesis::GetDefaultMinSize(diagonal); + bool _minSizeRel = BLSURFPlugin_Hypothesis::GetDefaultMinSizeRel(); + double _maxSize = BLSURFPlugin_Hypothesis::GetDefaultMaxSize(diagonal); + bool _maxSizeRel = BLSURFPlugin_Hypothesis::GetDefaultMaxSizeRel(); + double _gradation = BLSURFPlugin_Hypothesis::GetDefaultGradation(); + bool _quadAllowed = BLSURFPlugin_Hypothesis::GetDefaultQuadAllowed(); + double _angleMesh = BLSURFPlugin_Hypothesis::GetDefaultAngleMesh(); + double _chordalError = BLSURFPlugin_Hypothesis::GetDefaultChordalError(diagonal); + bool _anisotropic = BLSURFPlugin_Hypothesis::GetDefaultAnisotropic(); + double _anisotropicRatio = BLSURFPlugin_Hypothesis::GetDefaultAnisotropicRatio(); + bool _removeTinyEdges = BLSURFPlugin_Hypothesis::GetDefaultRemoveTinyEdges(); + double _tinyEdgeLength = BLSURFPlugin_Hypothesis::GetDefaultTinyEdgeLength(diagonal); + 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(); // PreCAD - int _precadMergeEdges = BLSURFPlugin_Hypothesis::GetDefaultPreCADMergeEdges(); - int _precadRemoveNanoEdges = BLSURFPlugin_Hypothesis::GetDefaultPreCADRemoveNanoEdges(); - int _precadDiscardInput = BLSURFPlugin_Hypothesis::GetDefaultPreCADDiscardInput(); - double _precadEpsNano = BLSURFPlugin_Hypothesis::GetDefaultPreCADEpsNano(); + int _precadMergeEdges = BLSURFPlugin_Hypothesis::GetDefaultPreCADMergeEdges(); + int _precadProcess3DTopology = BLSURFPlugin_Hypothesis::GetDefaultPreCADProcess3DTopology(); + int _precadDiscardInput = BLSURFPlugin_Hypothesis::GetDefaultPreCADDiscardInput(); if (hyp) { MESSAGE("BLSURFPlugin_BLSURF::SetParameters"); - _topology = (int) hyp->GetTopology(); _physicalMesh = (int) hyp->GetPhysicalMesh(); - _phySize = hyp->GetPhySize(); _geometricMesh = (int) hyp->GetGeometricMesh(); - _angleMeshS = hyp->GetAngleMeshS(); - _angleMeshC = hyp->GetAngleMeshC(); - _gradation = hyp->GetGradation(); + if (hyp->GetPhySize() > 0) + _phySize = hyp->GetPhySize(); + _phySizeRel = hyp->IsPhySizeRel(); + if (hyp->GetMinSize() > 0) + _minSize = hyp->GetMinSize(); + _minSizeRel = hyp->IsMinSizeRel(); + if (hyp->GetMaxSize() > 0) + _maxSize = hyp->GetMaxSize(); + _maxSizeRel = hyp->IsMaxSizeRel(); + if (hyp->GetGradation() > 0) + _gradation = hyp->GetGradation(); _quadAllowed = hyp->GetQuadAllowed(); - _decimesh = hyp->GetDecimesh(); + if (hyp->GetAngleMesh() > 0) + _angleMesh = hyp->GetAngleMesh(); + if (hyp->GetChordalError() > 0) + _chordalError = hyp->GetChordalError(); + _anisotropic = hyp->GetAnisotropic(); + if (hyp->GetAnisotropicRatio() >= 0) + _anisotropicRatio = hyp->GetAnisotropicRatio(); + _removeTinyEdges = hyp->GetRemoveTinyEdges(); + if (hyp->GetTinyEdgeLength() > 0) + _tinyEdgeLength = hyp->GetTinyEdgeLength(); + _badElementRemoval = hyp->GetBadElementRemoval(); + if (hyp->GetBadElementAspectRatio() >= 0) + _badElementAspectRatio = hyp->GetBadElementAspectRatio(); + _optimizeMesh = hyp->GetOptimizeMesh(); + _quadraticMesh = hyp->GetQuadraticMesh(); _verb = hyp->GetVerbosity(); - if ( hyp->GetPhyMin() != ::BLSURFPlugin_Hypothesis::undefinedDouble() ) - blsurf_set_param(bls, "hphymin", to_string(hyp->GetPhyMin()).c_str()); - if ( hyp->GetPhyMax() != ::BLSURFPlugin_Hypothesis::undefinedDouble() ) - blsurf_set_param(bls, "hphymax", to_string(hyp->GetPhyMax()).c_str()); - if ( hyp->GetGeoMin() != ::BLSURFPlugin_Hypothesis::undefinedDouble() ) - blsurf_set_param(bls, "hgeomin", to_string(hyp->GetGeoMin()).c_str()); - if ( hyp->GetGeoMax() != ::BLSURFPlugin_Hypothesis::undefinedDouble() ) - blsurf_set_param(bls, "hgeomax", to_string(hyp->GetGeoMax()).c_str()); + _topology = (int) hyp->GetTopology(); + // PreCAD + _precadMergeEdges = hyp->GetPreCADMergeEdges(); + _precadProcess3DTopology = hyp->GetPreCADProcess3DTopology(); + _precadDiscardInput = hyp->GetPreCADDiscardInput(); const BLSURFPlugin_Hypothesis::TOptionValues & opts = hyp->GetOptionValues(); BLSURFPlugin_Hypothesis::TOptionValues::const_iterator opIt; for ( opIt = opts.begin(); opIt != opts.end(); ++opIt ) if ( !opIt->second.empty() ) { - MESSAGE("blsurf_set_param(): " << opIt->first << " = " << opIt->second); - blsurf_set_param(bls, opIt->first.c_str(), opIt->second.c_str()); + MESSAGE("cadsurf_set_param(): " << opIt->first << " = " << opIt->second); + cadsurf_set_param(css, opIt->first.c_str(), opIt->second.c_str()); } const BLSURFPlugin_Hypothesis::TOptionValues & preCADopts = hyp->GetPreCADOptionValues(); @@ -745,52 +790,89 @@ void BLSURFPlugin_BLSURF::SetParameters( if ( !opIt->second.empty() ) { if (_topology == BLSURFPlugin_Hypothesis::PreCAD) { MESSAGE("precad_set_param(): " << opIt->first << " = " << opIt->second); - blsurf_set_param(bls, opIt->first.c_str(), opIt->second.c_str()); + precad_set_param(pcs, opIt->first.c_str(), opIt->second.c_str()); } } - - // PreCAD - _precadMergeEdges = hyp->GetPreCADMergeEdges(); - _precadRemoveNanoEdges = hyp->GetPreCADRemoveNanoEdges(); - _precadDiscardInput = hyp->GetPreCADDiscardInput(); - _precadEpsNano = hyp->GetPreCADEpsNano(); - - } else { - //0020968: EDF1545 SMESH: Problem in the creation of a mesh group on geometry - // GetDefaultPhySize() sometimes leads to computation failure - _phySize = mesh.GetShapeDiagonalSize() / _gen->GetBoundaryBoxSegmentation(); - MESSAGE("BLSURFPlugin_BLSURF::SetParameters using defaults"); } +// 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"); +// } // PreCAD if (_topology == BLSURFPlugin_Hypothesis::PreCAD) { *use_precad = true; precad_set_param(pcs, "verbose", to_string(_verb).c_str()); precad_set_param(pcs, "merge_edges", _precadMergeEdges ? "1" : "0"); - precad_set_param(pcs, "remove_nano_edges", _precadRemoveNanoEdges ? "1" : "0"); + precad_set_param(pcs, "process_3d_topology", _precadProcess3DTopology ? "1" : "0"); precad_set_param(pcs, "discard_input_topology", _precadDiscardInput ? "1" : "0"); - if ( _precadEpsNano != ::BLSURFPlugin_Hypothesis::undefinedDouble() ) - precad_set_param(pcs, "eps_nano", to_string(_precadEpsNano).c_str()); - } - - _smp_phy_size = _phySize; - blsurf_set_param(bls, "topo_points", _topology == BLSURFPlugin_Hypothesis::Process || _topology == BLSURFPlugin_Hypothesis::Process2 ? "1" : "0"); - blsurf_set_param(bls, "topo_curves", _topology == BLSURFPlugin_Hypothesis::Process || _topology == BLSURFPlugin_Hypothesis::Process2 ? "1" : "0"); - blsurf_set_param(bls, "topo_project", _topology == BLSURFPlugin_Hypothesis::Process || _topology == BLSURFPlugin_Hypothesis::Process2 ? "1" : "0"); - blsurf_set_param(bls, "clean_boundary", _topology == BLSURFPlugin_Hypothesis::Process2 ? "1" : "0"); - blsurf_set_param(bls, "close_boundary", _topology == BLSURFPlugin_Hypothesis::Process2 ? "1" : "0"); - blsurf_set_param(bls, "hphy_flag", to_string(_physicalMesh).c_str()); - blsurf_set_param(bls, "hphydef", to_string(_phySize).c_str()); - blsurf_set_param(bls, "hgeo_flag", to_string(_geometricMesh).c_str()); - blsurf_set_param(bls, "relax_size", _decimesh ? "0": to_string(_geometricMesh).c_str()); - blsurf_set_param(bls, "angle_meshs", to_string(_angleMeshS).c_str()); - blsurf_set_param(bls, "angle_meshc", to_string(_angleMeshC).c_str()); - blsurf_set_param(bls, "gradation", to_string(_gradation).c_str()); - blsurf_set_param(bls, "patch_independent", _decimesh ? "1" : "0"); - blsurf_set_param(bls, "element", _quadAllowed ? "q1.0" : "p1"); - blsurf_set_param(bls, "verb", to_string(_verb).c_str()); + } - if (_physicalMesh == BLSURFPlugin_Hypothesis::SizeMap){ + bool useGradation = false; + switch (_physicalMesh) + { + case BLSURFPlugin_Hypothesis::PhysicalGlobalSize: + cadsurf_set_param(css, "physical_size_mode", "global"); + cadsurf_set_param(css, "global_physical_size", _phySizeRel ? to_string_rel(_phySize).c_str() : to_string(_phySize).c_str()); + break; + case BLSURFPlugin_Hypothesis::PhysicalLocalSize: + cadsurf_set_param(css, "physical_size_mode", "local"); + cadsurf_set_param(css, "global_physical_size", _phySizeRel ? to_string_rel(_phySize).c_str() : to_string(_phySize).c_str()); + useGradation = true; + break; + default: + cadsurf_set_param(css, "physical_size_mode", "none"); + } + + switch (_geometricMesh) + { + case BLSURFPlugin_Hypothesis::GeometricalGlobalSize: + cadsurf_set_param(css, "geometric_size_mode", "global"); + cadsurf_set_param(css, "geometric_approximation", to_string(_angleMesh).c_str()); + cadsurf_set_param(css, "chordal_error", to_string(_chordalError).c_str()); + useGradation = true; + break; + case BLSURFPlugin_Hypothesis::GeometricalLocalSize: + cadsurf_set_param(css, "geometric_size_mode", "local"); + cadsurf_set_param(css, "geometric_approximation", to_string(_angleMesh).c_str()); + cadsurf_set_param(css, "chordal_error", to_string(_chordalError).c_str()); + useGradation = true; + break; + default: + cadsurf_set_param(css, "geometric_size_mode", "none"); + } + + cadsurf_set_param(css, "minsize", _minSizeRel ? to_string_rel(_minSize).c_str() : to_string(_minSize).c_str()); + cadsurf_set_param(css, "maxsize", _maxSizeRel ? to_string_rel(_maxSize).c_str() : to_string(_maxSize).c_str()); + if ( useGradation ) + cadsurf_set_param(css, "gradation", to_string(_gradation).c_str()); + cadsurf_set_param(css, "element_generation", _quadAllowed ? "quad_dominant" : "triangle"); + + + cadsurf_set_param(css, "metric", _anisotropic ? "anisotropic" : "isotropic"); + if ( _anisotropic ) + cadsurf_set_param(css, "anisotropic_ratio", to_string(_anisotropicRatio).c_str()); + cadsurf_set_param(css, "remove_tiny_edges", _removeTinyEdges ? "1" : "0"); + if ( _removeTinyEdges ) + cadsurf_set_param(css, "tiny_edge_length", to_string(_tinyEdgeLength).c_str()); + cadsurf_set_param(css, "force_bad_surface_element_removal", _badElementRemoval ? "1" : "0"); + if ( _badElementRemoval ) + cadsurf_set_param(css, "bad_surface_element_aspect_ratio", to_string(_badElementAspectRatio).c_str()); + cadsurf_set_param(css, "optimisation", _optimizeMesh ? "yes" : "no"); + cadsurf_set_param(css, "element_order", _quadraticMesh ? "quadratic" : "linear"); + cadsurf_set_param(css, "verbose", to_string(_verb).c_str()); + + _smp_phy_size = _phySizeRel ? _phySize*diagonal : _phySize; + std::cout << "_smp_phy_size = " << _smp_phy_size << std::endl; + + if (_physicalMesh == BLSURFPlugin_Hypothesis::PhysicalLocalSize){ TopoDS_Shape GeomShape; TopoDS_Shape AttShape; TopAbs_ShapeEnum GeomType; @@ -802,7 +884,7 @@ void BLSURFPlugin_BLSURF::SetParameters( BLSURFPlugin_Hypothesis::TSizeMap::const_iterator smIt = sizeMaps.begin(); for ( ; smIt != sizeMaps.end(); ++smIt ) { if ( !smIt->second.empty() ) { - MESSAGE("blsurf_set_sizeMap(): " << smIt->first << " = " << smIt->second); + MESSAGE("cadsurf_set_sizeMap(): " << smIt->first << " = " << smIt->second); GeomShape = entryToShape(smIt->first); GeomType = GeomShape.ShapeType(); MESSAGE("Geomtype is " << GeomType); @@ -900,42 +982,46 @@ void BLSURFPlugin_BLSURF::SetParameters( // // TODO appeler le constructeur des attracteurs directement ici MESSAGE("Setting Attractors"); - const BLSURFPlugin_Hypothesis::TSizeMap attractors = BLSURFPlugin_Hypothesis::GetAttractorEntries(hyp); - BLSURFPlugin_Hypothesis::TSizeMap::const_iterator atIt = attractors.begin(); - for ( ; atIt != attractors.end(); ++atIt ) { - if ( !atIt->second.empty() ) { - MESSAGE("blsurf_set_attractor(): " << atIt->first << " = " << atIt->second); - GeomShape = entryToShape(atIt->first); - GeomType = GeomShape.ShapeType(); - // Group Management - if (GeomType == TopAbs_COMPOUND){ - for (TopoDS_Iterator it (GeomShape); it.More(); it.Next()){ - if (it.Value().ShapeType() == TopAbs_FACE){ - HasSizeMapOnFace = true; - createAttractorOnFace(it.Value(), atIt->second); +// if ( !_phySizeRel ) { + const BLSURFPlugin_Hypothesis::TSizeMap attractors = BLSURFPlugin_Hypothesis::GetAttractorEntries(hyp); + BLSURFPlugin_Hypothesis::TSizeMap::const_iterator atIt = attractors.begin(); + for ( ; atIt != attractors.end(); ++atIt ) { + if ( !atIt->second.empty() ) { + MESSAGE("cadsurf_set_attractor(): " << atIt->first << " = " << atIt->second); + GeomShape = entryToShape(atIt->first); + GeomType = GeomShape.ShapeType(); + // Group Management + if (GeomType == TopAbs_COMPOUND){ + for (TopoDS_Iterator it (GeomShape); it.More(); it.Next()){ + if (it.Value().ShapeType() == TopAbs_FACE){ + HasSizeMapOnFace = true; + createAttractorOnFace(it.Value(), atIt->second, _phySizeRel ? _phySize*diagonal : _phySize); + } } } - } - if (GeomType == TopAbs_FACE){ - HasSizeMapOnFace = true; - createAttractorOnFace(GeomShape, atIt->second); - } -/* - if (GeomType == TopAbs_EDGE){ - HasSizeMapOnEdge = true; - HasSizeMapOnFace = true; - EdgeId2SizeMap[TopoDS::Edge(GeomShape).HashCode(IntegerLast())] = atIt->second; - } - if (GeomType == TopAbs_VERTEX){ - HasSizeMapOnVertex = true; - HasSizeMapOnEdge = true; - HasSizeMapOnFace = true; - VertexId2SizeMap[TopoDS::Vertex(GeomShape).HashCode(IntegerLast())] = atIt->second; + if (GeomType == TopAbs_FACE){ + HasSizeMapOnFace = true; + createAttractorOnFace(GeomShape, atIt->second, _phySizeRel ? _phySize*diagonal : _phySize); + } + /* + if (GeomType == TopAbs_EDGE){ + HasSizeMapOnEdge = true; + HasSizeMapOnFace = true; + EdgeId2SizeMap[TopoDS::Edge(GeomShape).HashCode(IntegerLast())] = atIt->second; + } + if (GeomType == TopAbs_VERTEX){ + HasSizeMapOnVertex = true; + HasSizeMapOnEdge = true; + HasSizeMapOnFace = true; + VertexId2SizeMap[TopoDS::Vertex(GeomShape).HashCode(IntegerLast())] = atIt->second; + } + */ } -*/ } - } +// } +// else +// MESSAGE("Impossible to create the attractors when the physical size is relative"); // Class Attractors // temporary commented out for testing @@ -953,7 +1039,7 @@ void BLSURFPlugin_BLSURF::SetParameters( BLSURFPlugin_Hypothesis::TAttractorMap::const_iterator AtIt = class_attractors.begin(); for ( ; AtIt != class_attractors.end(); ++AtIt ) { if ( !AtIt->second->Empty() ) { - // MESSAGE("blsurf_set_attractor(): " << AtIt->first << " = " << AtIt->second); + // MESSAGE("cadsurf_set_attractor(): " << AtIt->first << " = " << AtIt->second); GeomShape = entryToShape(AtIt->first); AttShape = AtIt->second->GetAttractorShape(); GeomType = GeomShape.ShapeType(); @@ -1054,7 +1140,7 @@ void BLSURFPlugin_BLSURF::SetParameters( MESSAGE("Setting Size Map on FACES "); // #if BLSURF_VERSION_LONG < "3.1.1" - blsurf_data_set_sizemap_iso_cad_face(bls, size_on_surface, &_smp_phy_size); + cadsurf_data_set_sizemap_iso_cad_face(css, size_on_surface, &_smp_phy_size); // #else // if (*use_precad) // iso_sizemap_f = sizemap_new(c, distene_sizemap_type_iso_cad_face, (void *)size_on_surface, NULL); @@ -1065,7 +1151,7 @@ void BLSURFPlugin_BLSURF::SetParameters( if (HasSizeMapOnEdge){ MESSAGE("Setting Size Map on EDGES "); // #if BLSURF_VERSION_LONG < "3.1.1" - blsurf_data_set_sizemap_iso_cad_edge(bls, size_on_edge, &_smp_phy_size); + cadsurf_data_set_sizemap_iso_cad_edge(css, size_on_edge, &_smp_phy_size); // #else // if (*use_precad) // iso_sizemap_e = sizemap_new(c, distene_sizemap_type_iso_cad_edge, (void *)size_on_edge, NULL); @@ -1076,7 +1162,7 @@ void BLSURFPlugin_BLSURF::SetParameters( if (HasSizeMapOnVertex){ MESSAGE("Setting Size Map on VERTICES "); // #if BLSURF_VERSION_LONG < "3.1.1" - blsurf_data_set_sizemap_iso_cad_point(bls, size_on_vertex, &_smp_phy_size); + cadsurf_data_set_sizemap_iso_cad_point(css, size_on_vertex, &_smp_phy_size); // #else // if (*use_precad) // iso_sizemap_p = sizemap_new(c, distene_sizemap_type_iso_cad_point, (void *)size_on_vertex, NULL); @@ -1089,59 +1175,323 @@ void BLSURFPlugin_BLSURF::SetParameters( namespace { + // -------------------------------------------------------------------------- /*! * \brief Class correctly terminating usage of BLSURF library at destruction */ class BLSURF_Cleaner { context_t * _ctx; - blsurf_session_t* _bls; + cadsurf_session_t* _css; cad_t * _cad; dcad_t * _dcad; public: BLSURF_Cleaner(context_t * ctx, - blsurf_session_t* bls, + cadsurf_session_t* css, cad_t * cad, dcad_t * dcad) : _ctx ( ctx ), - _bls ( bls ), + _css ( css ), _cad ( cad ), _dcad( dcad ) { } ~BLSURF_Cleaner() { - blsurf_session_delete(_bls); + Clean( /*exceptContext=*/false ); + } + void Clean(const bool exceptContext) + { + if ( _css ) + { + cadsurf_session_delete(_css); _css = 0; + + // #if BLSURF_VERSION_LONG >= "3.1.1" + // // if(geo_sizemap_e) + // // distene_sizemap_delete(geo_sizemap_e); + // // if(geo_sizemap_f) + // // distene_sizemap_delete(geo_sizemap_f); + // if(iso_sizemap_p) + // distene_sizemap_delete(iso_sizemap_p); + // if(iso_sizemap_e) + // distene_sizemap_delete(iso_sizemap_e); + // if(iso_sizemap_f) + // distene_sizemap_delete(iso_sizemap_f); + // + // // if(clean_geo_sizemap_e) + // // distene_sizemap_delete(clean_geo_sizemap_e); + // // if(clean_geo_sizemap_f) + // // distene_sizemap_delete(clean_geo_sizemap_f); + // if(clean_iso_sizemap_p) + // distene_sizemap_delete(clean_iso_sizemap_p); + // if(clean_iso_sizemap_e) + // distene_sizemap_delete(clean_iso_sizemap_e); + // if(clean_iso_sizemap_f) + // distene_sizemap_delete(clean_iso_sizemap_f); + // #endif + + cad_delete(_cad); _cad = 0; + dcad_delete(_dcad); _dcad = 0; + if ( !exceptContext ) + { + context_delete(_ctx); _ctx = 0; + } + } + } + }; - // #if BLSURF_VERSION_LONG >= "3.1.1" - // // if(geo_sizemap_e) - // // distene_sizemap_delete(geo_sizemap_e); - // // if(geo_sizemap_f) - // // distene_sizemap_delete(geo_sizemap_f); - // if(iso_sizemap_p) - // distene_sizemap_delete(iso_sizemap_p); - // if(iso_sizemap_e) - // distene_sizemap_delete(iso_sizemap_e); - // if(iso_sizemap_f) - // distene_sizemap_delete(iso_sizemap_f); - // - // // if(clean_geo_sizemap_e) - // // distene_sizemap_delete(clean_geo_sizemap_e); - // // if(clean_geo_sizemap_f) - // // distene_sizemap_delete(clean_geo_sizemap_f); - // if(clean_iso_sizemap_p) - // distene_sizemap_delete(clean_iso_sizemap_p); - // if(clean_iso_sizemap_e) - // distene_sizemap_delete(clean_iso_sizemap_e); - // if(clean_iso_sizemap_f) - // distene_sizemap_delete(clean_iso_sizemap_f); - // #endif - - cad_delete(_cad); - dcad_delete(_dcad); - context_delete(_ctx); + // -------------------------------------------------------------------------- + // comparator to sort nodes and sub-meshes + struct ShapeTypeCompare + { + // sort nodes by position in the following order: + // SMDS_TOP_FACE=2, SMDS_TOP_EDGE=1, SMDS_TOP_VERTEX=0, SMDS_TOP_3DSPACE=3 + int operator()( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2 ) const + { + SMDS_TypeOfPosition pos1 = n1->GetPosition()->GetTypeOfPosition(); + SMDS_TypeOfPosition pos2 = n2->GetPosition()->GetTypeOfPosition(); + if ( pos1 == pos2 ) return 0; + if ( pos1 < pos2 || pos1 == SMDS_TOP_3DSPACE ) return 1; + return -1; + } + // sort sub-meshes in order: EDGE, VERTEX + bool operator()( const SMESHDS_SubMesh* s1, const SMESHDS_SubMesh* s2 ) const + { + int isVertex1 = ( s1 && s1->NbElements() == 0 ); + int isVertex2 = ( s2 && s2->NbElements() == 0 ); + if ( isVertex1 == isVertex2 ) + return s1 < s2; + return isVertex1 < isVertex2; + } + }; + + //================================================================================ + /*! + * \brief Fills groups on nodes to be merged + */ + //================================================================================ + + void getNodeGroupsToMerge( const SMESHDS_SubMesh* smDS, + const TopoDS_Shape& shape, + SMESH_MeshEditor::TListOfListOfNodes& nodeGroupsToMerge) + { + SMDS_NodeIteratorPtr nIt = smDS->GetNodes(); + switch ( shape.ShapeType() ) + { + case TopAbs_VERTEX: { + std::list< const SMDS_MeshNode* > nodes; + while ( nIt->more() ) + nodes.push_back( nIt->next() ); + if ( nodes.size() > 1 ) + nodeGroupsToMerge.push_back( nodes ); + break; + } + case TopAbs_EDGE: { + std::multimap< double, const SMDS_MeshNode* > u2node; + const SMDS_EdgePosition* ePos; + while ( nIt->more() ) + { + const SMDS_MeshNode* n = nIt->next(); + if (( ePos = dynamic_cast< const SMDS_EdgePosition* >( n->GetPosition() ))) + u2node.insert( make_pair( ePos->GetUParameter(), n )); + } + if ( u2node.size() < 2 ) return; + + double tol = (( u2node.rbegin()->first - u2node.begin()->first ) / 20.) / u2node.size(); + std::multimap< double, const SMDS_MeshNode* >::iterator un2, un1; + for ( un2 = u2node.begin(), un1 = un2++; un2 != u2node.end(); un1 = un2++ ) + { + if (( un2->first - un1->first ) <= tol ) + { + std::list< const SMDS_MeshNode* > nodes; + nodes.push_back( un1->second ); + while (( un2->first - un1->first ) <= tol ) + { + nodes.push_back( un2->second ); + if ( ++un2 == u2node.end()) { + --un2; + break; + } + } + // make nodes created on the boundary of viscous layer replace nodes created + // by BLSURF as their SMDS_Position is more correct + nodes.sort( ShapeTypeCompare() ); + nodeGroupsToMerge.push_back( nodes ); + } + } + break; + } + default: ; + } + // SMESH_MeshEditor::TListOfListOfNodes::const_iterator nll = nodeGroupsToMerge.begin(); + // for ( ; nll != nodeGroupsToMerge.end(); ++nll ) + // { + // cout << "Merge "; + // const std::list< const SMDS_MeshNode* >& nl = *nll; + // std::list< const SMDS_MeshNode* >::const_iterator nIt = nl.begin(); + // for ( ; nIt != nl.end(); ++nIt ) + // cout << (*nIt) << " "; + // cout << endl; + // } + // cout << endl; + } + + //================================================================================ + /*! + * \brief A temporary mesh used to compute mesh on a proxy FACE + */ + //================================================================================ + + struct TmpMesh: public SMESH_Mesh + { + typedef std::map TN2NMap; + TN2NMap _tmp2origNN; + TopoDS_Face _proxyFace; + + TmpMesh() + { + _myMeshDS = new SMESHDS_Mesh( _id, true ); + } + //-------------------------------------------------------------------------------- + /*! + * \brief Creates a FACE bound by viscous layers and mesh each its EDGE with 1 segment + */ + //-------------------------------------------------------------------------------- + + const TopoDS_Face& makeProxyFace( SMESH_ProxyMesh::Ptr& viscousMesh, + const TopoDS_Face& origFace) + { + // get data of nodes on inner boundary of viscous layers + SMESH_Mesh* origMesh = viscousMesh->GetMesh(); + TError err; + TSideVector wireVec = StdMeshers_FaceSide::GetFaceWires(origFace, *origMesh, + /*skipMediumNodes = */true, + err, viscousMesh ); + if ( err && err->IsKO() ) + throw *err.get(); // it should be caught at SMESH_subMesh + + // proxy nodes and corresponding tmp VERTEXes + std::vector origNodes; + std::vector tmpVertex; + + // create a proxy FACE + TopoDS_Shape origFaceCopy = origFace.EmptyCopied(); + BRepBuilderAPI_MakeFace newFace( TopoDS::Face( origFaceCopy )); + for ( size_t iW = 0; iW != wireVec.size(); ++iW ) + { + StdMeshers_FaceSidePtr& wireData = wireVec[iW]; + const UVPtStructVec& wirePoints = wireData->GetUVPtStruct(); + if ( wirePoints.size() < 3 ) + continue; + + BRepBuilderAPI_MakePolygon wire; + for ( size_t iN = 1; iN < wirePoints.size(); ++iN ) + { + wire.Add( SMESH_TNodeXYZ( wirePoints[ iN ].node )); + origNodes.push_back( wirePoints[ iN ].node ); + tmpVertex.push_back( wire.LastVertex() ); + } + tmpVertex[0] = wire.FirstVertex(); + wire.Close(); + if ( !wire.IsDone() ) + throw SALOME_Exception("BLSURFPlugin_BLSURF: BRepBuilderAPI_MakePolygon failed"); + newFace.Add( wire ); + } + _proxyFace = newFace; + + // set a new shape to mesh + TopoDS_Compound auxCompoundToMesh; + BRep_Builder shapeBuilder; + shapeBuilder.MakeCompound( auxCompoundToMesh ); + shapeBuilder.Add( auxCompoundToMesh, _proxyFace ); + shapeBuilder.Add( auxCompoundToMesh, origMesh->GetShapeToMesh() ); + + ShapeToMesh( auxCompoundToMesh ); + + //TopExp_Explorer fExp( auxCompoundToMesh, TopAbs_FACE ); + //_proxyFace = TopoDS::Face( fExp.Current() ); + + + // Make input mesh for BLSURF: segments on EDGE's of newFace + + // make nodes and fill in _tmp2origNN + // + SMESHDS_Mesh* tmpMeshDS = GetMeshDS(); + for ( size_t i = 0; i < origNodes.size(); ++i ) + { + GetSubMesh( tmpVertex[i] )->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + if ( const SMDS_MeshNode* tmpN = SMESH_Algo::VertexNode( tmpVertex[i], tmpMeshDS )) + _tmp2origNN.insert( _tmp2origNN.end(), make_pair( tmpN, origNodes[i] )); + else + throw SALOME_Exception("BLSURFPlugin_BLSURF: a proxy vertex not meshed"); + } + + // make segments + TopoDS_Vertex v1, v2; + for ( TopExp_Explorer edge( _proxyFace, TopAbs_EDGE ); edge.More(); edge.Next() ) + { + const TopoDS_Edge& E = TopoDS::Edge( edge.Current() ); + TopExp::Vertices( E, v1, v2 ); + const SMDS_MeshNode* n1 = SMESH_Algo::VertexNode( v1, tmpMeshDS ); + const SMDS_MeshNode* n2 = SMESH_Algo::VertexNode( v2, tmpMeshDS ); + + if ( SMDS_MeshElement* seg = tmpMeshDS->AddEdge( n1, n2 )) + tmpMeshDS->SetMeshElementOnShape( seg, E ); + } + + return _proxyFace; + } + + //-------------------------------------------------------------------------------- + /*! + * \brief Fill in the origMesh with faces computed by BLSURF in this tmp mesh + */ + //-------------------------------------------------------------------------------- + + void FillInOrigMesh( SMESH_Mesh& origMesh, + const TopoDS_Face& origFace ) + { + SMESH_MesherHelper helper( origMesh ); + helper.SetSubShape( origFace ); + helper.SetElementsOnShape( true ); + + // iterate over tmp faces and copy them in origMesh + const SMDS_MeshNode* nodes[27]; + const SMDS_MeshNode* nullNode = 0; + double xyz[3]; + SMDS_FaceIteratorPtr fIt = GetMeshDS()->facesIterator(/*idInceasingOrder=*/true); + while ( fIt->more() ) + { + const SMDS_MeshElement* f = fIt->next(); + SMDS_ElemIteratorPtr nIt = f->nodesIterator(); + int nbN = 0; + for ( ; nIt->more(); ++nbN ) + { + const SMDS_MeshNode* n = static_cast( nIt->next() ); + TN2NMap::iterator n2nIt = + _tmp2origNN.insert( _tmp2origNN.end(), make_pair( n, nullNode )); + if ( !n2nIt->second ) { + n->GetXYZ( xyz ); + gp_XY uv = helper.GetNodeUV( _proxyFace, n ); + n2nIt->second = helper.AddNode( xyz[0], xyz[1], xyz[2], uv.X(), uv.Y() ); + } + nodes[ nbN ] = n2nIt->second; + } + switch( nbN ) { + case 3: helper.AddFace( nodes[0], nodes[1], nodes[2] ); break; + // case 6: helper.AddFace( nodes[0], nodes[1], nodes[2], + // nodes[3], nodes[4], nodes[5]); break; + case 4: helper.AddFace( nodes[0], nodes[1], nodes[2], nodes[3] ); break; + // case 9: helper.AddFace( nodes[0], nodes[1], nodes[2], nodes[3], + // nodes[4], nodes[5], nodes[6], nodes[7], nodes[8]); break; + // case 8: helper.AddFace( nodes[0], nodes[1], nodes[2], nodes[3], + // nodes[4], nodes[5], nodes[6], nodes[7]); break; + } + } } }; + + } // namespace status_t curv_fun(real t, real *uv, real *dt, real *dtt, void *user_data); @@ -1163,9 +1513,83 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) // Fix problem with locales Kernel_Utils::Localizer aLocalizer; + if ( !compute( aMesh, aShape )) + return false; + + if ( _haveViscousLayers ) + { + // Compute viscous layers + + TopTools_MapOfShape map; + for (TopExp_Explorer face_iter(aShape,TopAbs_FACE);face_iter.More();face_iter.Next()) + { + const TopoDS_Face& F = TopoDS::Face(face_iter.Current()); + if ( !map.Add( F )) continue; + SMESH_ProxyMesh::Ptr viscousMesh = StdMeshers_ViscousLayers2D::Compute( aMesh, F ); + if ( !viscousMesh ) + return false; // error in StdMeshers_ViscousLayers2D::Compute() + + // Compute BLSURF mesh on viscous layers + + if ( viscousMesh->NbProxySubMeshes() > 0 ) + { + TmpMesh tmpMesh; + const TopoDS_Face& proxyFace = tmpMesh.makeProxyFace( viscousMesh, F ); + if ( !compute( tmpMesh, proxyFace )) + return false; + tmpMesh.FillInOrigMesh( aMesh, F ); + } + } + + // Re-compute BLSURF mesh on the rest faces if the mesh was cleared + + for (TopExp_Explorer face_iter(aShape,TopAbs_FACE);face_iter.More();face_iter.Next()) + { + const TopoDS_Face& F = TopoDS::Face(face_iter.Current()); + SMESH_subMesh* fSM = aMesh.GetSubMesh( F ); + if ( fSM->IsMeshComputed() ) continue; + + if ( !compute( aMesh, aShape )) + return false; + break; + } + } + return true; +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape) +{ /* create a distene context (generic object) */ status_t status = STATUS_ERROR; + SMESHDS_Mesh* meshDS = aMesh.GetMeshDS(); + SMESH_MesherHelper helper( aMesh ); + // do not call helper.IsQuadraticSubMesh() because sub-meshes + // may be cleaned and helper.myTLinkNodeMap gets invalid in such a case + bool haveQuadraticSubMesh = SMESH_MesherHelper( aMesh ).IsQuadraticSubMesh( aShape ); + bool quadraticSubMeshAndViscousLayer = false; + bool needMerge = false; + typedef set< SMESHDS_SubMesh*, ShapeTypeCompare > TSubMeshSet; + TSubMeshSet edgeSubmeshes; + TSubMeshSet& mergeSubmeshes = edgeSubmeshes; + + TopTools_IndexedMapOfShape fmap; + TopTools_IndexedMapOfShape emap; + TopTools_IndexedMapOfShape pmap; + + // Issue 0019864. On DebianSarge, FE signals do not obey to OSD::SetSignal(false) +#ifndef WNT + feclearexcept( FE_ALL_EXCEPT ); + int oldFEFlags = fedisableexcept( FE_ALL_EXCEPT ); +#endif + context_t *ctx = context_new(); /* Set the message callback in the working context */ @@ -1178,7 +1602,7 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) #endif /* create the CAD object we will work on. It is associated to the context ctx. */ - cad_t *c = cad_new(ctx); + cad_t *c = cad_new(ctx); dcad_t *dcad = dcad_new(c); FacesWithSizeMap.Clear(); @@ -1190,15 +1614,6 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) VerticesWithSizeMap.Clear(); VertexId2SizeMap.clear(); - SMESH_MesherHelper helper( aMesh ); - // do not call helper.IsQuadraticSubMesh() because submeshes - // may be cleaned and helper.myTLinkNodeMap gets invalid in such a case - const bool haveQudraticSubMesh = SMESH_MesherHelper( aMesh ).IsQuadraticSubMesh( aShape ); - helper.SetIsQuadratic( haveQudraticSubMesh ); - bool needMerge = false; - set< SMESH_subMesh* > edgeSubmeshes; - set< SMESH_subMesh* >& mergeSubmeshes = edgeSubmeshes; - /* Now fill the CAD object with data from your CAD * environement. This is the most complex part of a successfull * integration. @@ -1206,50 +1621,50 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) // PreCAD // If user requests it, send the CAD through Distene preprocessor : PreCAD - cad_t *cleanc = NULL; + cad_t *cleanc = NULL; // preprocessed cad precad_session_t *pcs = precad_session_new(ctx); precad_data_set_cad(pcs, c); - blsurf_session_t *bls = blsurf_session_new(ctx); + cadsurf_session_t *css = cadsurf_session_new(ctx); - // an object that correctly deletes all blsurf objects at destruction - BLSURF_Cleaner cleaner( ctx,bls,c,dcad ); + // an object that correctly deletes all cadsurf objects at destruction + BLSURF_Cleaner cleaner( ctx,css,c,dcad ); MESSAGE("BEGIN SetParameters"); bool use_precad = false; SetParameters( -// #if BLSURF_VERSION_LONG >= "3.1.1" -// c, -// #endif - _hypothesis, bls, pcs, aMesh, &use_precad); + // #if BLSURF_VERSION_LONG >= "3.1.1" + // c, + // #endif + _hypothesis, css, pcs, aMesh, &use_precad); MESSAGE("END SetParameters"); + haveQuadraticSubMesh = haveQuadraticSubMesh || (_hypothesis != NULL && _hypothesis->GetQuadraticMesh()); + helper.SetIsQuadratic( haveQuadraticSubMesh ); + + // To remove as soon as quadratic mesh is allowed - BEGIN + // GDD: Viscous layer is not allowed with quadratic mesh + if (_haveViscousLayers && haveQuadraticSubMesh ) { + quadraticSubMeshAndViscousLayer = true; + _haveViscousLayers = !haveQuadraticSubMesh; + _comment += "Warning: Viscous layer is not possible with a quadratic mesh, it is ignored."; + error(COMPERR_WARNING, _comment); + } + // To remove as soon as quadratic mesh is allowed - END + // needed to prevent the opencascade memory managmement from freeing things vector curves; vector surfaces; - surfaces.resize(0); - curves.resize(0); - - TopTools_IndexedMapOfShape fmap; - TopTools_IndexedMapOfShape emap; - TopTools_IndexedMapOfShape pmap; - fmap.Clear(); - FaceId2PythonSmp.clear(); emap.Clear(); - EdgeId2PythonSmp.clear(); pmap.Clear(); + FaceId2PythonSmp.clear(); + EdgeId2PythonSmp.clear(); VertexId2PythonSmp.clear(); - assert(Py_IsInitialized()); - PyGILState_STATE gstate; - gstate = PyGILState_Ensure(); - - string theSizeMapStr; - /**************************************************************************************** - FACES + FACES *****************************************************************************************/ int iface = 0; string bad_end = "return"; @@ -1258,8 +1673,15 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) TopExp::MapShapes(aShape,TopAbs_VERTEX,_map); int ienf = _map.Extent(); - for (TopExp_Explorer face_iter(aShape,TopAbs_FACE);face_iter.More();face_iter.Next()) { - TopoDS_Face f=TopoDS::Face(face_iter.Current()); + assert(Py_IsInitialized()); + PyGILState_STATE gstate; + gstate = PyGILState_Ensure(); + + string theSizeMapStr; + + for (TopExp_Explorer face_iter(aShape,TopAbs_FACE);face_iter.More();face_iter.Next()) + { + TopoDS_Face f = TopoDS::Face(face_iter.Current()); // make INTERNAL face oriented FORWARD (issue 0020993) if (f.Orientation() != TopAbs_FORWARD && f.Orientation() != TopAbs_REVERSED ) @@ -1267,39 +1689,39 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) if (fmap.FindIndex(f) > 0) continue; + iface = fmap.Add(f); - fmap.Add(f); - iface++; surfaces.push_back(BRep_Tool::Surface(f)); - /* create an object representing the face for blsurf */ + /* create an object representing the face for cadsurf */ /* where face_id is an integer identifying the face. * surf_function is the function that defines the surface - * (For this face, it will be called by blsurf with your_face_object_ptr + * (For this face, it will be called by cadsurf with your_face_object_ptr * as last parameter. */ cad_face_t *fce = cad_face_new(c, iface, surf_fun, surfaces.back()); - /* by default a face has no tag (color). The following call sets it to the same value as the face_id : */ + /* by default a face has no tag (color). + The following call sets it to the same value as the face_id : */ cad_face_set_tag(fce, iface); /* Set face orientation (optional if you want a well oriented output mesh)*/ - if(f.Orientation() != TopAbs_FORWARD){ + if(f.Orientation() != TopAbs_FORWARD) cad_face_set_orientation(fce, CAD_ORIENTATION_REVERSED); - } else { + else cad_face_set_orientation(fce, CAD_ORIENTATION_FORWARD); - } - if (HasSizeMapOnFace && !use_precad){ -// MESSAGE("A size map is defined on a face") -// std::cout << "A size map is defined on a face" << std::endl; + if (HasSizeMapOnFace && !use_precad) + { + // ----------------- // Classic size map + // ----------------- faceKey = FacesWithSizeMap.FindIndex(f); - if (FaceId2SizeMap.find(faceKey)!=FaceId2SizeMap.end()){ + if (FaceId2SizeMap.find(faceKey)!=FaceId2SizeMap.end()) { MESSAGE("A size map is defined on face :"<second[0],attractor_iter->second[1]}; + double uvCoords[2] = {attractor_iter->second[0],attractor_iter->second[1]}; ienf++; MESSAGE("Add cad point on (u,v)=(" << uvCoords[0] << "," << uvCoords[1] << ") with id = " << ienf); cad_point_t* point_p = cad_point_new(fce, ienf, uvCoords); @@ -1354,101 +1776,106 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) } } + // ----------------- // Class Attractors + // ----------------- std::map::iterator clAttractor_iter = FaceId2ClassAttractor.find(faceKey); if (clAttractor_iter != FaceId2ClassAttractor.end()){ - MESSAGE("Face indice: " << iface); - MESSAGE("Adding attractor"); - FaceIndex2ClassAttractor[iface]=clAttractor_iter->second; - FaceId2ClassAttractor.erase(clAttractor_iter); - } + MESSAGE("Face indice: " << iface); + MESSAGE("Adding attractor"); + FaceIndex2ClassAttractor[iface]=clAttractor_iter->second; + FaceId2ClassAttractor.erase(clAttractor_iter); } + } // if (HasSizeMapOnFace && !use_precad) + // ------------------ // Enforced Vertices - faceKey = FacesWithEnforcedVertices.FindIndex(f); - std::map::const_iterator evmIt = FaceId2EnforcedVertexCoords.find(faceKey); - if (evmIt != FaceId2EnforcedVertexCoords.end()) { - MESSAGE("Some enforced vertices are defined"); - BLSURFPlugin_Hypothesis::TEnfVertexCoordsList evl; - MESSAGE("Face indice: " << iface); - MESSAGE("Adding enforced vertices"); - evl = evmIt->second; - MESSAGE("Number of vertices to add: "<< evl.size()); - BLSURFPlugin_Hypothesis::TEnfVertexCoordsList::const_iterator evlIt = evl.begin(); - for (; evlIt != evl.end(); ++evlIt) { - BLSURFPlugin_Hypothesis::TEnfVertexCoords xyzCoords; - xyzCoords.push_back(evlIt->at(2)); - xyzCoords.push_back(evlIt->at(3)); - xyzCoords.push_back(evlIt->at(4)); - MESSAGE("Check position of vertex =(" << xyzCoords[0] << "," << xyzCoords[1] << "," << xyzCoords[2] << ")"); - gp_Pnt P(xyzCoords[0],xyzCoords[1],xyzCoords[2]); - BRepClass_FaceClassifier scl(f,P,1e-7); - // OCC 6.3sp6 : scl.Perform() is bugged. The function was rewritten -// BRepClass_FaceClassifierPerform(&scl,f,P,1e-7); - // OCC 6.5.2: scl.Perform() is not bugged anymore - scl.Perform(f, P, 1e-7); - TopAbs_State result = scl.State(); - MESSAGE("Position of point on face: "<::const_iterator evmIt = FaceId2EnforcedVertexCoords.find(faceKey); + if (evmIt != FaceId2EnforcedVertexCoords.end()) { + MESSAGE("Some enforced vertices are defined"); + BLSURFPlugin_Hypothesis::TEnfVertexCoordsList evl; + MESSAGE("Face indice: " << iface); + MESSAGE("Adding enforced vertices"); + evl = evmIt->second; + MESSAGE("Number of vertices to add: "<< evl.size()); + BLSURFPlugin_Hypothesis::TEnfVertexCoordsList::const_iterator evlIt = evl.begin(); + for (; evlIt != evl.end(); ++evlIt) { + BLSURFPlugin_Hypothesis::TEnfVertexCoords xyzCoords; + xyzCoords.push_back(evlIt->at(2)); + xyzCoords.push_back(evlIt->at(3)); + xyzCoords.push_back(evlIt->at(4)); + MESSAGE("Check position of vertex =(" << xyzCoords[0] << "," << xyzCoords[1] << "," << xyzCoords[2] << ")"); + gp_Pnt P(xyzCoords[0],xyzCoords[1],xyzCoords[2]); + BRepClass_FaceClassifier scl(f,P,1e-7); + // OCC 6.3sp6 : scl.Perform() is bugged. The function was rewritten + // BRepClass_FaceClassifierPerform(&scl,f,P,1e-7); + // OCC 6.5.2: scl.Perform() is not bugged anymore + scl.Perform(f, P, 1e-7); + TopAbs_State result = scl.State(); + MESSAGE("Position of point on face: "<at(0),evlIt->at(1)}; + ienf++; + MESSAGE("Add cad point on (u,v)=(" << uvCoords[0] << "," << uvCoords[1] << ") with id = " << ienf); + cad_point_t* point_p = cad_point_new(fce, ienf, uvCoords); + int tag = 0; + std::map< BLSURFPlugin_Hypothesis::TEnfVertexCoords, BLSURFPlugin_Hypothesis::TEnfVertexList >::const_iterator enfCoordsIt = EnfVertexCoords2EnfVertexList.find(xyzCoords); + if (enfCoordsIt != EnfVertexCoords2EnfVertexList.end() && + !enfCoordsIt->second.empty() ) { - // Point is inside face and not on border - MESSAGE("Point is in face: node is created"); - double uvCoords[2] = {evlIt->at(0),evlIt->at(1)}; - ienf++; - MESSAGE("Add cad point on (u,v)=(" << uvCoords[0] << "," << uvCoords[1] << ") with id = " << ienf); - cad_point_t* point_p = cad_point_new(fce, ienf, uvCoords); - int tag = 0; - std::map< BLSURFPlugin_Hypothesis::TEnfVertexCoords, BLSURFPlugin_Hypothesis::TEnfVertexList >::const_iterator enfCoordsIt = EnfVertexCoords2EnfVertexList.find(xyzCoords); - if (enfCoordsIt != EnfVertexCoords2EnfVertexList.end() && - !enfCoordsIt->second.empty() ) - { - TopoDS_Vertex v = (*enfCoordsIt->second.begin())->vertex; - if ( v.IsNull() ) v = (*enfCoordsIt->second.rbegin())->vertex; - if ( !v.IsNull() ) { - tag = pmap.Add( v ); - mergeSubmeshes.insert( aMesh.GetSubMesh( v )); - //if ( tag != pmap.Extent() ) - needMerge = true; - } + // to merge nodes of an INTERNAL vertex belonging to several faces + TopoDS_Vertex v = (*enfCoordsIt->second.begin())->vertex; + if ( v.IsNull() ) v = (*enfCoordsIt->second.rbegin())->vertex; + if ( !v.IsNull() ) { + tag = pmap.Add( v ); + SMESH_subMesh* vSM = aMesh.GetSubMesh( v ); + vSM->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + mergeSubmeshes.insert( vSM->GetSubMeshDS() ); + //if ( tag != pmap.Extent() ) + needMerge = true; } - if ( tag == 0 ) tag = ienf; - cad_point_set_tag(point_p, tag); } + if ( tag == 0 ) tag = ienf; + cad_point_set_tag(point_p, tag); } - FaceId2EnforcedVertexCoords.erase(faceKey); } -// else -// std::cout << "No enforced vertex defined" << std::endl; -// } + FaceId2EnforcedVertexCoords.erase(faceKey); + } /**************************************************************************************** - EDGES - now create the edges associated to this face + EDGES + now create the edges associated to this face *****************************************************************************************/ int edgeKey = -1; - for (TopExp_Explorer edge_iter(f,TopAbs_EDGE);edge_iter.More();edge_iter.Next()) { + for (TopExp_Explorer edge_iter(f,TopAbs_EDGE);edge_iter.More();edge_iter.Next()) + { TopoDS_Edge e = TopoDS::Edge(edge_iter.Current()); int ic = emap.FindIndex(e); if (ic <= 0) @@ -1474,15 +1901,49 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) EdgeId2SizeMap.erase(edgeKey); } } + /* data of nodes existing on the edge */ + StdMeshers_FaceSidePtr nodeData; + SMESH_subMesh* sm = aMesh.GetSubMesh( e ); + if ( !sm->IsEmpty() ) + { + SMESH_subMeshIteratorPtr subsmIt = sm->getDependsOnIterator( /*includeSelf=*/true, + /*complexFirst=*/false); + while ( subsmIt->more() ) + edgeSubmeshes.insert( subsmIt->next()->GetSubMeshDS() ); + + nodeData.reset( new StdMeshers_FaceSide( f, e, &aMesh, /*isForwrd = */true, + /*ignoreMedium=*/haveQuadraticSubMesh)); + if ( nodeData->MissVertexNode() ) + return error(COMPERR_BAD_INPUT_MESH,"No node on vertex"); - /* attach the edge to the current blsurf face */ + const std::vector& nodeDataVec = nodeData->GetUVPtStruct(); + if ( !nodeDataVec.empty() ) + { + if ( Abs( nodeDataVec[0].param - tmin ) > Abs( nodeDataVec.back().param - tmin )) + { + nodeData->Reverse(); + nodeData->GetUVPtStruct(); // nodeData recomputes nodeDataVec + } + // tmin and tmax can change in case of viscous layer on an adjacent edge + tmin = nodeDataVec.front().param; + tmax = nodeDataVec.back().param; + } + else + { + cout << "---------------- Invalid nodeData" << endl; + nodeData.reset(); + } + } + + /* attach the edge to the current cadsurf face */ cad_edge_t *edg = cad_edge_new(fce, ic, tmin, tmax, curv_fun, curves.back()); - /* by default an edge has no tag (color). The following call sets it to the same value as the edge_id : */ + /* by default an edge has no tag (color). + The following call sets it to the same value as the edge_id : */ cad_edge_set_tag(edg, ic); /* by default, an edge does not necessalry appear in the resulting mesh, - unless the following property is set : + unless the following property is set : */ cad_edge_set_property(edg, EDGE_PROPERTY_SOFT_REQUIRED); @@ -1491,29 +1952,27 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) cad_edge_set_property(edg, EDGE_PROPERTY_INTERNAL); // pass existing nodes of sub-meshes to BLSURF - SMESH_subMesh* sm = aMesh.GetSubMesh( e ); - if ( !sm->IsEmpty() ) + if ( nodeData ) { - edgeSubmeshes.insert( sm ); - - StdMeshers_FaceSide edgeOfFace( f, e, &aMesh, e.Orientation() == TopAbs_FORWARD, - /*ignoreMedium=*/haveQudraticSubMesh); - if ( edgeOfFace.MissVertexNode() ) - return error(COMPERR_BAD_INPUT_MESH,"No node on vertex"); - - const int nbNodes = edgeOfFace.NbPoints(); + const std::vector& nodeDataVec = nodeData->GetUVPtStruct(); + const int nbNodes = nodeDataVec.size(); dcad_edge_discretization_t *dedge; dcad_get_edge_discretization(dcad, edg, &dedge); dcad_edge_discretization_set_vertex_count( dedge, nbNodes ); - const std::vector& nodeData = edgeOfFace.GetUVPtStruct(); + // cout << endl << " EDGE " << ic << endl; + // cout << "tmin = "<= "3.1.1" -// /* We can now get the updated sizemaps (if any) */ -// // if(geo_sizemap_e) -// // clean_geo_sizemap_e = precad_new_sizemap(pcs, geo_sizemap_e); -// // -// // if(geo_sizemap_f) -// // clean_geo_sizemap_f = precad_new_sizemap(pcs, geo_sizemap_f); -// -// if(iso_sizemap_p) -// clean_iso_sizemap_p = precad_new_sizemap(pcs, iso_sizemap_p); -// -// if(iso_sizemap_e) -// clean_iso_sizemap_e = precad_new_sizemap(pcs, iso_sizemap_e); -// -// if(iso_sizemap_f) -// clean_iso_sizemap_f = precad_new_sizemap(pcs, iso_sizemap_f); -// #endif - - // Now we can delete the PreCAD session - precad_session_delete(pcs); + // #if BLSURF_VERSION_LONG >= "3.1.1" + // /* We can now get the updated sizemaps (if any) */ + // // if(geo_sizemap_e) + // // clean_geo_sizemap_e = precad_new_sizemap(pcs, geo_sizemap_e); + // // + // // if(geo_sizemap_f) + // // clean_geo_sizemap_f = precad_new_sizemap(pcs, geo_sizemap_f); + // + // if(iso_sizemap_p) + // clean_iso_sizemap_p = precad_new_sizemap(pcs, iso_sizemap_p); + // + // if(iso_sizemap_e) + // clean_iso_sizemap_e = precad_new_sizemap(pcs, iso_sizemap_e); + // + // if(iso_sizemap_f) + // clean_iso_sizemap_f = precad_new_sizemap(pcs, iso_sizemap_f); + // #endif } + // Now we can delete the PreCAD session + precad_session_delete(pcs); } - blsurf_data_set_dcad(bls, dcad); + cadsurf_data_set_dcad(css, dcad); if (cleanc) { // Give the pre-processed CAD object to the current BLSurf session - blsurf_data_set_cad(bls, cleanc); + cadsurf_data_set_cad(css, cleanc); } else { // Use the original one - blsurf_data_set_cad(bls, c); + cadsurf_data_set_cad(css, c); } -// #if BLSURF_VERSION_LONG >= "3.1.1" -// blsurf_data_set_sizemap(bls, clean_iso_sizemap_p); -// blsurf_data_set_sizemap(bls, clean_iso_sizemap_e); -// blsurf_data_set_sizemap(bls, clean_iso_sizemap_f); -// #endif - std::cout << std::endl; std::cout << "Beginning of Surface Mesh generation" << std::endl; std::cout << std::endl; - // Issue 0019864. On DebianSarge, FE signals do not obey to OSD::SetSignal(false) -#ifndef WNT - feclearexcept( FE_ALL_EXCEPT ); - int oldFEFlags = fedisableexcept( FE_ALL_EXCEPT ); -#endif - try { OCC_CATCH_SIGNALS; - status = blsurf_compute_mesh(bls); + status = cadsurf_compute_mesh(css); } catch ( std::exception& exc ) { @@ -1702,22 +2143,24 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) } catch (...) { if ( _comment.empty() ) - _comment = "Exception in blsurf_compute_mesh()"; + _comment = "Exception in cadsurf_compute_mesh()"; } if ( status != STATUS_OK) { // There was an error while meshing - //return error(_comment); + error(_comment); } + PyGILState_Release(gstate); + std::cout << std::endl; std::cout << "End of Surface Mesh generation" << std::endl; std::cout << std::endl; mesh_t *msh = NULL; - blsurf_data_get_mesh(bls, &msh); + cadsurf_data_get_mesh(css, &msh); if(!msh){ /* release the mesh object */ - blsurf_data_regain_mesh(bls, msh); + cadsurf_data_regain_mesh(css, msh); return error(_comment); } @@ -1725,30 +2168,17 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) if (_hypothesis) GMFFileName = _hypothesis->GetGMFFile(); if (GMFFileName != "") { -// bool GMFFileMode = _hypothesis->GetGMFFileMode(); + // bool GMFFileMode = _hypothesis->GetGMFFileMode(); bool asciiFound = (GMFFileName.find(".mesh",GMFFileName.length()-5) != std::string::npos); bool binaryFound = (GMFFileName.find(".meshb",GMFFileName.length()-6) != std::string::npos); if (!asciiFound && !binaryFound) GMFFileName.append(".mesh"); - /* - if (GMFFileMode) { - if (!binaryFound) { - if (asciiFound) - GMFFileName.append("b"); - else - GMFFileName.append(".meshb"); - } - } - else { - if (!asciiFound) - GMFFileName.append(".mesh"); - } - */ mesh_write_mesh(msh, GMFFileName.c_str()); } - /* retrieve mesh data (see distene/mesh.h) */ + /* retrieve mesh data (see meshgems/mesh.h) */ integer nv, ne, nt, nq, vtx[4], tag; + integer *evedg, *evtri, *evquad, type; real xyz[3]; mesh_get_vertex_count(msh, &nv); @@ -1756,8 +2186,10 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) mesh_get_triangle_count(msh, &nt); mesh_get_quadrangle_count(msh, &nq); + evedg = (integer *)mesh_calloc_generic_buffer(msh); + evtri = (integer *)mesh_calloc_generic_buffer(msh); + evquad = (integer *)mesh_calloc_generic_buffer(msh); - SMESHDS_Mesh* meshDS = aMesh.GetMeshDS(); SMDS_MeshNode** nodes = new SMDS_MeshNode*[nv+1]; bool* tags = new bool[nv+1]; @@ -1809,7 +2241,7 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) aGroupDS->SMDSGroup().Add(nodes[iv]); MESSAGE("Node ID: " << nodes[iv]->GetID()); // How can I inform the hypothesis ? -// _hypothesis->AddEnfVertexNodeID(currentEnfVertex->grpName,nodes[iv]->GetID()); + // _hypothesis->AddEnfVertexNodeID(currentEnfVertex->grpName,nodes[iv]->GetID()); groupDone = true; MESSAGE("Successfully added enforced vertex to existing group " << currentEnfVertex->grpName); break; @@ -1833,8 +2265,7 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) } } - - // internal point are tagged to zero + // internal points are tagged to zero if(tag > 0 && tag <= pmap.Extent() ){ meshDS->SetNodeOnVertex(nodes[iv], TopoDS::Vertex(pmap(tag))); tags[iv] = false; @@ -1845,8 +2276,9 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) /* enumerate edges */ for(int it=1;it<=ne;it++) { - + SMDS_MeshEdge* edg; mesh_get_edge_vertices(msh, it, vtx); + mesh_get_edge_extra_vertices(msh, it, &type, evedg); mesh_get_edge_tag(msh, it, &tag); if (tags[vtx[0]]) { Set_NodeOnEdge(meshDS, nodes[vtx[0]], emap(tag)); @@ -1856,16 +2288,26 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) Set_NodeOnEdge(meshDS, nodes[vtx[1]], emap(tag)); tags[vtx[1]] = false; }; - SMDS_MeshEdge* edg = helper.AddEdge(nodes[vtx[0]], nodes[vtx[1]]); + if (type == MESHGEMS_MESH_ELEMENT_TYPE_EDGE3) { + // QUADRATIC EDGE + if (tags[evedg[0]]) { + Set_NodeOnEdge(meshDS, nodes[evedg[0]], emap(tag)); + tags[evedg[0]] = false; + } + edg = meshDS->AddEdge(nodes[vtx[0]], nodes[vtx[1]], nodes[evedg[0]]); + } + else { + edg = helper.AddEdge(nodes[vtx[0]], nodes[vtx[1]]); + } meshDS->SetMeshElementOnShape(edg, TopoDS::Edge(emap(tag))); } /* enumerate triangles */ for(int it=1;it<=nt;it++) { + SMDS_MeshFace* tri; mesh_get_triangle_vertices(msh, it, vtx); - SMDS_MeshFace* tri = helper.AddFace(nodes[vtx[0]], nodes[vtx[1]], nodes[vtx[2]]); + mesh_get_triangle_extra_vertices(msh, it, &type, evtri); mesh_get_triangle_tag(msh, it, &tag); - meshDS->SetMeshElementOnShape(tri, TopoDS::Face(fmap(tag))); if (tags[vtx[0]]) { meshDS->SetNodeOnFace(nodes[vtx[0]], TopoDS::Face(fmap(tag))); tags[vtx[0]] = false; @@ -1878,14 +2320,35 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) meshDS->SetNodeOnFace(nodes[vtx[2]], TopoDS::Face(fmap(tag))); tags[vtx[2]] = false; }; + if (type == MESHGEMS_MESH_ELEMENT_TYPE_TRIA6) { + // QUADRATIC TRIANGLE + if (tags[evtri[0]]) { + meshDS->SetNodeOnFace(nodes[evtri[0]], TopoDS::Face(fmap(tag))); + tags[evtri[0]] = false; + } + if (tags[evtri[1]]) { + meshDS->SetNodeOnFace(nodes[evtri[1]], TopoDS::Face(fmap(tag))); + tags[evtri[1]] = false; + } + if (tags[evtri[2]]) { + meshDS->SetNodeOnFace(nodes[evtri[2]], TopoDS::Face(fmap(tag))); + tags[evtri[2]] = false; + } + tri = meshDS->AddFace(nodes[vtx[0]], nodes[vtx[1]], nodes[vtx[2]], + nodes[evtri[0]], nodes[evtri[1]], nodes[evtri[2]]); + } + else { + tri = helper.AddFace(nodes[vtx[0]], nodes[vtx[1]], nodes[vtx[2]]); + } + meshDS->SetMeshElementOnShape(tri, TopoDS::Face(fmap(tag))); } /* enumerate quadrangles */ for(int it=1;it<=nq;it++) { + SMDS_MeshFace* quad; mesh_get_quadrangle_vertices(msh, it, vtx); - SMDS_MeshFace* quad = helper.AddFace(nodes[vtx[0]], nodes[vtx[1]], nodes[vtx[2]], nodes[vtx[3]]); + mesh_get_quadrangle_extra_vertices(msh, it, &type, evquad); mesh_get_quadrangle_tag(msh, it, &tag); - meshDS->SetMeshElementOnShape(quad, TopoDS::Face(fmap(tag))); if (tags[vtx[0]]) { meshDS->SetNodeOnFace(nodes[vtx[0]], TopoDS::Face(fmap(tag))); tags[vtx[0]] = false; @@ -1902,59 +2365,110 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) meshDS->SetNodeOnFace(nodes[vtx[3]], TopoDS::Face(fmap(tag))); tags[vtx[3]] = false; }; + if (type == MESHGEMS_MESH_ELEMENT_TYPE_QUAD9) { + // QUADRATIC QUADRANGLE + std::cout << "This is a quadratic quadrangle" << std::endl; + if (tags[evquad[0]]) { + meshDS->SetNodeOnFace(nodes[evquad[0]], TopoDS::Face(fmap(tag))); + tags[evquad[0]] = false; + } + if (tags[evquad[1]]) { + meshDS->SetNodeOnFace(nodes[evquad[1]], TopoDS::Face(fmap(tag))); + tags[evquad[1]] = false; + } + if (tags[evquad[2]]) { + meshDS->SetNodeOnFace(nodes[evquad[2]], TopoDS::Face(fmap(tag))); + tags[evquad[2]] = false; + } + if (tags[evquad[3]]) { + meshDS->SetNodeOnFace(nodes[evquad[3]], TopoDS::Face(fmap(tag))); + tags[evquad[3]] = false; + } + if (tags[evquad[4]]) { + meshDS->SetNodeOnFace(nodes[evquad[4]], TopoDS::Face(fmap(tag))); + tags[evquad[4]] = false; + } + quad = meshDS->AddFace(nodes[vtx[0]], nodes[vtx[1]], nodes[vtx[2]], nodes[vtx[3]], + nodes[evquad[0]], nodes[evquad[1]], nodes[evquad[2]], nodes[evquad[3]], + nodes[evquad[4]]); + } + else { + quad = helper.AddFace(nodes[vtx[0]], nodes[vtx[1]], nodes[vtx[2]], nodes[vtx[3]]); + } + meshDS->SetMeshElementOnShape(quad, TopoDS::Face(fmap(tag))); } - // SetIsAlwaysComputed( true ) to sub-meshes of EDGEs w/o mesh - TopLoc_Location loc; double f,l; - for (int i = 1; i <= emap.Extent(); i++) - if ( SMESH_subMesh* sm = aMesh.GetSubMeshContaining( emap( i ))) - sm->SetIsAlwaysComputed( true ); - for (int i = 1; i <= pmap.Extent(); i++) - if ( SMESH_subMesh* sm = aMesh.GetSubMeshContaining( pmap( i ))) - if ( !sm->IsMeshComputed() ) - sm->SetIsAlwaysComputed( true ); + /* release the mesh object, the rest is released by cleaner */ + cadsurf_data_regain_mesh(css, msh); + + delete [] nodes; + delete [] tags; - if ( needMerge ) + if ( needMerge ) // sew mesh computed by BLSURF with pre-existing mesh { - set< SMESH_subMesh* >::iterator smIt = mergeSubmeshes.begin(); - for ( ; smIt != mergeSubmeshes.end(); ++smIt ) + SMESH_MeshEditor editor( &aMesh ); + SMESH_MeshEditor::TListOfListOfNodes nodeGroupsToMerge; + TIDSortedElemSet segementsOnEdge; + TIDSortedNodeSet nodesOnEdge; + TSubMeshSet::iterator smIt; + SMESHDS_SubMesh* smDS; + typedef SMDS_StdIterator< const SMDS_MeshNode*, SMDS_NodeIteratorPtr > TNodeIterator; + double tol; + + // merge nodes on EDGE's with ones computed by BLSURF + for ( smIt = mergeSubmeshes.begin(); smIt != mergeSubmeshes.end(); ++smIt ) { - SMESH_subMesh* sm = *smIt; - SMESH_subMeshIteratorPtr subsmIt = sm->getDependsOnIterator( /*includeSelf=*/true, - /*complexFirst=*/false); - TIDSortedNodeSet nodesOnEdge; - double mergeTolerance = 1e-7, tol; - while ( subsmIt->more() ) + if (! (smDS = *smIt) ) continue; + getNodeGroupsToMerge( smDS, meshDS->IndexToShape((*smIt)->GetID()), nodeGroupsToMerge ); + + SMDS_ElemIteratorPtr segIt = smDS->GetElements(); + while ( segIt->more() ) + segementsOnEdge.insert( segIt->next() ); + } + // merge nodes + editor.MergeNodes( nodeGroupsToMerge ); + + // merge segments + SMESH_MeshEditor::TListOfListOfElementsID equalSegments; + editor.FindEqualElements( segementsOnEdge, equalSegments ); + editor.MergeElements( equalSegments ); + + // remove excess segments created on the boundary of viscous layers + const SMDS_TypeOfPosition onFace = SMDS_TOP_FACE; + for ( int i = 1; i <= emap.Extent(); ++i ) + { + if ( SMESHDS_SubMesh* smDS = meshDS->MeshElements( emap( i ))) { - // get nodes from an edge - sm = subsmIt->next(); - if ( SMESHDS_SubMesh* smDS = sm->GetSubMeshDS() ) + SMDS_ElemIteratorPtr segIt = smDS->GetElements(); + while ( segIt->more() ) { - SMDS_NodeIteratorPtr nIt = smDS->GetNodes(); - while ( nIt->more() ) - nodesOnEdge.insert( nIt->next() ); + const SMDS_MeshElement* seg = segIt->next(); + if ( seg->GetNode(0)->GetPosition()->GetTypeOfPosition() == onFace || + seg->GetNode(1)->GetPosition()->GetTypeOfPosition() == onFace ) + meshDS->RemoveFreeElement( seg, smDS ); } - // get max tolerance - TopoDS_Shape subShape = sm->GetSubShape(); - if ( subShape.ShapeType() == TopAbs_EDGE ) - tol = BRep_Tool::Tolerance( TopoDS::Edge( subShape )); - else - tol = BRep_Tool::Tolerance( TopoDS::Vertex( subShape )); - mergeTolerance = Max( tol, mergeTolerance ); } - // find nodes to merge - SMESH_MeshEditor::TListOfListOfNodes nodeGroupsToMerge; - SMESH_MeshEditor editor( &aMesh ); - editor.FindCoincidentNodes( nodesOnEdge, mergeTolerance*2, nodeGroupsToMerge ); - // merge - editor.MergeNodes( nodeGroupsToMerge ); } } - delete [] nodes; + // SetIsAlwaysComputed( true ) to sub-meshes of EDGEs w/o mesh + TopLoc_Location loc; double f,l; + for (int i = 1; i <= emap.Extent(); i++) + if ( SMESH_subMesh* sm = aMesh.GetSubMeshContaining( emap( i ))) + sm->SetIsAlwaysComputed( true ); + for (int i = 1; i <= pmap.Extent(); i++) + if ( SMESH_subMesh* sm = aMesh.GetSubMeshContaining( pmap( i ))) + if ( !sm->IsMeshComputed() ) + sm->SetIsAlwaysComputed( true ); - /* release the mesh object */ - blsurf_data_regain_mesh(bls, msh); + // Set error to FACE's w/o elements + for ( int i = 1; i <= fmap.Extent(); ++i ) + { + SMESH_subMesh* sm = aMesh.GetSubMesh( fmap(i) ); + if ( !sm->GetSubMeshDS() || sm->GetSubMeshDS()->NbElements() == 0 ) + sm->GetComputeError().reset + ( new SMESH_ComputeError( COMPERR_ALGO_FAILED, _comment, this )); + } // Issue 0019864. On DebianSarge, FE signals do not obey to OSD::SetSignal(false) #ifndef WNT @@ -1964,20 +2478,26 @@ bool BLSURFPlugin_BLSURF::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) #endif /* - std::cout << "FacesWithSizeMap" << std::endl; - FacesWithSizeMap.Statistics(std::cout); - std::cout << "EdgesWithSizeMap" << std::endl; - EdgesWithSizeMap.Statistics(std::cout); - std::cout << "VerticesWithSizeMap" << std::endl; - VerticesWithSizeMap.Statistics(std::cout); - std::cout << "FacesWithEnforcedVertices" << std::endl; - FacesWithEnforcedVertices.Statistics(std::cout); + std::cout << "FacesWithSizeMap" << std::endl; + FacesWithSizeMap.Statistics(std::cout); + std::cout << "EdgesWithSizeMap" << std::endl; + EdgesWithSizeMap.Statistics(std::cout); + std::cout << "VerticesWithSizeMap" << std::endl; + VerticesWithSizeMap.Statistics(std::cout); + std::cout << "FacesWithEnforcedVertices" << std::endl; + FacesWithEnforcedVertices.Statistics(std::cout); */ MESSAGE("END OF BLSURFPlugin_BLSURF::Compute()"); - return true; + return ( status == STATUS_OK && !quadraticSubMeshAndViscousLayer ); } +//================================================================================ +/*! + * \brief Terminates computation + */ +//================================================================================ + #ifdef WITH_SMESH_CANCEL_COMPUTE void BLSURFPlugin_BLSURF::CancelCompute() { @@ -2010,8 +2530,8 @@ void BLSURFPlugin_BLSURF::Set_NodeOnEdge(SMESHDS_Mesh* meshDS, SMDS_MeshNode* no pa = (double)proj.LowerDistanceParameter(); // Issue 0020656. Move node if it is too far from edge gp_Pnt curve_pnt = curve->Value( pa ); - double dist2 = pnt.SquareDistance( curve_pnt ); - double tol = BRep_Tool::Tolerance( edge ); + double dist2 = pnt.SquareDistance( curve_pnt ); + double tol = BRep_Tool::Tolerance( edge ); if ( 1e-14 < dist2 && dist2 <= 1000*tol ) // large enough and within tolerance { curve_pnt.Transform( loc ); @@ -2025,51 +2545,7 @@ void BLSURFPlugin_BLSURF::Set_NodeOnEdge(SMESHDS_Mesh* meshDS, SMDS_MeshNode* no meshDS->SetNodeOnEdge(node, edge, pa); } -//============================================================================= -/*! - * - */ -//============================================================================= - -ostream & BLSURFPlugin_BLSURF::SaveTo(ostream & save) -{ - return save; -} - -//============================================================================= -/*! - * - */ -//============================================================================= - -istream & BLSURFPlugin_BLSURF::LoadFrom(istream & load) -{ - return load; -} - -//============================================================================= -/*! - * - */ -//============================================================================= - -ostream & operator << (ostream & save, BLSURFPlugin_BLSURF & hyp) -{ - return hyp.SaveTo( save ); -} - -//============================================================================= -/*! - * - */ -//============================================================================= - -istream & operator >> (istream & load, BLSURFPlugin_BLSURF & hyp) -{ - return hyp.LoadFrom( load ); -} - -/* Curve definition function See cad_curv_t in file distene/cad.h for +/* Curve definition function See cad_curv_t in file meshgems/cad.h for * more information. * NOTE : if when your CAD systems evaluates second * order derivatives it also computes first order derivatives and @@ -2110,7 +2586,7 @@ status_t curv_fun(real t, real *uv, real *dt, real *dtt, void *user_data) } /* Surface definition function. - * See cad_surf_t in file distene/cad.h for more information. + * See cad_surf_t in file meshgems/cad.h for more information. * NOTE : if when your CAD systems evaluates second order derivatives it also * computes first order derivatives and function evaluation, you can optimize * this example by making only one CAD call and filling the necessary xyz, du, dv, etc.. @@ -2159,20 +2635,6 @@ status_t surf_fun(real *uv, real *xyz, real*du, real *dv, status_t size_on_surface(integer face_id, real *uv, real *size, void *user_data) { - if (face_id == 1) { - if (my_u_min > uv[0]) { - my_u_min = uv[0]; - } - if (my_v_min > uv[1]) { - my_v_min = uv[1]; - } - if (my_u_max < uv[0]) { - my_u_max = uv[0]; - } - if (my_v_max < uv[1]) { - my_v_max = uv[1]; - } - } //MESSAGE("size_on_surface") if (FaceId2PythonSmp.count(face_id) != 0){ //MESSAGE("A size map is used to calculate size on face : "<Empty()) - double result = FaceIndex2ClassAttractor[face_id]->GetSize(uv[0],uv[1]); + real result = FaceIndex2ClassAttractor[face_id]->GetSize(uv[0],uv[1]); *size = result; - // MESSAGE("f(" << uv[0] << "," << uv[1] << ")" << " = " << result); } else { // MESSAGE("List of attractor is empty !!!") - *size = *((double*)user_data); + *size = *((real*)user_data); } +// std::cout << "Size_on_surface sur la face " << face_id << " donne une size de: " << *size << std::endl; return STATUS_OK; } @@ -2226,8 +2688,13 @@ status_t size_on_edge(integer edge_id, real t, real *size, void *user_data) PyGILState_STATE gstate; gstate = PyGILState_Ensure(); pyresult = PyObject_CallFunction(EdgeId2PythonSmp[edge_id],(char*)"(f)",t); - double result; - if ( pyresult == NULL){ + real result; + if ( pyresult != NULL) { + result = PyFloat_AsDouble(pyresult); + Py_DECREF(pyresult); +// *size = result; + } + else{ fflush(stderr); string err_description=""; new_stderr = newPyStdOut(err_description); @@ -2236,17 +2703,13 @@ status_t size_on_edge(integer edge_id, real t, real *size, void *user_data) PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__")); Py_DECREF(new_stderr); MESSAGE("Can't evaluate f(" << t << ")" << " error is " << err_description); - result = *((double*)user_data); - } - else { - result = PyFloat_AsDouble(pyresult); - Py_DECREF(pyresult); + result = *((real*)user_data); } *size = result; PyGILState_Release(gstate); } else { - *size = *((double*)user_data); + *size = *((real*)user_data); } return STATUS_OK; } @@ -2260,8 +2723,13 @@ status_t size_on_vertex(integer point_id, real *size, void *user_data) PyGILState_STATE gstate; gstate = PyGILState_Ensure(); pyresult = PyObject_CallFunction(VertexId2PythonSmp[point_id],(char*)""); - double result; - if ( pyresult == NULL){ + real result; + if ( pyresult != NULL) { + result = PyFloat_AsDouble(pyresult); + Py_DECREF(pyresult); +// *size = result; + } + else { fflush(stderr); string err_description=""; new_stderr = newPyStdOut(err_description); @@ -2270,17 +2738,13 @@ status_t size_on_vertex(integer point_id, real *size, void *user_data) PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__")); Py_DECREF(new_stderr); MESSAGE("Can't evaluate f()" << " error is " << err_description); - result = *((double*)user_data); - } - else { - result = PyFloat_AsDouble(pyresult); - Py_DECREF(pyresult); + result = *((real*)user_data); } *size = result; PyGILState_Release(gstate); } else { - *size = *((double*)user_data); + *size = *((real*)user_data); } return STATUS_OK; } @@ -2314,7 +2778,7 @@ status_t message_cb(message_t *msg, void *user_data) } /* This is the interrupt callback. PreCAD/BLSurf will call this - * function regularily. See the file distene/interrupt.h + * function regularily. See the file meshgems/interrupt.h */ status_t interrupt_cb(integer *interrupt_status, void *user_data) { @@ -2345,19 +2809,23 @@ bool BLSURFPlugin_BLSURF::Evaluate(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape, MapShapeNbElems& aResMap) { + double diagonal = aMesh.GetShapeDiagonalSize(); + double bbSegmentation = _gen->GetBoundaryBoxSegmentation(); int _physicalMesh = BLSURFPlugin_Hypothesis::GetDefaultPhysicalMesh(); - double _phySize = BLSURFPlugin_Hypothesis::GetDefaultPhySize(); + double _phySize = BLSURFPlugin_Hypothesis::GetDefaultPhySize(diagonal, bbSegmentation); + bool _phySizeRel = BLSURFPlugin_Hypothesis::GetDefaultPhySizeRel(); //int _geometricMesh = BLSURFPlugin_Hypothesis::GetDefaultGeometricMesh(); - //double _angleMeshS = BLSURFPlugin_Hypothesis::GetDefaultAngleMeshS(); - double _angleMeshC = BLSURFPlugin_Hypothesis::GetDefaultAngleMeshC(); + double _angleMesh = BLSURFPlugin_Hypothesis::GetDefaultAngleMesh(); bool _quadAllowed = BLSURFPlugin_Hypothesis::GetDefaultQuadAllowed(); if(_hypothesis) { _physicalMesh = (int) _hypothesis->GetPhysicalMesh(); - _phySize = _hypothesis->GetPhySize(); + _phySizeRel = _hypothesis->IsPhySizeRel(); + if ( _hypothesis->GetPhySize() > 0) + _phySize = _phySizeRel ? diagonal*_hypothesis->GetPhySize() : _hypothesis->GetPhySize(); //_geometricMesh = (int) hyp->GetGeometricMesh(); - //_angleMeshS = hyp->GetAngleMeshS(); - _angleMeshC = _hypothesis->GetAngleMeshC(); - _quadAllowed = _hypothesis->GetQuadAllowed(); + if (_hypothesis->GetAngleMesh() > 0) + _angleMesh = _hypothesis->GetAngleMesh(); + _quadAllowed = _hypothesis->GetQuadAllowed(); } else { //0020968: EDF1545 SMESH: Problem in the creation of a mesh group on geometry // GetDefaultPhySize() sometimes leads to computation failure @@ -2365,7 +2833,7 @@ bool BLSURFPlugin_BLSURF::Evaluate(SMESH_Mesh& aMesh, MESSAGE("BLSURFPlugin_BLSURF::SetParameters using defaults"); } - bool IsQuadratic = false; + bool IsQuadratic = _quadraticMesh; // ---------------- // evaluate 1D @@ -2401,7 +2869,7 @@ bool BLSURFPlugin_BLSURF::Evaluate(SMESH_Mesh& aMesh, V1 = V2; P2 = P3; } - nb1d = (int)( fullAng/_angleMeshC + 1 ); + nb1d = (int)( fullAng/_angleMesh + 1 ); } fullNbSeg += nb1d; std::vector aVec(SMDSEntity_Last); @@ -2491,56 +2959,3 @@ bool BLSURFPlugin_BLSURF::Evaluate(SMESH_Mesh& aMesh, return true; } - -//============================================================================= -/*! - * Rewritting of the BRepClass_FaceClassifier::Perform function which is bugged (CAS 6.3sp6) - * Following line was added: - * myExtrem.Perform(P); - */ -//============================================================================= -void BLSURFPlugin_BLSURF::BRepClass_FaceClassifierPerform(BRepClass_FaceClassifier* fc, - const TopoDS_Face& face, - const gp_Pnt& P, - const Standard_Real Tol) -{ - //-- Voir BRepExtrema_ExtPF.cxx - BRepAdaptor_Surface Surf(face); - Standard_Real U1, U2, V1, V2; - BRepTools::UVBounds(face, U1, U2, V1, V2); - Extrema_ExtPS myExtrem; - myExtrem.Initialize(Surf, U1, U2, V1, V2, Tol, Tol); - myExtrem.Perform(P); - //---------------------------------------------------------- - //-- On cherche le point le plus proche , PUIS - //-- On le classifie. - Standard_Integer nbv = 0; // xpu - Standard_Real MaxDist = RealLast(); - Standard_Integer indice = 0; - if (myExtrem.IsDone()) { - nbv = myExtrem.NbExt(); - for (Standard_Integer i = 1; i <= nbv; i++) { -#if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1 - Standard_Real d = myExtrem.SquareDistance(i); -#else - Standard_Real d = myExtrem.Value(i); - d = Abs(d); -#endif - if (d <= MaxDist) { - MaxDist = d; - indice = i; - } - } - } - if (indice) { - gp_Pnt2d Puv; - Standard_Real U1,U2; - myExtrem.Point(indice).Parameter(U1, U2); - Puv.SetCoord(U1, U2); - fc->Perform(face, Puv, Tol); - } - else { - fc->Perform(face, gp_Pnt2d(U1-1.0,V1 - 1.0), Tol); //-- NYI etc BUG PAS BEAU En attendant l acces a rejected - //-- le resultat est TopAbs_OUT; - } -} diff --git a/src/BLSURFPlugin/BLSURFPlugin_BLSURF.hxx b/src/BLSURFPlugin/BLSURFPlugin_BLSURF.hxx index 6069072..cbee8ae 100644 --- a/src/BLSURFPlugin/BLSURFPlugin_BLSURF.hxx +++ b/src/BLSURFPlugin/BLSURFPlugin_BLSURF.hxx @@ -47,21 +47,22 @@ #endif #include -#include "SMESH_Algo.hxx" -#include "SMESH_Mesh.hxx" +#include +#include #include #include #include #include +#include #include #include CORBA_CLIENT_HEADER(SALOMEDS) #include CORBA_CLIENT_HEADER(GEOM_Gen) #include "Utils_SALOME_Exception.hxx" extern "C"{ -#include "distene/blsurf.h" -#include "distene/api.h" -#include "distene/precad.h" +#include +#include +#include } #include @@ -89,21 +90,20 @@ class BLSURFPlugin_BLSURF: public SMESH_2D_Algo { #ifdef WITH_SMESH_CANCEL_COMPUTE virtual void CancelCompute(); - bool computeCanceled() { return _compute_canceled;}; + bool computeCanceled() { return _compute_canceled; } #endif virtual bool Evaluate(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape, MapShapeNbElems& aResMap); - ostream & SaveTo(ostream & save); - istream & LoadFrom(istream & load); - friend ostream & operator << (ostream & save, BLSURFPlugin_BLSURF & hyp); - friend istream & operator >> (istream & load, BLSURFPlugin_BLSURF & hyp); - protected: const BLSURFPlugin_Hypothesis* _hypothesis; + bool _haveViscousLayers; private: + bool compute(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape); + TopoDS_Shape entryToShape(std::string entry); void createEnforcedVertexOnFace(TopoDS_Shape FaceShape, BLSURFPlugin_Hypothesis::TEnfVertexList enfVertexList); void Set_NodeOnEdge(SMESHDS_Mesh* meshDS, SMDS_MeshNode* node, const TopoDS_Shape& ed); diff --git a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.cxx b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.cxx index f934918..ada8a38 100644 --- a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.cxx +++ b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.cxx @@ -41,24 +41,32 @@ //============================================================================= BLSURFPlugin_Hypothesis::BLSURFPlugin_Hypothesis(int hypId, int studyId, SMESH_Gen * gen) : - SMESH_Hypothesis(hypId, studyId, gen), _topology(GetDefaultTopology()), + SMESH_Hypothesis(hypId, studyId, gen), _physicalMesh(GetDefaultPhysicalMesh()), - _phySize(GetDefaultPhySize()), - _phyMax(GetDefaultMaxSize()), - _phyMin(GetDefaultMinSize()), - _hgeoMax(GetDefaultMaxSize()), - _hgeoMin(GetDefaultMinSize()), _geometricMesh(GetDefaultGeometricMesh()), - _angleMeshS(GetDefaultAngleMeshS()), - _angleMeshC(GetDefaultAngleMeshC()), + _phySize(GetDefaultPhySize()), + _phySizeRel(GetDefaultPhySizeRel()), + _minSize(GetDefaultMinSize()), + _minSizeRel(GetDefaultMinSizeRel()), + _maxSize(GetDefaultMaxSize()), + _maxSizeRel(GetDefaultMaxSizeRel()), _gradation(GetDefaultGradation()), _quadAllowed(GetDefaultQuadAllowed()), - _decimesh(GetDefaultDecimesh()), + _angleMesh(GetDefaultAngleMesh()), + _chordalError(GetDefaultChordalError()), + _anisotropic(GetDefaultAnisotropic()), + _anisotropicRatio(GetDefaultAnisotropicRatio()), + _removeTinyEdges(GetDefaultRemoveTinyEdges()), + _tinyEdgeLength(GetDefaultTinyEdgeLength()), + _badElementRemoval(GetDefaultBadElementRemoval()), + _badElementAspectRatio(GetDefaultBadElementAspectRatio()), + _optimizeMesh(GetDefaultOptimizeMesh()), + _quadraticMesh(GetDefaultQuadraticMesh()), _verb(GetDefaultVerbosity()), + _topology(GetDefaultTopology()), _preCADMergeEdges(GetDefaultPreCADMergeEdges()), - _preCADRemoveNanoEdges(GetDefaultPreCADRemoveNanoEdges()), + _preCADProcess3DTopology(GetDefaultPreCADProcess3DTopology()), _preCADDiscardInput(GetDefaultPreCADDiscardInput()), - _preCADEpsNano(GetDefaultPreCADEpsNano()), _sizeMap(GetDefaultSizeMap()), _attractors(GetDefaultSizeMap()), _classAttractors(GetDefaultAttractorMap()), @@ -76,33 +84,64 @@ BLSURFPlugin_Hypothesis::BLSURFPlugin_Hypothesis(int hypId, int studyId, SMESH_G _param_algo_dim = 2; // _GMFFileMode = false; // GMF ascii mode - - // to disable writing boundaries - //_phyMin = _phyMax = _hgeoMin = _hgeoMax = undefinedDouble(); + 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 + "jacobian_rectification_respect_geometry", // default = 1 + "proximity", // default = 0 + "rectify_jacobian", // default = 1 + "respect_geometry", // default = 1 + "" // mark of end + }; - const char* intOptionNames[] = { "addsurf_ivertex", "anisotropic", "background", "CheckAdjacentEdges", "CheckCloseEdges", - "CheckWellDefined", "coiter", "communication", "debug", "decim", "export_flag", "file_h", "frontal", "gridnu", "gridnv", - "hinterpol_flag", "hmean_flag", "intermedfile", "memory", "normals", "optim", "pardom_flag", "pinch", "refs", - "rigid", "surforient", "tconf", "topo_collapse", - "proximity", "prox_nb_layer", "prox_ratio", // detects the volumic proximity of surfaces - "" // 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 + "" // mark of end }; - const char* doubleOptionNames[] = { "addsurf_angle", "addsurf_R", "addsurf_H", "addsurf_FG", "addsurf_r", - "addsurf_PA", "angle_compcurv", "angle_ridge", "anisotropic_ratio", "CoefRectangle", "eps_collapse", "eps_ends", "eps_pardom", "LSS", - "topo_eps1", "topo_eps2", "" // mark of end + const char* doubleOptionNames[] = { "surface_intersections_processing_max_cost",// default = 15 + "periodic_tolerance", // default = diag/100 + "prox_ratio", + "" // mark of end }; - const char* charOptionNames[] = { "export_format", "export_option", "import_option", "prefix", "" // mark of end + const char* charOptionNames[] = { "required_entities", // default = "respect" + "tags", // default = "respect" + "" // mark of end }; // PreCAD advanced options - const char* preCADintOptionNames[] = { "closed_geometry", "debug", "manifold_geometry", "create_tag_on_collision","" // mark of end + const char* preCADboolOptionNames[] = { "closed_geometry", // default = 0 + "create_tag_on_collision", // default = 1 + "debug", // default = 0 + "remove_tiny_edges", // default = 0 + "" // mark of end }; - const char* preCADdoubleOptionNames[] = { "eps_nano_relative", "eps_sewing", "eps_sewing_relative", "periodic_tolerance", - "periodic_tolerance_relative", "periodic_split_tolerance", "periodic_split_tolerance_relative", "" // mark of end + 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 + "" // mark of end + }; + const char* preCADcharOptionNames[] = { "required_entities", // default = "respect" + "tags", // default = "respect" + "" // mark of end }; int i = 0; + while (boolOptionNames[i][0]) + _option2value[boolOptionNames[i++]].clear(); + + i = 0; + while (preCADboolOptionNames[i][0]) + _preCADoption2value[preCADboolOptionNames[i++]].clear(); + + i = 0; while (intOptionNames[i][0]) _option2value[intOptionNames[i++]].clear(); @@ -125,6 +164,11 @@ BLSURFPlugin_Hypothesis::BLSURFPlugin_Hypothesis(int hypId, int studyId, SMESH_G _charOptions.insert(charOptionNames[i]); _option2value[charOptionNames[i++]].clear(); } + i = 0; + while (preCADcharOptionNames[i][0]) { + _preCADdoubleOptions.insert(preCADcharOptionNames[i]); + _preCADoption2value[preCADdoubleOptionNames[i++]].clear(); + } @@ -167,26 +211,34 @@ TopoDS_Shape BLSURFPlugin_Hypothesis::entryToShape(std::string entry) } //============================================================================= -void BLSURFPlugin_Hypothesis::SetTopology(Topology theTopology) { - if (theTopology != _topology) { - _topology = theTopology; +void BLSURFPlugin_Hypothesis::SetPhysicalMesh(PhysicalMesh thePhysicalMesh) { + if (thePhysicalMesh != _physicalMesh) { + _physicalMesh = thePhysicalMesh; NotifySubMeshesHypothesisModification(); } } //============================================================================= -void BLSURFPlugin_Hypothesis::SetPhysicalMesh(PhysicalMesh thePhysicalMesh) { - if (thePhysicalMesh != _physicalMesh) { - _physicalMesh = thePhysicalMesh; +void BLSURFPlugin_Hypothesis::SetGeometricMesh(GeometricMesh theGeometricMesh) { + if (theGeometricMesh != _geometricMesh) { + _geometricMesh = theGeometricMesh; +// switch (_geometricMesh) { +// case DefaultGeom: +// default: +// _angleMesh = GetDefaultAngleMesh(); +// _gradation = GetDefaultGradation(); +// break; +// } NotifySubMeshesHypothesisModification(); } } //============================================================================= -void BLSURFPlugin_Hypothesis::SetPhySize(double theVal) { - if (theVal != _phySize) { +void BLSURFPlugin_Hypothesis::SetPhySize(double theVal, bool isRelative) { + if ((theVal != _phySize) || (isRelative != _phySizeRel)) { + _phySizeRel = isRelative; if (theVal == 0) { - _phySize = GetPhyMax(); + _phySize = GetMaxSize(); MESSAGE("Warning: nul physical size is not allowed"); } else @@ -196,88 +248,123 @@ void BLSURFPlugin_Hypothesis::SetPhySize(double theVal) { } //============================================================================= -void BLSURFPlugin_Hypothesis::SetPhyMin(double theMinSize) { - if (theMinSize != _phyMin) { - _phyMin = theMinSize; +void BLSURFPlugin_Hypothesis::SetMinSize(double theMinSize, bool isRelative) { + if ((theMinSize != _minSize) || (isRelative != _minSizeRel)) { + _minSizeRel = isRelative; + _minSize = theMinSize; NotifySubMeshesHypothesisModification(); } } //============================================================================= -void BLSURFPlugin_Hypothesis::SetPhyMax(double theMaxSize) { - if (theMaxSize != _phyMax) { - _phyMax = theMaxSize; +void BLSURFPlugin_Hypothesis::SetMaxSize(double theMaxSize, bool isRelative) { + if ((theMaxSize != _maxSize) || (isRelative != _maxSizeRel)) { + _maxSizeRel = isRelative; + _maxSize = theMaxSize; NotifySubMeshesHypothesisModification(); } } //============================================================================= -void BLSURFPlugin_Hypothesis::SetGeoMin(double theMinSize) { - if (theMinSize != _hgeoMin) { - _hgeoMin = theMinSize; +void BLSURFPlugin_Hypothesis::SetGradation(double theVal) { + if (theVal != _gradation) { + _gradation = theVal; NotifySubMeshesHypothesisModification(); } } //============================================================================= -void BLSURFPlugin_Hypothesis::SetGeoMax(double theMaxSize) { - if (theMaxSize != _hgeoMax) { - _hgeoMax = theMaxSize; +void BLSURFPlugin_Hypothesis::SetQuadAllowed(bool theVal) { + if (theVal != _quadAllowed) { + _quadAllowed = theVal; NotifySubMeshesHypothesisModification(); } } //============================================================================= -void BLSURFPlugin_Hypothesis::SetGeometricMesh(GeometricMesh theGeometricMesh) { - if (theGeometricMesh != _geometricMesh) { - _geometricMesh = theGeometricMesh; - switch (_geometricMesh) { - case DefaultGeom: - default: - _angleMeshS = GetDefaultAngleMeshS(); - _gradation = GetDefaultGradation(); - break; - } +void BLSURFPlugin_Hypothesis::SetAngleMesh(double theVal) { + if (theVal != _angleMesh) { + _angleMesh = theVal; NotifySubMeshesHypothesisModification(); } } //============================================================================= -void BLSURFPlugin_Hypothesis::SetAngleMeshS(double theVal) { - if (theVal != _angleMeshS) { - _angleMeshS = theVal; +void BLSURFPlugin_Hypothesis::SetChordalError(double theDistance) { + if (theDistance != _chordalError) { + _chordalError = theDistance; NotifySubMeshesHypothesisModification(); } } //============================================================================= -void BLSURFPlugin_Hypothesis::SetAngleMeshC(double theVal) { - if (theVal != _angleMeshC) { - _angleMeshC = theVal; +void BLSURFPlugin_Hypothesis::SetAnisotropic(bool theVal) { + if (theVal != _anisotropic) { + _anisotropic = theVal; NotifySubMeshesHypothesisModification(); } } //============================================================================= -void BLSURFPlugin_Hypothesis::SetGradation(double theVal) { - if (theVal != _gradation) { - _gradation = theVal; +void BLSURFPlugin_Hypothesis::SetAnisotropicRatio(double theVal) { + if (theVal != _anisotropicRatio) { + _anisotropicRatio = theVal; NotifySubMeshesHypothesisModification(); } } //============================================================================= -void BLSURFPlugin_Hypothesis::SetQuadAllowed(bool theVal) { - if (theVal != _quadAllowed) { - _quadAllowed = theVal; +void BLSURFPlugin_Hypothesis::SetRemoveTinyEdges(bool theVal) { + if (theVal != _removeTinyEdges) { + _removeTinyEdges = theVal; + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +void BLSURFPlugin_Hypothesis::SetTinyEdgeLength(double theVal) { + if (theVal != _tinyEdgeLength) { + _tinyEdgeLength = theVal; NotifySubMeshesHypothesisModification(); } } //============================================================================= -void BLSURFPlugin_Hypothesis::SetDecimesh(bool theVal) { - if (theVal != _decimesh) { - _decimesh = theVal; +void BLSURFPlugin_Hypothesis::SetBadElementRemoval(bool theVal) { + if (theVal != _badElementRemoval) { + _badElementRemoval = theVal; + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +void BLSURFPlugin_Hypothesis::SetBadElementAspectRatio(double theVal) { + if (theVal != _badElementAspectRatio) { + _badElementAspectRatio = theVal; + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +void BLSURFPlugin_Hypothesis::SetOptimizeMesh(bool theVal) { + if (theVal != _optimizeMesh) { + _optimizeMesh = theVal; + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +void BLSURFPlugin_Hypothesis::SetQuadraticMesh(bool theVal) { + if (theVal != _quadraticMesh) { + _quadraticMesh = theVal; + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +void BLSURFPlugin_Hypothesis::SetTopology(Topology theTopology) { + if (theTopology != _topology) { + _topology = theTopology; NotifySubMeshesHypothesisModification(); } } @@ -293,17 +380,17 @@ void BLSURFPlugin_Hypothesis::SetVerbosity(int theVal) { //============================================================================= void BLSURFPlugin_Hypothesis::SetPreCADMergeEdges(bool theVal) { if (theVal != _preCADMergeEdges) { - SetTopology(PreCAD); +// SetTopology(PreCAD); _preCADMergeEdges = theVal; NotifySubMeshesHypothesisModification(); } } //============================================================================= -void BLSURFPlugin_Hypothesis::SetPreCADRemoveNanoEdges(bool theVal) { - if (theVal != _preCADRemoveNanoEdges) { - SetTopology(PreCAD); - _preCADRemoveNanoEdges = theVal; +void BLSURFPlugin_Hypothesis::SetPreCADProcess3DTopology(bool theVal) { + if (theVal != _preCADProcess3DTopology) { +// SetTopology(PreCAD); + _preCADProcess3DTopology = theVal; NotifySubMeshesHypothesisModification(); } } @@ -311,21 +398,12 @@ void BLSURFPlugin_Hypothesis::SetPreCADRemoveNanoEdges(bool theVal) { //============================================================================= void BLSURFPlugin_Hypothesis::SetPreCADDiscardInput(bool theVal) { if (theVal != _preCADDiscardInput) { - SetTopology(PreCAD); +// SetTopology(PreCAD); _preCADDiscardInput = theVal; NotifySubMeshesHypothesisModification(); } } -//============================================================================= -void BLSURFPlugin_Hypothesis::SetPreCADEpsNano(double theVal) { - if (theVal != _preCADEpsNano) { - SetTopology(PreCAD); - _preCADEpsNano = theVal; - NotifySubMeshesHypothesisModification(); - } -} - //============================================================================= // void BLSURFPlugin_Hypothesis::SetGMFFile(const std::string& theFileName, bool isBinary) void BLSURFPlugin_Hypothesis::SetGMFFile(const std::string& theFileName) @@ -464,7 +542,7 @@ void BLSURFPlugin_Hypothesis::ClearPreCADOption(const std::string& optionName) { //======================================================================= void BLSURFPlugin_Hypothesis::SetSizeMapEntry(const std::string& entry, const std::string& sizeMap) { if (_sizeMap[entry].compare(sizeMap) != 0) { - SetPhysicalMesh(SizeMap); + SetPhysicalMesh(PhysicalLocalSize); _sizeMap[entry] = sizeMap; NotifySubMeshesHypothesisModification(); } @@ -493,7 +571,7 @@ BLSURFPlugin_Hypothesis::TSizeMap BLSURFPlugin_Hypothesis::GetSizeMapEntries(con //======================================================================= void BLSURFPlugin_Hypothesis::SetAttractorEntry(const std::string& entry, const std::string& attractor) { if (_attractors[entry].compare(attractor) != 0) { - SetPhysicalMesh(SizeMap); + SetPhysicalMesh(PhysicalLocalSize); _attractors[entry] = attractor; NotifySubMeshesHypothesisModification(); } @@ -522,7 +600,7 @@ BLSURFPlugin_Hypothesis::TSizeMap BLSURFPlugin_Hypothesis::GetAttractorEntries(c //======================================================================= void BLSURFPlugin_Hypothesis::SetClassAttractorEntry(const std::string& entry, const std::string& attEntry, double StartSize, double EndSize, double ActionRadius, double ConstantRadius) { - SetPhysicalMesh(SizeMap); + SetPhysicalMesh(PhysicalLocalSize); // The new attractor can't be defined on the same face as another sizemap TSizeMap::iterator it = _sizeMap.find( entry ); @@ -676,7 +754,7 @@ bool BLSURFPlugin_Hypothesis::SetEnforcedVertex(TEntry theFaceEntry, TEnfName th MESSAGE("BLSURFPlugin_Hypothesis::SetEnforcedVertex("<< theFaceEntry << ", " << x << ", " << y << ", " << z << ", " << theVertexName << ", " << theVertexEntry << ", " << theGroupName << ")"); - SetPhysicalMesh(SizeMap); + SetPhysicalMesh(PhysicalLocalSize); // TEnfVertexList::iterator it; bool toNotify = false; @@ -1114,7 +1192,7 @@ void BLSURFPlugin_Hypothesis::SetInternalEnforcedVertexAllFaces(bool toEnforceIn if (toEnforceInternalVertices != _enforcedInternalVerticesAllFaces) { _enforcedInternalVerticesAllFaces = toEnforceInternalVertices; if (toEnforceInternalVertices) - SetPhysicalMesh(SizeMap); + SetPhysicalMesh(PhysicalLocalSize); NotifySubMeshesHypothesisModification(); } } @@ -1130,13 +1208,45 @@ void BLSURFPlugin_Hypothesis::SetInternalEnforcedVertexAllFacesGroup(BLSURFPlugi //============================================================================= std::ostream & BLSURFPlugin_Hypothesis::SaveTo(std::ostream & save) { + // We must keep at least the same number of arguments when increasing the SALOME version + // When BLSURF becomes CADMESH, some parameters were fused into a single one. Thus the same + // parameter can be written several times to keep the old global number of parameters. + + // Treat old options which are now in the advanced options + TOptionValues::iterator op_val; + int _decimesh = -1; + int _preCADRemoveNanoEdges = -1; + double _preCADEpsNano = -1.0; + op_val = _option2value.find("respect_geometry"); + if (op_val != _option2value.end()) { + std::string value = op_val->second; + if (!value.empty()) + _decimesh = value.compare("1") == 0 ? 1 : 0; + } + op_val = _preCADoption2value.find("remove_tiny_edges"); + if (op_val != _preCADoption2value.end()) { + std::string value = op_val->second; + if (!value.empty()) + _preCADRemoveNanoEdges = value.compare("1") == 0 ? 1 : 0; + } + op_val = _preCADoption2value.find("tiny_edge_length"); + if (op_val != _preCADoption2value.end()) { + std::string value = op_val->second; + if (!value.empty()) + _preCADEpsNano = strtod(value.c_str(), NULL); + } + save << " " << (int) _topology << " " << (int) _physicalMesh << " " << (int) _geometricMesh << " " << _phySize << " " - << _angleMeshS << " " << _gradation << " " << (int) _quadAllowed << " " << (int) _decimesh; - save << " " << _phyMin << " " << _phyMax << " " << _angleMeshC << " " << _hgeoMin << " " << _hgeoMax << " " << _verb; - save << " " << (int) _preCADMergeEdges << " " << (int) _preCADRemoveNanoEdges << " " << (int) _preCADDiscardInput << " " << _preCADEpsNano ; + << _angleMesh << " " << _gradation << " " << (int) _quadAllowed << " " << _decimesh; + save << " " << _minSize << " " << _maxSize << " " << _angleMesh << " " << _minSize << " " << _maxSize << " " << _verb; + save << " " << (int) _preCADMergeEdges << " " << _preCADRemoveNanoEdges << " " << (int) _preCADDiscardInput << " " << _preCADEpsNano ; save << " " << (int) _enforcedInternalVerticesAllFaces; + save << " " << (int) _phySizeRel << " " << (int) _minSizeRel << " " << (int) _maxSizeRel << " " << _chordalError ; + save << " " << (int) _anisotropic << " " << _anisotropicRatio << " " << (int) _removeTinyEdges << " " << _tinyEdgeLength ; + save << " " << (int) _badElementRemoval << " " << _badElementAspectRatio << " " << (int) _optimizeMesh << " " << (int) _quadraticMesh ; + save << " " << (int) _preCADProcess3DTopology; - TOptionValues::iterator op_val = _option2value.begin(); + op_val = _option2value.begin(); if (op_val != _option2value.end()) { save << " " << "__OPTIONS_BEGIN__"; for (; op_val != _option2value.end(); ++op_val) { @@ -1247,6 +1357,7 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) { bool isOK = true; int i; double val; + std::string option_or_sm; isOK = (load >> i); if (isOK) @@ -1274,7 +1385,7 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) { isOK = (load >> val); if (isOK) - _angleMeshS = val; + _angleMesh = val; else load.clear(std::ios::badbit | load.rdstate()); @@ -1291,38 +1402,46 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) { load.clear(std::ios::badbit | load.rdstate()); isOK = (load >> i); - if (isOK) - _decimesh = (bool) i; + if (isOK) { + if ( i != -1) { // if value is -1, then this is no longer a standard option + std::string & value = _option2value["respect_geometry"]; + bool _decimesh = (bool) i; + value = _decimesh ? "1" : "0"; + } + } else load.clear(std::ios::badbit | load.rdstate()); isOK = (load >> val); if (isOK) - _phyMin = val; + _minSize = val; else load.clear(std::ios::badbit | load.rdstate()); isOK = (load >> val); if (isOK) - _phyMax = val; + _maxSize = val; else load.clear(std::ios::badbit | load.rdstate()); isOK = (load >> val); if (isOK) - _angleMeshC = val; + // former parameter: get min value + _angleMesh = min(val,_angleMesh); else load.clear(std::ios::badbit | load.rdstate()); isOK = (load >> val); if (isOK) - _hgeoMin = val; + // former parameter: get min value + _minSize = min(val,_minSize); else load.clear(std::ios::badbit | load.rdstate()); isOK = (load >> val); if (isOK) - _hgeoMax = val; + // former parameter: get max value + _maxSize = max(val,_maxSize); else load.clear(std::ios::badbit | load.rdstate()); @@ -1339,8 +1458,13 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) { load.clear(std::ios::badbit | load.rdstate()); isOK = (load >> i); - if (isOK) - _preCADRemoveNanoEdges = (bool) i; + if (isOK) { + if ( i != -1) { // if value is -1, then this is no longer a standard option + std::string & value = _preCADoption2value["remove_tiny_edges"]; + bool _preCADRemoveNanoEdges = (bool) i; + value = _preCADRemoveNanoEdges ? "1" : "0"; + } + } else load.clear(std::ios::badbit | load.rdstate()); @@ -1351,8 +1475,14 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) { load.clear(std::ios::badbit | load.rdstate()); isOK = (load >> val); - if (isOK) - _preCADEpsNano = val; + if (isOK) { // _preCADEpsNano + if ( (i + 1.0) < 1e-6 ) { // if value is -1, then this is no longer a standard option: get optional value "tiny_edge_length" instead + std::string & value = _preCADoption2value["tiny_edge_length"]; + std::ostringstream oss; + oss << i; + value = oss.str(); + } + } else load.clear(std::ios::badbit | load.rdstate()); @@ -1362,7 +1492,9 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) { else load.clear(std::ios::badbit | load.rdstate()); - std::string option_or_sm; + // New options with MeshGems-CADSurf + + bool hasCADSurfOptions = false; bool hasOptions = false; bool hasPreCADOptions = false; bool hasSizeMap = false; @@ -1372,6 +1504,11 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) { isOK = (load >> option_or_sm); if (isOK) + if ( (option_or_sm == "1")||(option_or_sm == "0") ) { + i = atoi(option_or_sm.c_str()); + hasCADSurfOptions = true; + _phySizeRel = (bool) i; + } if (option_or_sm == "__OPTIONS_BEGIN__") hasOptions = true; else if (option_or_sm == "__PRECAD_OPTIONS_BEGIN__") @@ -1385,6 +1522,99 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) { else if (option_or_sm == "__ENFORCED_VERTICES_BEGIN__") hasEnforcedVertex = true; + if (isOK && hasCADSurfOptions) { + isOK = (load >> i); + if (isOK) + _minSizeRel = (bool) i; + else + load.clear(std::ios::badbit | load.rdstate()); + + isOK = (load >> i); + if (isOK) + _maxSizeRel = (bool) i; + else + load.clear(std::ios::badbit | load.rdstate()); + + isOK = (load >> val); + if (isOK) + _chordalError = val; + else + load.clear(std::ios::badbit | load.rdstate()); + + isOK = (load >> i); + if (isOK) + _anisotropic = (bool) i; + else + load.clear(std::ios::badbit | load.rdstate()); + + isOK = (load >> val); + if (isOK) + _anisotropicRatio = val; + else + load.clear(std::ios::badbit | load.rdstate()); + + isOK = (load >> i); + if (isOK) + _removeTinyEdges = (bool) i; + else + load.clear(std::ios::badbit | load.rdstate()); + + isOK = (load >> val); + if (isOK) + _tinyEdgeLength = val; + else + load.clear(std::ios::badbit | load.rdstate()); + + isOK = (load >> i); + if (isOK) + _badElementRemoval = (bool) i; + else + load.clear(std::ios::badbit | load.rdstate()); + + isOK = (load >> val); + if (isOK) + _badElementAspectRatio = val; + else + load.clear(std::ios::badbit | load.rdstate()); + + isOK = (load >> i); + if (isOK) + _optimizeMesh = (bool) i; + else + load.clear(std::ios::badbit | load.rdstate()); + + isOK = (load >> i); + if (isOK) + _quadraticMesh = (bool) i; + else + load.clear(std::ios::badbit | load.rdstate()); + + isOK = (load >> i); + if (isOK) + _preCADProcess3DTopology = (bool) i; + else + load.clear(std::ios::badbit | load.rdstate()); + + } + + + if (hasCADSurfOptions) { + isOK = (load >> option_or_sm); + if (isOK) + if (option_or_sm == "__OPTIONS_BEGIN__") + hasOptions = true; + else if (option_or_sm == "__PRECAD_OPTIONS_BEGIN__") + hasPreCADOptions = 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; + } + std::string optName, optValue; while (isOK && hasOptions) { isOK = (load >> optName); @@ -1731,79 +1961,81 @@ bool BLSURFPlugin_Hypothesis::SetParametersByMesh(const SMESH_Mesh* theMesh, con return false; } -//============================================================================= +//================================================================================ /*! - * \brief Initialize my parameter values by default parameters. - * \retval bool - true if parameter values have been successfully defined + * \brief Returns default global constant physical size given a default value of element length ratio */ -//============================================================================= +//================================================================================ -bool BLSURFPlugin_Hypothesis::SetParametersByDefaults(const TDefaults& dflts, const SMESH_Mesh* theMesh) { - return bool(_phySize = dflts._elemLength); +double BLSURFPlugin_Hypothesis::GetDefaultPhySize(double diagonal, double bbSegmentation) { + if (bbSegmentation != 0 && diagonal != 0) + return diagonal / bbSegmentation ; + return 10; } -//============================================================================= -BLSURFPlugin_Hypothesis::Topology BLSURFPlugin_Hypothesis::GetDefaultTopology() { - return FromCAD; -} +//================================================================================ +/*! + * \brief Returns default min size given a default value of element length ratio + */ +//================================================================================ -//============================================================================= -BLSURFPlugin_Hypothesis::PhysicalMesh BLSURFPlugin_Hypothesis::GetDefaultPhysicalMesh() { - return PhysicalUserDefined; +double BLSURFPlugin_Hypothesis::GetDefaultMinSize(double diagonal) { + if (diagonal != 0) + return diagonal / 1000.0 ; + return undefinedDouble(); } -//============================================================================= -double BLSURFPlugin_Hypothesis::GetDefaultPhySize() { - return 10; -} +//================================================================================ +/*! + * \brief Returns default max size given a default value of element length ratio + */ +//================================================================================ -//====================================================================== -double BLSURFPlugin_Hypothesis::GetDefaultMaxSize() { - return undefinedDouble(); // 1e+4; +double BLSURFPlugin_Hypothesis::GetDefaultMaxSize(double diagonal) { + if (diagonal != 0) + return diagonal / 5.0 ; + return undefinedDouble(); } -//====================================================================== -double BLSURFPlugin_Hypothesis::GetDefaultMinSize() { - return undefinedDouble(); //1e-4; -} +//================================================================================ +/*! + * \brief Returns default chordal error given a default value of element length ratio + */ +//================================================================================ -//====================================================================== -BLSURFPlugin_Hypothesis::GeometricMesh BLSURFPlugin_Hypothesis::GetDefaultGeometricMesh() { - return DefaultGeom; +double BLSURFPlugin_Hypothesis::GetDefaultChordalError(double diagonal) { + if (diagonal != 0) + return diagonal; + return undefinedDouble(); } -//============================================================================= -double BLSURFPlugin_Hypothesis::GetDefaultAngleMeshS() { - return 8; -} +//================================================================================ +/*! + * \brief Returns default tiny edge length given a default value of element length ratio + */ +//================================================================================ -//============================================================================= -double BLSURFPlugin_Hypothesis::GetDefaultGradation() { - return 1.1; +double BLSURFPlugin_Hypothesis::GetDefaultTinyEdgeLength(double diagonal) { + if (diagonal != 0) + return diagonal * 1e-6 ; + return undefinedDouble(); } //============================================================================= -bool BLSURFPlugin_Hypothesis::GetDefaultQuadAllowed() { - return false; -} - +/*! + * \brief Initialize my parameter values by default parameters. + * \retval bool - true if parameter values have been successfully defined + */ //============================================================================= -bool BLSURFPlugin_Hypothesis::GetDefaultDecimesh() { - return false; -} - -//====================================================================== -double BLSURFPlugin_Hypothesis::GetDefaultPreCADEpsNano() { - return undefinedDouble(); //1e-4; -} -//====================================================================== -std::string BLSURFPlugin_Hypothesis::GetDefaultGMFFile() { - return ""; -} +bool BLSURFPlugin_Hypothesis::SetParametersByDefaults(const TDefaults& dflts, const SMESH_Mesh* theMesh) { + double diagonal = dflts._elemLength*_gen->GetBoundaryBoxSegmentation(); + _phySize = GetDefaultPhySize(diagonal, _gen->GetBoundaryBoxSegmentation()); + _minSize = GetDefaultMinSize(diagonal); + _maxSize = GetDefaultMaxSize(diagonal); + _chordalError = GetDefaultChordalError(diagonal); + _tinyEdgeLength = GetDefaultTinyEdgeLength(diagonal); -//============================================================================= -bool BLSURFPlugin_Hypothesis::GetDefaultInternalEnforcedVertex() { - return false; + return true; +// return bool(_phySize = dflts._elemLength); } - diff --git a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.hxx b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.hxx index 2b014b0..7475444 100644 --- a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.hxx +++ b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.hxx @@ -54,48 +54,37 @@ public: enum PhysicalMesh { DefaultSize, - PhysicalUserDefined, - SizeMap + PhysicalGlobalSize, + PhysicalLocalSize }; enum GeometricMesh { DefaultGeom, - UserDefined + GeometricalGlobalSize, + GeometricalLocalSize }; static const char* GetHypType() { return "BLSURF_Parameters"; } TopoDS_Shape entryToShape(std::string entry); - void SetTopology(Topology theTopology); - Topology GetTopology() const { return _topology; } - void SetPhysicalMesh(PhysicalMesh thePhysicalMesh); PhysicalMesh GetPhysicalMesh() const { return _physicalMesh; } - void SetPhySize(double thePhySize); - double GetPhySize() const { return _phySize; } - - void SetPhyMin(double theMinSize); - double GetPhyMin() const { return _phyMin; } - - void SetPhyMax(double theMaxSize); - double GetPhyMax() const { return _phyMax; } - void SetGeometricMesh(GeometricMesh theGeometricMesh); GeometricMesh GetGeometricMesh() const { return _geometricMesh; } - void SetAngleMeshS(double theAngle); - double GetAngleMeshS() const { return _angleMeshS; } - - void SetAngleMeshC(double theAngle); - double GetAngleMeshC() const { return _angleMeshC; } + void SetPhySize(double thePhySize, bool isRelative = false); + double GetPhySize() const { return _phySize; } + bool IsPhySizeRel() const { return _phySizeRel; } - void SetGeoMin(double theMinSize); - double GetGeoMin() const { return _hgeoMin; } + void SetMinSize(double theMinSize, bool isRelative = false); + double GetMinSize() const { return _minSize; } + bool IsMinSizeRel() const { return _minSizeRel; } - void SetGeoMax(double theMaxSize); - double GetGeoMax() const { return _hgeoMax; } + void SetMaxSize(double theMaxSize, bool isRelative = false); + double GetMaxSize() const { return _maxSize; } + bool IsMaxSizeRel() const { return _maxSizeRel; } void SetGradation(double theGradation); double GetGradation() const { return _gradation; } @@ -103,8 +92,38 @@ public: void SetQuadAllowed(bool theVal); bool GetQuadAllowed() const { return _quadAllowed; } - void SetDecimesh(bool theVal); - bool GetDecimesh() const { return _decimesh; } + void SetAngleMesh(double theAngle); + double GetAngleMesh() const { return _angleMesh; } + + void SetChordalError(double theDistance); + double GetChordalError() const { return _chordalError; } + + void SetAnisotropic(bool theVal); + bool GetAnisotropic() const { return _anisotropic; } + + void SetAnisotropicRatio(double theVal); + double GetAnisotropicRatio() const { return _anisotropicRatio; } + + void SetRemoveTinyEdges(bool theVal); + bool GetRemoveTinyEdges() const { return _removeTinyEdges; } + + void SetTinyEdgeLength(double theVal); + double GetTinyEdgeLength() const { return _tinyEdgeLength; } + + void SetBadElementRemoval(bool theVal); + bool GetBadElementRemoval() const { return _badElementRemoval; } + + void SetBadElementAspectRatio(double theVal); + double GetBadElementAspectRatio() const { return _badElementAspectRatio; } + + void SetOptimizeMesh(bool theVal); + bool GetOptimizeMesh() const { return _optimizeMesh; } + + void SetQuadraticMesh(bool theVal); + bool GetQuadraticMesh() const { return _quadraticMesh; } + + void SetTopology(Topology theTopology); + Topology GetTopology() const { return _topology; } void SetVerbosity(int theVal); int GetVerbosity() const { return _verb; } @@ -115,14 +134,11 @@ public: void SetPreCADMergeEdges(bool theVal); bool GetPreCADMergeEdges() const { return _preCADMergeEdges; } - void SetPreCADRemoveNanoEdges(bool theVal); - bool GetPreCADRemoveNanoEdges() const { return _preCADRemoveNanoEdges; } + void SetPreCADProcess3DTopology(bool theVal); + bool GetPreCADProcess3DTopology() const { return _preCADProcess3DTopology; } void SetPreCADDiscardInput(bool theVal); bool GetPreCADDiscardInput() const { return _preCADDiscardInput; } - - void SetPreCADEpsNano(double theVal); - double GetPreCADEpsNano() const { return _preCADEpsNano; } typedef std::map TSizeMap; @@ -286,23 +302,39 @@ public: // void SetInternalEnforcedVertex(TEntry theFaceEntry, bool toEnforceInternalVertices, TEnfGroupName theGroupName); // bool GetInternalEnforcedVertex(const TEntry& theFaceEntry); - static Topology GetDefaultTopology(); - static PhysicalMesh GetDefaultPhysicalMesh(); - static double GetDefaultPhySize(); - static double GetDefaultMaxSize(); - static double GetDefaultMinSize(); - static GeometricMesh GetDefaultGeometricMesh(); - static double GetDefaultAngleMeshS(); - static double GetDefaultAngleMeshC() { return GetDefaultAngleMeshS(); } - static double GetDefaultGradation(); - static bool GetDefaultQuadAllowed(); - static bool GetDefaultDecimesh(); - static int GetDefaultVerbosity() { return 10; } + static PhysicalMesh GetDefaultPhysicalMesh() { return PhysicalGlobalSize; } + static GeometricMesh GetDefaultGeometricMesh() { return DefaultGeom; } + static double GetDefaultPhySize(double diagonal, double bbSegmentation); + static double GetDefaultPhySize() { return undefinedDouble(); } + static bool GetDefaultPhySizeRel() { return false; } + static double GetDefaultMinSize(double diagonal); + static double GetDefaultMinSize() { return undefinedDouble(); } + static bool GetDefaultMinSizeRel() { return false; } + static double GetDefaultMaxSize(double diagonal); + static double GetDefaultMaxSize() { return undefinedDouble(); } + static bool GetDefaultMaxSizeRel() { return false; } + static double GetDefaultGradation() { return 1.3; } + static bool GetDefaultQuadAllowed() { return false; } + static double GetDefaultAngleMesh() { return 22.0; } + + static double GetDefaultChordalError(double diagonal); + static double GetDefaultChordalError() { return undefinedDouble(); } + static bool GetDefaultAnisotropic() { return false; } + static double GetDefaultAnisotropicRatio() { return 0.0; } + static bool GetDefaultRemoveTinyEdges() { return false; } + static double GetDefaultTinyEdgeLength(double diagonal); + static double GetDefaultTinyEdgeLength() { return undefinedDouble(); } + static bool GetDefaultBadElementRemoval() { return false; } + static double GetDefaultBadElementAspectRatio() {return 1000.0; } + static bool GetDefaultOptimizeMesh() { return true; } + static bool GetDefaultQuadraticMesh() { return false; } + + static int GetDefaultVerbosity() { return 3; } + static Topology GetDefaultTopology() { return FromCAD; } // PreCAD - static bool GetDefaultPreCADMergeEdges() { return false; } - static bool GetDefaultPreCADRemoveNanoEdges() { return false; } + static bool GetDefaultPreCADMergeEdges() { return true; } + static bool GetDefaultPreCADProcess3DTopology() { return true; } static bool GetDefaultPreCADDiscardInput() { return false; } - static double GetDefaultPreCADEpsNano(); static TSizeMap GetDefaultSizeMap() { return TSizeMap();} static TAttractorMap GetDefaultAttractorMap() { return TAttractorMap(); } @@ -315,7 +347,7 @@ public: static TEnfVertexEntryEnfVertexMap GetDefaultEnfVertexEntryEnfVertexMap() { return TEnfVertexEntryEnfVertexMap(); } static TGroupNameNodeIDMap GetDefaultGroupNameNodeIDMap() { return TGroupNameNodeIDMap(); } - static bool GetDefaultInternalEnforcedVertex(); + static bool GetDefaultInternalEnforcedVertex() { return false; } /* TODO GROUPS static TGroupNameEnfVertexListMap GetDefaultGroupNameEnfVertexListMap() { return TGroupNameEnfVertexListMap(); } @@ -344,7 +376,7 @@ public: // void SetGMFFile(const std::string& theFileName, bool isBinary); void SetGMFFile(const std::string& theFileName); std::string GetGMFFile() const { return _GMFFileName; } - static std::string GetDefaultGMFFile(); + static std::string GetDefaultGMFFile() { return "";} // bool GetGMFFileMode() const { return _GMFFileMode; } // Persistence @@ -369,23 +401,35 @@ public: private: - Topology _topology; PhysicalMesh _physicalMesh; - double _phySize, _phyMin, _phyMax; GeometricMesh _geometricMesh; - double _angleMeshS, _angleMeshC, _hgeoMin, _hgeoMax; + double _phySize; + bool _phySizeRel; + double _minSize, _maxSize; + bool _minSizeRel, _maxSizeRel; double _gradation; bool _quadAllowed; - bool _decimesh; + double _angleMesh; + double _chordalError; + bool _anisotropic; + double _anisotropicRatio; + bool _removeTinyEdges; + double _tinyEdgeLength; + bool _badElementRemoval; + double _badElementAspectRatio; + bool _optimizeMesh; + bool _quadraticMesh; int _verb; + Topology _topology; bool _preCADMergeEdges; - bool _preCADRemoveNanoEdges; + bool _preCADProcess3DTopology; bool _preCADDiscardInput; double _preCADEpsNano; TOptionValues _option2value, _preCADoption2value; - TOptionNames _doubleOptions, _charOptions, _preCADdoubleOptions, _preCADcharOptions; + TOptionNames _doubleOptions, _charOptions; + TOptionNames _preCADdoubleOptions, _preCADcharOptions; TSizeMap _sizeMap; TSizeMap _attractors; TAttractorMap _classAttractors; diff --git a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.cxx b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.cxx index 0190ed0..77af19a 100644 --- a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.cxx +++ b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.cxx @@ -61,61 +61,62 @@ BLSURFPlugin_Hypothesis_i::~BLSURFPlugin_Hypothesis_i() { MESSAGE( "BLSURFPlugin_Hypothesis_i::~BLSURFPlugin_Hypothesis_i" ); } +//============================================================================= + +//============================================================================= /*! - * BLSURFPlugin_Hypothesis_i::SetTopology + * BLSURFPlugin_Hypothesis_i::SetPhysicalMesh * - * Set topology + * Set PhysicalMesh */ //============================================================================= -void BLSURFPlugin_Hypothesis_i::SetTopology(CORBA::Long theValue) { - // MESSAGE("BLSURFPlugin_Hypothesis_i::SetTopology"); +void BLSURFPlugin_Hypothesis_i::SetPhysicalMesh(CORBA::Long theValue) { + // MESSAGE("BLSURFPlugin_Hypothesis_i::SetPhysicalMesh"); ASSERT(myBaseImpl); - this->GetImpl()->SetTopology((::BLSURFPlugin_Hypothesis::Topology) theValue); - SMESH::TPythonDump() << _this() << ".SetTopology( " << theValue << " )"; + this->GetImpl()->SetPhysicalMesh((::BLSURFPlugin_Hypothesis::PhysicalMesh) theValue); + SMESH::TPythonDump() << _this() << ".SetPhysicalMesh( " << theValue << " )"; } //============================================================================= /*! - * BLSURFPlugin_Hypothesis_i::GetTopology + * BLSURFPlugin_Hypothesis_i::GetPhysicalMesh * - * Get Topology + * Get PhysicalMesh */ //============================================================================= -CORBA::Long BLSURFPlugin_Hypothesis_i::GetTopology() { - // MESSAGE("BLSURFPlugin_Hypothesis_i::GetTopology"); +CORBA::Long BLSURFPlugin_Hypothesis_i::GetPhysicalMesh() { + // MESSAGE("BLSURFPlugin_Hypothesis_i::GetPhysicalMesh"); ASSERT(myBaseImpl); - return this->GetImpl()->GetTopology(); + return this->GetImpl()->GetPhysicalMesh(); } -//============================================================================= - //============================================================================= /*! - * BLSURFPlugin_Hypothesis_i::SetPhysicalMesh + * BLSURFPlugin_Hypothesis_i::SetGeometricMesh * - * Set PhysicalMesh + * Set GeometricMesh */ //============================================================================= -void BLSURFPlugin_Hypothesis_i::SetPhysicalMesh(CORBA::Long theValue) { - // MESSAGE("BLSURFPlugin_Hypothesis_i::SetPhysicalMesh"); +void BLSURFPlugin_Hypothesis_i::SetGeometricMesh(CORBA::Long theValue) { + // MESSAGE("BLSURFPlugin_Hypothesis_i::SetGeometricMesh"); ASSERT(myBaseImpl); - this->GetImpl()->SetPhysicalMesh((::BLSURFPlugin_Hypothesis::PhysicalMesh) theValue); - SMESH::TPythonDump() << _this() << ".SetPhysicalMesh( " << theValue << " )"; + this->GetImpl()->SetGeometricMesh((::BLSURFPlugin_Hypothesis::GeometricMesh) theValue); + SMESH::TPythonDump() << _this() << ".SetGeometricMesh( " << theValue << " )"; } //============================================================================= /*! - * BLSURFPlugin_Hypothesis_i::GetPhysicalMesh + * BLSURFPlugin_Hypothesis_i::GetGeometricMesh * - * Get PhysicalMesh + * Get GeometricMesh */ //============================================================================= -CORBA::Long BLSURFPlugin_Hypothesis_i::GetPhysicalMesh() { - // MESSAGE("BLSURFPlugin_Hypothesis_i::GetPhysicalMesh"); +CORBA::Long BLSURFPlugin_Hypothesis_i::GetGeometricMesh() { + // MESSAGE("BLSURFPlugin_Hypothesis_i::GetGeometricMesh"); ASSERT(myBaseImpl); - return this->GetImpl()->GetPhysicalMesh(); + return this->GetImpl()->GetGeometricMesh(); } //============================================================================= @@ -128,10 +129,24 @@ CORBA::Long BLSURFPlugin_Hypothesis_i::GetPhysicalMesh() { void BLSURFPlugin_Hypothesis_i::SetPhySize(CORBA::Double theValue) { // MESSAGE("BLSURFPlugin_Hypothesis_i::SetPhySize"); ASSERT(myBaseImpl); - this->GetImpl()->SetPhySize(theValue); + this->GetImpl()->SetPhySize(theValue, false); SMESH::TPythonDump() << _this() << ".SetPhySize( " << theValue << " )"; } +//============================================================================= +/*! + * BLSURFPlugin_Hypothesis_i::SetPhySizeRel + * + * Set Relative PhySize + */ +//============================================================================= +void BLSURFPlugin_Hypothesis_i::SetPhySizeRel(CORBA::Double theValue) { +// MESSAGE("BLSURFPlugin_Hypothesis_i::SetPhySizeRel"); + ASSERT(myBaseImpl); + this->GetImpl()->SetPhySize(theValue, true); + SMESH::TPythonDump() << _this() << ".SetPhySize( " << theValue << ", isRelative = True )"; +} + //============================================================================= /*! * BLSURFPlugin_Hypothesis_i::GetPhySize @@ -146,214 +161,440 @@ CORBA::Double BLSURFPlugin_Hypothesis_i::GetPhySize() { } //============================================================================= -void BLSURFPlugin_Hypothesis_i::SetPhyMin(CORBA::Double theMinSize) { +/*! + * BLSURFPlugin_Hypothesis_i::IsPhySizeRel + * + * Returns True if PhySize is relative + */ +//============================================================================= +CORBA::Boolean BLSURFPlugin_Hypothesis_i::IsPhySizeRel() { +// MESSAGE("BLSURFPlugin_Hypothesis_i::IsPhySizeRel"); ASSERT(myBaseImpl); - if (GetPhyMin() != theMinSize) { - this->GetImpl()->SetPhyMin(theMinSize); - SMESH::TPythonDump() << _this() << ".SetPhyMin( " << theMinSize << " )"; + return this->GetImpl()->IsPhySizeRel(); +} + +//============================================================================= +void BLSURFPlugin_Hypothesis_i::SetMinSize(CORBA::Double theMinSize) { + ASSERT(myBaseImpl); + if (GetMinSize() != theMinSize) { + this->GetImpl()->SetMinSize(theMinSize, false); + SMESH::TPythonDump() << _this() << ".SetMinSize( " << theMinSize << " )"; } } //============================================================================= -CORBA::Double BLSURFPlugin_Hypothesis_i::GetPhyMin() { +void BLSURFPlugin_Hypothesis_i::SetMinSizeRel(CORBA::Double theMinSize) { ASSERT(myBaseImpl); - return this->GetImpl()->GetPhyMin(); + if ( IsMinSizeRel() && (GetMinSize() != theMinSize) ) { + this->GetImpl()->SetMinSize(theMinSize, true); + SMESH::TPythonDump() << _this() << ".SetMinSize( " << theMinSize << ", isRelative = True )"; + } } //============================================================================= -void BLSURFPlugin_Hypothesis_i::SetPhyMax(CORBA::Double theMaxSize) { +CORBA::Double BLSURFPlugin_Hypothesis_i::GetMinSize() { ASSERT(myBaseImpl); - if (GetPhyMax() != theMaxSize) { - this->GetImpl()->SetPhyMax(theMaxSize); - SMESH::TPythonDump() << _this() << ".SetPhyMax( " << theMaxSize << " )"; + return this->GetImpl()->GetMinSize(); +} + +//============================================================================= +CORBA::Boolean BLSURFPlugin_Hypothesis_i::IsMinSizeRel() { +// MESSAGE("BLSURFPlugin_Hypothesis_i::IsMinSizeRel"); + ASSERT(myBaseImpl); + return this->GetImpl()->IsMinSizeRel(); +} + +//============================================================================= +void BLSURFPlugin_Hypothesis_i::SetMaxSize(CORBA::Double theMaxSize) { + ASSERT(myBaseImpl); + if (GetMaxSize() != theMaxSize) { + this->GetImpl()->SetMaxSize(theMaxSize, false); + SMESH::TPythonDump() << _this() << ".SetMaxSize( " << theMaxSize << " )"; } } //============================================================================= -CORBA::Double BLSURFPlugin_Hypothesis_i::GetPhyMax() { +void BLSURFPlugin_Hypothesis_i::SetMaxSizeRel(CORBA::Double theMaxSize) { ASSERT(myBaseImpl); - return this->GetImpl()->GetPhyMax(); + if ( IsMaxSizeRel() && (GetMaxSize() != theMaxSize) ) { + this->GetImpl()->SetMaxSize(theMaxSize, true); + SMESH::TPythonDump() << _this() << ".SetMaxSize( " << theMaxSize << ", isRelative = True )"; + } +} + +//============================================================================= +CORBA::Double BLSURFPlugin_Hypothesis_i::GetMaxSize() { + ASSERT(myBaseImpl); + return this->GetImpl()->GetMaxSize(); +} + +//============================================================================= +CORBA::Boolean BLSURFPlugin_Hypothesis_i::IsMaxSizeRel() { +// MESSAGE("BLSURFPlugin_Hypothesis_i::IsMaxSizeRel"); + ASSERT(myBaseImpl); + return this->GetImpl()->IsMaxSizeRel(); } //============================================================================= /*! - * BLSURFPlugin_Hypothesis_i::SetGeometricMesh + * BLSURFPlugin_Hypothesis_i::SetGradation * - * Set GeometricMesh + * Set Gradation */ +//============================================================================= +void BLSURFPlugin_Hypothesis_i::SetGradation(CORBA::Double theValue) { + // MESSAGE("BLSURFPlugin_Hypothesis_i::SetGradation"); + ASSERT(myBaseImpl); + this->GetImpl()->SetGradation(theValue); + SMESH::TPythonDump() << _this() << ".SetGradation( " << theValue << " )"; +} //============================================================================= -void BLSURFPlugin_Hypothesis_i::SetGeometricMesh(CORBA::Long theValue) { - // MESSAGE("BLSURFPlugin_Hypothesis_i::SetGeometricMesh"); +/*! + * BLSURFPlugin_Hypothesis_i::GetGradation + * + * Get Gradation + */ +//============================================================================= +CORBA::Double BLSURFPlugin_Hypothesis_i::GetGradation() { + // MESSAGE("BLSURFPlugin_Hypothesis_i::GetGradation"); ASSERT(myBaseImpl); - this->GetImpl()->SetGeometricMesh((::BLSURFPlugin_Hypothesis::GeometricMesh) theValue); - SMESH::TPythonDump() << _this() << ".SetGeometricMesh( " << theValue << " )"; + return this->GetImpl()->GetGradation(); } //============================================================================= /*! - * BLSURFPlugin_Hypothesis_i::GetGeometricMesh + * BLSURFPlugin_Hypothesis_i::SetQuadAllowed * - * Get GeometricMesh + * Set true or false */ //============================================================================= -CORBA::Long BLSURFPlugin_Hypothesis_i::GetGeometricMesh() { - // MESSAGE("BLSURFPlugin_Hypothesis_i::GetGeometricMesh"); +void BLSURFPlugin_Hypothesis_i::SetQuadAllowed(CORBA::Boolean theValue) { + // MESSAGE("BLSURFPlugin_Hypothesis_i::SetQuadAllowed"); ASSERT(myBaseImpl); - return this->GetImpl()->GetGeometricMesh(); + this->GetImpl()->SetQuadAllowed(theValue); + std::string theValueStr = theValue ? "True" : "False"; + SMESH::TPythonDump() << _this() << ".SetQuadAllowed( " << theValueStr.c_str() << " )"; } //============================================================================= /*! - * BLSURFPlugin_Hypothesis_i::SetAngleMeshS + * BLSURFPlugin_Hypothesis_i::GetQuadAllowed * - * Set AngleMeshS + * Get true or false */ //============================================================================= -void BLSURFPlugin_Hypothesis_i::SetAngleMeshS(CORBA::Double theValue) { - // MESSAGE("BLSURFPlugin_Hypothesis_i::SetAngleMeshS"); +CORBA::Boolean BLSURFPlugin_Hypothesis_i::GetQuadAllowed() { + // MESSAGE("BLSURFPlugin_Hypothesis_i::GetQuadAllowed"); ASSERT(myBaseImpl); - this->GetImpl()->SetAngleMeshS(theValue); - SMESH::TPythonDump() << _this() << ".SetAngleMeshS( " << theValue << " )"; + return this->GetImpl()->GetQuadAllowed(); } //============================================================================= /*! - * BLSURFPlugin_Hypothesis_i::GetAngleMeshS + * BLSURFPlugin_Hypothesis_i::SetAngleMesh * - * Get AngleMeshS + * Set AngleMesh */ //============================================================================= -CORBA::Double BLSURFPlugin_Hypothesis_i::GetAngleMeshS() { - // MESSAGE("BLSURFPlugin_Hypothesis_i::GetAngleMeshS"); +void BLSURFPlugin_Hypothesis_i::SetAngleMesh(CORBA::Double theValue) { + // MESSAGE("BLSURFPlugin_Hypothesis_i::SetAngleMesh"); ASSERT(myBaseImpl); - return this->GetImpl()->GetAngleMeshS(); + this->GetImpl()->SetAngleMesh(theValue); + SMESH::TPythonDump() << _this() << ".SetAngleMesh( " << theValue << " )"; } //============================================================================= -void BLSURFPlugin_Hypothesis_i::SetAngleMeshC(CORBA::Double angle) { +/*! + * BLSURFPlugin_Hypothesis_i::GetAngleMesh + * + * Get AngleMesh + */ +//============================================================================= +CORBA::Double BLSURFPlugin_Hypothesis_i::GetAngleMesh() { + // MESSAGE("BLSURFPlugin_Hypothesis_i::GetAngleMesh"); ASSERT(myBaseImpl); - this->GetImpl()->SetAngleMeshC(angle); - SMESH::TPythonDump() << _this() << ".SetAngleMeshC( " << angle << " )"; + return this->GetImpl()->GetAngleMesh(); } //============================================================================= -CORBA::Double BLSURFPlugin_Hypothesis_i::GetAngleMeshC() { +/*! + * BLSURFPlugin_Hypothesis_i::SetChordalError + * + * Set Chordal Error + */ +//============================================================================= +void BLSURFPlugin_Hypothesis_i::SetChordalError(CORBA::Double theValue) { + // MESSAGE("BLSURFPlugin_Hypothesis_i::SetChordalError"); ASSERT(myBaseImpl); - return this->GetImpl()->GetAngleMeshC(); + this->GetImpl()->SetChordalError(theValue); + SMESH::TPythonDump() << _this() << ".SetChordalError( " << theValue << " )"; } //============================================================================= -void BLSURFPlugin_Hypothesis_i::SetGeoMin(CORBA::Double theMinSize) { +/*! + * BLSURFPlugin_Hypothesis_i::GetChordalError + * + * Get Chordal Error + */ +//============================================================================= +CORBA::Double BLSURFPlugin_Hypothesis_i::GetChordalError() { + // MESSAGE("BLSURFPlugin_Hypothesis_i::GetChordalError"); ASSERT(myBaseImpl); - if (GetGeoMin() != theMinSize) { - this->GetImpl()->SetGeoMin(theMinSize); - SMESH::TPythonDump() << _this() << ".SetGeoMin( " << theMinSize << " )"; - } + return this->GetImpl()->GetChordalError(); } //============================================================================= -CORBA::Double BLSURFPlugin_Hypothesis_i::GetGeoMin() { +/*! + * BLSURFPlugin_Hypothesis_i::SetAnisotropic + * + * Set true or false + */ +//============================================================================= +void BLSURFPlugin_Hypothesis_i::SetAnisotropic(CORBA::Boolean theValue) { + // MESSAGE("BLSURFPlugin_Hypothesis_i::SetAnisotropic"); ASSERT(myBaseImpl); - return this->GetImpl()->GetGeoMin(); + this->GetImpl()->SetAnisotropic(theValue); + std::string theValueStr = theValue ? "True" : "False"; + SMESH::TPythonDump() << _this() << ".SetAnisotropic( " << theValueStr.c_str() << " )"; } //============================================================================= -void BLSURFPlugin_Hypothesis_i::SetGeoMax(CORBA::Double theMaxSize) { +/*! + * BLSURFPlugin_Hypothesis_i::GetAnisotropic + * + * Get true or false + */ +//============================================================================= +CORBA::Boolean BLSURFPlugin_Hypothesis_i::GetAnisotropic() { + // MESSAGE("BLSURFPlugin_Hypothesis_i::GetAnisotropic"); ASSERT(myBaseImpl); - if (GetGeoMax() != theMaxSize) { - this->GetImpl()->SetGeoMax(theMaxSize); - SMESH::TPythonDump() << _this() << ".SetGeoMax( " << theMaxSize << " )"; - } + return this->GetImpl()->GetAnisotropic(); } //============================================================================= -CORBA::Double BLSURFPlugin_Hypothesis_i::GetGeoMax() { +/*! + * BLSURFPlugin_Hypothesis_i::SetAnisotropicRatio + * + * Set Anisotropic Ratio + */ +//============================================================================= +void BLSURFPlugin_Hypothesis_i::SetAnisotropicRatio(CORBA::Double theValue) { + // MESSAGE("BLSURFPlugin_Hypothesis_i::SetAnisotropicRatio"); ASSERT(myBaseImpl); - return this->GetImpl()->GetGeoMax(); + this->GetImpl()->SetAnisotropicRatio(theValue); + SMESH::TPythonDump() << _this() << ".SetAnisotropicRatio( " << theValue << " )"; } //============================================================================= /*! - * BLSURFPlugin_Hypothesis_i::SetGradation + * BLSURFPlugin_Hypothesis_i::GetAnisotropicRatio * - * Set Gradation + * Get Anisotropic Ratio */ //============================================================================= -void BLSURFPlugin_Hypothesis_i::SetGradation(CORBA::Double theValue) { - // MESSAGE("BLSURFPlugin_Hypothesis_i::SetGradation"); +CORBA::Double BLSURFPlugin_Hypothesis_i::GetAnisotropicRatio() { + // MESSAGE("BLSURFPlugin_Hypothesis_i::GetAnisotropicRatio"); ASSERT(myBaseImpl); - this->GetImpl()->SetGradation(theValue); - SMESH::TPythonDump() << _this() << ".SetGradation( " << theValue << " )"; + return this->GetImpl()->GetAnisotropicRatio(); } + //============================================================================= /*! - * BLSURFPlugin_Hypothesis_i::GetGradation + * BLSURFPlugin_Hypothesis_i::SetRemoveTinyEdges * - * Get Gradation + * Set true or false */ //============================================================================= -CORBA::Double BLSURFPlugin_Hypothesis_i::GetGradation() { - // MESSAGE("BLSURFPlugin_Hypothesis_i::GetGradation"); +void BLSURFPlugin_Hypothesis_i::SetRemoveTinyEdges(CORBA::Boolean theValue) { + // MESSAGE("BLSURFPlugin_Hypothesis_i::SetRemoveTinyEdges"); ASSERT(myBaseImpl); - return this->GetImpl()->GetGradation(); + this->GetImpl()->SetRemoveTinyEdges(theValue); + std::string theValueStr = theValue ? "True" : "False"; + SMESH::TPythonDump() << _this() << ".SetRemoveTinyEdges( " << theValueStr.c_str() << " )"; } //============================================================================= /*! - * BLSURFPlugin_Hypothesis_i::SetQuadAllowed + * BLSURFPlugin_Hypothesis_i::GetRemoveTinyEdges + * + * Get true or false + */ +//============================================================================= +CORBA::Boolean BLSURFPlugin_Hypothesis_i::GetRemoveTinyEdges() { + // MESSAGE("BLSURFPlugin_Hypothesis_i::GetRemoveTinyEdges"); + ASSERT(myBaseImpl); + return this->GetImpl()->GetRemoveTinyEdges(); +} + +//============================================================================= +/*! + * BLSURFPlugin_Hypothesis_i::SetTinyEdgeLength + * + * Set Tiny Edge Length + */ +//============================================================================= +void BLSURFPlugin_Hypothesis_i::SetTinyEdgeLength(CORBA::Double theValue) { + // MESSAGE("BLSURFPlugin_Hypothesis_i::SetTinyEdgeLength"); + ASSERT(myBaseImpl); + this->GetImpl()->SetTinyEdgeLength(theValue); + SMESH::TPythonDump() << _this() << ".SetTinyEdgeLength( " << theValue << " )"; +} + +//============================================================================= +/*! + * BLSURFPlugin_Hypothesis_i::GetTinyEdgeLength + * + * Get Tiny Edge Length + */ +//============================================================================= +CORBA::Double BLSURFPlugin_Hypothesis_i::GetTinyEdgeLength() { + // MESSAGE("BLSURFPlugin_Hypothesis_i::GetTinyEdgeLength"); + ASSERT(myBaseImpl); + return this->GetImpl()->GetTinyEdgeLength(); +} + +//============================================================================= +/*! + * BLSURFPlugin_Hypothesis_i::SetBadElementRemoval * * Set true or false */ //============================================================================= -void BLSURFPlugin_Hypothesis_i::SetQuadAllowed(CORBA::Boolean theValue) { - // MESSAGE("BLSURFPlugin_Hypothesis_i::SetQuadAllowed"); +void BLSURFPlugin_Hypothesis_i::SetBadElementRemoval(CORBA::Boolean theValue) { + // MESSAGE("BLSURFPlugin_Hypothesis_i::SetBadElementRemoval"); ASSERT(myBaseImpl); - this->GetImpl()->SetQuadAllowed(theValue); + this->GetImpl()->SetBadElementRemoval(theValue); std::string theValueStr = theValue ? "True" : "False"; - SMESH::TPythonDump() << _this() << ".SetQuadAllowed( " << theValueStr.c_str() << " )"; + SMESH::TPythonDump() << _this() << ".SetBadElementRemoval( " << theValueStr.c_str() << " )"; } //============================================================================= /*! - * BLSURFPlugin_Hypothesis_i::GetQuadAllowed + * BLSURFPlugin_Hypothesis_i::GetBadElementRemoval * * Get true or false */ //============================================================================= -CORBA::Boolean BLSURFPlugin_Hypothesis_i::GetQuadAllowed() { - // MESSAGE("BLSURFPlugin_Hypothesis_i::GetQuadAllowed"); +CORBA::Boolean BLSURFPlugin_Hypothesis_i::GetBadElementRemoval() { + // MESSAGE("BLSURFPlugin_Hypothesis_i::GetBadElementRemoval"); ASSERT(myBaseImpl); - return this->GetImpl()->GetQuadAllowed(); + return this->GetImpl()->GetBadElementRemoval(); } //============================================================================= /*! - * BLSURFPlugin_Hypothesis_i::SetDecimesh + * BLSURFPlugin_Hypothesis_i::SetBadElementAspectRatio + * + * Set Bad Surface Element Aspect Ratio + */ +//============================================================================= +void BLSURFPlugin_Hypothesis_i::SetBadElementAspectRatio(CORBA::Double theValue) { + // MESSAGE("BLSURFPlugin_Hypothesis_i::SetBadElementAspectRatio"); + ASSERT(myBaseImpl); + this->GetImpl()->SetBadElementAspectRatio(theValue); + SMESH::TPythonDump() << _this() << ".SetBadElementAspectRatio( " << theValue << " )"; +} + +//============================================================================= +/*! + * BLSURFPlugin_Hypothesis_i::GetBadElementAspectRatio + * + * Get Bad Surface Element Aspect Ratio + */ +//============================================================================= +CORBA::Double BLSURFPlugin_Hypothesis_i::GetBadElementAspectRatio() { + // MESSAGE("BLSURFPlugin_Hypothesis_i::GetBadElementAspectRatio"); + ASSERT(myBaseImpl); + return this->GetImpl()->GetBadElementAspectRatio(); +} + +//============================================================================= +/*! + * BLSURFPlugin_Hypothesis_i::SetOptimizeMesh * * Set true or false */ //============================================================================= -void BLSURFPlugin_Hypothesis_i::SetDecimesh(CORBA::Boolean theValue) { - // MESSAGE("BLSURFPlugin_Hypothesis_i::SetDecimesh"); +void BLSURFPlugin_Hypothesis_i::SetOptimizeMesh(CORBA::Boolean theValue) { + // MESSAGE("BLSURFPlugin_Hypothesis_i::SetOptimizeMesh"); ASSERT(myBaseImpl); - this->GetImpl()->SetDecimesh(theValue); + this->GetImpl()->SetOptimizeMesh(theValue); std::string theValueStr = theValue ? "True" : "False"; - SMESH::TPythonDump() << _this() << ".SetDecimesh( " << theValueStr.c_str() << " )"; + SMESH::TPythonDump() << _this() << ".SetOptimizeMesh( " << theValueStr.c_str() << " )"; } //============================================================================= /*! - * BLSURFPlugin_Hypothesis_i::GetDecimesh + * BLSURFPlugin_Hypothesis_i::GetOptimizeMesh * * Get true or false */ //============================================================================= -CORBA::Boolean BLSURFPlugin_Hypothesis_i::GetDecimesh() { - // MESSAGE("BLSURFPlugin_Hypothesis_i::GetDecimesh"); +CORBA::Boolean BLSURFPlugin_Hypothesis_i::GetOptimizeMesh() { + // MESSAGE("BLSURFPlugin_Hypothesis_i::GetOptimizeMesh"); + ASSERT(myBaseImpl); + return this->GetImpl()->GetOptimizeMesh(); +} + +//============================================================================= +/*! + * BLSURFPlugin_Hypothesis_i::SetQuadraticMesh + * + * Set true or false + */ +//============================================================================= +void BLSURFPlugin_Hypothesis_i::SetQuadraticMesh(CORBA::Boolean theValue) { + // MESSAGE("BLSURFPlugin_Hypothesis_i::SetQuadraticMesh"); + ASSERT(myBaseImpl); + this->GetImpl()->SetQuadraticMesh(theValue); + std::string theValueStr = theValue ? "True" : "False"; + SMESH::TPythonDump() << _this() << ".SetQuadraticMesh( " << theValueStr.c_str() << " )"; +} + +//============================================================================= +/*! + * BLSURFPlugin_Hypothesis_i::GetQuadraticMesh + * + * Get true or false + */ +//============================================================================= +CORBA::Boolean BLSURFPlugin_Hypothesis_i::GetQuadraticMesh() { + // MESSAGE("BLSURFPlugin_Hypothesis_i::GetQuadraticMesh"); + ASSERT(myBaseImpl); + return this->GetImpl()->GetQuadraticMesh(); +} + + + + + +/*! + * BLSURFPlugin_Hypothesis_i::SetTopology + * + * Set topology + */ + +//============================================================================= +void BLSURFPlugin_Hypothesis_i::SetTopology(CORBA::Long theValue) { + // MESSAGE("BLSURFPlugin_Hypothesis_i::SetTopology"); + ASSERT(myBaseImpl); + this->GetImpl()->SetTopology((::BLSURFPlugin_Hypothesis::Topology) theValue); + SMESH::TPythonDump() << _this() << ".SetTopology( " << theValue << " )"; +} + +//============================================================================= +/*! + * BLSURFPlugin_Hypothesis_i::GetTopology + * + * Get Topology + */ +//============================================================================= +CORBA::Long BLSURFPlugin_Hypothesis_i::GetTopology() { + // MESSAGE("BLSURFPlugin_Hypothesis_i::GetTopology"); ASSERT(myBaseImpl); - return this->GetImpl()->GetDecimesh(); + return this->GetImpl()->GetTopology(); } //============================================================================= @@ -402,30 +643,30 @@ CORBA::Boolean BLSURFPlugin_Hypothesis_i::GetPreCADMergeEdges() { //============================================================================= /*! - * BLSURFPlugin_Hypothesis_i::SetPreCADRemoveNanoEdges + * BLSURFPlugin_Hypothesis_i::SetPreCADProcess3DTopology * * Set true or false */ //============================================================================= -void BLSURFPlugin_Hypothesis_i::SetPreCADRemoveNanoEdges(CORBA::Boolean theValue) { - // MESSAGE("BLSURFPlugin_Hypothesis_i::SetPreCADRemoveNanoEdges"); +void BLSURFPlugin_Hypothesis_i::SetPreCADProcess3DTopology(CORBA::Boolean theValue) { + // MESSAGE("BLSURFPlugin_Hypothesis_i::SetPreCADProcess3DTopology"); ASSERT(myBaseImpl); - this->GetImpl()->SetPreCADRemoveNanoEdges(theValue); + this->GetImpl()->SetPreCADProcess3DTopology(theValue); std::string theValueStr = theValue ? "True" : "False"; - SMESH::TPythonDump() << _this() << ".SetPreCADRemoveNanoEdges( " << theValueStr.c_str() << " )"; + SMESH::TPythonDump() << _this() << ".SetPreCADProcess3DTopology( " << theValueStr.c_str() << " )"; } //============================================================================= /*! - * BLSURFPlugin_Hypothesis_i::GetPreCADRemoveNanoEdges + * BLSURFPlugin_Hypothesis_i::GetPreCADProcess3DTopology * * Get true or false */ //============================================================================= -CORBA::Boolean BLSURFPlugin_Hypothesis_i::GetPreCADRemoveNanoEdges() { - // MESSAGE("BLSURFPlugin_Hypothesis_i::GetPreCADRemoveNanoEdges"); +CORBA::Boolean BLSURFPlugin_Hypothesis_i::GetPreCADProcess3DTopology() { + // MESSAGE("BLSURFPlugin_Hypothesis_i::GetPreCADProcess3DTopology"); ASSERT(myBaseImpl); - return this->GetImpl()->GetPreCADRemoveNanoEdges(); + return this->GetImpl()->GetPreCADProcess3DTopology(); } //============================================================================= @@ -456,32 +697,6 @@ CORBA::Boolean BLSURFPlugin_Hypothesis_i::GetPreCADDiscardInput() { return this->GetImpl()->GetPreCADDiscardInput(); } -//============================================================================= -/*! - * BLSURFPlugin_Hypothesis_i::SetPreCADEpsNano - * - * Set length for nano edges - */ -//============================================================================= -void BLSURFPlugin_Hypothesis_i::SetPreCADEpsNano(CORBA::Double theValue) { - // MESSAGE("BLSURFPlugin_Hypothesis_i::SetPreCADEpsNano"); - ASSERT(myBaseImpl); - this->GetImpl()->SetPreCADEpsNano(theValue); - SMESH::TPythonDump() << _this() << ".SetPreCADEpsNano( " << theValue << " )"; -} - -//============================================================================= -/*! - * BLSURFPlugin_Hypothesis_i::GetPreCADEpsNano - * - * Get length of nano edges - */ -//============================================================================= -CORBA::Double BLSURFPlugin_Hypothesis_i::GetPreCADEpsNano() { - // MESSAGE("BLSURFPlugin_Hypothesis_i::GetPreCADEpsNano"); - ASSERT(myBaseImpl); - return this->GetImpl()->GetPreCADEpsNano(); -} //============================================================================= @@ -695,6 +910,38 @@ void BLSURFPlugin_Hypothesis_i::SetSizeMapEntry(const char* entry, const char* s //============================================================================= +void BLSURFPlugin_Hypothesis_i::SetConstantSizeMapEntry(const char* entry, GEOM::shape_type shapeType, CORBA::Double sizeMap) + throw (SALOME::SALOME_Exception) { + ASSERT(myBaseImpl); + MESSAGE("ENGINE : SETSIZEMAP START ENTRY : " << entry); + bool valueChanged = false; + std::ostringstream sizeMapFunction; + switch (shapeType) { + case GEOM::FACE: sizeMapFunction << "def f(u,v): return " << sizeMap ; break; + case GEOM::EDGE: sizeMapFunction << "def f(t): return " << sizeMap ; break; + case GEOM::VERTEX: sizeMapFunction << "def f(): return " << sizeMap ; break; + } + try { + valueChanged = (this->GetImpl()->GetSizeMapEntry(entry) != sizeMapFunction.str()); + if (valueChanged) + this->GetImpl()->SetSizeMapEntry(entry, sizeMapFunction.str()); + } catch (const std::invalid_argument& ex) { + SALOME::ExceptionStruct ExDescription; + ExDescription.text = ex.what(); + ExDescription.type = SALOME::BAD_PARAM; + ExDescription.sourceFile = "BLSURFPlugin_Hypothesis::SetSizeMapEntry(entry,sizemap)"; + ExDescription.lineNumber = 0; + throw SALOME::SALOME_Exception(ExDescription); + } catch (SALOME_Exception& ex) { + THROW_SALOME_CORBA_EXCEPTION( ex.what() ,SALOME::BAD_PARAM ); + } + MESSAGE("ENGINE : SETSIZEMAP END ENTRY : " << entry); + if (valueChanged) + SMESH::TPythonDump() << _this() << ".SetConstantSizeMap(" << entry << ", '" << sizeMap << "' )"; +} + +//============================================================================= + void BLSURFPlugin_Hypothesis_i::SetAttractorEntry(const char* entry, const char* attractor) throw (SALOME::SALOME_Exception) { ASSERT(myBaseImpl); @@ -725,7 +972,7 @@ void BLSURFPlugin_Hypothesis_i::SetAttractorEntry(const char* entry, const char* //============================================================================= -void BLSURFPlugin_Hypothesis_i::SetClassAttractorEntry(const char* entry, const char* att_entry, double StartSize, double EndSize, double ActionRadius, double ConstantRadius) //TODO à finir +void BLSURFPlugin_Hypothesis_i::SetClassAttractorEntry(const char* entry, const char* att_entry, CORBA::Double StartSize, CORBA::Double EndSize, CORBA::Double ActionRadius, CORBA::Double ConstantRadius) //TODO à finir throw (SALOME::SALOME_Exception) { ASSERT(myBaseImpl); @@ -937,6 +1184,19 @@ void BLSURFPlugin_Hypothesis_i::SetSizeMap(const GEOM::GEOM_Object_ptr GeomObj, SetSizeMapEntry(entry.c_str(), sizeMap); } +//============================================================================= + +void BLSURFPlugin_Hypothesis_i::SetConstantSizeMap(const GEOM::GEOM_Object_ptr GeomObj, CORBA::Double sizeMap) { + ASSERT(myBaseImpl); + string entry = GeomObj->GetStudyEntry(); + GEOM::shape_type shapeType = GeomObj->GetShapeType(); + if (shapeType == GEOM::COMPOUND) + shapeType = GeomObj->GetMaxShapeType(); + MESSAGE("IDL : GetName : " << GeomObj->GetName()); + MESSAGE("IDL : SETSIZEMAP ( "<< entry << " , " << sizeMap << ")"); + SetConstantSizeMapEntry(entry.c_str(), shapeType, sizeMap); +} + //============================================================================= void BLSURFPlugin_Hypothesis_i::UnsetSizeMap(const GEOM::GEOM_Object_ptr GeomObj) { ASSERT(myBaseImpl); @@ -967,7 +1227,7 @@ void BLSURFPlugin_Hypothesis_i::UnsetAttractor(GEOM::GEOM_Object_ptr GeomObj) { SMESH::TPythonDump() << _this() << ".UnsetAttractor( " << entry.c_str() << " )"; } -void BLSURFPlugin_Hypothesis_i::SetAttractorGeom(GEOM::GEOM_Object_ptr theFace, GEOM::GEOM_Object_ptr theAttractor, double StartSize, double EndSize, double ActionRadius, double ConstantRadius) +void BLSURFPlugin_Hypothesis_i::SetAttractorGeom(GEOM::GEOM_Object_ptr theFace, GEOM::GEOM_Object_ptr theAttractor, CORBA::Double StartSize, CORBA::Double EndSize, CORBA::Double ActionRadius, CORBA::Double ConstantRadius) { ASSERT(myBaseImpl); string theFaceEntry; @@ -2400,3 +2660,75 @@ char* BLSURFPlugin_Hypothesis_i::GetGMFFile() { CORBA::Boolean BLSURFPlugin_Hypothesis_i::IsDimSupported(SMESH::Dimension type) { return type == SMESH::DIM_2D; } + +// +// Obsolete methods - To be removed in V7 +// + +void BLSURFPlugin_Hypothesis_i::SetPhyMin(CORBA::Double theMinSize) { + this->SetMinSize(theMinSize); +} +CORBA::Double BLSURFPlugin_Hypothesis_i::GetPhyMin() { + return this->GetMinSize(); +} +void BLSURFPlugin_Hypothesis_i::SetPhyMax(CORBA::Double theMaxSize) { + this->SetMaxSize(theMaxSize); +} +CORBA::Double BLSURFPlugin_Hypothesis_i::GetPhyMax() { + return this->GetMaxSize(); +} +void BLSURFPlugin_Hypothesis_i::SetGeoMin(CORBA::Double theMinSize) { + this->SetMinSize(theMinSize); +} +CORBA::Double BLSURFPlugin_Hypothesis_i::GetGeoMin() { + return this->GetMinSize(); +} +void BLSURFPlugin_Hypothesis_i::SetGeoMax(CORBA::Double theMaxSize) { + this->SetMaxSize(theMaxSize); +} +CORBA::Double BLSURFPlugin_Hypothesis_i::GetGeoMax() { + return this->GetMaxSize(); +} +void BLSURFPlugin_Hypothesis_i::SetAngleMeshS(CORBA::Double theValue) { + this->SetAngleMesh(theValue); +} +CORBA::Double BLSURFPlugin_Hypothesis_i::GetAngleMeshS() { + return this->GetAngleMesh(); +} +void BLSURFPlugin_Hypothesis_i::SetAngleMeshC(CORBA::Double theValue) { + this->SetAngleMesh(theValue); +} +CORBA::Double BLSURFPlugin_Hypothesis_i::GetAngleMeshC() { + return this->GetAngleMesh(); +} +void BLSURFPlugin_Hypothesis_i::SetDecimesh(CORBA::Boolean theValue) { + std::string theValueStr = theValue ? "1" : "0"; + this->SetOptionValue("respect_geometry",theValueStr.c_str()); +} +CORBA::Boolean BLSURFPlugin_Hypothesis_i::GetDecimesh() { + std::string theValueStr = this->GetOptionValue("respect_geometry"); + if (theValueStr.empty() || theValueStr == "respect") + return true; + return false; +} +void BLSURFPlugin_Hypothesis_i::SetPreCADRemoveNanoEdges(CORBA::Boolean theValue) { + std::string theValueStr = theValue ? "1" : "0"; + this->SetPreCADOptionValue("remove_tiny_edges",theValueStr.c_str()); +} +CORBA::Boolean BLSURFPlugin_Hypothesis_i::GetPreCADRemoveNanoEdges() { + std::string theValueStr = this->GetPreCADOptionValue("remove_tiny_edges"); + if (theValueStr == "1") + return true; + return false; +} +void BLSURFPlugin_Hypothesis_i::SetPreCADEpsNano(CORBA::Double theValue) { + std::ostringstream theValueStr; + theValueStr << theValue; + this->SetPreCADOptionValue("tiny_edge_length",theValueStr.str().c_str()); +} +CORBA::Double BLSURFPlugin_Hypothesis_i::GetPreCADEpsNano() { + std::istringstream theValueStr(this->GetPreCADOptionValue("tiny_edge_length")); + double result; + theValueStr >> result; + return result; +} diff --git a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.hxx b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.hxx index 2c96546..3712bee 100644 --- a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.hxx +++ b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.hxx @@ -45,35 +45,26 @@ public: // Destructor virtual ~BLSURFPlugin_Hypothesis_i(); - void SetTopology(CORBA::Long theValue); - CORBA::Long GetTopology(); - void SetPhysicalMesh(CORBA::Long theValue); CORBA::Long GetPhysicalMesh(); - void SetPhySize(CORBA::Double theValue); - CORBA::Double GetPhySize(); - - void SetPhyMin(CORBA::Double theMinSize); - CORBA::Double GetPhyMin(); - - void SetPhyMax(CORBA::Double theMaxSize); - CORBA::Double GetPhyMax(); - void SetGeometricMesh(CORBA::Long theValue); CORBA::Long GetGeometricMesh(); - void SetAngleMeshS(CORBA::Double theValue); - CORBA::Double GetAngleMeshS(); - - void SetAngleMeshC(CORBA::Double angle); - CORBA::Double GetAngleMeshC(); + void SetPhySize(CORBA::Double theValue); + void SetPhySizeRel(CORBA::Double theValue); + CORBA::Double GetPhySize(); + CORBA::Boolean IsPhySizeRel(); - void SetGeoMin(CORBA::Double theMinSize); - CORBA::Double GetGeoMin(); + void SetMinSize(CORBA::Double theMinSize); + void SetMinSizeRel(CORBA::Double theMinSize); + CORBA::Double GetMinSize(); + CORBA::Boolean IsMinSizeRel(); - void SetGeoMax(CORBA::Double theMaxSize); - CORBA::Double GetGeoMax(); + void SetMaxSize(CORBA::Double theMaxSize); + void SetMaxSizeRel(CORBA::Double theMaxSize); + CORBA::Double GetMaxSize(); + CORBA::Boolean IsMaxSizeRel(); void SetGradation(CORBA::Double theValue); CORBA::Double GetGradation(); @@ -81,8 +72,38 @@ public: void SetQuadAllowed(CORBA::Boolean theValue); CORBA::Boolean GetQuadAllowed(); - void SetDecimesh(CORBA::Boolean theValue); - CORBA::Boolean GetDecimesh(); + 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 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(); + + void SetTopology(CORBA::Long theValue); + CORBA::Long GetTopology(); void SetVerbosity(CORBA::Short theVal) throw (SALOME::SALOME_Exception); CORBA::Short GetVerbosity(); @@ -90,15 +111,12 @@ public: void SetPreCADMergeEdges(CORBA::Boolean theValue); CORBA::Boolean GetPreCADMergeEdges(); - void SetPreCADRemoveNanoEdges(CORBA::Boolean theValue); - CORBA::Boolean GetPreCADRemoveNanoEdges(); + void SetPreCADProcess3DTopology(CORBA::Boolean theValue); + CORBA::Boolean GetPreCADProcess3DTopology(); void SetPreCADDiscardInput(CORBA::Boolean theValue); CORBA::Boolean GetPreCADDiscardInput(); - void SetPreCADEpsNano(CORBA::Double theValue); - CORBA::Double GetPreCADEpsNano(); - void SetOptionValue(const char* optionName, const char* optionValue) throw (SALOME::SALOME_Exception); void SetPreCADOptionValue(const char* optionName, const char* optionValue) throw (SALOME::SALOME_Exception); char* GetOptionValue(const char* optionName) throw (SALOME::SALOME_Exception); @@ -115,6 +133,8 @@ public: void SetSizeMapEntry(const char* entry, const char* sizeMap) throw (SALOME::SALOME_Exception); + void SetConstantSizeMapEntry(const char* entry, GEOM::shape_type shapeType, CORBA::Double sizeMap) throw (SALOME::SALOME_Exception); + char* GetSizeMapEntry(const char* entry) throw (SALOME::SALOME_Exception); void UnsetEntry(const char* entry); @@ -125,6 +145,8 @@ public: void SetSizeMap(GEOM::GEOM_Object_ptr GeomObj, const char* sizeMap); + void SetConstantSizeMap(GEOM::GEOM_Object_ptr GeomObj, CORBA::Double sizeMap); + void UnsetSizeMap(GEOM::GEOM_Object_ptr GeomObj); void ClearSizeMaps(); @@ -144,11 +166,11 @@ public: * Set/get/unset an attractor on a face */ - void SetAttractorGeom(GEOM::GEOM_Object_ptr GeomObj, GEOM::GEOM_Object_ptr Attractor, double StartSize, double EndSize, double ActionRadius, double ConstantRadius ); + void SetAttractorGeom(GEOM::GEOM_Object_ptr GeomObj, GEOM::GEOM_Object_ptr Attractor, CORBA::Double StartSize, CORBA::Double EndSize, CORBA::Double ActionRadius, CORBA::Double ConstantRadius ); void UnsetAttractorGeom(GEOM::GEOM_Object_ptr GeomObj); - void SetClassAttractorEntry(const char* entry, const char* att_entry, double StartSize, double EndSize, double ActionRadius, double ConstantRadius) throw (SALOME::SALOME_Exception); + void SetClassAttractorEntry(const char* entry, const char* att_entry, CORBA::Double StartSize, CORBA::Double EndSize, CORBA::Double ActionRadius, CORBA::Double ConstantRadius) throw (SALOME::SALOME_Exception); BLSURFPlugin::TAttParamsMap* GetAttractorParams(); @@ -247,6 +269,29 @@ public: // Verify whether hypothesis supports given entity type CORBA::Boolean IsDimSupported(SMESH::Dimension type); + + + // + // Obsolete methods - To be removed in V7 + // + void SetPhyMin(CORBA::Double theMinSize); + CORBA::Double GetPhyMin(); + void SetPhyMax(CORBA::Double theMaxSize); + CORBA::Double GetPhyMax(); + void SetGeoMin(CORBA::Double theMinSize); + CORBA::Double GetGeoMin(); + void SetGeoMax(CORBA::Double theMaxSize); + CORBA::Double GetGeoMax(); + void SetAngleMeshS(CORBA::Double angle); + CORBA::Double GetAngleMeshS(); + void SetAngleMeshC(CORBA::Double angle); + CORBA::Double GetAngleMeshC(); + void SetDecimesh(CORBA::Boolean toIgnoreEdges); + CORBA::Boolean GetDecimesh(); + void SetPreCADRemoveNanoEdges(CORBA::Boolean toRemoveNanoEdges); + CORBA::Boolean GetPreCADRemoveNanoEdges(); + void SetPreCADEpsNano(CORBA::Double epsNano); + CORBA::Double GetPreCADEpsNano(); }; #endif diff --git a/src/BLSURFPlugin/Makefile.am b/src/BLSURFPlugin/Makefile.am index 2d9cab3..6b0ad88 100644 --- a/src/BLSURFPlugin/Makefile.am +++ b/src/BLSURFPlugin/Makefile.am @@ -43,20 +43,20 @@ dist_libBLSURFEngine_la_SOURCES = \ BLSURFPlugin_i.cxx \ BLSURFPlugin_Attractor.cxx -libBLSURFEngine_la_CPPFLAGS = \ - $(QT_INCLUDES) \ - $(PYTHON_INCLUDES) \ - $(KERNEL_CXXFLAGS) \ - $(GUI_CXXFLAGS) \ - $(MED_CXXFLAGS) \ - $(GEOM_CXXFLAGS) \ - $(CAS_CPPFLAGS) \ - $(VTK_INCLUDES) \ - $(BLSURF_INCLUDES) \ - $(SMESH_CXXFLAGS) \ - $(CORBA_CXXFLAGS) \ - $(CORBA_INCLUDES) \ - $(BOOST_CPPFLAGS) \ +libBLSURFEngine_la_CPPFLAGS = \ + $(QT_INCLUDES) \ + $(PYTHON_INCLUDES) \ + $(KERNEL_CXXFLAGS) \ + $(GUI_CXXFLAGS) \ + $(MED_CXXFLAGS) \ + $(GEOM_CXXFLAGS) \ + $(CAS_CPPFLAGS) \ + $(VTK_INCLUDES) \ + $(MESHGEMS_CADSURF_INCLUDES) \ + $(SMESH_CXXFLAGS) \ + $(CORBA_CXXFLAGS) \ + $(CORBA_INCLUDES) \ + $(BOOST_CPPFLAGS) \ -I$(top_builddir)/idl #Qt uniquement necessaire pour le getActiveStudyDocument de SMeshGuiUtils.h @@ -65,7 +65,7 @@ libBLSURFEngine_la_LDFLAGS = \ ../../idl/libSalomeIDLBLSURFPLUGIN.la \ $(PYTHON_LIBS) \ $(CAS_KERNEL) -lTKBRep -lTKGeomBase -lTKGeomAlgo -lTKTopAlgo -lTKLCAF -lTKXSBase -lTKG2d -lTKG3d -lTKShHealing \ - $(BLSURF_LIBS) \ + $(MESHGEMS_CADSURF_LIBS) \ $(SMESH_LDFLAGS) -lSMESHimpl -lSMESHEngine -lStdMeshers -lStdMeshersEngine -lSMDS -lSMESHDS \ $(GEOM_LDFLAGS) -lGEOMbasic \ $(MED_LDFLAGS) -lSalomeIDLMED \ diff --git a/src/GUI/BLSURFPluginGUI_AdvWidget.cxx b/src/GUI/BLSURFPluginGUI_AdvWidget.cxx new file mode 100644 index 0000000..314f492 --- /dev/null +++ b/src/GUI/BLSURFPluginGUI_AdvWidget.cxx @@ -0,0 +1,56 @@ +// Copyright (C) 2007-2012 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// --- +// File : BLSURFPluginGUI_Dlg.cxx +// Authors : Gilles DAVID (OCC) +// --- +// + +#include "BLSURFPluginGUI_Dlg.h" + +#include + +#include + + +////////////////////////////////////////// +// BLSURFPluginGUI_AdvWidget +////////////////////////////////////////// + +BLSURFPluginGUI_AdvWidget::BLSURFPluginGUI_AdvWidget( QWidget* parent, Qt::WindowFlags f ) +: QWidget( parent, f ) +{ + setupUi( this ); + myOptionTable->horizontalHeader()->hideSection( OPTION_ID_COLUMN ); +} + +BLSURFPluginGUI_AdvWidget::~BLSURFPluginGUI_AdvWidget() +{ +} + +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")) + fileName.append(".mesh"); + myGMFFileName->setText(fileName); +} + + diff --git a/src/GUI/BLSURFPluginGUI_AdvWidget_QTD.ui b/src/GUI/BLSURFPluginGUI_AdvWidget_QTD.ui new file mode 100644 index 0000000..b9580bf --- /dev/null +++ b/src/GUI/BLSURFPluginGUI_AdvWidget_QTD.ui @@ -0,0 +1,202 @@ + + + BLSURFPluginGUI_AdvWidget_QTD + + + + 0 + 0 + 567 + 226 + + + + + 0 + + + + + + + true + + + true + + + true + + + false + + + false + + + true + + + + OPTION_ID_COLUMN + + + + + OPTION_TYPE_COLUMN + + + + + OPTION_NAME_COLUMN + + + + + OPTION_VALUE_COLUMN + + + + + + + + BLSURF_ADD_OPTION + + + + + + + BLSURF_REMOVE_OPTION + + + + + + + + + 0 + + + + + BLSURF_PRECAD_GROUP + + + true + + + false + + + + + + BLSURF_PRECAD_MERGE_EDGES + + + true + + + + + + + BLSURF_PRECAD_PROCESS_3D_TOPOLOGY + + + true + + + + + + + BLSURF_PRECAD_DISCARD_INPUT + + + + + + + + + + BLSURF_GMF_FILE + + + + + + + + + + Qt::Vertical + + + + 20 + 53 + + + + + + + + BLSURF_VERBOSITY + + + + + + + 100 + + + 5 + + + + + + + + + myOptionTable + addBtn + rmBtn + myPreCADGroupBox + myPreCADMergeEdges + myPreCADProcess3DTopology + myPreCADDiscardInput + myVerbosity + chooseGMFBtn + myGMFFileName + + + + + chooseGMFBtn + clicked() + BLSURFPluginGUI_AdvWidget_QTD + onChooseGMFFile() + + + 371 + 136 + + + 328 + 194 + + + + + + onChooseGMFFile() + + diff --git a/src/GUI/BLSURFPluginGUI_Dlg.h b/src/GUI/BLSURFPluginGUI_Dlg.h new file mode 100644 index 0000000..a8693fe --- /dev/null +++ b/src/GUI/BLSURFPluginGUI_Dlg.h @@ -0,0 +1,97 @@ +// Copyright (C) 2007-2012 CEA/DEN, EDF R&D, OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// File : DlgRef.h +// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) + +#ifndef BLSURFPLUGINGUI_H +#define BLSURFPLUGINGUI_H + +enum PhysicalMesh + { + DefaultSize = 0, + PhysicalGlobalSize, + PhysicalLocalSize + }; + +enum GeometricMesh + { + DefaultGeom = 0, + GeometricalGlobalSize, + GeometricalLocalSize + }; + +enum Topology { + FromCAD = 0, + Process, + Process2, + PreCAD + } ; + +enum { + OPTION_ID_COLUMN = 0, + OPTION_TYPE_COLUMN, + OPTION_NAME_COLUMN, + OPTION_VALUE_COLUMN, + NB_COLUMNS, +}; + +////////////////////////////////////////// +// BLSURFPluginGUI_StdWidget +////////////////////////////////////////// + +#include "ui_BLSURFPluginGUI_StdWidget_QTD.h" +#include "BLSURFPluginGUI_HypothesisCreator.h" + +class BLSURFPLUGIN_GUI_EXPORT BLSURFPluginGUI_StdWidget : public QWidget, + public Ui::BLSURFPluginGUI_StdWidget_QTD +{ + Q_OBJECT + +public: + BLSURFPluginGUI_StdWidget( QWidget* = 0, Qt::WindowFlags = 0 ); + ~BLSURFPluginGUI_StdWidget(); + +public slots: + void onPhysicalMeshChanged(); + void onGeometricMeshChanged(); + void onEditingFinished(); + void resizeWidgets(); +}; + +////////////////////////////////////////// +// BLSURFPluginGUI_AdvWidget +////////////////////////////////////////// + +#include "ui_BLSURFPluginGUI_AdvWidget_QTD.h" + +class BLSURFPLUGIN_GUI_EXPORT BLSURFPluginGUI_AdvWidget : public QWidget, + public Ui::BLSURFPluginGUI_AdvWidget_QTD +{ + Q_OBJECT + +public: + BLSURFPluginGUI_AdvWidget( QWidget* = 0, Qt::WindowFlags = 0 ); + ~BLSURFPluginGUI_AdvWidget(); + +public slots: + void onChooseGMFFile(); +}; + +#endif \ No newline at end of file diff --git a/src/GUI/BLSURFPluginGUI_HypothesisCreator.cxx b/src/GUI/BLSURFPluginGUI_HypothesisCreator.cxx index 4884edf..daee40e 100644 --- a/src/GUI/BLSURFPluginGUI_HypothesisCreator.cxx +++ b/src/GUI/BLSURFPluginGUI_HypothesisCreator.cxx @@ -25,7 +25,7 @@ // --- // #include "BLSURFPluginGUI_HypothesisCreator.h" -// #include +#include "BLSURFPluginGUI_Dlg.h" #include "GeometryGUI.h" @@ -40,25 +40,24 @@ #include #include -#include +#include +#include #include -#include -#include #include -#include #include +#include #include +#include +#include #include -#include -#include -#include -#include #include -#include -#include -#include +#include +#include #include -#include +#include +#include +#include +#include #include #include @@ -81,38 +80,12 @@ #include #include -#define WITH_SIZE_BOUNDARIES - -enum Topology { - FromCAD, - Process, - Process2, - PreCAD - } ; - -enum PhysicalMesh - { - DefaultSize = 0, - PhysicalUserDefined, - SizeMap - }; - -enum GeometricMesh - { - DefaultGeom = 0, - UserDefined - }; enum { STD_TAB = 0, ADV_TAB, SMP_TAB, ENF_TAB, - OPTION_ID_COLUMN = 0, - OPTION_TYPE_COLUMN, - OPTION_NAME_COLUMN, - OPTION_VALUE_COLUMN, - NB_COLUMNS, SMP_NAME_COLUMN =0, SMP_SIZEMAP_COLUMN, SMP_ENTRY_COLUMN, @@ -426,75 +399,6 @@ bool EnforcedTreeWidgetDelegate::vertexExists(QAbstractItemModel *model, // END EnforcedTreeWidgetDelegate // -// -// BEGIN BLSURFPluginGUI_ObjectReferenceParamWdg -// -//================================================================================ - -// BLSURFPluginGUI_ObjectReferenceParamWdg::BLSURFPluginGUI_ObjectReferenceParamWdg -// ( SUIT_SelectionFilter* f, QWidget* parent, bool multiSelection) -// : StdMeshersGUI_ObjectReferenceParamWdg(f, parent, multiSelection) -// { -// init(); -// } -// -// -// BLSURFPluginGUI_ObjectReferenceParamWdg::BLSURFPluginGUI_ObjectReferenceParamWdg -// ( MeshObjectType objType, QWidget* parent, bool multiSelection ) -// : StdMeshersGUI_ObjectReferenceParamWdg( objType, parent, multiSelection ) -// { -// init(); -// } -// -// BLSURFPluginGUI_ObjectReferenceParamWdg::~BLSURFPluginGUI_ObjectReferenceParamWdg() -// { -// if ( myFilter ) -// { -// mySelectionMgr->removeFilter( myFilter ); -// delete myFilter; -// } -// } -// -// void BLSURFPluginGUI_ObjectReferenceParamWdg::init() -// { -// StdMeshersGUI_ObjectReferenceParamWdg::init(); -// disconnect( mySelButton, SIGNAL(clicked()), SLOT(activateSelection())); -// connect( mySelButton, SIGNAL(toggled(bool)), SLOT(setActivationStatus(bool))); -// } -// -// void BLSURFPluginGUI_ObjectReferenceParamWdg::setActivationStatus(bool status) -// { -// if (status) -// activateSelection(); -// else -// deactivateSelection(); -// } -// -// void BLSURFPluginGUI_ObjectReferenceParamWdg::activateSelectionOnly() -// { -// if ( !mySelectionActivated && mySelectionMgr ) -// { -// mySelectionActivated = true; -// mySelectionMgr->clearFilters(); -// if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) -// aViewWindow->SetSelectionMode(ActorSelection); -// if ( myFilter ) -// mySelectionMgr->installFilter( myFilter ); -// connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), SLOT(onSelectionDone())); -// } -// emit selectionActivated(); -// } -// -// void BLSURFPluginGUI_ObjectReferenceParamWdg::deactivateSelectionOnly() -// { -// mySelectionActivated = false; -// disconnect(mySelectionMgr, 0, this, 0 ); -// mySelectionMgr->removeFilter( myFilter ); -// } -// -// -// END BLSURFPluginGUI_ObjectReferenceParamWdg -// /** * \brief {BLSURFPluginGUI_HypothesisCreator constructor} @@ -562,17 +466,17 @@ bool BLSURFPluginGUI_HypothesisCreator::checkParams(QString& msg) const if ( ok ) { - myOptionTable->setFocus(); + myAdvWidget->myOptionTable->setFocus(); QApplication::instance()->processEvents(); - int row = 0, nbRows = myOptionTable->rowCount(); + int row = 0, nbRows = myAdvWidget->myOptionTable->rowCount(); for ( ; row < nbRows; ++row ) { - QString name = myOptionTable->item( row, OPTION_NAME_COLUMN )->text(); - QString value = myOptionTable->item( row, OPTION_VALUE_COLUMN )->text().trimmed(); + QString name = myAdvWidget->myOptionTable->item( row, OPTION_NAME_COLUMN )->text(); + QString value = myAdvWidget->myOptionTable->item( row, OPTION_VALUE_COLUMN )->text().trimmed(); if ( !value.isEmpty() ) { try { - QString optionType = myOptionTable->item( row, OPTION_TYPE_COLUMN )->text().trimmed(); + 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") @@ -656,169 +560,43 @@ QFrame* BLSURFPluginGUI_HypothesisCreator::buildFrame() tab->setTabPosition( QTabWidget::North ); lay->addWidget( tab ); + myName = 0; + // basic parameters myStdGroup = new QWidget(); QGridLayout* aStdLayout = new QGridLayout( myStdGroup ); aStdLayout->setSpacing( 6 ); aStdLayout->setMargin( 11 ); - - myName = 0; + if( isCreation() ) myName = new QLineEdit( myStdGroup ); - - myGradation = new SMESHGUI_SpinBox( myStdGroup ); - myGradation->RangeStepAndValidator(1.1, 2.5, 0.1, "length_precision"); - - myPhysicalMesh = new QComboBox( myStdGroup ); - QStringList physicalTypes; - physicalTypes << tr( "BLSURF_DEFAULT_USER" ) << tr( "BLSURF_CUSTOM_USER" ) << tr( "BLSURF_SIZE_MAP"); - myPhysicalMesh->addItems( physicalTypes ); - - myPhySize = new SMESHGUI_SpinBox( myStdGroup ); - myPhySize->RangeStepAndValidator(0, COORD_MAX, 10.0, "length_precision"); - -#ifdef WITH_SIZE_BOUNDARIES - myPhyMin = new SMESHGUI_SpinBox( myStdGroup ); - myPhyMin->RangeStepAndValidator(0, COORD_MAX, 10.0, "length_precision"); - myPhyMin->setText(""); - myPhyMax = new SMESHGUI_SpinBox( myStdGroup ); - myPhyMax->RangeStepAndValidator(0, COORD_MAX, 10.0, "length_precision"); - myPhyMax->setText(""); -#endif - - myGeometricMesh = new QComboBox( myStdGroup ); - QStringList types; - types << tr( "BLSURF_DEFAULT_GEOM" ) << tr( "BLSURF_CUSTOM_GEOM" ); - myGeometricMesh->addItems( types ); - - myAngleMeshS = new SMESHGUI_SpinBox( myStdGroup ); - myAngleMeshS->RangeStepAndValidator(0, 16, 0.5, "angular_precision"); - - myAngleMeshC = new SMESHGUI_SpinBox( myStdGroup ); - myAngleMeshC->RangeStepAndValidator(0, 16, 0.5, "angular_precision"); - -#ifdef WITH_SIZE_BOUNDARIES - myGeoMin = new SMESHGUI_SpinBox( myStdGroup ); - myGeoMin->RangeStepAndValidator(0, COORD_MAX, 10.0, "length_precision"); - myGeoMin->setText(""); - myGeoMax = new SMESHGUI_SpinBox( myStdGroup ); - myGeoMax->RangeStepAndValidator(0, COORD_MAX, 10.0, "length_precision"); - myGeoMax->setText(""); -#endif - myAllowQuadrangles = new QCheckBox( tr( "BLSURF_ALLOW_QUADRANGLES" ), myStdGroup ); - myDecimesh = new QCheckBox( tr( "BLSURF_DECIMESH" ), myStdGroup ); - - // ADD WIDGETS (STANDARD TAB) + myStdWidget = new BLSURFPluginGUI_StdWidget(myStdGroup); + int row = 0; if( isCreation() ) { - aStdLayout->addWidget( new QLabel( tr( "SMESH_NAME" ), myStdGroup ), row, 0, 1, 1 ); - aStdLayout->addWidget( myName, row++, 1, 1, 3 ); - } - aStdLayout->addWidget( new QLabel( tr( "BLSURF_PHY_MESH" ), myStdGroup ), row, 0, 1, 1 ); - aStdLayout->addWidget( myPhysicalMesh, row++, 1, 1, 1 ); - aStdLayout->addWidget( new QLabel( tr( "BLSURF_HPHYDEF" ), myStdGroup), row, 0, 1, 1 ); - aStdLayout->addWidget( myPhySize, row++, 1, 1, 1 ); - aStdLayout->addWidget( new QLabel( tr( "BLSURF_GRADATION" ), myStdGroup ), row, 0, 1, 1 ); - aStdLayout->addWidget( myGradation, row++, 1, 1, 1 ); -#ifdef WITH_SIZE_BOUNDARIES - aStdLayout->addWidget( new QLabel( tr( "BLSURF_HPHYMIN" ), myStdGroup ), row, 0, 1, 1 ); - aStdLayout->addWidget( myPhyMin, row++, 1, 1, 1 ); - aStdLayout->addWidget( new QLabel( tr( "BLSURF_HPHYMAX" ), myStdGroup ), row, 0, 1, 1 ); - aStdLayout->addWidget( myPhyMax, row++, 1, 1, 1 ); -#endif + aStdLayout->addWidget( new QLabel( tr( "SMESH_NAME" ), myStdGroup ), 0, 0, 1, 1 ); + aStdLayout->addWidget( myName, row++, 1, 1, 3 ); + } + aStdLayout->addWidget( myStdWidget, row++, 0, 1, 4 ); + int maxrow = row; + row = 0; if( isCreation() ) row = 1; - else - row = 0; - aStdLayout->addWidget( new QLabel( tr( "BLSURF_GEOM_MESH" ), myStdGroup ), row, 2, 1, 1 ); - aStdLayout->addWidget( myGeometricMesh, row++, 3, 1, 1 ); - aStdLayout->addWidget( new QLabel( tr( "BLSURF_ANGLE_MESH_S" ), myStdGroup ), row, 2, 1, 1 ); - aStdLayout->addWidget( myAngleMeshS, row++, 3, 1, 1 ); - aStdLayout->addWidget( new QLabel( tr( "BLSURF_ANGLE_MESH_C" ), myStdGroup ), row, 2, 1, 1 ); - aStdLayout->addWidget( myAngleMeshC, row++, 3, 1, 1 ); -#ifdef WITH_SIZE_BOUNDARIES - aStdLayout->addWidget( new QLabel( tr( "BLSURF_HGEOMIN" ), myStdGroup ), row, 2, 1, 1 ); - aStdLayout->addWidget( myGeoMin, row++, 3, 1, 1 ); - aStdLayout->addWidget( new QLabel( tr( "BLSURF_HGEOMAX" ), myStdGroup ), row, 2, 1, 1 ); - aStdLayout->addWidget( myGeoMax, row++, 3, 1, 1 ); -#endif - row = max(row,maxrow)+1; - aStdLayout->addWidget( myAllowQuadrangles, row, 0, 1, 2 ); - aStdLayout->addWidget( myDecimesh, row++, 2, 1, 2 ); +// row = max(row,maxrow)+1; aStdLayout->setRowStretch(row,1); + aStdLayout->setColumnStretch(1,1); maxrow = row; + // advanced parameters myAdvGroup = new QWidget(); QGridLayout* anAdvLayout = new QGridLayout( myAdvGroup ); anAdvLayout->setSpacing( 6 ); - anAdvLayout->setMargin( 11 ); - anAdvLayout->setRowStretch( 4, 5 ); - anAdvLayout->setColumnStretch( 1, 5 ); - - myTopology = new QComboBox( myAdvGroup ); - QStringList topologyTypes; - topologyTypes << tr( "BLSURF_TOPOLOGY_CAD" ) - << tr( "BLSURF_TOPOLOGY_PROCESS" ) - << tr( "BLSURF_TOPOLOGY_PROCESS2" ) - << tr( "BLSURF_TOPOLOGY_PRECAD" ); - myTopology->addItems( topologyTypes ); - - myVerbosity = new QSpinBox( myAdvGroup ); - myVerbosity->setMinimum( 0 ); - myVerbosity->setMaximum( 100 ); - myVerbosity->setSingleStep( 5 ); - - myOptionTable = new QTableWidget( 0, NB_COLUMNS, myAdvGroup ); - QStringList headers; - headers << tr( "OPTION_ID_COLUMN" )<< tr( "OPTION_TYPE_COLUMN" ) << tr( "OPTION_NAME_COLUMN" ) << tr( "OPTION_VALUE_COLUMN" ); - myOptionTable->setHorizontalHeaderLabels( headers ); - myOptionTable->horizontalHeader()->hideSection( OPTION_ID_COLUMN ); -// myOptionTable->horizontalHeader()->hideSection( OPTION_TYPE_COLUMN ); - myOptionTable->horizontalHeader()->setStretchLastSection(true); - myOptionTable->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft); - //myOptionTable->setColumnReadOnly( OPTION_NAME_COLUMN, TRUE );////// - //myOptionTable->setColumnReadOnly( OPTION_VALUE_COLUMN, FALSE );///// - myOptionTable->verticalHeader()->hide(); - //myOptionTable->setSelectionBehavior( QAbstractItemView::SelectRows ); - - QPushButton* addBtn = new QPushButton( tr( "ADD_OPTION"), myAdvGroup ); - addBtn->setMenu( new QMenu() ); - QPushButton* rmBtn = new QPushButton( tr( "REMOVE_OPTION"), myAdvGroup ); - - myPreCADGroupBox = new QGroupBox(tr("BLSURF_PRECAD_GROUP"), myAdvGroup ); - myPreCADGroupBox->setEnabled(false); - QGridLayout* aPreCADGroupLayout = new QGridLayout(myPreCADGroupBox); - myPreCADMergeEdges = new QCheckBox(tr("BLSURF_PRECAD_MERGE_EDGES"),myPreCADGroupBox); - aPreCADGroupLayout->addWidget(myPreCADMergeEdges,0,0,1,2); - myPreCADRemoveNanoEdges = new QCheckBox(tr("BLSURF_PRECAD_REMOVE_NANO_EDGES"),myPreCADGroupBox); - aPreCADGroupLayout->addWidget(myPreCADRemoveNanoEdges,1,0,1,2); - myPreCADEpsNano = new SMESHGUI_SpinBox(myPreCADGroupBox); - myPreCADEpsNano->RangeStepAndValidator(0, COORD_MAX, 10.0, "length_precision"); - myPreCADEpsNano->setText(""); - aPreCADGroupLayout->addWidget( new QLabel( tr( "BLSURF_PRECAD_EPS_NANO" ), myPreCADGroupBox ), 2, 0, 1, 1 ); - aPreCADGroupLayout->addWidget(myPreCADEpsNano, 2, 1, 1, 1 ); - myPreCADDiscardInput = new QCheckBox(tr("BLSURF_PRECAD_DISCARD_INPUT"),myPreCADGroupBox); - aPreCADGroupLayout->addWidget(myPreCADDiscardInput, 3, 0, 1, 2); - - QPushButton* chooseGMFBtn = new QPushButton( tr( "BLSURF_GMF_FILE" ), myAdvGroup ); - myGMFFileName = new QLineEdit(myAdvGroup); -// myGMFFileMode = new QCheckBox(tr("BLSURF_GMF_MODE"),myAdvGroup); - - // ADD WIDGETS (ADVANCED TAB) - anAdvLayout->addWidget( new QLabel( tr( "BLSURF_VERBOSITY" ), myAdvGroup ), 0, 0, 1, 1 ); - anAdvLayout->addWidget( myVerbosity, 0, 1, 1, 1 ); - anAdvLayout->addWidget( new QLabel( tr( "BLSURF_TOPOLOGY" ), myAdvGroup ), 1, 0, 1, 1 ); - anAdvLayout->addWidget( myTopology, 1, 1, 1, 1 ); - anAdvLayout->addWidget( myPreCADGroupBox , 2, 0, 1, 2 ); - anAdvLayout->addWidget( addBtn, 0, 2, 1, 1 ); - anAdvLayout->addWidget( rmBtn, 0, 3, 1, 1 ); - anAdvLayout->addWidget( myOptionTable, 1, 2, 3, 2 ); - anAdvLayout->addWidget( chooseGMFBtn, 3, 0, 1, 1 ); - anAdvLayout->addWidget( myGMFFileName, 3, 1, 1, 1 ); -// anAdvLayout->addWidget( myGMFFileMode, 4, 0, 1, 2 ); - anAdvLayout->setRowStretch(4,1); + anAdvLayout->setMargin( 11 ); + myAdvWidget = new BLSURFPluginGUI_AdvWidget(myAdvGroup); + myAdvWidget->addBtn->setMenu( new QMenu() ); + anAdvLayout->addWidget( myAdvWidget); // Size Maps parameters @@ -1057,19 +835,14 @@ QFrame* BLSURFPluginGUI_HypothesisCreator::buildFrame() // --- tab->insertTab( STD_TAB, myStdGroup, tr( "SMESH_ARGUMENTS" ) ); tab->insertTab( ADV_TAB, myAdvGroup, tr( "BLSURF_ADV_ARGS" ) ); - tab->insertTab( SMP_TAB, mySmpGroup, tr( "BLSURF_SIZE_MAP" ) ); + tab->insertTab( SMP_TAB, mySmpGroup, tr( "LOCAL_SIZE" ) ); tab->insertTab( ENF_TAB, myEnfGroup, tr( "BLSURF_ENF_VER" ) ); tab->setCurrentIndex( STD_TAB ); - // --- - connect( myGeometricMesh, SIGNAL( activated( int ) ), this, SLOT( onGeometricMeshChanged() ) ); - connect( myPhysicalMesh, SIGNAL( activated( int ) ), this, SLOT( onPhysicalMeshChanged() ) ); - connect( myTopology, SIGNAL( activated( int ) ), this, SLOT( onTopologyChanged( int ) ) ); - connect( addBtn->menu(), SIGNAL( aboutToShow() ), this, SLOT( onAddOption() ) ); - connect( addBtn->menu(), SIGNAL( triggered( QAction* ) ), this, SLOT( onOptionChosenInPopup( QAction* ) ) ); - connect( rmBtn, SIGNAL( clicked()), this, SLOT( onDeleteOption() ) ); - connect( chooseGMFBtn, SIGNAL( clicked()), this, SLOT( onChooseGMFFile() ) ); + 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() ) ); // Size Maps connect( addMapButton, SIGNAL( clicked()), this, SLOT( onAddMap() ) ); @@ -1430,9 +1203,9 @@ void BLSURFPluginGUI_HypothesisCreator::onAddEnforcedVertices() { for (int column = 0; column < myEnforcedTreeWidget->columnCount(); ++column) myEnforcedTreeWidget->resizeColumnToContents(column); - if ( myPhysicalMesh->currentIndex() != SizeMap ) { - myPhysicalMesh->setCurrentIndex( SizeMap ); - onPhysicalMeshChanged(); + if ( myStdWidget->myPhysicalMesh->currentIndex() != PhysicalLocalSize ) { + myStdWidget->myPhysicalMesh->setCurrentIndex( PhysicalLocalSize ); + myStdWidget->onPhysicalMeshChanged(); } } @@ -1482,12 +1255,7 @@ void BLSURFPluginGUI_HypothesisCreator::onRemoveEnforcedVertex() { void BLSURFPluginGUI_HypothesisCreator::onInternalVerticesClicked(int state) { - if (state == Qt::Checked) { - myInternalEnforcedVerticesAllFacesGroup->setEnabled(true); - } - if (state == Qt::Unchecked) { - myInternalEnforcedVerticesAllFacesGroup->setEnabled(false); - } + myInternalEnforcedVerticesAllFacesGroup->setEnabled(state == Qt::Checked); } /** BLSURFPluginGUI_HypothesisCreator::retrieveParams() @@ -1506,47 +1274,62 @@ void BLSURFPluginGUI_HypothesisCreator::retrieveParams() const QFontMetrics metrics( myName->font() ); myName->setMinimumWidth( metrics.width( data.myName )+5 ); } - myTopology->setCurrentIndex( data.myTopology ); - myPreCADGroupBox->setEnabled(data.myTopology == PreCAD); - myPreCADMergeEdges->setChecked( data.myPreCADMergeEdges ); - myPreCADRemoveNanoEdges->setChecked( data.myPreCADRemoveNanoEdges ); - myPreCADDiscardInput->setChecked( data.myPreCADDiscardInput ); - MESSAGE("data.myPreCADEpsNano: "<setText(""); + myStdWidget->myPhysicalMesh->setCurrentIndex( data.myPhysicalMesh ); + myStdWidget->myGeometricMesh->setCurrentIndex( data.myGeometricMesh ); + if (data.myPhySize <= 0) + myStdWidget->myPhySize->setText(""); else - myPreCADEpsNano->SetValue( data.myPreCADEpsNano ); - myPhysicalMesh->setCurrentIndex( data.myPhysicalMesh ); - myPhySize->SetValue( data.myPhySize ); -#ifdef WITH_SIZE_BOUNDARIES - MESSAGE("data.myPhyMin: "<setText(""); + myStdWidget->myPhySize->SetValue( data.myPhySize ); + myStdWidget->myPhySizeRel->setChecked( data.myPhySizeRel ); + if (data.myMinSize < 0) + myStdWidget->myMinSize->setText(""); else - myPhyMin->SetValue( data.myPhyMin ); - MESSAGE("data.myPhyMax: "<setText(""); + myStdWidget->myMinSize->SetValue( data.myMinSize ); + myStdWidget->myMinSizeRel->setChecked( data.myMinSizeRel ); + if (data.myMaxSize < 0) + myStdWidget->myMaxSize->setText(""); else - myPhyMax->SetValue( data.myPhyMax ); - MESSAGE("data.myGeoMin: "<setText(""); + myStdWidget->myMaxSize->SetValue( data.myMaxSize ); + myStdWidget->myMaxSizeRel->setChecked( data.myMaxSizeRel ); + if (data.myGradation <= 0) + myStdWidget->myGradation->setText(""); else - myGeoMin->SetValue( data.myGeoMin ); - MESSAGE("data.myGeoMax: "<setText(""); + myStdWidget->myGradation->SetValue( data.myGradation ); + myStdWidget->myAllowQuadrangles->setChecked( data.myAllowQuadrangles ); + + if (data.myAngleMesh < 0) + myStdWidget->myAngleMesh->setText(""); else - myGeoMax->SetValue( data.myGeoMax ); -#endif - myGeometricMesh->setCurrentIndex( data.myGeometricMesh ); - myAngleMeshS->SetValue( data.myAngleMeshS ); - myAngleMeshC->SetValue( data.myAngleMeshC ); - myGradation->SetValue( data.myGradation ); - myAllowQuadrangles->setChecked( data.myAllowQuadrangles ); - myDecimesh->setChecked( data.myDecimesh ); - myVerbosity->setValue( data.myVerbosity ); + myStdWidget->myAngleMesh->SetValue( data.myAngleMesh ); + if (data.myChordalError <= 0) + myStdWidget->myChordalError->setText(""); + else + myStdWidget->myChordalError->SetValue( data.myChordalError ); + myStdWidget->myAnisotropic->setChecked( data.myAnisotropic ); + if (data.myAnisotropicRatio <= 0) + myStdWidget->myAnisotropicRatio->setText(""); + else + myStdWidget->myAnisotropicRatio->SetValue( data.myAnisotropicRatio ); + myStdWidget->myRemoveTinyEdges->setChecked( data.myRemoveTinyEdges ); + if (data.myTinyEdgeLength <= 0) + myStdWidget->myTinyEdgeLength->setText(""); + else + myStdWidget->myTinyEdgeLength->SetValue( data.myTinyEdgeLength ); + myStdWidget->myForceBadElementRemoval->setChecked( data.myForceBadElementRemoval ); + if (data.myBadElementAspectRatio <= 0) + myStdWidget->myBadElementAspectRatio->setText(""); + else + myStdWidget->myBadElementAspectRatio->SetValue( data.myBadElementAspectRatio ); + myStdWidget->myOptimizeMesh->setChecked( data.myOptimizeMesh ); + myStdWidget->myQuadraticMesh->setChecked( data.myQuadraticMesh ); + + myStdWidget->resizeWidgets(); + + myAdvWidget->myVerbosity->setValue( data.myVerbosity ); + myAdvWidget->myPreCADGroupBox->setChecked(data.myTopology == PreCAD); + myAdvWidget->myPreCADMergeEdges->setChecked( data.myPreCADMergeEdges ); + myAdvWidget->myPreCADProcess3DTopology->setChecked( data.myPreCADProcess3DTopology ); + myAdvWidget->myPreCADDiscardInput->setChecked( data.myPreCADDiscardInput ); if ( myOptions.operator->() ) { // MESSAGE("retrieveParams():myOptions->length() = " << myOptions->length()); @@ -1555,18 +1338,18 @@ void BLSURFPluginGUI_HypothesisCreator::retrieveParams() const QStringList name_value = option.split( ":", QString::KeepEmptyParts ); if ( name_value.count() > 1 ) { QString idStr = QString("%1").arg( i ); - int row = myOptionTable->rowCount(); - myOptionTable->setRowCount( row+1 ); - myOptionTable->setItem( row, OPTION_ID_COLUMN, new QTableWidgetItem( idStr ) ); - myOptionTable->item( row, OPTION_ID_COLUMN )->setFlags( 0 ); - myOptionTable->setItem( row, OPTION_TYPE_COLUMN, new QTableWidgetItem( "BLSURF" ) ); - myOptionTable->item( row, OPTION_TYPE_COLUMN )->setFlags( 0 ); - myOptionTable->setItem( row, OPTION_NAME_COLUMN, new QTableWidgetItem( name_value[0] ) ); - myOptionTable->item( row, OPTION_NAME_COLUMN )->setFlags( 0 ); - myOptionTable->setItem( row, OPTION_VALUE_COLUMN, new QTableWidgetItem( name_value[1] ) ); - myOptionTable->item( row, OPTION_VALUE_COLUMN )->setFlags( Qt::ItemIsSelectable | - Qt::ItemIsEditable | - Qt::ItemIsEnabled ); + 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[0] ) ); + myAdvWidget->myOptionTable->item( row, OPTION_NAME_COLUMN )->setFlags( 0 ); + myAdvWidget->myOptionTable->setItem( row, OPTION_VALUE_COLUMN, new QTableWidgetItem( name_value[1] ) ); + myAdvWidget->myOptionTable->item( row, OPTION_VALUE_COLUMN )->setFlags( Qt::ItemIsSelectable | + Qt::ItemIsEditable | + Qt::ItemIsEnabled ); } } } @@ -1577,23 +1360,23 @@ void BLSURFPluginGUI_HypothesisCreator::retrieveParams() const QStringList name_value = option.split( ":", QString::KeepEmptyParts ); if ( name_value.count() > 1 ) { QString idStr = QString("%1").arg( i ); - int row = myOptionTable->rowCount(); - myOptionTable->setRowCount( row+1 ); - myOptionTable->setItem( row, OPTION_ID_COLUMN, new QTableWidgetItem( idStr ) ); - myOptionTable->item( row, OPTION_ID_COLUMN )->setFlags( 0 ); - myOptionTable->setItem( row, OPTION_TYPE_COLUMN, new QTableWidgetItem( "PRECAD" ) ); - myOptionTable->item( row, OPTION_TYPE_COLUMN )->setFlags( 0 ); - myOptionTable->setItem( row, OPTION_NAME_COLUMN, new QTableWidgetItem( name_value[0] ) ); - myOptionTable->item( row, OPTION_NAME_COLUMN )->setFlags( 0 ); - myOptionTable->setItem( row, OPTION_VALUE_COLUMN, new QTableWidgetItem( name_value[1] ) ); - myOptionTable->item( row, OPTION_VALUE_COLUMN )->setFlags( Qt::ItemIsSelectable | - Qt::ItemIsEditable | - Qt::ItemIsEnabled ); + 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[0] ) ); + myAdvWidget->myOptionTable->item( row, OPTION_NAME_COLUMN )->setFlags( 0 ); + myAdvWidget->myOptionTable->setItem( row, OPTION_VALUE_COLUMN, new QTableWidgetItem( name_value[1] ) ); + myAdvWidget->myOptionTable->item( row, OPTION_VALUE_COLUMN )->setFlags( Qt::ItemIsSelectable | + Qt::ItemIsEditable | + Qt::ItemIsEnabled ); } } } - myOptionTable->resizeColumnToContents( OPTION_NAME_COLUMN ); - myGMFFileName->setText(QString(data.myGMFFileName.c_str())); + myAdvWidget->myOptionTable->resizeColumnToContents( OPTION_NAME_COLUMN ); + myAdvWidget->myGMFFileName->setText(QString(data.myGMFFileName.c_str())); // myGMFFileMode->setChecked(data.myGMFFileMode); // Sizemaps @@ -1674,8 +1457,8 @@ void BLSURFPluginGUI_HypothesisCreator::retrieveParams() const myInternalEnforcedVerticesAllFacesGroup->setEnabled(data.myInternalEnforcedVerticesAllFaces); // update widgets - that->onPhysicalMeshChanged(); - that->onGeometricMeshChanged(); + that->myStdWidget->onPhysicalMeshChanged(); + that->myStdWidget->onGeometricMeshChanged(); } /** BLSURFPluginGUI_HypothesisCreator::storeParams() @@ -1704,37 +1487,39 @@ bool BLSURFPluginGUI_HypothesisCreator::readParamsFromHypo( BlsurfHypothesisData HypothesisData* data = SMESH::GetHypothesisData( hypType() ); h_data.myName = isCreation() && data ? hypName() : ""; - h_data.myTopology = (int) h->GetTopology(); - h_data.myPhysicalMesh = (int) h->GetPhysicalMesh(); - h_data.myPhySize = h->GetPhySize(); - h_data.myGeometricMesh = (int) h->GetGeometricMesh(); - h_data.myAngleMeshS = h->GetAngleMeshS(); - h_data.myAngleMeshC = h->GetAngleMeshC(); - h_data.myGradation = h->GetGradation(); - h_data.myAllowQuadrangles = h->GetQuadAllowed(); - h_data.myDecimesh = h->GetDecimesh(); - h_data.myVerbosity = h->GetVerbosity(); - h_data.myPreCADMergeEdges = h->GetPreCADMergeEdges(); - h_data.myPreCADRemoveNanoEdges = h->GetPreCADRemoveNanoEdges(); - h_data.myPreCADDiscardInput = h->GetPreCADDiscardInput(); - double EpsNano = h->GetPreCADEpsNano(); - h_data.myPreCADEpsNano = EpsNano > 0 ? EpsNano : -1.0; - -#ifdef WITH_SIZE_BOUNDARIES - double PhyMin = h->GetPhyMin(); - double PhyMax = h->GetPhyMax(); - double GeoMin = h->GetGeoMin(); - double GeoMax = h->GetGeoMax(); -// if ( PhyMin > 0 ) -// h_data.myPhyMin = PhyMin > 0 ? QString::number( h->GetPhyMin() ) : QString(""); -// h_data.myPhyMax = PhyMax > 0 ? QString::number( h->GetPhyMax() ) : QString(""); -// h_data.myGeoMin = GeoMin > 0 ? QString::number( h->GetGeoMin() ) : QString(""); -// h_data.myGeoMax = GeoMax > 0 ? QString::number( h->GetGeoMax() ) : QString(""); - h_data.myPhyMin = PhyMin > 0 ? PhyMin : -1.0; - h_data.myPhyMax = PhyMax > 0 ? PhyMax : -1.0; - h_data.myGeoMin = GeoMin > 0 ? GeoMin : -1.0; - h_data.myGeoMax = GeoMax > 0 ? GeoMax : -1.0; -#endif + h_data.myPhysicalMesh = (int) h->GetPhysicalMesh(); + h_data.myGeometricMesh = (int) h->GetGeometricMesh(); + h_data.myPhySize = h->GetPhySize(); + h_data.myPhySizeRel = h->IsPhySizeRel(); + double minSize = h->GetMinSize(); + double maxSize = h->GetMaxSize(); + h_data.myMinSize = minSize > 0 ? minSize : -1.0; + h_data.myMinSizeRel = h->IsMinSizeRel(); + h_data.myMaxSize = maxSize > 0 ? maxSize : -1.0; + h_data.myMaxSizeRel = h->IsMaxSizeRel(); + h_data.myGradation = h->GetGradation(); + h_data.myAllowQuadrangles = h->GetQuadAllowed(); + double angle = h->GetAngleMesh(); + h_data.myAngleMesh = angle > 0 ? angle : -1.0; + double chordalError = h->GetChordalError(); + h_data.myChordalError = chordalError > 0 ? chordalError : -1.0; + h_data.myAnisotropic = h->GetAnisotropic(); + double myAnisotropicRatio = h->GetAnisotropicRatio(); + h_data.myAnisotropicRatio = myAnisotropicRatio > 0 ? myAnisotropicRatio : -1.0; + h_data.myRemoveTinyEdges = h->GetRemoveTinyEdges(); + double myTinyEdgeLength = h->GetTinyEdgeLength(); + h_data.myTinyEdgeLength = myTinyEdgeLength > 0 ? myTinyEdgeLength : -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.myPreCADMergeEdges = h->GetPreCADMergeEdges(); + h_data.myPreCADProcess3DTopology = h->GetPreCADProcess3DTopology(); + h_data.myPreCADDiscardInput = h->GetPreCADDiscardInput(); + BLSURFPluginGUI_HypothesisCreator* that = (BLSURFPluginGUI_HypothesisCreator*)this; that->myOptions = h->GetOptionValues(); @@ -1886,52 +1671,77 @@ bool BLSURFPluginGUI_HypothesisCreator::storeParamsToHypo( const BlsurfHypothesi bool ok = true; try { - if( isCreation() ) + if ( isCreation() ) SMESH::SetName( SMESH::FindSObject( h ), h_data.myName.toLatin1().constData() ); - if ( h->GetTopology() != h_data.myTopology ) // avoid duplication of DumpPython commands - h->SetTopology( (int) h_data.myTopology ); - if ( h->GetPhysicalMesh() != h_data.myPhysicalMesh ) + if ( h->GetPhysicalMesh() != h_data.myPhysicalMesh ) // avoid duplication of DumpPython commands h->SetPhysicalMesh( (int) h_data.myPhysicalMesh ); if ( h->GetGeometricMesh() != (int) h_data.myGeometricMesh ) h->SetGeometricMesh( (int) h_data.myGeometricMesh ); + + if ( ((int) h_data.myPhysicalMesh == PhysicalGlobalSize)||((int) h_data.myPhysicalMesh == PhysicalLocalSize) ) { + if ( h->GetPhySize() != h_data.myPhySize ) { + if ( h_data.myPhySizeRel ) + h->SetPhySizeRel( h_data.myPhySize ); + else + h->SetPhySize( h_data.myPhySize ); + } + } + if (h->GetMinSize() != h_data.myMinSize) { + if ( h_data.myMinSizeRel ) + h->SetMinSizeRel( h_data.myMinSize <= 0 ? -1 : h_data.myMinSize ); + else + h->SetMinSize( h_data.myMinSize <= 0 ? -1 : h_data.myMinSize ); + } + if (h->GetMaxSize() != h_data.myMaxSize) { + if ( h_data.myMaxSizeRel ) + h->SetMaxSizeRel( h_data.myMaxSize <= 0 ? -1 : h_data.myMaxSize ); + else + h->SetMaxSize( h_data.myMaxSize <= 0 ? -1 : h_data.myMaxSize ); + } if ( h->GetGradation() != h_data.myGradation ) - h->SetGradation( h_data.myGradation ); + h->SetGradation( h_data.myGradation <= 0 ? -1 : h_data.myGradation ); if ( h->GetQuadAllowed() != h_data.myAllowQuadrangles ) h->SetQuadAllowed( h_data.myAllowQuadrangles ); - if ( h->GetDecimesh() != h_data.myDecimesh ) - h->SetDecimesh( h_data.myDecimesh ); + + if ( (int) h_data.myGeometricMesh != DefaultGeom ) { + if ( h->GetAngleMesh() != h_data.myAngleMesh ) + h->SetAngleMesh( h_data.myAngleMesh <= 0 ? -1 :h_data.myAngleMesh ); + if ( h->GetChordalError() != h_data.myChordalError ) + h->SetChordalError( h_data.myChordalError <= 0 ? -1 :h_data.myChordalError ); + } + + if ( h->GetAnisotropic() != h_data.myAnisotropic ) + h->SetAnisotropic( h_data.myAnisotropic ); + if ( h_data.myAnisotropic && ( h->GetAnisotropicRatio() != h_data.myAnisotropicRatio ) ) + h->SetAnisotropicRatio( h_data.myAnisotropicRatio <= 0 ? -1 :h_data.myAnisotropicRatio ); + + if ( h->GetRemoveTinyEdges() != h_data.myRemoveTinyEdges ) + h->SetRemoveTinyEdges( h_data.myRemoveTinyEdges ); + if ( h_data.myRemoveTinyEdges && ( h->GetTinyEdgeLength() != h_data.myTinyEdgeLength ) ) + h->SetTinyEdgeLength( h_data.myTinyEdgeLength <= 0 ? -1 :h_data.myTinyEdgeLength ); + + if ( h->GetBadElementRemoval() != h_data.myForceBadElementRemoval ) + h->SetBadElementRemoval( h_data.myForceBadElementRemoval ); + if ( h_data.myForceBadElementRemoval && ( h->GetBadElementAspectRatio() != h_data.myBadElementAspectRatio ) ) + h->SetBadElementAspectRatio( h_data.myBadElementAspectRatio <= 0 ? -1 :h_data.myBadElementAspectRatio ); + + if ( h->GetOptimizeMesh() != h_data.myOptimizeMesh ) + h->SetOptimizeMesh( h_data.myOptimizeMesh ); + + if ( h->GetQuadraticMesh() != h_data.myQuadraticMesh ) + h->SetQuadraticMesh( h_data.myQuadraticMesh ); + 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->GetPreCADMergeEdges() != h_data.myPreCADMergeEdges ) h->SetPreCADMergeEdges( h_data.myPreCADMergeEdges ); - if ( h->GetPreCADRemoveNanoEdges() != h_data.myPreCADRemoveNanoEdges ) - h->SetPreCADRemoveNanoEdges( h_data.myPreCADRemoveNanoEdges ); + if ( h->GetPreCADProcess3DTopology() != h_data.myPreCADProcess3DTopology ) + h->SetPreCADProcess3DTopology( h_data.myPreCADProcess3DTopology ); if ( h->GetPreCADDiscardInput() != h_data.myPreCADDiscardInput ) h->SetPreCADDiscardInput( h_data.myPreCADDiscardInput ); - if ( h->GetPreCADEpsNano() != h_data.myPreCADEpsNano && h_data.myPreCADEpsNano > 0) - h->SetPreCADEpsNano( h_data.myPreCADEpsNano ); - - if( ((int) h_data.myPhysicalMesh == PhysicalUserDefined)||((int) h_data.myPhysicalMesh == SizeMap) ) { - if ( h->GetPhySize() != h_data.myPhySize ) - h->SetPhySize( h_data.myPhySize ); - } - if( (int) h_data.myGeometricMesh == UserDefined ) { - if ( h->GetAngleMeshS() != h_data.myAngleMeshS ) - h->SetAngleMeshS( h_data.myAngleMeshS ); - if ( h->GetAngleMeshC() != h_data.myAngleMeshC ) - h->SetAngleMeshC( h_data.myAngleMeshC ); - } -#ifdef WITH_SIZE_BOUNDARIES - if (h->GetPhyMin() != h_data.myPhyMin && h_data.myPhyMin > 0) - h->SetPhyMin( h_data.myPhyMin ); - if (h->GetPhyMax() != h_data.myPhyMax && h_data.myPhyMax > 0) - h->SetPhyMax( h_data.myPhyMax ); - if (h->GetGeoMin() != h_data.myGeoMin && h_data.myGeoMin > 0) - h->SetGeoMin( h_data.myGeoMin ); - if (h->GetGeoMax() != h_data.myGeoMax && h_data.myGeoMax > 0) - h->SetGeoMax( h_data.myGeoMax ); -#endif h->SetOptionValues( myOptions ); // is set in checkParams() h->SetPreCADOptionValues( myPreCADOptions ); // is set in checkParams() @@ -2046,57 +1856,72 @@ QString BLSURFPluginGUI_HypothesisCreator::readParamsFromWidgets( BlsurfHypothes { MESSAGE("BLSURFPluginGUI_HypothesisCreator::readParamsFromWidgets"); h_data.myName = myName ? myName->text() : ""; - h_data.myTopology = myTopology->currentIndex(); - h_data.myPhysicalMesh = myPhysicalMesh->currentIndex(); - h_data.myPhySize = myPhySize->GetValue(); -#ifdef WITH_SIZE_BOUNDARIES - h_data.myPhyMin = myPhyMin->GetValue(); - h_data.myPhyMax = myPhyMax->GetValue(); - h_data.myGeoMin = myGeoMin->GetValue(); - h_data.myGeoMax = myGeoMax->GetValue(); -#endif - h_data.myGeometricMesh = myGeometricMesh->currentIndex(); - h_data.myAngleMeshS = myAngleMeshS->GetValue(); - h_data.myAngleMeshC = myAngleMeshC->GetValue(); - h_data.myGradation = myGradation->GetValue(); - h_data.myAllowQuadrangles = myAllowQuadrangles->isChecked(); - h_data.myDecimesh = myDecimesh->isChecked(); - h_data.myVerbosity = myVerbosity->value(); - h_data.myPreCADMergeEdges = myPreCADMergeEdges->isChecked(); - h_data.myPreCADRemoveNanoEdges = myPreCADRemoveNanoEdges->isChecked(); - h_data.myPreCADDiscardInput = myPreCADDiscardInput->isChecked(); - h_data.myPreCADEpsNano = myPreCADEpsNano->GetValue(); + h_data.myPhysicalMesh = myStdWidget->myPhysicalMesh->currentIndex(); + h_data.myGeometricMesh = myStdWidget->myGeometricMesh->currentIndex(); + h_data.myPhySize = myStdWidget->myPhySize->text().isEmpty() ? -1.0 : myStdWidget->myPhySize->GetValue(); + h_data.myPhySizeRel = myStdWidget->myPhySizeRel->isChecked(); + h_data.myMinSize = myStdWidget->myMinSize->text().isEmpty() ? -1.0 : myStdWidget->myMinSize->GetValue(); + 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.myGradation = myStdWidget->myGradation->text().isEmpty() ? -1.0 : myStdWidget->myGradation->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(); + h_data.myAnisotropic = myStdWidget->myAnisotropic->isChecked(); + 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.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.myPreCADProcess3DTopology = myAdvWidget->myPreCADProcess3DTopology->isChecked(); + h_data.myPreCADDiscardInput = myAdvWidget->myPreCADDiscardInput->isChecked(); QString guiHyp; - guiHyp += tr("BLSURF_TOPOLOGY") + " = " + QString::number( h_data.myTopology ) + "; "; guiHyp += tr("BLSURF_PHY_MESH") + " = " + QString::number( h_data.myPhysicalMesh ) + "; "; - guiHyp += tr("BLSURF_HPHYDEF") + " = " + QString::number( h_data.myPhySize ) + "; "; guiHyp += tr("BLSURF_GEOM_MESH") + " = " + QString::number( h_data.myGeometricMesh ) + "; "; - guiHyp += tr("BLSURF_ANGLE_MESH_S") + " = " + QString::number( h_data.myAngleMeshS ) + "; "; + guiHyp += tr("BLSURF_HPHYDEF") + " = " + QString::number( h_data.myPhySize ) + "; "; + guiHyp += tr("BLSURF_HPHYDEF") + " " + tr("BLSURF_SIZE_REL") +" = " + QString(h_data.myPhySizeRel ? "yes" : "no") + "; "; + guiHyp += tr("BLSURF_MINSIZE") + " = "+ QString::number( h_data.myMinSize ) + "; "; + guiHyp += tr("BLSURF_MINSIZE") + " " + tr("BLSURF_SIZE_REL") + " = " + QString(h_data.myMinSizeRel ? "yes" : "no") + "; "; + guiHyp += tr("BLSURF_MAXSIZE") + " = "+ QString::number( h_data.myMaxSize ) + "; "; + guiHyp += tr("BLSURF_MAXSIZE") + " " + tr("BLSURF_SIZE_REL") + " = " + QString(h_data.myMaxSizeRel ? "yes" : "no") + "; "; guiHyp += tr("BLSURF_GRADATION") + " = " + QString::number( h_data.myGradation ) + "; "; guiHyp += tr("BLSURF_ALLOW_QUADRANGLES") + " = " + QString(h_data.myAllowQuadrangles ? "yes" : "no") + "; "; - guiHyp += tr("BLSURF_DECIMESH") + " = " + QString(h_data.myDecimesh ? "yes" : "no") + "; "; -#ifdef WITH_SIZE_BOUNDARIES - guiHyp += "hphymin = " + QString::number( h_data.myPhyMin ) + "; "; - guiHyp += "hphymax = " + QString::number( h_data.myPhyMax ) + "; "; - guiHyp += "hgeomin = " + QString::number( h_data.myGeoMin ) + "; "; - guiHyp += "hgeomax = " + QString::number( h_data.myGeoMax ) + "; "; -#endif + guiHyp += tr("BLSURF_ANGLE_MESH") + " = " + QString::number( h_data.myAngleMesh ) + "; "; + guiHyp += tr("BLSURF_CHORDAL_ERROR") + " = " + QString::number( h_data.myChordalError ) + "; "; + guiHyp += tr("BLSURF_ANISOTROPIC") + " = " + QString(h_data.myAnisotropic ? "yes" : "no") + "; "; + guiHyp += tr("BLSURF_ANISOTROPIC_RATIO") + " = " + QString::number( h_data.myAnisotropicRatio ) + "; "; + + + guiHyp += tr("BLSURF_REMOVE_TINY_EDGES") + " = " + QString(h_data.myRemoveTinyEdges ? "yes" : "no") + "; "; + guiHyp += tr("BLSURF_TINY_EDGES_LENGTH") + " = " + QString::number( h_data.myTinyEdgeLength ) + "; "; + guiHyp += tr("BLSURF_REMOVE_SLIVERS") + " = " + QString(h_data.myForceBadElementRemoval ? "yes" : "no") + "; "; + guiHyp += tr("BLSURF_BAD_SURFACE_ELEMENT_ASPECT_RATIO") + " = " + QString::number( h_data.myBadElementAspectRatio ) + "; "; + guiHyp += tr("BLSURF_OPTIMISATION") + " = " + QString(h_data.myOptimizeMesh ? "yes" : "no") + "; "; + guiHyp += tr("BLSURF_ELEMENT_ORDER") + " = " + QString(h_data.myQuadraticMesh ? "yes" : "no") + "; "; + + + 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_NANO_EDGES") + " = " + QString(h_data.myPreCADRemoveNanoEdges ? "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") + "; "; - guiHyp += tr("BLSURF_PRECAD_EPS_NANO") + " = " + QString::number( h_data.myPreCADEpsNano ) + "; "; BLSURFPluginGUI_HypothesisCreator* that = (BLSURFPluginGUI_HypothesisCreator*)this; - int row = 0, nbRows = myOptionTable->rowCount(); + int row = 0, nbRows = myAdvWidget->myOptionTable->rowCount(); for ( ; row < nbRows; ++row ) { - int id = myOptionTable->item( row, OPTION_ID_COLUMN )->text().toInt(); - std::string optionType = myOptionTable->item( row, OPTION_TYPE_COLUMN )->text().toStdString(); + int id = myAdvWidget->myOptionTable->item( row, OPTION_ID_COLUMN )->text().toInt(); + std::string optionType = myAdvWidget->myOptionTable->item( row, OPTION_TYPE_COLUMN )->text().toStdString(); if ( id >= 0 && ( ( optionType == "BLSURF" && id < myOptions->length() ) || ( optionType == "PRECAD" && id < myPreCADOptions->length() ) ) ) { - QString name = myOptionTable->item( row, OPTION_NAME_COLUMN )->text(); - QString value = myOptionTable->item( row, OPTION_VALUE_COLUMN )->text().trimmed(); + 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") @@ -2112,7 +1937,7 @@ QString BLSURFPluginGUI_HypothesisCreator::readParamsFromWidgets( BlsurfHypothes } } - h_data.myGMFFileName = myGMFFileName->text().toStdString(); + h_data.myGMFFileName = myAdvWidget->myGMFFileName->text().toStdString(); // h_data.myGMFFileMode = myGMFFileMode->isChecked(); // SizeMap @@ -2186,58 +2011,6 @@ QString BLSURFPluginGUI_HypothesisCreator::readParamsFromWidgets( BlsurfHypothes return guiHyp; } - -void BLSURFPluginGUI_HypothesisCreator::onTopologyChanged(int index) { - MESSAGE("BLSURFPluginGUI_HypothesisCreator::onTopologyChanged"); - myPreCADGroupBox->setEnabled(index == PreCAD); -} - -void BLSURFPluginGUI_HypothesisCreator::onPhysicalMeshChanged() { - MESSAGE("BLSURFPluginGUI_HypothesisCreator::onPhysicalMeshChanged"); - bool isPhysicalUserDefined = (myPhysicalMesh->currentIndex() == PhysicalUserDefined); - bool isSizeMap = (myPhysicalMesh->currentIndex() == SizeMap); - bool isCustom = (isPhysicalUserDefined || isSizeMap) ; - bool geomIsCustom = (myGeometricMesh->currentIndex() == UserDefined); - - myGradation->setEnabled(!isPhysicalUserDefined || geomIsCustom); - myPhySize->setEnabled(isCustom); - myPhyMax->setEnabled(isCustom); - myPhyMin->setEnabled(isCustom); - - if ( !myGradation->isEnabled()) - myGradation->SetValue( 1.1 ); - - if ( !isCustom ) { - if ( myGeometricMesh->currentIndex() == DefaultGeom ) { - myGeometricMesh->setCurrentIndex( UserDefined ); - onGeometricMeshChanged(); - } - } -} - -void BLSURFPluginGUI_HypothesisCreator::onGeometricMeshChanged() { - MESSAGE("BLSURFPluginGUI_HypothesisCreator::onGeometricMeshChanged"); - bool isCustom = (myGeometricMesh->currentIndex() == UserDefined); - bool phyIsSizemap = (myPhysicalMesh->currentIndex() == SizeMap); - - myAngleMeshS->setEnabled(isCustom); - myAngleMeshC->setEnabled(isCustom); - myGradation->setEnabled(isCustom || phyIsSizemap); - myGeoMax->setEnabled(isCustom); - myGeoMin->setEnabled(isCustom); - - if ( !myGradation->isEnabled()) - myGradation->SetValue( 1.1 ); - - if ( ! isCustom ) { - // hphy_flag = 0 and hgeo_flag = 0 is not allowed (spec) - if ( myPhysicalMesh->currentIndex() == DefaultSize ) { - myPhysicalMesh->setCurrentIndex( PhysicalUserDefined ); - onPhysicalMeshChanged(); - } - } -} - void BLSURFPluginGUI_HypothesisCreator::onAddOption() { QMenu* menu = (QMenu*)sender(); @@ -2264,7 +2037,7 @@ void BLSURFPluginGUI_HypothesisCreator::onAddOption() void BLSURFPluginGUI_HypothesisCreator::onOptionChosenInPopup( QAction* a ) { - myOptionTable->setFocus(); + myAdvWidget->myOptionTable->setFocus(); QMenu* menu = (QMenu*)( a->parent() ); int idx = menu->actions().indexOf( a ); @@ -2281,69 +2054,59 @@ void BLSURFPluginGUI_HypothesisCreator::onOptionChosenInPopup( QAction* a ) QString optionName = option.split( ":", QString::KeepEmptyParts )[0]; // look for a row with optionName - int row = 0, nbRows = myOptionTable->rowCount(); + int row = 0, nbRows = myAdvWidget->myOptionTable->rowCount(); for ( ; row < nbRows; ++row ) - if ( myOptionTable->item( row, OPTION_ID_COLUMN )->text() == idStr ) - if ( myOptionTable->item( row, OPTION_TYPE_COLUMN )->text() == optionType ) + if ( myAdvWidget->myOptionTable->item( row, OPTION_ID_COLUMN )->text() == idStr ) + if ( myAdvWidget->myOptionTable->item( row, OPTION_TYPE_COLUMN )->text() == optionType ) break; // add a row if not found if ( row == nbRows ) { - myOptionTable->setRowCount( row+1 ); - myOptionTable->setItem( row, OPTION_ID_COLUMN, new QTableWidgetItem( idStr ) ); - myOptionTable->item( row, OPTION_ID_COLUMN )->setFlags( 0 ); - myOptionTable->setItem( row, OPTION_TYPE_COLUMN, new QTableWidgetItem( optionType ) ); - myOptionTable->item( row, OPTION_TYPE_COLUMN )->setFlags( 0 ); - myOptionTable->setItem( row, OPTION_NAME_COLUMN, new QTableWidgetItem( optionName ) ); - myOptionTable->item( row, OPTION_NAME_COLUMN )->setFlags( 0 ); - myOptionTable->setItem( row, OPTION_VALUE_COLUMN, new QTableWidgetItem( "" ) ); - myOptionTable->item( row, OPTION_VALUE_COLUMN )->setFlags( Qt::ItemIsSelectable | - Qt::ItemIsEditable | - Qt::ItemIsEnabled ); - myOptionTable->resizeColumnToContents( OPTION_NAME_COLUMN ); - } - myOptionTable->clearSelection(); - myOptionTable->scrollToItem( myOptionTable->item( row, OPTION_VALUE_COLUMN ) ); - //myOptionTable->item( row, OPTION_VALUE_COLUMN )->setSelected( true ); - myOptionTable->setCurrentCell( row, OPTION_VALUE_COLUMN ); - //myOptionTable->openPersistentEditor( myOptionTable->item( row, OPTION_VALUE_COLUMN ) ); + 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 ); + 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(); + myAdvWidget->myOptionTable->scrollToItem( myAdvWidget->myOptionTable->item( row, OPTION_VALUE_COLUMN ) ); + //myAdvWidget->myOptionTable->item( row, OPTION_VALUE_COLUMN )->setSelected( true ); + myAdvWidget->myOptionTable->setCurrentCell( row, OPTION_VALUE_COLUMN ); + //myAdvWidget->myOptionTable->openPersistentEditor( myOptionTable->item( row, OPTION_VALUE_COLUMN ) ); } void BLSURFPluginGUI_HypothesisCreator::onDeleteOption() { // clear option values and remember selected row QList selectedRows; - QList selected = myOptionTable->selectedItems(); + QList selected = myAdvWidget->myOptionTable->selectedItems(); QTableWidgetItem* item; foreach( item, selected ) { int row = item->row(); if ( !selectedRows.contains( row ) ) { selectedRows.append( row ); - int id = myOptionTable->item( row, OPTION_ID_COLUMN )->text().toInt(); - std::string optionType = myOptionTable->item( row, OPTION_TYPE_COLUMN )->text().toStdString(); + int id = myAdvWidget->myOptionTable->item( row, OPTION_ID_COLUMN )->text().toInt(); + QString optionType = myAdvWidget->myOptionTable->item( row, OPTION_TYPE_COLUMN )->text(); if ( id >= 0 ) if (optionType == "BLSURF" && id < myOptions->length() ) - myOptions[ id ] = myOptionTable->item( row, OPTION_NAME_COLUMN )->text().toLatin1().constData(); + myOptions[ id ] = myAdvWidget->myOptionTable->item( row, OPTION_NAME_COLUMN )->text().toLatin1().constData(); else if (optionType == "PRECAD" && id < myPreCADOptions->length() ) - myPreCADOptions[ id ] = myOptionTable->item( row, OPTION_NAME_COLUMN )->text().toLatin1().constData(); + myPreCADOptions[ id ] = myAdvWidget->myOptionTable->item( row, OPTION_NAME_COLUMN )->text().toLatin1().constData(); } } qSort( selectedRows ); QListIterator it( selectedRows ); it.toBack(); while ( it.hasPrevious() ) - myOptionTable->removeRow( it.previous() ); + myAdvWidget->myOptionTable->removeRow( it.previous() ); } -void BLSURFPluginGUI_HypothesisCreator::onChooseGMFFile() -{ -// QFileDialog dlg(0); -// dlg.selectFile(myGMFFileName->text()); -// dlg.setNameFilter(tr("BLSURF_GMF_FILE_FORMAT")); -// dlg.setDefaultSuffix(QString("mesh")); - myGMFFileName->setText(QFileDialog::getSaveFileName(0, tr("BLSURF_GMF_FILE_DIALOG"), myGMFFileName->text(), tr("BLSURF_GMF_FILE_FORMAT"))); -} - - // ********************** // *** BEGIN SIZE MAP *** // ********************** @@ -2677,9 +2440,9 @@ void BLSURFPluginGUI_HypothesisCreator::insertElement(GEOM::GEOM_Object_var anOb mySizeMapTable->resizeColumnToContents( SMP_ENTRY_COLUMN ); mySizeMapTable->clearSelection(); - if ( myPhysicalMesh->currentIndex() != SizeMap ) { - myPhysicalMesh->setCurrentIndex( SizeMap ); - onPhysicalMeshChanged(); + if ( myStdWidget->myPhysicalMesh->currentIndex() != PhysicalLocalSize ) { + myStdWidget->myPhysicalMesh->setCurrentIndex( PhysicalLocalSize ); + myStdWidget->onPhysicalMeshChanged(); } } @@ -2765,9 +2528,9 @@ void BLSURFPluginGUI_HypothesisCreator::insertAttractor(GEOM::GEOM_Object_var aF mySizeMapTable->resizeColumnToContents( SMP_NAME_COLUMN ); mySizeMapTable->resizeColumnToContents( SMP_SIZEMAP_COLUMN ); - if ( myPhysicalMesh->currentIndex() != SizeMap ) { - myPhysicalMesh->setCurrentIndex( SizeMap ); - onPhysicalMeshChanged(); + if ( myStdWidget->myPhysicalMesh->currentIndex() != PhysicalLocalSize ) { + myStdWidget->myPhysicalMesh->setCurrentIndex( PhysicalLocalSize ); + myStdWidget->onPhysicalMeshChanged(); } MESSAGE("mySMPMap.size() = "< +#include + +using namespace std; + +////////////////////////////////////////// +// BLSURFPluginGUI_StdWidget +////////////////////////////////////////// + +BLSURFPluginGUI_StdWidget::BLSURFPluginGUI_StdWidget( QWidget* parent, Qt::WindowFlags f ) +: QWidget( parent, f ) +{ + setupUi( this ); + myPhySize->RangeStepAndValidator(0, COORD_MAX, 10.0, "length_precision"); + myMinSize->RangeStepAndValidator(0, COORD_MAX, 10.0, "length_precision"); + myMaxSize->RangeStepAndValidator(0, COORD_MAX, 10.0, "length_precision"); + myGradation->RangeStepAndValidator(1.1, 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"); + myBadElementAspectRatio->RangeStepAndValidator(0, COORD_MAX, 1000, "length_precision"); + myMinSize->setText(""); + myMaxSize->setText(""); + myAngleMesh->setText(""); + myChordalError->setText(""); + myAnisotropicRatio->setText(""); + myTinyEdgeLength->setText(""); + myBadElementAspectRatio->setText(""); +} + +BLSURFPluginGUI_StdWidget::~BLSURFPluginGUI_StdWidget() +{ +} + +void BLSURFPluginGUI_StdWidget::onPhysicalMeshChanged() { + bool isPhysicalGlobalSize = (myPhysicalMesh->currentIndex() == PhysicalGlobalSize); + bool isPhysicalLocalSize = (myPhysicalMesh->currentIndex() == PhysicalLocalSize); + bool isCustom = (isPhysicalGlobalSize || isPhysicalLocalSize) ; + bool geomIsCustom = (myGeometricMesh->currentIndex() != DefaultGeom); + + myGradation->setEnabled(!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); + + GeomParamsGroupBox->setEnabled(isCustom); + myGradation->setEnabled(isCustom || isPhysicalLocalSize); + + if ( ! isCustom ) { + // hphy_flag = 0 and hgeo_flag = 0 is not allowed (spec) + if ( myPhysicalMesh->currentIndex() == DefaultSize ) { + myPhysicalMesh->setCurrentIndex( PhysicalGlobalSize ); + onPhysicalMeshChanged(); + } + } +} + +void BLSURFPluginGUI_StdWidget::resizeWidgets() { + // Set minimum width of spin boxes + // Main parameters + QFontMetrics metrics1( myPhySize->font() ); + QFontMetrics metrics2( myMinSize->font() ); + QFontMetrics metrics3( myMaxSize->font() ); + int width1 = metrics1.width(myPhySize->GetString()); + int width2 = metrics2.width(myMinSize->GetString()); + int width3 = metrics3.width(myMaxSize->GetString()); + int max_width = max(width1,width2); + max_width = max(max_width, width3); + myPhySize->setMinimumWidth( max_width+50 ); + myMinSize->setMinimumWidth( max_width+50 ); + myMaxSize->setMinimumWidth( max_width+50 ); + // Geometrical parameters + metrics1 = myAngleMesh->font(); + metrics2 = myChordalError->font(); + width1 = metrics1.width(myAngleMesh->GetString()); + width2 = metrics2.width(myChordalError->GetString()); + max_width = max(width1,width2); + myAngleMesh->setMinimumWidth( max_width+50 ); + myChordalError->setMinimumWidth( max_width+50 ); + // Other parameters + metrics1 = myAnisotropicRatio->font(); + metrics2 = myTinyEdgeLength->font(); + metrics3 = myBadElementAspectRatio->font(); + width1 = metrics1.width(myAnisotropicRatio->GetString()); + width2 = metrics2.width(myTinyEdgeLength->GetString()); + width3 = metrics3.width(myBadElementAspectRatio->GetString()); + max_width = max(width1,width2); + max_width = max(max_width, width3); + myAnisotropicRatio->setMinimumWidth( max_width+50 ); + myTinyEdgeLength->setMinimumWidth( max_width+50 ); + myBadElementAspectRatio->setMinimumWidth( max_width+50 ); +} + +void BLSURFPluginGUI_StdWidget::onEditingFinished() { + SMESHGUI_SpinBox* spinBox = (SMESHGUI_SpinBox*)sender(); + bool isEmpty = spinBox->editor()->text().isEmpty(); + if ( isEmpty ) { + spinBox->SetValue(-1); + spinBox->setText(""); + } +} + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/GUI/BLSURFPluginGUI_StdWidget_QTD.ui b/src/GUI/BLSURFPluginGUI_StdWidget_QTD.ui new file mode 100644 index 0000000..9167973 --- /dev/null +++ b/src/GUI/BLSURFPluginGUI_StdWidget_QTD.ui @@ -0,0 +1,548 @@ + + + Gilles DAVID (OCC) + BLSURFPluginGUI_StdWidget_QTD + + + + 0 + 0 + 588 + 244 + + + + + 0 + + + + + BLSURF_MESH_TYPE + + + + + + BLSURF_PHY_MESH + + + + + + + BLSURF_PHY_MESH_TOOLTIP + + + 1 + + + + BLSURF_DEFAULT_USER + + + + + GLOBAL_SIZE + + + + + LOCAL_SIZE + + + + + + + + BLSURF_GEOM_MESH + + + + + + + BLSURF_GEOM_MESH_TOOLTIP + + + + BLSURF_DEFAULT_USER + + + + + GLOBAL_SIZE + + + + + + + + + + + false + + + BLSURF_GEOMETRICAL_PARAMETERS + + + + + + + + + + + + BLSURF_ANGLE_MESH_TOOLTIP + + + BLSURF_ANGLE_MESH + + + + + + + BLSURF_CHORDAL_TOOLTIP + + + BLSURF_CHORDAL_ERROR + + + + + + + + + + BLSURF_MAIN_PARAMETERS + + + + + + BLSURF_HPHYDEF_TOOLTIP + + + BLSURF_HPHYDEF + + + + + + + + + + BLSURF_SIZE_REL_TOOLTIP + + + BLSURF_SIZE_REL + + + + + + + + + + BLSURF_SIZE_REL_TOOLTIP + + + BLSURF_SIZE_REL + + + + + + + 10.000000000000000 + + + + + + + BLSURF_SIZE_REL_TOOLTIP + + + BLSURF_SIZE_REL + + + + + + + BLSURF_GRADATION_TOOLTIP + + + BLSURF_GRADATION + + + + + + + false + + + + + + + BLSURF_MINSIZE + + + + + + + BLSURF_MAXSIZE + + + + + + + BLSURF_ELEMENT_ORDER + + + + + + + + + + BLSURF_OTHER_PARAMETERS + + + + + + BLSURF_ANISOTROPIC_TOOLTIP + + + BLSURF_ANISOTROPIC + + + + + + + false + + + + + + + BLSURF_REMOVE_TINY_EDGES_TOOLTIP + + + BLSURF_REMOVE_TINY_EDGES + + + + + + + false + + + + + + + BLSURF_REMOVE_SLIVERS_TOOLTIP + + + BLSURF_REMOVE_SLIVERS + + + + + + + false + + + + + + + BLSURF_OPTIMISATION_TOOLTIP + + + BLSURF_OPTIMISATION + + + true + + + + + + + BLSURF_ALLOW_QUADRANGLES + + + + + + + + + + + SMESHGUI_SpinBox + QDoubleSpinBox +
SMESHGUI_SpinBox.h
+
+
+ + myPhysicalMesh + myGeometricMesh + myPhySize + myPhySizeRel + myMinSize + myMinSizeRel + myMaxSize + myMaxSizeRel + myGradation + myQuadraticMesh + myAngleMesh + myChordalError + myAnisotropic + myAnisotropicRatio + myRemoveTinyEdges + myTinyEdgeLength + myForceBadElementRemoval + myBadElementAspectRatio + myOptimizeMesh + myAllowQuadrangles + + + + + myGeometricMesh + activated(int) + BLSURFPluginGUI_StdWidget_QTD + onGeometricMeshChanged() + + + 188 + 60 + + + 281 + 243 + + + + + myPhysicalMesh + activated(int) + BLSURFPluginGUI_StdWidget_QTD + onPhysicalMeshChanged() + + + 188 + 37 + + + 218 + 243 + + + + + myAnisotropic + toggled(bool) + myAnisotropicRatio + setEnabled(bool) + + + 384 + 122 + + + 541 + 127 + + + + + myRemoveTinyEdges + toggled(bool) + myTinyEdgeLength + setEnabled(bool) + + + 414 + 151 + + + 547 + 152 + + + + + myForceBadElementRemoval + toggled(bool) + myBadElementAspectRatio + setEnabled(bool) + + + 448 + 181 + + + 542 + 180 + + + + + myAnisotropic + toggled(bool) + myChordalError + setDisabled(bool) + + + 441 + 119 + + + 525 + 60 + + + + + myAnisotropic + toggled(bool) + label_8 + setDisabled(bool) + + + 425 + 121 + + + 438 + 64 + + + + + myPhySize + editingFinished() + BLSURFPluginGUI_StdWidget_QTD + onEditingFinished() + + + 159 + 119 + + + 220 + 90 + + + + + myMinSize + editingFinished() + BLSURFPluginGUI_StdWidget_QTD + onEditingFinished() + + + 144 + 150 + + + 205 + 83 + + + + + myMaxSize + editingFinished() + BLSURFPluginGUI_StdWidget_QTD + onEditingFinished() + + + 128 + 176 + + + 135 + 83 + + + + + myGradation + editingFinished() + BLSURFPluginGUI_StdWidget_QTD + onEditingFinished() + + + 170 + 201 + + + 315 + 121 + + + + + myAngleMesh + editingFinished() + BLSURFPluginGUI_StdWidget_QTD + onEditingFinished() + + + 548 + 34 + + + 566 + 86 + + + + + myChordalError + editingFinished() + BLSURFPluginGUI_StdWidget_QTD + onEditingFinished() + + + 542 + 56 + + + 537 + 86 + + + + + + onGeometricMeshChanged() + onPhysicalMeshChanged() + onEditingFinished() + +
diff --git a/src/GUI/BLSURFPlugin_msg_en.ts b/src/GUI/BLSURFPlugin_msg_en.ts index e533c0a..767eb12 100644 --- a/src/GUI/BLSURFPlugin_msg_en.ts +++ b/src/GUI/BLSURFPlugin_msg_en.ts @@ -4,76 +4,159 @@ @default - ADD_OPTION - Add option + BLSURF_MESH_TYPE + Type of mesh - BLSURF_ALLOW_QUADRANGLES - Allow Quadrangles (Test) + BLSURF_PHY_MESH + Physical Mesh - BLSURF_ANGLE_MESH_C - Angle Mesh C + BLSURF_PHY_MESH_TOOLTIP + <b><u>Physical size mode</u></b><br><br> +- "Global size": the physical size is global and the mesher will use the global physical size provided.<br> +- "Local size": the size is locally computed, on curves and surfaces, using the associated physical sizemap functions.<br> +- "None": no physical size will be computed. - BLSURF_ANGLE_MESH_S - Angle Mesh S + BLSURF_GEOM_MESH + Geometrical Mesh - BLSURF_CUSTOM_GEOM - Custom + BLSURF_GEOM_MESH_TOOLTIP + <b><u>Geometric size mode</u></b><br><br> +- "Global size": the geometrical size is global and the mesher will use the geometrical approximation provided by the geometrical parameters..<br> +- "None": no geometrical sizes will be computed. - BLSURF_CUSTOM_USER - Custom + BLSURF_DEFAULT_USER + None - BLSURF_DECIMESH - Patch independent + GLOBAL_SIZE + Global size - BLSURF_DEFAULT_GEOM - None + LOCAL_SIZE + Local size - BLSURF_DEFAULT_USER - None + BLSURF_MAIN_PARAMETERS + Main parameters - BLSURF_GEOM_MESH - Geometrical Mesh + BLSURF_HPHYDEF + User Size + + + BLSURF_HPHYDEF_TOOLTIP + Defines the constant global size.<br> +The default computed value is <em>diag</em>/<em>ratio</em>, where <em>ratio</em> is defined in the preferences. + + + BLSURF_MINSIZE + Min Size + + + BLSURF_MINSIZE_TOOLTIP + Defines the global minimum cell size desired.<br> +The default computed value is <em>diag</em>/1000. + + + BLSURF_MAXSIZE + Max Size + + + BLSURF_MAXSIZE_TOOLTIP + Defines the global maximum cell size desired.<br> +The default computed value is <em>diag</em>/5. + + + BLSURF_SIZE_REL + Relative value + + + BLSURF_SIZE_REL_TOOLTIP + The value is relative to <em>diag</em> BLSURF_GRADATION Gradation - BLSURF_HGEOMAX - Max Geometrical Size + BLSURF_GRADATION_TOOLTIP + Maximum ratio between the lengths of two adjacent edges. - BLSURF_HGEOMIN - Min Geometrical Size + BLSURF_ALLOW_QUADRANGLES + Allow Quadrangles - BLSURF_HPHYDEF - User Size + BLSURF_GEOMETRICAL_PARAMETERS + Geometrical parameters - BLSURF_HPHYMAX - Max Physical Size + BLSURF_ANGLE_MESH + Mesh angle - BLSURF_HPHYMIN - Min Physical Size + BLSURF_ANGLE_MESH_TOOLTIP + Limiting angle between the plane of a triangle of the mesh and each of the tangent planes at the three vertices.<br> +The smaller this angle is, the closer the mesh is to the exact surface, and the denser the resulting mesh is. - BLSURF_HYPOTHESIS - BLSURF 2D + BLSURF_CHORDAL_ERROR + Mesh distance - BLSURF_PHY_MESH - Physical Mesh + BLSURF_CHORDAL_TOOLTIP + Maximum desired distance between a triangle and its supporting CAD surface.<br> +The smaller this distance is, the closer the mesh is to the exact surface (only available in isotropic meshing). + + + BLSURF_OTHER_PARAMETERS + Other parameters + + + BLSURF_ANISOTROPIC + Anisotropic + + + BLSURF_ANISOTROPIC_TOOLTIP + If checked, this parameter defines the maximum anisotropic ratio of the metric governing the anisotropic meshing process.<br> + The default value of 0 means that the metric (and thus the generated elements) can be arbitrarily stretched. + + + BLSURF_REMOVE_TINY_EDGES + Remove tiny edges + + + 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_REMOVE_SLIVERS + Remove bad elements + + + BLSURF_REMOVE_SLIVERS_TOOLTIP + If checked, this parameter defines the aspect ratio triggering the "bad element” classification. + + + BLSURF_OPTIMISATION + Mesh optimisation + + + BLSURF_OPTIMISATION_TOOLTIP + If checked, MeshGems-CADSurf will optimize the mesh in order to get better shaped elements. + + + BLSURF_ELEMENT_ORDER + Quadratic mesh + + + BLSURF_HYPOTHESIS + BLSURF 2D BLSURF_ADV_ARGS @@ -109,7 +192,7 @@ OBLIGATORY_VALUE - (Obligatory value) + (Mandatory value) OPTION_TYPE_COLUMN @@ -132,7 +215,11 @@ PreCAD - REMOVE_OPTION + BLSURF_ADD_OPTION + Add option + + + BLSURF_REMOVE_OPTION Clear option @@ -160,21 +247,13 @@ Merge edges - BLSURF_PRECAD_REMOVE_NANO_EDGES - Remove nano edges + BLSURF_PRECAD_PROCESS_3D_TOPOLOGY + Process 3D topology BLSURF_PRECAD_DISCARD_INPUT Discard input topology - - BLSURF_PRECAD_EPS_NANO - Nano edge length - - - BLSURF_SIZE_MAP - Local Size - SMP_ENTRY_COLUMN Entry diff --git a/src/GUI/BLSURFPlugin_msg_fr.ts b/src/GUI/BLSURFPlugin_msg_fr.ts index 6a8bde3..fbe4538 100755 --- a/src/GUI/BLSURFPlugin_msg_fr.ts +++ b/src/GUI/BLSURFPlugin_msg_fr.ts @@ -4,76 +4,159 @@ @default - ADD_OPTION - Ajouter l'option + BLSURF_MESH_TYPE + Type de maillage - BLSURF_ALLOW_QUADRANGLES - Autoriser les quadrangles (Test) + BLSURF_PHY_MESH + Maillage physique - BLSURF_ANGLE_MESH_C - Angle de maillage C + BLSURF_PHY_MESH_TOOLTIP + <b><u>Mode de taille physique</u></b><br><br> +- "Taille globale": la taille physique est globale et le mailleur utilisera la taille physique globale fournie.<br> +- "Taille locale": la taille est localement calculée sur les courbes et surfaces en utilisant les fonctions de carte de taille associées.<br> +- "Inactive": aucune taille physique ne sera calculée. - BLSURF_ANGLE_MESH_S - Angle de maillage S + BLSURF_GEOM_MESH + Maillage géométrique - BLSURF_CUSTOM_GEOM - Personnalisé + BLSURF_GEOM_MESH_TOOLTIP + <b><u>Mode de taille géométrique</u></b><br><br> +- "Taille globale": la taille géométrique est globale et le mailleur utilisera l'approximation géométrique fournie par les paramètres géométriques.<br> +- "Inactive": aucune taille géométrique ne sera calculée. - BLSURF_CUSTOM_USER - Personnalisé + BLSURF_DEFAULT_USER + Inactif - BLSURF_DECIMESH - S'affranchir des frontières des surfaces + GLOBAL_SIZE + Taille globale - BLSURF_DEFAULT_GEOM - Inactif + LOCAL_SIZE + Taille locale - BLSURF_DEFAULT_USER - Inactif + BLSURF_MAIN_PARAMETERS + Paramètres principaux - BLSURF_GEOM_MESH - Maillage géométrique + BLSURF_HPHYDEF + Taille d'utilisateur + + + BLSURF_HPHYDEF_TOOLTIP + Défini la taille globale constante pour le maillage physique.<br> +La valeur par défaut est calculée par <em>diag</em>/<em>ratio</em>, où <em>ratio</em> est défini dans les préférences. + + + BLSURF_MINSIZE + Taille minimale + + + BLSURF_MINSIZE_TOOLTIP + Défini la taille globale minimum de cellule désirée.<br> +La valeur par défaut est calculée par <em>diag</em>/1000. + + + BLSURF_MAXSIZE + Taille maximale + + + BLSURF_MAXSIZE_TOOLTIP + Défini la taille globale maximum de cellule désirée.<br> +La valeur par défaut est calculée par <em>diag</em>/5. + + + BLSURF_SIZE_REL + Valeur relative + + + BLSURF_SIZE_REL_TOOLTIP + La valeur est relative à <em>diag</em> BLSURF_GRADATION Taux d'accroissement - BLSURF_HGEOMAX - Taille géométrique maximale + BLSURF_GRADATION_TOOLTIP + Ratio maximum entre les longueurs de deux segments adjacents. - BLSURF_HGEOMIN - Taille géométrique minimale + BLSURF_ALLOW_QUADRANGLES + Autoriser les quadrangles - BLSURF_HPHYDEF - Taille d'utilisateur + BLSURF_GEOMETRICAL_PARAMETERS + Paramètres géometriques - BLSURF_HPHYMAX - Taille physique maximale + BLSURF_ANGLE_MESH + Angle de maillage - BLSURF_HPHYMIN - Taille physique minimale + BLSURF_ANGLE_MESH_TOOLTIP + Limite d'angle entre le plan d'un triangle du maillage et chacun des plans tangents aux sommets.<br> +Plus l'angle est petit, plus le maillage sera dense et proche de la géométrie. - BLSURF_HYPOTHESIS - BLSURF 2D + BLSURF_CHORDAL_ERROR + Distance du maillage - BLSURF_PHY_MESH - Maillage physique + BLSURF_CHORDAL_TOOLTIP + Distance maximum désirée entre un triangle et sa surface CAO.<br> +Plus la distance est petite, plus le maillage sera proche de la surface (disponible en mode isotrope seulement). + + + BLSURF_OTHER_PARAMETERS + Autres paramètres + + + BLSURF_ANISOTROPIC + Anisotropie + + + BLSURF_ANISOTROPIC_TOOLTIP + Si activé, ce paramètre défini le ratio d'anisotropie maximum de la métrique pilotant de processus de maillage anisotropique.<br> + La valeur par défaut de 0 signifie que la métrique (et donc les éléments générés) peut être étirée arbitrairement. + + + BLSURF_REMOVE_TINY_EDGES + Enlever les petites arêtes + + + 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_REMOVE_SLIVERS + Enlever les mauvais éléments + + + BLSURF_REMOVE_SLIVERS_TOOLTIP + Si activé, ce paramètre défini les proportions déclenchants la classification des "mauvais éléments”. + + + BLSURF_OPTIMISATION + Optimisation du maillage + + + BLSURF_OPTIMISATION_TOOLTIP + Si activé, MeshGems-CADSurf optimisera le maillage pour obtenir des éléments de meilleurs qualité. + + + BLSURF_ELEMENT_ORDER + Maillage quadratique + + + BLSURF_HYPOTHESIS + BLSURF 2D BLSURF_ADV_ARGS @@ -132,7 +215,11 @@ PreCAD - REMOVE_OPTION + BLSURF_ADD_OPTION + Ajouter l'option + + + BLSURF_REMOVE_OPTION Effacer l'option @@ -160,21 +247,13 @@ Fusionner des arêtes - BLSURF_PRECAD_REMOVE_NANO_EDGES - Supprimer les petites arêtes + BLSURF_PRECAD_PROCESS_3D_TOPOLOGY + Nettoyer la CAO BLSURF_PRECAD_DISCARD_INPUT Ignorer la topologie - - BLSURF_PRECAD_EPS_NANO - Longueur max des petites arêtes - - - BLSURF_SIZE_MAP - Tailles locales - SMP_ENTRY_COLUMN Entrée diff --git a/src/GUI/Makefile.am b/src/GUI/Makefile.am index 8f0b6a0..e77ad36 100644 --- a/src/GUI/Makefile.am +++ b/src/GUI/Makefile.am @@ -26,6 +26,7 @@ include $(top_srcdir)/adm_local/unix/make_common_starter.am # header files salomeinclude_HEADERS = \ + BLSURFPluginGUI_Dlg.h \ BLSURFPluginGUI_HypothesisCreator.h # Libraries targets @@ -33,10 +34,19 @@ lib_LTLIBRARIES = libBLSURFPluginGUI.la dist_libBLSURFPluginGUI_la_SOURCES = \ BLSURFPluginGUI.cxx \ + BLSURFPluginGUI_StdWidget.cxx \ + BLSURFPluginGUI_AdvWidget.cxx \ BLSURFPluginGUI_HypothesisCreator.cxx MOC_FILES = \ - BLSURFPluginGUI_HypothesisCreator_moc.cxx + BLSURFPluginGUI_HypothesisCreator_moc.cxx \ + BLSURFPluginGUI_Dlg_moc.cxx + +UIC_FILES = \ + ui_BLSURFPluginGUI_StdWidget_QTD.h \ + ui_BLSURFPluginGUI_AdvWidget_QTD.h + +BUILT_SOURCES = $(UIC_FILES) nodist_libBLSURFPluginGUI_la_SOURCES = \ $(MOC_FILES) @@ -56,17 +66,18 @@ libBLSURFPluginGUI_la_CPPFLAGS = \ $(BOOST_CPPFLAGS) \ $(CORBA_CXXFLAGS) \ $(CORBA_INCLUDES) \ - $(BLSURF_INCLUDES) \ + $(MESHGEMS_CADSURF_INCLUDES) \ -I$(srcdir)/../BLSURFPlugin \ -I$(top_builddir)/idl libBLSURFPluginGUI_la_LDFLAGS = \ - $(QT_LIBS) \ + $(QT_LIBS) $(QT_MT_LIBS)\ ../BLSURFPlugin/libBLSURFEngine.la \ + ../../idl/libSalomeIDLBLSURFPLUGIN.la \ $(GUI_LDFLAGS) -lqtx -lSalomeApp -lsuit -lSalomeObject -lLightApp \ $(GEOM_LDFLAGS) -lGEOM \ - ${SMESH_LDFLAGS} -lSMESH -lGeomSelectionTools -lStdMeshersGUI -lSMESHFiltersSelection \ - $(CAS_KERNEL) $(BLSURF_LIBS) + ${SMESH_LDFLAGS} -lSMESH -lSMESHEngine -lGeomSelectionTools -lStdMeshersGUI -lSMESHFiltersSelection \ + $(CAS_KERNEL) $(MESHGEMS_CADSURF_LIBS) # resources files nodist_salomeres_DATA = \ -- 2.39.2