From: vsr Date: Fri, 21 Feb 2020 12:13:04 +0000 (+0300) Subject: Merge branch 'occ/shaper2smesh' X-Git-Tag: V9_5_0a1~5 X-Git-Url: http://git.salome-platform.org/gitweb/?p=modules%2Fsmesh.git;a=commitdiff_plain;h=6472eab132825fec572beda8276947593f85ffa1;hp=59fe51ff7f83a733aee46ecad7adb391bc4323bf Merge branch 'occ/shaper2smesh' --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 10fb7d492..3515fa48d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,10 +76,11 @@ OPTION(SALOME_BUILD_TESTS "Build SALOME tests" ON) OPTION(SALOME_BUILD_DOC "Generate SALOME SMESH documentation" ON) # Advanced options: -OPTION(SALOME_BUILD_GUI "Enable GUI" ON) -OPTION(SALOME_SMESH_USE_CGNS "Enable import/export to CGNS format" OFF) -OPTION(SALOME_SMESH_USE_TBB "Enable parallel computation" OFF) -OPTION(SALOME_SMESH_DYNLOAD_LOCAL "Load plug-ins' symbols locally (Linux only)" ON) +OPTION(SALOME_BUILD_GUI "Enable GUI" ON) +OPTION(SALOME_SMESH_USE_CGNS "Enable import/export to CGNS format" OFF) +OPTION(SALOME_SMESH_USE_TBB "Enable parallel computation" OFF) +OPTION(SALOME_SMESH_DYNLOAD_LOCAL "Load plug-ins' symbols locally (Linux only)" ON) +OPTION(SMESH_USE_MESHGEMS_HYPOSET "Prefer MeshGems algorithms in sets of hypotheses" OFF) CMAKE_DEPENDENT_OPTION(SALOME_SMESH_BUILD_FRENCH_DOC "Generate SALOME SMESH French documentation" OFF "SALOME_BUILD_DOC" OFF) @@ -87,6 +88,12 @@ IF(SALOME_SMESH_DYNLOAD_LOCAL) ADD_DEFINITIONS(-DDYNLOAD_LOCAL) ENDIF(SALOME_SMESH_DYNLOAD_LOCAL) +IF(SMESH_USE_MESHGEMS_HYPOSET) + SET(SMESH_USE_MESHGEMS_HYPOSET_VAR "true") +ELSE(SMESH_USE_MESHGEMS_HYPOSET) + SET(SMESH_USE_MESHGEMS_HYPOSET_VAR "false") +ENDIF(SMESH_USE_MESHGEMS_HYPOSET) + #On Linux use Fortran to compile MEFISTO2D IF(NOT WIN32) ENABLE_LANGUAGE(Fortran) @@ -94,7 +101,7 @@ IF(NOT WIN32) ADD_DEFINITIONS(-DENABLE_MEFISTO) ENDIF(NOT WIN32) -MARK_AS_ADVANCED(SALOME_BUILD_GUI SALOME_SMESH_USE_CGNS SALOME_SMESH_USE_TBB SALOME_SMESH_DYNLOAD_LOCAL) +MARK_AS_ADVANCED(SALOME_BUILD_GUI SALOME_SMESH_USE_CGNS SALOME_SMESH_USE_TBB SALOME_SMESH_DYNLOAD_LOCAL SMESH_USE_MESHGEMS_HYPOSET) # Prerequisites # ============= diff --git a/bin/smesh_setenv.py b/bin/smesh_setenv.py index 1500621f8..6826ab0ce 100644 --- a/bin/smesh_setenv.py +++ b/bin/smesh_setenv.py @@ -18,64 +18,64 @@ # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # -import os, sys +""" +Set-up additional environment needed for SMESH module and meshing plugins. +""" + +import os +import os.path as osp +import sys +from xml.dom.minidom import parse from setenv import add_path, get_lib_dir, salome_subdir # ----------------------------------------------------------------------------- def set_env(args): - """Add to the PATH-variables modules specific paths""" - psep = os.pathsep - python_version="python%d.%d" % sys.version_info[0:2] + """Set-up additional environment needed for SMESH module and plugins""" + py_version = 'python{}.{}'.format(*sys.version_info[:2]) + + # search and set-up meshing plugins + plugins = [] + resource_dirs = [] + for var in [i for i in os.environ if i.endswith('_ROOT_DIR') and os.environ[i]]: + plugin_root = os.environ[var] + plugin_name = var[:-9] # plugin name as extracted from environment variable + plugin_lname = plugin_name.lower() # plugin name in lowercase + # look for NAMEOFPlugin.xml file among resource files + # resource dir must be /share/salome/resources/ + resource_dir = osp.join(plugin_root, 'share', salome_subdir, 'resources', plugin_lname) + if not os.access(resource_dir, os.F_OK): + continue # directory does not exist or isn't accessible - if "SALOME_StdMeshersResources" not in os.environ: - os.environ["SALOME_StdMeshersResources"] \ - = os.path.join(os.environ["SMESH_ROOT_DIR"],"share",salome_subdir,"resources","smesh") - pass + for resource_file in [i for i in os.listdir(resource_dir) \ + if osp.isfile(os.path.join(resource_dir, i))]: + # look for resource file (XML) to extract valid plugin name + if resource_file.lower() == f'{plugin_lname}.xml': + try: + # get plugin name from 'resources' attribute of 'meshers-group' xml node + # as name extracted from environment variable can be in wrong case + xml_doc = parse(osp.join(resource_dir, resource_file)) + plugin_name = xml_doc.getElementsByTagName('meshers-group')[0].getAttribute('resources') - # find plugins - plugin_list = ["StdMeshers"] - resource_path_list = [] - for env_var in list(os.environ.keys()): - value = os.environ[env_var] - if env_var[-9:] == "_ROOT_DIR" and value: - plugin_root = value - plugin = env_var[:-9] # plugin name may have wrong case + # add plugin to the list of available meshing plugins + plugins.append(plugin_name) + resource_dirs.append(resource_dir) - # look for NAMEOFPlugin.xml file among resource files - resource_dir = os.path.join(plugin_root,"share",salome_subdir,"resources",plugin.lower()) - if not os.access( resource_dir, os.F_OK ): continue - for resource_file in os.listdir( resource_dir ): - if not resource_file.endswith( ".xml") or \ - resource_file.lower() != plugin.lower() + ".xml": - continue - # use "resources" attribute of "meshers-group" as name of plugin in a right case - from xml.dom.minidom import parse - xml_doc = parse( os.path.join( resource_dir, resource_file )) - meshers_nodes = xml_doc.getElementsByTagName("meshers-group") - if not meshers_nodes or not meshers_nodes[0].hasAttribute("resources"): continue - plugin = meshers_nodes[0].getAttribute("resources") - if plugin in plugin_list: continue + # setup environment needed for plugin + add_path(osp.join(plugin_root, 'bin', salome_subdir), 'PATH') + add_path(osp.join(plugin_root, get_lib_dir(), salome_subdir), 'PATH' \ + if sys.platform == 'win32' else 'LD_LIBRARY_PATH') + add_path(osp.join(plugin_root, 'bin', salome_subdir), 'PYTHONPATH') + add_path(osp.join(plugin_root, get_lib_dir(), salome_subdir), 'PYTHONPATH') + add_path(osp.join(plugin_root, get_lib_dir(), py_version, 'site-packages', + salome_subdir), 'PYTHONPATH') - # add paths of plugin - plugin_list.append(plugin) - if "SALOME_"+plugin+"Resources" not in os.environ: - resource_path = os.path.join(plugin_root,"share",salome_subdir,"resources",plugin.lower()) - os.environ["SALOME_"+plugin+"Resources"] = resource_path - resource_path_list.append( resource_path ) - add_path(os.path.join(plugin_root,get_lib_dir(),python_version, "site-packages",salome_subdir), "PYTHONPATH") - add_path(os.path.join(plugin_root,get_lib_dir(),salome_subdir), "PYTHONPATH") + break # one resource file is enough! + except: + continue # invalid resource valid - if sys.platform == "win32": - add_path(os.path.join(plugin_root,get_lib_dir(),salome_subdir), "PATH") - add_path(os.path.join(plugin_root,"bin",salome_subdir), "PYTHONPATH") - else: - add_path(os.path.join(plugin_root,get_lib_dir(),salome_subdir), "LD_LIBRARY_PATH") - add_path(os.path.join(plugin_root,"bin",salome_subdir), "PYTHONPATH") - add_path(os.path.join(plugin_root,"bin",salome_subdir), "PATH") - pass - pass - break - os.environ["SMESH_MeshersList"] = ":".join(plugin_list) - os.environ["SalomeAppConfig"] = os.environ["SalomeAppConfig"] + psep + psep.join(resource_path_list) + # full list of known meshers + os.environ['SMESH_MeshersList'] = os.pathsep.join(['StdMeshers'] + plugins) + # access to resources + os.environ['SalomeAppConfig'] = os.pathsep.join(os.environ['SalomeAppConfig'].split(os.pathsep) + resource_dirs) diff --git a/doc/salome/examples/cartesian_algo.py b/doc/salome/examples/cartesian_algo.py index 26bdb8bf0..d7d64b8b7 100644 --- a/doc/salome/examples/cartesian_algo.py +++ b/doc/salome/examples/cartesian_algo.py @@ -14,10 +14,13 @@ smesh = smeshBuilder.New() # create a sphere sphere = geompy.MakeSphereR( 50 ) -geompy.addToStudy( sphere, "sphere" ) + +# cut the sphere by a box +box = geompy.MakeBoxDXDYDZ( 100, 100, 100 ) +partition = geompy.MakePartition([ sphere ], [ box ], theName="partition") # create a mesh and assign a "Body Fitting" algo -mesh = smesh.Mesh( sphere ) +mesh = smesh.Mesh( partition ) cartAlgo = mesh.BodyFitted() # define a cartesian grid using Coordinates @@ -38,7 +41,27 @@ mesh.Compute() print("nb hexahedra",mesh.NbHexas()) print("nb tetrahedra",mesh.NbTetras()) print("nb polyhedra",mesh.NbPolyhedrons()) +print("nb faces",mesh.NbFaces()) +print() + +# activate creation of faces +cartHyp.SetToCreateFaces( True ) + +mesh.Compute() +print("nb hexahedra",mesh.NbHexas()) +print("nb tetrahedra",mesh.NbTetras()) +print("nb polyhedra",mesh.NbPolyhedrons()) +print("nb faces",mesh.NbFaces()) +print() +# enable consideration of shared faces +cartHyp.SetToConsiderInternalFaces( True ) +mesh.Compute() +print("nb hexahedra",mesh.NbHexas()) +print("nb tetrahedra",mesh.NbTetras()) +print("nb polyhedra",mesh.NbPolyhedrons()) +print("nb faces",mesh.NbFaces()) +print() # define the grid by setting different spacing in 2 sub-ranges of geometry spaceFuns = ["5","10+10*t"] diff --git a/doc/salome/examples/defining_hypotheses_ex17.py b/doc/salome/examples/defining_hypotheses_ex17.py index f2b7d8c20..cadd71e24 100644 --- a/doc/salome/examples/defining_hypotheses_ex17.py +++ b/doc/salome/examples/defining_hypotheses_ex17.py @@ -33,16 +33,22 @@ mesh.Segment().NumberOfSegments( 4 ) mesh.Triangle() mesh.Quadrangle(face1) -mesh.Compute() algo3D = mesh.Tetrahedron() thickness = 20 numberOfLayers = 10 stretchFactor = 1.5 -layersHyp = algo3D.ViscousLayers(thickness,numberOfLayers,stretchFactor,ignoreFaces) +groupName = "Boundary layers" +layersHyp = algo3D.ViscousLayers(thickness,numberOfLayers,stretchFactor, + ignoreFaces, # optional + groupName = groupName) # optional mesh.Compute() +# retrieve boundary prisms created by mesh.Compute() +boundaryGroup = mesh.GetGroupByName( layersHyp.GetGroupName() )[0] +print( "Nb boundary prisms", boundaryGroup.Size() ) + mesh.MakeGroup("Tetras",SMESH.VOLUME,SMESH.FT_ElemGeomType,"=",SMESH.Geom_TETRA) mesh.MakeGroup("Pyras",SMESH.VOLUME,SMESH.FT_ElemGeomType,"=",SMESH.Geom_PYRAMID) mesh.MakeGroup("Prims",SMESH.VOLUME,SMESH.FT_ElemGeomType,"=",SMESH.Geom_PENTA) @@ -55,12 +61,17 @@ edgeIds = geompy.SubShapeAllIDs( face1, geompy.ShapeType["EDGE"])[:-1] mesh = smesh.Mesh(face1,"VicsousLayers2D") mesh.Segment().NumberOfSegments( 5 ) -# viscous layers should be created on 1 edge, as we set 3 edges to ignore -vlHyp = mesh.Triangle().ViscousLayers2D( 2, 3, 1.5, edgeIds, isEdgesToIgnore=True ) - +# viscous layers will be created on 1 edge, as we set 3 edges to ignore +vlHyp = mesh.Triangle().ViscousLayers2D( 2, 3, 1.5, + edgeIds, isEdgesToIgnore=True, # optional + groupName=groupName) # optional mesh.Compute() -# viscous layers should be created on 3 edges, as we pass isEdgesToIgnore=False +# retrieve boundary elements created by mesh.Compute() +quadrangles = mesh.GetGroupByName( vlHyp.GetGroupName() )[0] +print( "Nb boundary quadrangles", quadrangles.Size() ) + +# viscous layers will be created on 3 edges, as we pass isEdgesToIgnore=False vlHyp.SetEdges( edgeIds, False ) mesh.Compute() diff --git a/doc/salome/gui/SMESH/images/cartesian3D_hyp.png b/doc/salome/gui/SMESH/images/cartesian3D_hyp.png index c9a605fea..9f4c59a03 100644 Binary files a/doc/salome/gui/SMESH/images/cartesian3D_hyp.png and b/doc/salome/gui/SMESH/images/cartesian3D_hyp.png differ diff --git a/doc/salome/gui/SMESH/images/hypo_sets.png b/doc/salome/gui/SMESH/images/hypo_sets.png index 2a9859d23..14af9af48 100644 Binary files a/doc/salome/gui/SMESH/images/hypo_sets.png and b/doc/salome/gui/SMESH/images/hypo_sets.png differ diff --git a/doc/salome/gui/SMESH/images/pref21.png b/doc/salome/gui/SMESH/images/pref21.png index 1f5d63cf9..b0d756fd7 100644 Binary files a/doc/salome/gui/SMESH/images/pref21.png and b/doc/salome/gui/SMESH/images/pref21.png differ diff --git a/doc/salome/gui/SMESH/images/viscous_layers_2d_hyp.png b/doc/salome/gui/SMESH/images/viscous_layers_2d_hyp.png index 4ad6ee0ec..f9b952fd7 100644 Binary files a/doc/salome/gui/SMESH/images/viscous_layers_2d_hyp.png and b/doc/salome/gui/SMESH/images/viscous_layers_2d_hyp.png differ diff --git a/doc/salome/gui/SMESH/images/viscous_layers_hyp.png b/doc/salome/gui/SMESH/images/viscous_layers_hyp.png index aaf9ad658..b7bbffbe6 100644 Binary files a/doc/salome/gui/SMESH/images/viscous_layers_hyp.png and b/doc/salome/gui/SMESH/images/viscous_layers_hyp.png differ diff --git a/doc/salome/gui/SMESH/input/additional_hypo.rst b/doc/salome/gui/SMESH/input/additional_hypo.rst index c6665910d..6fa98f9c2 100644 --- a/doc/salome/gui/SMESH/input/additional_hypo.rst +++ b/doc/salome/gui/SMESH/input/additional_hypo.rst @@ -108,6 +108,8 @@ computations. boundary faces/edges of the shape of this sub-mesh, at same time possibly being internal faces/edges within the whole model. +* **Create groups from layers** - activates creation of a group containing elements of the layers. + .. image:: ../images/viscous_layers_on_submesh.png :align: center diff --git a/doc/salome/gui/SMESH/input/basic_meshing_algos.rst b/doc/salome/gui/SMESH/input/basic_meshing_algos.rst index 692232fd1..d636b15f9 100644 --- a/doc/salome/gui/SMESH/input/basic_meshing_algos.rst +++ b/doc/salome/gui/SMESH/input/basic_meshing_algos.rst @@ -53,6 +53,7 @@ An algorithm represents either an implementation of a certain meshing technique * :ref:`Extrusion 3D ` - for meshing prismatic 3D shapes with hexahedra and prisms. * :ref:`Quadrangle: Medial Axis Projection ` - for quadrangle meshing of faces with sinuous borders and rings. * **Polygon per Face** meshing algorithm - generates one mesh face (either a triangle, a quadrangle or a polygon) per a geometrical face using all nodes from the face boundary. + * **Polyhedron per Solid** meshing algorithm - generates one mesh volume (of a classical type or a polyhedron) per a geometrical solid using all faces of the solid boundary. It does not require that 2D mesh is generated on geometrical faces. It creates one mesh edge per geometrical edges and applies **Polygon per Face** to faces if they are not meshed by optional algorithms of lower dimensions. * :ref:`Projection algorithms ` - for meshing by projection of another mesh. * :ref:`Import algorithms ` - for meshing by importing elements from another mesh. * :ref:`Radial Prism ` - for meshing 3D geometrical objects with cavities with hexahedra and prisms. diff --git a/doc/salome/gui/SMESH/input/cartesian_algo.rst b/doc/salome/gui/SMESH/input/cartesian_algo.rst index 46605bbe4..345872871 100644 --- a/doc/salome/gui/SMESH/input/cartesian_algo.rst +++ b/doc/salome/gui/SMESH/input/cartesian_algo.rst @@ -52,6 +52,9 @@ This dialog allows to define .. centered:: Implement Edges switched off to the left and on to the right +* **Create Faces** check-box activates creation on mesh faces. +* **Consider Shared and Internal Faces** check-box activates treatment of faces shared by solids and internal. By default the algorithm considers only outer boundaries of the geometry. +* **Apply Threshold to Shared / Internal Faces** check-box activates application of **Threshold** to cells cut by shared and internal faces, that can cause appearance of holes inside the mesh. * **Definition mode** allows choosing how Cartesian structured grid is defined. Location of nodes along each grid axis is defined individually: * You can specify the **Coordinates** of grid nodes. **Insert** button inserts a node at **Step** distance (negative or positive) from the selected node. **Delete** button removes the selected node. Double click on a coordinate in the list enables its edition. **Note** that node coordinates are measured along directions of axes that can differ from the directions of the Global Coordinate System. diff --git a/doc/salome/gui/SMESH/input/constructing_meshes.rst b/doc/salome/gui/SMESH/input/constructing_meshes.rst index f5aca4457..05c4c0d39 100644 --- a/doc/salome/gui/SMESH/input/constructing_meshes.rst +++ b/doc/salome/gui/SMESH/input/constructing_meshes.rst @@ -160,7 +160,6 @@ To construct a mesh: List of sets of hypotheses. Tag *[custom]* is automatically added to the sets defined by the user. .. note:: - * *"Automatic"* in the names of predefined sets of hypotheses does not actually mean that they are suitable for meshing any geometry. * The list of sets of hypotheses can be shorter than in the above image depending on the geometry dimension. diff --git a/doc/salome/gui/SMESH/input/mesh_preferences.rst b/doc/salome/gui/SMESH/input/mesh_preferences.rst index 734011f1b..027518e91 100644 --- a/doc/salome/gui/SMESH/input/mesh_preferences.rst +++ b/doc/salome/gui/SMESH/input/mesh_preferences.rst @@ -101,6 +101,10 @@ General Preferences * **Default Number of Segments** - defines the default number of segments in :ref:`Number of Segments ` hypothesis. +.. _use_meshgems_pref: + + * **Use MeshGems meshers when assigning set of hypotheses** - if activated, commercial meshers of MeshGems suite are used instead of a free mesher NETGEN when assigning a set of hypotheses in Create Mesh/Sub-mesh dialog. + * **Mesh loading** * **No mesh loading from study file at hypothesis modification** - if activated, the mesh data will not be loaded from the study file when a hypothesis is modified. This allows saving time by omitting loading data of a large mesh that is planned to be recomputed with other parameters. diff --git a/idl/SMESH_BasicHypothesis.idl b/idl/SMESH_BasicHypothesis.idl index a4bb746a6..1f8bf76f6 100644 --- a/idl/SMESH_BasicHypothesis.idl +++ b/idl/SMESH_BasicHypothesis.idl @@ -924,6 +924,9 @@ module StdMeshers void SetMethod( in VLExtrusionMethod how ); VLExtrusionMethod GetMethod(); + + void SetGroupName(in string name); + string GetGroupName(); }; /*! @@ -965,6 +968,9 @@ module StdMeshers */ void SetStretchFactor(in double factor) raises (SALOME::SALOME_Exception); double GetStretchFactor(); + + void SetGroupName(in string name); + string GetGroupName(); }; /*! @@ -1031,7 +1037,7 @@ module StdMeshers boolean GetFixedPoint(out SMESH::PointStruct p); /*! - * Enables implementation of geometrical edges into the mesh. If this feature + * Enable implementation of geometrical edges into the mesh. If this feature * is disabled, sharp edges of the shape are lost ("smoothed") in the mesh if * they don't coincide with the grid lines */ @@ -1039,17 +1045,35 @@ module StdMeshers boolean GetToAddEdges(); /*! - * Returns axes at which a number of generated hexahedra is maximal + * Enable treatment of geom faces, either shared by solids or internal. + */ + void SetToConsiderInternalFaces(in boolean toTreat); + boolean GetToConsiderInternalFaces(); + + /*! + * Enable applying size threshold to grid cells cut by internal geom faces. + */ + void SetToUseThresholdForInternalFaces(in boolean toUse); + boolean GetToUseThresholdForInternalFaces(); + + /*! + * Enable creation of mesh faces. + */ + void SetToCreateFaces(in boolean toCreate); + boolean GetToCreateFaces(); + + /*! + * Return axes at which a number of generated hexahedra is maximal */ void ComputeOptimalAxesDirs(in GEOM::GEOM_Object shape, in boolean isOrthogonal, out SMESH::DirStruct x, out SMESH::DirStruct y, - out SMESH::DirStruct z ) + out SMESH::DirStruct z ) raises (SALOME::SALOME_Exception); /*! - * \brief Computes node coordinates by spacing functions + * \brief Compute node coordinates by spacing functions * \param x0 - lower coordinate * \param x1 - upper coordinate * \param spaceFuns - space functions @@ -1114,6 +1138,13 @@ module StdMeshers { }; + /*! + * StdMeshers_PolyhedronPerSolid_3D: interface of "Polyhedron Per Solid" 3D algorithm + */ + interface StdMeshers_PolyhedronPerSolid_3D : SMESH::SMESH_3D_Algo + { + }; + /*! * StdMeshers_Hexa_3D: interface of "Hexahedron (i,j,k)" algorithm */ diff --git a/idl/SMESH_Gen.idl b/idl/SMESH_Gen.idl index cdb800e87..f612bb08e 100644 --- a/idl/SMESH_Gen.idl +++ b/idl/SMESH_Gen.idl @@ -116,6 +116,15 @@ module SMESH }; typedef sequence compute_error_array; + /*! + * Way to initialize hypothesis + */ + struct HypInitParams + { + short way; // 0 - by mesh, 1 - by geometry size + prefered parameters, 2 - by averageLength + double averageLength; + boolean quadDominated; + }; interface SMESH_Gen : Engines::EngineComponent, SALOMEDS::Driver { @@ -164,6 +173,15 @@ module SMESH in string theLibName ) raises ( SALOME::SALOME_Exception ); + /*! + * Create a hypothesis and initialize it by average length + */ + SMESH_Hypothesis CreateHypothesisByAverageLength( in string theHypName, + in string theLibName, + in double theAverageLength, + in boolean theQuadDominated) + raises ( SALOME::SALOME_Exception ); + /*! * Return a hypothesis holding parameter values corresponding either to the mesh * existing on the given geometry or to size of the geometry. @@ -175,7 +193,7 @@ module SMESH in string theLibName, in SMESH_Mesh theMesh, in GEOM::GEOM_Object theGeom, - in boolean byMesh) + in HypInitParams theWay) raises ( SALOME::SALOME_Exception ); /*! diff --git a/resources/CMakeLists.txt b/resources/CMakeLists.txt index 9a122695a..405c626f7 100644 --- a/resources/CMakeLists.txt +++ b/resources/CMakeLists.txt @@ -21,7 +21,18 @@ # SET(SMESH_RESOURCES_FILES + ModuleMesh.png + advanced_mesh_info.png + bare_border_face.png + bare_border_volume.png + copy_mesh.png + copy_mesh_with_geom.png delete.png + mesh.png + mesh_0D_elem.png + mesh_0D_on_all_nodes.png + mesh_2d_from_3d.png + mesh_add.png mesh_add_sub.png mesh_algo_hexa.png mesh_algo_mefisto.png @@ -29,212 +40,204 @@ SET(SMESH_RESOURCES_FILES mesh_algo_regular.png mesh_algo_tetra.png mesh_angle.png + mesh_angle_measure.png mesh_area.png mesh_aspect.png mesh_aspect_3d.png + mesh_ball.png mesh_biquad_quadrangle.png mesh_biquad_triangle.png + mesh_bounding_box.png + mesh_build_compound.png mesh_choose.png mesh_choose_all.png mesh_clear.png mesh_compute.png - mesh_evaluate.png - mesh_order.png + mesh_conv_to_quad.png + mesh_cutGroups.png + mesh_cutquad.png + mesh_deflection.png + mesh_deleteGroups.png mesh_diagonal.png + mesh_duplicate_elem_only.png + mesh_duplicate_group_boundary.png + mesh_duplicate_nodes.png + mesh_duplicate_nodes_with_elem.png mesh_edit.png - mesh_hexa.png - mesh_hypo_area.png - mesh_hypo_length.png - mesh_hypo_segment.png - mesh_hypo_volume.png - mesh_hypo_edit.png - mesh_plus.png - mesh_minus.png - mesh_info.png - advanced_mesh_info.png - standard_mesh_info.png + mesh_edit_group.png mesh_elem_info.png mesh_equal_edge.png mesh_equal_face.png mesh_equal_node.png mesh_equal_volume.png - mesh_whatis.png - mesh_init.png - mesh_length.png - mesh_length_2d.png + mesh_evaluate.png + mesh_extmeth_face_offset.png + mesh_extmeth_node_offset.png + mesh_extmeth_surf_offset_smooth.png + mesh_extractGroup.png + mesh_extrusion.png + mesh_extrusionpath.png + mesh_face_groups_by_edges.png mesh_find_elem_by_point.png mesh_free_edges.png mesh_free_edges_2d.png + mesh_free_faces.png mesh_free_nodes.png + mesh_group.png + mesh_groups_from_gemetry.png + mesh_hexa.png + mesh_hide.png + mesh_hypo_area.png + mesh_hypo_edit.png + mesh_hypo_layer_distribution.png + mesh_hypo_length.png + mesh_hypo_segment.png + mesh_hypo_source_3d.png + mesh_hypo_source_edge.png + mesh_hypo_source_face.png + mesh_hypo_viscous_layers.png + mesh_hypo_volume.png + mesh_info.png + mesh_init.png + mesh_intersectGroups.png + mesh_length.png + mesh_length_2d.png + mesh_line.png + mesh_line_n.png + mesh_make_group.png mesh_max_element_length_2d.png mesh_max_element_length_3d.png - mesh_multi_edges.png - mesh_multi_edges_2d.png - mesh_line_n.png - mesh_line.png + mesh_measure_area.png + mesh_measure_basic_props.png + mesh_measure_length.png + mesh_measure_volume.png + mesh_merge_elements.png + mesh_merge_nodes.png + mesh_min_dist.png + mesh_minus.png mesh_move_node.png mesh_move_without_node.png + mesh_multi_edges.png + mesh_multi_edges_2d.png + mesh_node_to_point.png mesh_octahedron.png + mesh_offset.png + mesh_order.png mesh_orientation.png - mesh.png + mesh_pattern.png + mesh_pentahedron.png mesh_plugins_meshcut.png + mesh_plus.png + mesh_points.png mesh_polygon.png mesh_polyhedron.png - mesh_pyramid_n.png + mesh_precompute.png mesh_pyramid.png - mesh_quad_n.png + mesh_pyramid_n.png mesh_quad.png + mesh_quad_edge.png + mesh_quad_hexahedron.png + mesh_quad_n.png + mesh_quad_pentahedron.png + mesh_quad_polygon.png + mesh_quad_pyramid.png + mesh_quad_quadrangle.png + mesh_quad_tetrahedron.png + mesh_quad_triangle.png mesh_quadrangle_quadpref.png mesh_quadrangle_quadpref_reversed.png mesh_quadrangle_reduced.png mesh_quadrangle_standard.png mesh_quadrangle_triapref.png + mesh_quality.png mesh_rem_element.png mesh_rem_node.png mesh_rem_orphan_nodes.png + mesh_remove.png + mesh_renumbering_elements.png + mesh_renumbering_nodes.png + mesh_revolution.png + mesh_rotation.png + mesh_sew_bordertoside.png + mesh_sew_conform_freeborders.png + mesh_sew_freeborders.png + mesh_sew_sideelements.png mesh_shading.png + mesh_show.png mesh_shrink.png mesh_skew.png + mesh_smoothing.png + mesh_symmetry_axis.png + mesh_symmetry_plane.png + mesh_symmetry_point.png mesh_taper.png mesh_tetra.png + mesh_translation_points.png + mesh_translation_vector.png + mesh_tree_algo.png + mesh_tree_algo_0D.png + mesh_tree_algo_existing_2D.png mesh_tree_algo_hexa.png mesh_tree_algo_mefisto.png mesh_tree_algo_polygon.png - mesh_tree_algo.png - mesh_tree_algo_0D.png + mesh_tree_algo_prism.png + mesh_tree_algo_projection_2d.png mesh_tree_algo_quad.png + mesh_tree_algo_radial_prism.png + mesh_tree_algo_radial_quadrangle_1D2D.png mesh_tree_algo_regular.png mesh_tree_algo_tetra.png + mesh_tree_group.png + mesh_tree_group_on_filter.png + mesh_tree_hypo.png mesh_tree_hypo_area.png + mesh_tree_hypo_cartesian.png + mesh_tree_hypo_import_source_1d.png + mesh_tree_hypo_import_source_2d.png + mesh_tree_hypo_layers_distribution.png + mesh_tree_hypo_layers_distribution_2d.png mesh_tree_hypo_length.png - mesh_tree_hypo.png + mesh_tree_hypo_projection_2d.png + mesh_tree_hypo_projection_3d.png + mesh_tree_hypo_quadratic.png mesh_tree_hypo_segment.png + mesh_tree_hypo_source_3d_shape.png + mesh_tree_hypo_source_edge.png + mesh_tree_hypo_source_face.png + mesh_tree_hypo_viscous_layers.png mesh_tree_hypo_volume.png - mesh_tree_hypo_cartesian.png - mesh_tree_mesh.png mesh_tree_importedmesh.png - mesh_tree_mesh_warn.png + mesh_tree_mesh.png mesh_tree_mesh_geom_modif.png + mesh_tree_mesh_partial.png + mesh_tree_mesh_warn.png + mesh_triangle.png mesh_triangle_n.png mesh_triquad_hexahedron.png - mesh_triangle.png + mesh_union2tri.png + mesh_unionGroups.png + mesh_uniontri.png mesh_update.png - mesh_vertex_n.png mesh_vertex.png - mesh_0D_elem.png - mesh_0D_on_all_nodes.png + mesh_vertex_n.png mesh_volume_3d.png - bare_border_volume.png - bare_border_face.png - over_constrained_volume.png - over_constrained_face.png + mesh_whatis.png mesh_wireframe.png - mesh_points.png mesh_wrap.png - mesh_group.png - mesh_tree_group.png - mesh_tree_group_on_filter.png - mesh_edit_group.png - mesh_make_group.png - mesh_groups_from_gemetry.png - mesh_union2tri.png - mesh_uniontri.png - mesh_cutquad.png - mesh_smoothing.png - mesh_renumbering_nodes.png - mesh_renumbering_elements.png - mesh_extrusion.png - mesh_extrusionpath.png - mesh_revolution.png - ModuleMesh.png - mesh_unionGroups.png - mesh_intersectGroups.png - mesh_cutGroups.png - mesh_deleteGroups.png - mesh_translation_vector.png - mesh_translation_points.png - mesh_rotation.png - mesh_symmetry_point.png - mesh_symmetry_axis.png - mesh_symmetry_plane.png - mesh_sew_freeborders.png - mesh_sew_conform_freeborders.png - mesh_sew_bordertoside.png - mesh_sew_sideelements.png - mesh_merge_nodes.png - mesh_merge_elements.png - select1.png open.png - mesh_pattern.png - mesh_pentahedron.png + over_constrained_face.png + over_constrained_volume.png pattern_sample_2d.png pattern_sample_3D.png - mesh_add.png - mesh_remove.png - mesh_quad_edge.png - mesh_quad_triangle.png - mesh_quad_quadrangle.png - mesh_quad_polygon.png - mesh_quad_tetrahedron.png - mesh_quad_pyramid.png - mesh_quad_pentahedron.png - mesh_quad_hexahedron.png - mesh_conv_to_quad.png - mesh_tree_hypo_layers_distribution.png - mesh_tree_algo_radial_prism.png - mesh_tree_algo_radial_quadrangle_1D2D.png - mesh_tree_algo_existing_2D.png - mesh_tree_algo_prism.png - mesh_tree_algo_projection_2d.png - mesh_hypo_source_edge.png - mesh_hypo_source_3d.png - mesh_hypo_layer_distribution.png - mesh_hypo_source_face.png - mesh_tree_hypo_source_face.png - mesh_tree_hypo_source_edge.png - mesh_tree_hypo_source_3d_shape.png - mesh_tree_hypo_projection_3d.png - mesh_tree_hypo_projection_2d.png - mesh_tree_hypo_quadratic.png - mesh_build_compound.png - copy_mesh.png - copy_mesh_with_geom.png - mesh_node_to_point.png - mesh_tree_mesh_partial.png - mesh_extractGroup.png - mesh_precompute.png - mesh_2d_from_3d.png - mesh_free_faces.png + reorient_faces_face.png + reorient_faces_point.png + reorient_faces_volume.png scale.png scale_along_axes.png - split_into_tetra.png + select1.png split_biquad.png - mesh_duplicate_nodes.png - mesh_duplicate_nodes_with_elem.png - mesh_duplicate_elem_only.png - mesh_duplicate_group_boundary.png - mesh_bounding_box.png - mesh_hypo_viscous_layers.png - mesh_tree_hypo_viscous_layers.png - mesh_min_dist.png - reorient_faces_point.png - reorient_faces_face.png - reorient_faces_volume.png - mesh_ball.png - mesh_measure_basic_props.png - mesh_measure_length.png - mesh_measure_area.png - mesh_measure_volume.png - mesh_extmeth_node_offset.png - mesh_extmeth_surf_offset_smooth.png - mesh_extmeth_face_offset.png - mesh_quality.png - mesh_show.png - mesh_hide.png - mesh_deflection.png - mesh_offset.png - mesh_face_groups_by_edges.png - mesh_angle_measure.png + split_into_tetra.png + standard_mesh_info.png ) INSTALL(FILES ${SMESH_RESOURCES_FILES} DESTINATION ${SALOME_SMESH_INSTALL_RES_DATA}) diff --git a/resources/SalomeApp.xml.in b/resources/SalomeApp.xml.in index b78f7a903..4af56219a 100644 --- a/resources/SalomeApp.xml.in +++ b/resources/SalomeApp.xml.in @@ -76,6 +76,7 @@ + diff --git a/resources/StdMeshers.xml.in b/resources/StdMeshers.xml.in index 14ed93a0c..d70cdd45e 100644 --- a/resources/StdMeshers.xml.in +++ b/resources/StdMeshers.xml.in @@ -224,7 +224,6 @@ @@ -318,7 +317,7 @@ MEFISTO_2D=Triangle(algo=smeshBuilder.MEFISTO) LengthFromEdges=LengthFromEdges() MaxElementArea=MaxElementArea(SetMaxElementArea()) - ViscousLayers2D=ViscousLayers2D(SetTotalThickness(),SetNumberLayers(),SetStretchFactor(),SetEdges(1),SetEdges(2)) + ViscousLayers2D=ViscousLayers2D(SetTotalThickness(),SetNumberLayers(),SetStretchFactor(),SetEdges(1),SetEdges(2),SetGroupName()) @@ -335,7 +334,7 @@ Quadrangle_2D=Quadrangle(algo=smeshBuilder.QUADRANGLE) QuadrangleParams=QuadrangleParameters(SetQuadType(),SetTriaVertex(),SetEnforcedNodes(1),SetEnforcedNodes(2),SetCorners()) - ViscousLayers2D=ViscousLayers2D(SetTotalThickness(),SetNumberLayers(),SetStretchFactor(),SetIgnoreEdges()) + ViscousLayers2D=ViscousLayers2D(SetTotalThickness(),SetNumberLayers(),SetStretchFactor(),SetEdges(1),SetEdges(2),SetGroupName()) @@ -351,7 +350,7 @@ dim ="2"> QuadFromMedialAxis_1D2D=Quadrangle(algo=smeshBuilder.QUAD_MA_PROJ) - ViscousLayers2D=ViscousLayers2D(SetTotalThickness(),SetNumberLayers(),SetStretchFactor(),SetIgnoreEdges()) + ViscousLayers2D=ViscousLayers2D(SetTotalThickness(),SetNumberLayers(),SetStretchFactor(),SetEdges(1),SetEdges(2),SetGroupName()) NumberOfLayers2D=NumberOfLayers(SetNumberOfLayers()) @@ -367,7 +366,19 @@ dim ="2"> PolygonPerFace_2D=Polygon() - ViscousLayers2D=ViscousLayers2D(SetTotalThickness(),SetNumberLayers(),SetStretchFactor(),SetIgnoreEdges()) + ViscousLayers2D=ViscousLayers2D(SetTotalThickness(),SetNumberLayers(),SetStretchFactor(),SetEdges(1),SetEdges(2),SetGroupName()) + + + + + + PolyhedronPerSolid_3D=Polyhedron() + ViscousLayers=ViscousLayers(SetTotalThickness(),SetNumberLayers(),SetStretchFactor(),SetIgnoreEdges()) @@ -383,7 +394,7 @@ dim ="3"> Hexa_3D=Hexahedron(algo=smeshBuilder.Hexa) - ViscousLayers=ViscousLayers(SetTotalThickness(),SetNumberLayers(),SetStretchFactor(),SetFaces(1),SetFaces(2),SetMethod()) + ViscousLayers=ViscousLayers(SetTotalThickness(),SetNumberLayers(),SetStretchFactor(),SetFaces(1),SetFaces(2),SetMethod(),SetGroupName()) @@ -558,7 +569,6 @@ support-submeshes="false" output ="HEXA" need-hyp ="true" - context ="GLOBAL" dim ="3"> Cartesian_3D=BodyFitted() @@ -590,22 +600,48 @@ - + - - - - + + + + + + diff --git a/resources/mesh_tree_hypo_import_source_1d.png b/resources/mesh_tree_hypo_import_source_1d.png new file mode 100644 index 000000000..8db626043 Binary files /dev/null and b/resources/mesh_tree_hypo_import_source_1d.png differ diff --git a/resources/mesh_tree_hypo_import_source_2d.png b/resources/mesh_tree_hypo_import_source_2d.png new file mode 100644 index 000000000..3d4e1e245 Binary files /dev/null and b/resources/mesh_tree_hypo_import_source_2d.png differ diff --git a/resources/mesh_tree_hypo_layers_distribution_2d.png b/resources/mesh_tree_hypo_layers_distribution_2d.png new file mode 100644 index 000000000..fb5082f52 Binary files /dev/null and b/resources/mesh_tree_hypo_layers_distribution_2d.png differ diff --git a/src/Controls/SMESH_Controls.cxx b/src/Controls/SMESH_Controls.cxx index 676c68aca..fc7ba629b 100644 --- a/src/Controls/SMESH_Controls.cxx +++ b/src/Controls/SMESH_Controls.cxx @@ -142,13 +142,13 @@ namespace { // Case 1 Case 2 // | | | | | // | | | | | - // +-----+------+ +-----+------+ + // +-----+------+ +-----+------+ // | | | | // | | | | // result should be 2 in both cases // int aResult0 = 0, aResult1 = 0; - // last node, it is a medium one in a quadratic edge + // last node, it is a medium one in a quadratic edge const SMDS_MeshNode* aLastNode = anEdge->GetNode( anEdge->NbNodes() - 1 ); const SMDS_MeshNode* aNode0 = anEdge->GetNode( 0 ); const SMDS_MeshNode* aNode1 = anEdge->GetNode( 1 ); @@ -491,7 +491,7 @@ double MaxElementLength2D::GetValue( const TSequenceOfXYZ& P ) // } // } // { // polygons - + // } if( myPrecision >= 0 ) @@ -765,19 +765,9 @@ double AspectRatio::GetValue( long theId ) { double aVal = 0; myCurrElement = myMesh->FindElement( theId ); - if ( myCurrElement && myCurrElement->GetVtkType() == VTK_QUAD ) - { - // issue 21723 - vtkUnstructuredGrid* grid = const_cast( myMesh )->GetGrid(); - if ( vtkCell* avtkCell = grid->GetCell( myCurrElement->GetVtkID() )) - aVal = Round( vtkMeshQuality::QuadAspectRatio( avtkCell )); - } - else - { - TSequenceOfXYZ P; - if ( GetPoints( myCurrElement, P )) - aVal = Round( GetValue( P )); - } + TSequenceOfXYZ P; + if ( GetPoints( myCurrElement, P )) + aVal = Round( GetValue( P )); return aVal; } @@ -850,7 +840,7 @@ double AspectRatio::GetValue( const TSequenceOfXYZ& P ) // // alpha = sqrt( 1/32 ) // L = max( L1, L2, L3, L4, D1, D2 ) - // C1 = sqrt( ( L1^2 + L1^2 + L1^2 + L1^2 ) / 4 ) + // C1 = sqrt( L1^2 + L1^2 + L1^2 + L1^2 ) // C2 = min( S1, S2, S3, S4 ) // Li - lengths of the edges // Di - lengths of the diagonals @@ -861,10 +851,10 @@ double AspectRatio::GetValue( const TSequenceOfXYZ& P ) Max( aLen[ 2 ], Max( aLen[ 3 ], Max( aDia[ 0 ], aDia[ 1 ] ) ) ) ) ); - double C1 = sqrt( ( aLen[0] * aLen[0] + - aLen[1] * aLen[1] + - aLen[2] * aLen[2] + - aLen[3] * aLen[3] ) / 4. ); + double C1 = sqrt( aLen[0] * aLen[0] + + aLen[1] * aLen[1] + + aLen[2] * aLen[2] + + aLen[3] * aLen[3] ); double C2 = Min( anArea[ 0 ], Min( anArea[ 1 ], Min( anArea[ 2 ], anArea[ 3 ] ) ) ); @@ -894,24 +884,24 @@ double AspectRatio::GetValue( const TSequenceOfXYZ& P ) // // alpha = sqrt( 1/32 ) // L = max( L1, L2, L3, L4, D1, D2 ) - // C1 = sqrt( ( L1^2 + L1^2 + L1^2 + L1^2 ) / 4 ) + // C1 = sqrt( L1^2 + L1^2 + L1^2 + L1^2 ) // C2 = min( S1, S2, S3, S4 ) // Li - lengths of the edges // Di - lengths of the diagonals // Si - areas of the triangles const double alpha = sqrt( 1 / 32. ); double L = Max( aLen[ 0 ], - Max( aLen[ 1 ], - Max( aLen[ 2 ], - Max( aLen[ 3 ], - Max( aDia[ 0 ], aDia[ 1 ] ) ) ) ) ); - double C1 = sqrt( ( aLen[0] * aLen[0] + - aLen[1] * aLen[1] + - aLen[2] * aLen[2] + - aLen[3] * aLen[3] ) / 4. ); + Max( aLen[ 1 ], + Max( aLen[ 2 ], + Max( aLen[ 3 ], + Max( aDia[ 0 ], aDia[ 1 ] ) ) ) ) ); + double C1 = sqrt( aLen[0] * aLen[0] + + aLen[1] * aLen[1] + + aLen[2] * aLen[2] + + aLen[3] * aLen[3] ); double C2 = Min( anArea[ 0 ], - Min( anArea[ 1 ], - Min( anArea[ 2 ], anArea[ 3 ] ) ) ); + Min( anArea[ 1 ], + Min( anArea[ 2 ], anArea[ 3 ] ) ) ); if ( C2 <= theEps ) return theInf; return alpha * L * C1 / C2; @@ -2755,14 +2745,14 @@ bool FreeFaces::IsSatisfy( long theId ) SMDS_MeshElement* aVol = (SMDS_MeshElement*)volItr->next(); TItrMapOfVolume itr = mapOfVol.insert( std::make_pair( aVol, 0 )).first; (*itr).second++; - } + } } int nbVol = 0; TItrMapOfVolume volItr = mapOfVol.begin(); TItrMapOfVolume volEnd = mapOfVol.end(); for ( ; volItr != volEnd; ++volItr ) if ( (*volItr).second >= nbNode ) - nbVol++; + nbVol++; // face is not free if number of volumes constructed on their nodes more than one return (nbVol < 2); } @@ -3171,7 +3161,7 @@ namespace double dot = v1 * v2; // cos * |v1| * |v2| double l1 = v1.SquareMagnitude(); double l2 = v2.SquareMagnitude(); - return (( dot * cos >= 0 ) && + return (( dot * cos >= 0 ) && ( dot * dot ) / l1 / l2 >= ( cos * cos )); } } @@ -4272,6 +4262,7 @@ private: bool isOutOfFace (const gp_Pnt& p); bool isOutOfEdge (const gp_Pnt& p); bool isOutOfVertex(const gp_Pnt& p); + bool isOutOfNone (const gp_Pnt& p) { return true; } bool isBox (const TopoDS_Shape& s); bool (Classifier::* myIsOutFun)(const gp_Pnt& p); @@ -4593,7 +4584,7 @@ bool ElementsOnShape::IsSatisfy (const SMDS_MeshNode* node, { isNodeOut = false; if ( okShape ) - *okShape = myWorkClassifiers[i]->Shape(); + *okShape = myClassifiers[i].Shape(); break; } } @@ -4631,17 +4622,27 @@ void ElementsOnShape::Classifier::Init( const TopoDS_Shape& theShape, { Standard_Real u1,u2,v1,v2; Handle(Geom_Surface) surf = BRep_Tool::Surface( TopoDS::Face( theShape )); - surf->Bounds( u1,u2,v1,v2 ); - myProjFace.Init(surf, u1,u2, v1,v2, myTol ); - myIsOutFun = & ElementsOnShape::Classifier::isOutOfFace; + if ( surf.IsNull() ) + myIsOutFun = & ElementsOnShape::Classifier::isOutOfNone; + else + { + surf->Bounds( u1,u2,v1,v2 ); + myProjFace.Init(surf, u1,u2, v1,v2, myTol ); + myIsOutFun = & ElementsOnShape::Classifier::isOutOfFace; + } break; } case TopAbs_EDGE: { Standard_Real u1, u2; Handle(Geom_Curve) curve = BRep_Tool::Curve( TopoDS::Edge( theShape ), u1, u2); - myProjEdge.Init(curve, u1, u2); - myIsOutFun = & ElementsOnShape::Classifier::isOutOfEdge; + if ( curve.IsNull() ) + myIsOutFun = & ElementsOnShape::Classifier::isOutOfNone; + else + { + myProjEdge.Init(curve, u1, u2); + myIsOutFun = & ElementsOnShape::Classifier::isOutOfEdge; + } break; } case TopAbs_VERTEX: diff --git a/src/DriverMED/DriverMED_R_SMESHDS_Mesh.cxx b/src/DriverMED/DriverMED_R_SMESHDS_Mesh.cxx index a8ed41c9c..68f17df38 100644 --- a/src/DriverMED/DriverMED_R_SMESHDS_Mesh.cxx +++ b/src/DriverMED/DriverMED_R_SMESHDS_Mesh.cxx @@ -266,7 +266,7 @@ Driver_Mesh::Status DriverMED_R_SMESHDS_Mesh::Perform() } #endif if ( !anIsNodeNum ) - aNodeIds.swap( *(aBallInfo->myConn )); + aNodeIds.assign( aBallInfo->myConn->begin(), aBallInfo->myConn->end()); // allocate array of diameters vtkIdType maxID = myMesh->MaxElementID() + aNbBalls; diff --git a/src/DriverMED/DriverMED_W_SMESHDS_Mesh.cxx b/src/DriverMED/DriverMED_W_SMESHDS_Mesh.cxx index a4774fe23..30f3ac4a3 100644 --- a/src/DriverMED/DriverMED_W_SMESHDS_Mesh.cxx +++ b/src/DriverMED/DriverMED_W_SMESHDS_Mesh.cxx @@ -34,6 +34,7 @@ #include "SMDS_MeshNode.hxx" #include "SMDS_SetIterator.hxx" #include "SMESHDS_Mesh.hxx" +#include "MED_Common.hxx" #include diff --git a/src/DriverMED/DriverMED_W_SMESHDS_Mesh.h b/src/DriverMED/DriverMED_W_SMESHDS_Mesh.h index 76d85a0ff..d36b2169a 100644 --- a/src/DriverMED/DriverMED_W_SMESHDS_Mesh.h +++ b/src/DriverMED/DriverMED_W_SMESHDS_Mesh.h @@ -30,7 +30,7 @@ #include "SMESH_DriverMED.hxx" #include "Driver_SMESHDS_Mesh.h" -#include "MED_Common.hxx" +//#include "MED_Common.hxx" #include #include diff --git a/src/MEDWrapper/MED_Common.hxx b/src/MEDWrapper/MED_Common.hxx index f5bb08e40..26596f8b2 100644 --- a/src/MEDWrapper/MED_Common.hxx +++ b/src/MEDWrapper/MED_Common.hxx @@ -31,7 +31,7 @@ #include #include -#include +#include #ifdef WIN32 #pragma warning(disable:4099) @@ -41,11 +41,12 @@ namespace MED { typedef enum {eFAUX, eVRAI} EBooleen; typedef double TFloat; -#if defined(HAVE_F77INT64) - typedef long TInt; -#else - typedef int TInt; -#endif +// #if defined(HAVE_F77INT64) +// typedef long TInt; +// #else +// typedef int TInt; +// #endif + typedef med_int TInt; typedef hid_t TIdt; typedef herr_t TErr; diff --git a/src/MEFISTO2/Rn.h b/src/MEFISTO2/Rn.h index cae413d78..f832ad918 100644 --- a/src/MEFISTO2/Rn.h +++ b/src/MEFISTO2/Rn.h @@ -180,12 +180,12 @@ class R4: public R3 { friend std::ostream& operator <<(std::ostream& f, const R4 & P ) { f << P.x << ' ' << P.y << ' ' << P.z << ' ' << P.omega; return f; } - friend istream& operator >>(istream& f, R4 & P) + friend std::istream& operator >>(std::istream& f, R4 & P) { f >> P.x >> P.y >> P.z >> P.omega ; return f; } friend std::ostream& operator <<(std::ostream& f, const R4 * P ) { f << P->x << ' ' << P->y << ' ' << P->z << ' ' << P->omega; return f; } - friend istream& operator >>(istream& f, R4 * P) + friend std::istream& operator >>(std::istream& f, R4 * P) { f >> P->x >> P->y >> P->z >> P->omega ; return f; } public: diff --git a/src/OBJECT/SMESH_FaceOrientationFilter.cxx b/src/OBJECT/SMESH_FaceOrientationFilter.cxx index e77f9a7d8..515629ca9 100644 --- a/src/OBJECT/SMESH_FaceOrientationFilter.cxx +++ b/src/OBJECT/SMESH_FaceOrientationFilter.cxx @@ -25,18 +25,18 @@ #include +#include #include #include -#include -#include -#include -#include - #include -#include -#include #include #include +#include +#include +#include +#include +#include +#include #include @@ -216,13 +216,16 @@ void GetFaceParams( vtkCell* theFace, double theNormal[3], double& theSize ) vtkPoints* aPoints = theFace->GetPoints(); // here we get first 3 points from the face and calculate the normal as a cross-product of vectors - double x0 = aPoints->GetPoint(0)[0], y0 = aPoints->GetPoint(0)[1], z0 = aPoints->GetPoint(0)[2]; - double x1 = aPoints->GetPoint(1)[0], y1 = aPoints->GetPoint(1)[1], z1 = aPoints->GetPoint(1)[2]; - double x2 = aPoints->GetPoint(2)[0], y2 = aPoints->GetPoint(2)[1], z2 = aPoints->GetPoint(2)[2]; + // double x0 = aPoints->GetPoint(0)[0], y0 = aPoints->GetPoint(0)[1], z0 = aPoints->GetPoint(0)[2]; + // double x1 = aPoints->GetPoint(1)[0], y1 = aPoints->GetPoint(1)[1], z1 = aPoints->GetPoint(1)[2]; + // double x2 = aPoints->GetPoint(2)[0], y2 = aPoints->GetPoint(2)[1], z2 = aPoints->GetPoint(2)[2]; + + // theNormal[0] = ( y1 - y0 ) * ( z2 - z0 ) - ( z1 - z0 ) * ( y2 - y0 ); + // theNormal[1] = ( z1 - z0 ) * ( x2 - x0 ) - ( x1 - x0 ) * ( z2 - z0 ); + // theNormal[2] = ( x1 - x0 ) * ( y2 - y0 ) - ( y1 - y0 ) * ( x2 - x0 ); - theNormal[0] = ( y1 - y0 ) * ( z2 - z0 ) - ( z1 - z0 ) * ( y2 - y0 ); - theNormal[1] = ( z1 - z0 ) * ( x2 - x0 ) - ( x1 - x0 ) * ( z2 - z0 ); - theNormal[2] = ( x1 - x0 ) * ( y2 - y0 ) - ( y1 - y0 ) * ( x2 - x0 ); + // issue #18665: Polyhedron volume calculation + vtkPolygon::ComputeNormal( aPoints, theNormal ); double* aBounds = theFace->GetBounds(); theSize = pow( pow( aBounds[1] - aBounds[0], 2 ) + diff --git a/src/SMDS/SMDS_BallElement.cxx b/src/SMDS/SMDS_BallElement.cxx index f73b4ec76..86dc634c7 100644 --- a/src/SMDS/SMDS_BallElement.cxx +++ b/src/SMDS/SMDS_BallElement.cxx @@ -29,7 +29,7 @@ void SMDS_BallElement::init(const SMDS_MeshNode * node, double diameter ) { - int nodeVtkID = node->GetVtkID(); + vtkIdType nodeVtkID = node->GetVtkID(); int vtkID = getGrid()->InsertNextLinkedCell( toVtkType( SMDSEntity_Ball ), 1, &nodeVtkID ); setVtkID( vtkID ); getGrid()->SetBallDiameter( GetVtkID(), diameter ); diff --git a/src/SMDS/SMDS_VolumeTool.cxx b/src/SMDS/SMDS_VolumeTool.cxx index 2148a15a5..fbb4f8b00 100644 --- a/src/SMDS/SMDS_VolumeTool.cxx +++ b/src/SMDS/SMDS_VolumeTool.cxx @@ -706,11 +706,12 @@ double SMDS_VolumeTool::GetSize() const if ( !myPolyedre ) return 0.; + SaveFacet savedFacet( myCurFace ); + // split a polyhedron into tetrahedrons - SaveFacet savedFacet( myCurFace ); + bool oriOk = true; SMDS_VolumeTool* me = const_cast< SMDS_VolumeTool* > ( this ); - XYZ origin( 1 + 1e-6, 22 + 2e-6, 333 + 3e-6 ); // for invalid poly: avoid lying on a facet plane for ( int f = 0; f < NbFaces(); ++f ) { me->setFace( f ); @@ -721,9 +722,12 @@ double SMDS_VolumeTool::GetSize() const area = area + p1.Crossed( p2 ); p1 = p2; } - V += ( p1 - origin ).Dot( area ); + V += p1.Dot( area ); + oriOk = oriOk && IsFaceExternal( f ); } V /= 6; + if ( !oriOk && V > 0 ) + V *= -1; } else { @@ -1203,11 +1207,13 @@ bool SMDS_VolumeTool::GetFaceNormal (int faceIndex, double & X, double & Y, doub XYZ aVec13( p3 - p1 ); XYZ cross = aVec12.Crossed( aVec13 ); - if ( myCurFace.myNbNodes >3*iQuad ) { - XYZ p4 ( myCurFace.myNodes[3*iQuad] ); + for ( int i = 3*iQuad; i < myCurFace.myNbNodes; i += iQuad ) + { + XYZ p4 ( myCurFace.myNodes[i] ); XYZ aVec14( p4 - p1 ); XYZ cross2 = aVec13.Crossed( aVec14 ); cross = cross + cross2; + aVec13 = aVec14; } double size = cross.Magnitude(); diff --git a/src/SMESH/SMESH_Gen.cxx b/src/SMESH/SMESH_Gen.cxx index 1e9c1471a..9c34d8a02 100644 --- a/src/SMESH/SMESH_Gen.cxx +++ b/src/SMESH/SMESH_Gen.cxx @@ -56,6 +56,13 @@ using namespace std; +// Environment variable separator +#ifdef WIN32 + #define env_sep ';' +#else + #define env_sep ':' +#endif + //============================================================================= /*! * Constructor @@ -984,7 +991,7 @@ std::vector< std::string > SMESH_Gen::GetPluginXMLPaths() while ( from < meshers.size() ) { // cut off plugin name - pos = meshers.find( ':', from ); + pos = meshers.find( env_sep, from ); if ( pos != string::npos ) plugin = meshers.substr( from, pos-from ); else diff --git a/src/SMESH/SMESH_Hypothesis.hxx b/src/SMESH/SMESH_Hypothesis.hxx index d1301c452..520e72477 100644 --- a/src/SMESH/SMESH_Hypothesis.hxx +++ b/src/SMESH/SMESH_Hypothesis.hxx @@ -95,11 +95,18 @@ public: */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape)=0; + enum InitWay { BY_MESH, BY_GEOM, BY_AVERAGE_LENGTH }; struct TDefaults { + InitWay _way; double _elemLength; int _nbSegments; + bool _quadDominated; + double _diagonal; TopoDS_Shape* _shape; // future shape of the mesh being created + + TDefaults(): + _way(BY_GEOM), _elemLength(0),_nbSegments(0),_quadDominated(false),_diagonal(0),_shape(0) {} }; /*! * \brief Initialize my parameter values by default parameters. diff --git a/src/SMESH/SMESH_Mesh.cxx b/src/SMESH/SMESH_Mesh.cxx index 7201c5280..cd5e4315c 100644 --- a/src/SMESH/SMESH_Mesh.cxx +++ b/src/SMESH/SMESH_Mesh.cxx @@ -176,10 +176,18 @@ SMESH_Mesh::~SMESH_Mesh() { if(MYDEBUG) MESSAGE("SMESH_Mesh::~SMESH_Mesh"); - // avoid usual removal of elements while processing RemoveHypothesis( algo ) event - SMESHDS_SubMeshIteratorPtr smIt = _myMeshDS->SubMeshes(); - while ( smIt->more() ) - const_cast( smIt->next() )->Clear(); + if ( _myDocument ) // avoid destructing _myMeshDS from ~SMESH_Gen() + _myDocument->RemoveMesh( _id ); + _myDocument = 0; + + // remove self from studyContext + if ( _gen ) + { + StudyContextStruct * studyContext = _gen->GetStudyContext(); + studyContext->mapMesh.erase( _id ); + } + + _myMeshDS->ClearMesh(); // issue 0020340: EDF 1022 SMESH : Crash with FindNodeClosestTo in a second new study // Notify event listeners at least that something happens @@ -200,16 +208,6 @@ SMESH_Mesh::~SMESH_Mesh() if ( _callUp) delete _callUp; _callUp = 0; - // remove self from studyContext - if ( _gen ) - { - StudyContextStruct * studyContext = _gen->GetStudyContext(); - studyContext->mapMesh.erase( _id ); - } - if ( _myDocument ) - _myDocument->RemoveMesh( _id ); - _myDocument = 0; - if ( _myMeshDS ) { // delete _myMeshDS, in a thread in order not to block closing a study with large meshes #ifndef WIN32 @@ -1191,11 +1189,11 @@ void SMESH_Mesh::NotifySubMeshesHypothesisModification(const SMESH_Hypothesis* h if ( !GetMeshDS()->IsUsedHypothesis( hyp )) return; - bool toCallBack = true; - if ( _callUp && hyp && NbNodes() == 0 ) // for not loaded mesh (#16648) + int nbEntities = ( _myMeshDS->NbNodes() + _myMeshDS->NbElements() ); + if ( hyp && _callUp && !_callUp->IsLoaded() ) // for not loaded mesh (#16648) { - _callUp->HypothesisModified( hyp->GetID() ); - toCallBack = ( NbNodes() > 0 ); + _callUp->HypothesisModified( hyp->GetID(), /*updateIcons=*/true ); + nbEntities = ( _myMeshDS->NbNodes() + _myMeshDS->NbElements() ); // after loading mesh } SMESH_Algo *algo; @@ -1265,8 +1263,9 @@ void SMESH_Mesh::NotifySubMeshesHypothesisModification(const SMESH_Hypothesis* h HasModificationsToDiscard(); // to reset _isModified flag if mesh becomes empty GetMeshDS()->Modified(); - if ( _callUp && hyp && toCallBack ) - _callUp->HypothesisModified( hyp->GetID() ); + int newNbEntities = ( _myMeshDS->NbNodes() + _myMeshDS->NbElements() ); + if ( hyp && _callUp ) + _callUp->HypothesisModified( hyp->GetID(), newNbEntities != nbEntities ); } //============================================================================= diff --git a/src/SMESH/SMESH_Mesh.hxx b/src/SMESH/SMESH_Mesh.hxx index 5eadb13c2..7549d2431 100644 --- a/src/SMESH/SMESH_Mesh.hxx +++ b/src/SMESH/SMESH_Mesh.hxx @@ -44,6 +44,7 @@ #include #include #include +#include #ifdef WIN32 #pragma warning(disable:4251) // Warning DLL Interface ... @@ -337,9 +338,10 @@ class SMESH_EXPORT SMESH_Mesh struct TCallUp // callback from SMESH to SMESH_I level { - virtual void RemoveGroup (const int theGroupID)=0; - virtual void HypothesisModified (int theHypID)=0; - virtual void Load ()=0; + virtual void RemoveGroup( const int theGroupID )=0; + virtual void HypothesisModified( int hypID, bool updateIcons )=0; + virtual void Load()=0; + virtual bool IsLoaded()=0; virtual ~TCallUp() {} }; void SetCallUp( TCallUp * upCaller ); @@ -360,7 +362,7 @@ class SMESH_EXPORT SMESH_Mesh bool IsOrderOK( const SMESH_subMesh* smBefore, const SMESH_subMesh* smAfter ) const; - std::ostream& Dump(ostream & save); + std::ostream& Dump(std::ostream & save); private: diff --git a/src/SMESH/SMESH_MeshEditor.cxx b/src/SMESH/SMESH_MeshEditor.cxx index b7c6ef24a..2104c7920 100644 --- a/src/SMESH/SMESH_MeshEditor.cxx +++ b/src/SMESH/SMESH_MeshEditor.cxx @@ -161,8 +161,7 @@ SMESH_MeshEditor::ElemFeatures::Init( const SMDS_MeshElement* elem, bool basicOn myIsQuad = elem->IsQuadratic(); if ( myType == SMDSAbs_Volume && !basicOnly ) { - vector quant = static_cast( elem )->GetQuantities(); - myPolyhedQuantities.swap( quant ); + myPolyhedQuantities = static_cast( elem )->GetQuantities(); } } } @@ -9880,10 +9879,10 @@ SMESH_MeshEditor::FindMatchingNodes(set& theSide1, set * faceSetPtr[] = { &theSide1, &theSide2 }; nReplaceMap.clear(); - if ( theFirstNode1 != theFirstNode2 ) - nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 )); - if ( theSecondNode1 != theSecondNode2 ) - nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 )); + //if ( theFirstNode1 != theFirstNode2 ) + nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 )); + //if ( theSecondNode1 != theSecondNode2 ) + nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 )); set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 )); diff --git a/src/SMESHDS/SMESHDS_SubMesh.cxx b/src/SMESHDS/SMESHDS_SubMesh.cxx index 503de16b0..8d5dee889 100644 --- a/src/SMESHDS/SMESHDS_SubMesh.cxx +++ b/src/SMESHDS/SMESHDS_SubMesh.cxx @@ -115,9 +115,12 @@ void SMESHDS_SubMesh::AddElement(const SMDS_MeshElement * elem) (LOCALIZED("add element in subshape already belonging to a subshape")); } } + else + { + ++myNbElements; + } elem->setShapeID( myIndex ); - myNbElements++; // remember element with smallest ID to optimize iteration on them add( elem ); @@ -178,8 +181,11 @@ void SMESHDS_SubMesh::AddNode(const SMDS_MeshNode * N) (LOCALIZED("a node being in sub-mesh is added to another sub-mesh")); return; // already in } + else + { + ++myNbNodes; + } N->setShapeID( myIndex ); - myNbNodes++; // remember node with smallest ID to optimize iteration on them add( N ); diff --git a/src/SMESHGUI/SMESHGUI.cxx b/src/SMESHGUI/SMESHGUI.cxx index c5404494a..ba08d5101 100644 --- a/src/SMESHGUI/SMESHGUI.cxx +++ b/src/SMESHGUI/SMESHGUI.cxx @@ -5115,9 +5115,9 @@ bool SMESHGUI::activateModule( SUIT_Study* study ) if ( aDesk ) { QList wndList = aDesk->windows(); SUIT_ViewWindow* wnd; - foreach(wnd, wndList) + foreach ( wnd, wndList ) { - connectView(wnd); + connectView( wnd ); // remove actors whose objects are removed in GetSMESHGen()->UpdateStudy() SMESH::UpdateActorsAfterUpdateStudy(wnd); @@ -5404,6 +5404,7 @@ void SMESHGUI::createPreferences() "SMESH", "nb_segments_per_edge" ); setPreferenceProperty( nbSeg, "min", 1 ); setPreferenceProperty( nbSeg, "max", 10000000 ); + addPreference( tr( "PREF_USE_MESHGEMS_HYPOSET" ), segGroup, LightApp_Preferences::Bool, "SMESH", "use-meshgems-hypo-sets" ); int loadGroup = addPreference( tr( "SMESH_PREF_MESH_LOADING" ), genTab ); addPreference( tr( "PREF_FORGET_MESH_AT_HYP_MODIF" ), loadGroup, LightApp_Preferences::Bool, diff --git a/src/SMESHGUI/SMESHGUI_GroupOnShapeDlg.cxx b/src/SMESHGUI/SMESHGUI_GroupOnShapeDlg.cxx index f7be40487..9054ad855 100644 --- a/src/SMESHGUI/SMESHGUI_GroupOnShapeDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_GroupOnShapeDlg.cxx @@ -206,7 +206,7 @@ LightApp_Dialog* SMESHGUI_GroupOnShapeOp::dlg() const */ //================================================================================ -static SMESH::ElementType elementType(GEOM::GEOM_Object_var geom) +SMESH::ElementType SMESHGUI_GroupOnShapeOp::ElementType(GEOM::GEOM_Object_var geom) { if ( !geom->_is_nil() ) { switch ( geom->GetShapeType() ) { @@ -232,7 +232,7 @@ static SMESH::ElementType elementType(GEOM::GEOM_Object_var geom) GEOM::ListOfLong_var ids = aGroupOp->GetObjects( geom ); if ( ids->length() && !mainShape->_is_nil() && !aShapeOp->_is_nil() ) { GEOM::GEOM_Object_wrap member = aShapeOp->GetSubShape( mainShape, ids[0] ); - return elementType( member ); + return ElementType( member ); } } } @@ -241,7 +241,7 @@ static SMESH::ElementType elementType(GEOM::GEOM_Object_var geom) GEOM::ListOfLong_var ids = aShapeOp->SubShapeAllIDs( geom, GEOM::SHAPE, false ); if ( ids->length() ) { GEOM::GEOM_Object_wrap member = aShapeOp->GetSubShape( geom, ids[0] ); - return elementType( member ); + return ElementType( member ); } } } @@ -336,7 +336,7 @@ bool SMESHGUI_GroupOnShapeOp::onApply() if ( geom->_is_nil() ) continue; // group type - SMESH::ElementType elemType = isNode ? SMESH::NODE : elementType( geom ); + SMESH::ElementType elemType = isNode ? SMESH::NODE : ElementType( geom ); if ( elemType == SMESH::ALL ) continue; diff --git a/src/SMESHGUI/SMESHGUI_GroupOnShapeDlg.h b/src/SMESHGUI/SMESHGUI_GroupOnShapeDlg.h index 63d946b7a..f88e9bef5 100644 --- a/src/SMESHGUI/SMESHGUI_GroupOnShapeDlg.h +++ b/src/SMESHGUI/SMESHGUI_GroupOnShapeDlg.h @@ -49,6 +49,7 @@ public: virtual LightApp_Dialog* dlg() const; static QString GetDefaultName(const QString& theOperation); + static SMESH::ElementType ElementType(GEOM::GEOM_Object_var geom); public slots: diff --git a/src/SMESHGUI/SMESHGUI_Hypotheses.cxx b/src/SMESHGUI/SMESHGUI_Hypotheses.cxx index 5522e3144..03767040c 100644 --- a/src/SMESHGUI/SMESHGUI_Hypotheses.cxx +++ b/src/SMESHGUI/SMESHGUI_Hypotheses.cxx @@ -27,10 +27,11 @@ #include "SMESHGUI.h" #include "SMESHGUI_HypothesesUtils.h" -#include "SMESHGUI_Utils.h" #include "SMESHGUI_SpinBox.h" +#include "SMESHGUI_Utils.h" #include "SMESHGUI_VTKUtils.h" #include "SMESH_Actor.h" +#include "SMESH_TypeDefs.hxx" // SALOME KERNEL includes #include @@ -147,10 +148,14 @@ void SMESHGUI_GenericHypothesisCreator::editHypothesis( SMESH::SMESH_Hypothesis_ Dlg->setWindowTitle( caption() ); Dlg->setObjectName( theHypName ); Dlg->setHIcon( icon() ); - Dlg->setType( type() ); + if ( theHypName == HypothesesSet::getCommonHypoSetHypoType() ) + Dlg->setType( tr( HypothesesSet::getCommonHypoSetHypoType()) ); + else + Dlg->setType( type() ); retrieveParams(); - Dlg->show(); + Dlg->show(); // w/o this Dlg blocks selection Dlg->resize( Dlg->minimumSizeHint() ); + Dlg->exec(); // w/o this we cant wait until edition ends when applying a hypo-set } else { emit finished( QDialog::Accepted ); @@ -180,10 +185,11 @@ QFrame* SMESHGUI_GenericHypothesisCreator::buildStdFrame() GroupC1Layout->setMargin( MARGIN ); ListOfStdParams::const_iterator anIt = params.begin(), aLast = params.end(); - for( int i=0; anIt!=aLast; anIt++, i++ ) + for( int i = 0; anIt != aLast; anIt++, i++ ) { - QLabel* lab = new QLabel( (*anIt).myName, GroupC1 ); - GroupC1Layout->addWidget( lab, i, 0 ); + QLabel* lab = anIt->hasName() ? new QLabel( anIt->myName, GroupC1 ) : NULL; + if ( lab ) + GroupC1Layout->addWidget( lab, i, 0 ); myParamLabels << lab; QWidget* w = getCustomWidget( *anIt, GroupC1, i ); @@ -246,9 +252,12 @@ QFrame* SMESHGUI_GenericHypothesisCreator::buildStdFrame() default:; } // switch( (*anIt).myValue.type() ) - if( w ) + if ( w ) { - GroupC1Layout->addWidget( w, i, 1 ); + if ( lab ) + GroupC1Layout->addWidget( w, i, 1 ); + else + GroupC1Layout->addWidget( w, i, 0, 1, 2 ); changeWidgets().append( w ); } } @@ -331,6 +340,8 @@ void SMESHGUI_GenericHypothesisCreator::onDialogFinished( int result ) myDlg->close(); //delete myDlg; since WA_DeleteOnClose==true myDlg = 0; + + SMESH::UpdateActorsAfterUpdateStudy();// remove actors of removed groups (#16522) if (SVTK_ViewWindow* vf = SMESH::GetCurrentVtkView()) { vf->Repaint(); } @@ -671,6 +682,14 @@ SMESHGUI_HypothesisDlg::~SMESHGUI_HypothesisDlg() delete myCreator; } +void SMESHGUI_HypothesisDlg::showEvent(QShowEvent *event) +{ + // resize( minimumSizeHint() ); + // adjustSize(); + + QtxDialog::showEvent( event ); +} + void SMESHGUI_HypothesisDlg::setCustomFrame( QFrame* f ) { if( f ) @@ -779,32 +798,44 @@ HypothesisData::HypothesisData( const QString& theTypeName, { } -HypothesesSet::HypothesesSet( const QString& theSetName ) - : myHypoSetName( theSetName ), - myIsAlgo( false ), - myIsCustom( false ) -{ -} - -HypothesesSet::HypothesesSet( const QString& theSetName, - const QStringList& theHypoList, - const QStringList& theAlgoList ) - : myHypoSetName( theSetName ), - myHypoList( theHypoList ), - myAlgoList( theAlgoList ), +// HypothesesSet::HypothesesSet( const QString& theSetName ) +// : myHypoSetName( theSetName ), +// myIsAlgo( false ), +// myIsCustom( false ) +// { +// } + +HypothesesSet::HypothesesSet( const QString& theSetName, + bool useCommonSize, bool isQuadDominated, + const QStringList& mainHypos, const QStringList& mainAlgos, + const QStringList& altHypos, const QStringList& altAlgos, + const QStringList& intHypos, const QStringList& intAlgos ) + : myUseCommonSize( useCommonSize ), + myQuadDominated( isQuadDominated ), + myHypoSetName( theSetName ), + myHypoList { mainHypos, altHypos, intHypos }, + myAlgoList { mainAlgos, altAlgos, intAlgos }, myIsAlgo( false ), - myIsCustom( false ) + myIsCustom( false ), + myIndex( 0 ) { + for ( myHypType = MAIN; myHypType < NB_HYP_TYPES; SMESHUtils::Increment( myHypType )) + for ( int isAlgo = myIsAlgo = 0; isAlgo < 2; myIsAlgo = ++isAlgo ) + { + QStringList& hyps = *list(); + for ( int i = 0; i < hyps.count(); ++i ) + hyps[ i ] = hyps[ i ].trimmed(); + } } -QStringList* HypothesesSet::list(bool is_algo) const +QStringList* HypothesesSet::list( bool is_algo, SetType setType) const { - return const_cast( &( is_algo ? myAlgoList : myHypoList ) ); + return const_cast( &( is_algo ? myAlgoList[setType] : myHypoList[setType] )); } QStringList* HypothesesSet::list() const { - return list( myIsAlgo ); + return list( myIsAlgo, myHypType ); } QString HypothesesSet::name() const @@ -812,23 +843,24 @@ QString HypothesesSet::name() const return myHypoSetName; } -void HypothesesSet::set( bool isAlgo, const QStringList& lst ) -{ - *list(isAlgo) = lst; -} +// void HypothesesSet::set( bool isAlgo, const QStringList& lst ) +// { +// *list(isAlgo) = lst; +// } -int HypothesesSet::count( bool isAlgo ) const -{ - return list(isAlgo)->count(); -} +// int HypothesesSet::count( bool isAlgo, SetType setType ) const +// { +// return list(isAlgo,setType)->count(); +// } -bool HypothesesSet::isAlgo() const -{ - return myIsAlgo; -} +// bool HypothesesSet::isAlgo() const +// { +// return myIsAlgo; +// } -void HypothesesSet::init( bool isAlgo ) +void HypothesesSet::init( bool isAlgo, SetType setType ) { + myHypType = setType; myIsAlgo = isAlgo; myIndex = 0; } @@ -858,16 +890,43 @@ bool HypothesesSet::getIsCustom() const return myIsCustom; } +void HypothesesSet::setAlgoAvailable( SetType type, bool isAvailable ) +{ + if ( MAIN <= type && type < NB_HYP_TYPES ) + myIsAlgoAvailable[ type ] = isAvailable; +} + +bool HypothesesSet::getAlgoAvailable( SetType type ) +{ + bool isAva = false; + if ( MAIN <= type && type < NB_HYP_TYPES ) + isAva = myIsAlgoAvailable[ type ]; + return isAva; +} + +HypothesesSet::SetType HypothesesSet::getPreferredHypType() +{ + SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr(); + int useAltHypos = !resMgr->booleanValue( "SMESH", "use-meshgems-hypo-sets", false ); + return ( HypothesesSet::SetType ) useAltHypos; +} + int HypothesesSet::maxDim() const { HypothesesSet * thisSet = (HypothesesSet*) this; int dim = -1; - for ( int isAlgo = 0; isAlgo < 2; ++isAlgo ) - { - for ( thisSet->init( isAlgo ); thisSet->more(); thisSet->next() ) - if ( HypothesisData* hypData = SMESH::GetHypothesisData( thisSet->current() )) - for ( int i = 0; i < hypData->Dim.count(); ++i ) - dim = qMax( dim, hypData->Dim[i] ); - } + for ( int setType = 0; setType < 2; ++setType ) + for ( int isAlgo = 0; isAlgo < 2; ++isAlgo ) + { + for ( thisSet->init( isAlgo, SetType( setType )); thisSet->more(); thisSet->next() ) + if ( HypothesisData* hypData = SMESH::GetHypothesisData( thisSet->current() )) + for ( int i = 0; i < hypData->Dim.count(); ++i ) + dim = qMax( dim, hypData->Dim[i] ); + } return dim; } + +const char* HypothesesSet::getCommonHypoSetHypoType() +{ + return "AverageLengthForHypoSet"; +} diff --git a/src/SMESHGUI/SMESHGUI_Hypotheses.h b/src/SMESHGUI/SMESHGUI_Hypotheses.h index e75b82262..b50f5f128 100644 --- a/src/SMESHGUI/SMESHGUI_Hypotheses.h +++ b/src/SMESHGUI/SMESHGUI_Hypotheses.h @@ -92,6 +92,8 @@ protected: const char* text() const { ((QByteArray&) myTextAsBytes) = myText.toUtf8(); return myTextAsBytes.constData(); } + void setNoName() { myName.clear(); } // ==> widget occupies both columns + bool hasName() const { return !myName.isEmpty(); } }; typedef QList ListOfStdParams; @@ -158,6 +160,7 @@ public: void setHIcon( const QPixmap& ); void setCustomFrame( QFrame* ); void setType( const QString& ); + void showEvent(QShowEvent *event); protected slots: virtual void accept(); @@ -215,32 +218,54 @@ struct HypothesisData class HypothesesSet { public: - HypothesesSet( const QString& ); - HypothesesSet( const QString&, const QStringList&, const QStringList& ); + + enum SetType { MAIN, ALT, INTERN, NB_HYP_TYPES }; //!< hypos/algos type: main, alternative, internal-edges + + //HypothesesSet( const QString& ); + HypothesesSet( const QString& name, + bool useCommonSize, bool isQuadDominated, + const QStringList& mainHypos, const QStringList& mainAlgos, + const QStringList& altHypos, const QStringList& altAlgos, + const QStringList& intHypos, const QStringList& intAlgos ); QString name() const; - void set( bool, const QStringList& ); - int count( bool ) const; + bool toUseCommonSize() const { return myUseCommonSize; } + bool isQuadDominated() const { return myQuadDominated; } + bool hasAlgo( SetType type ) const { return !myAlgoList[ type ].isEmpty(); } + //int count( bool, SetType ) const; + + int maxDim() const; void setIsCustom( bool ); bool getIsCustom() const; - int maxDim() const; - bool isAlgo() const; + void setAlgoAvailable( SetType type, bool isAvailable ); + bool getAlgoAvailable( SetType type ); + + static SetType getPreferredHypType(); + static const char* getCommonHypoSetHypoType(); + + //bool isAlgo() const; // CASCADE-like iteration - void init( bool ); + void init( bool, SetType ); bool more() const; void next(); QString current() const; private: - QStringList* list(bool) const; + QStringList* list(bool,SetType) const; QStringList* list() const; private: + bool myUseCommonSize; // Average size is asked only and used to create default hypotheses + bool myQuadDominated; QString myHypoSetName; - QStringList myHypoList, myAlgoList; + QStringList myHypoList[3], myAlgoList[3]; // per SetType + bool myIsAlgoAvailable[3]; // current state depending on geometry etc + + // iteration + SetType myHypType; bool myIsAlgo, myIsCustom; int myIndex; }; diff --git a/src/SMESHGUI/SMESHGUI_HypothesesUtils.cxx b/src/SMESHGUI/SMESHGUI_HypothesesUtils.cxx index eaaad911c..2660647d3 100644 --- a/src/SMESHGUI/SMESHGUI_HypothesesUtils.cxx +++ b/src/SMESHGUI/SMESHGUI_HypothesesUtils.cxx @@ -67,6 +67,7 @@ #define LoadLib( name ) LoadLibrary( name ) #define GetProc GetProcAddress #define UnLoadLib( handle ) FreeLibrary( handle ); + #define env_sep ";" #else // WIN32 #define LibHandle void* #ifdef DYNLOAD_LOCAL @@ -76,6 +77,7 @@ #endif // DYNLOAD_LOCAL #define GetProc dlsym #define UnLoadLib( handle ) dlclose( handle ); + #define env_sep ":" #endif // WIN32 #ifdef _DEBUG_ @@ -197,7 +199,7 @@ namespace SMESH if (cenv) HypsXml.sprintf("%s", cenv); - QStringList HypsXmlList = HypsXml.split(":", QString::SkipEmptyParts); + QStringList HypsXmlList = HypsXml.split(env_sep, QString::SkipEmptyParts); if (HypsXmlList.count() == 0) { SUIT_MessageBox::critical(SMESHGUI::desktop(), QObject::tr("SMESH_WRN_WARNING"), @@ -329,8 +331,7 @@ namespace SMESH hypoSet != myListOfHypothesesSets.end(); ++hypoSet ) { HypothesesSet* aSet = *hypoSet; - if ( aSet && ( aSet->count( true ) || aSet->count( false )) && - aSet->maxDim() <= maxDim) + if ( aSet && 0 <= aSet->maxDim() && aSet->maxDim() <= maxDim ) { aSetNameList.append( mangledHypoSetName( aSet )); } diff --git a/src/SMESHGUI/SMESHGUI_HypothesesUtils.h b/src/SMESHGUI/SMESHGUI_HypothesesUtils.h index 904a04b67..4f8840b2b 100644 --- a/src/SMESHGUI/SMESHGUI_HypothesesUtils.h +++ b/src/SMESHGUI/SMESHGUI_HypothesesUtils.h @@ -116,6 +116,7 @@ namespace SMESH SMESH::SMESH_Hypothesis_ptr ); typedef std::vector<_PTR(SObject)> SObjectList; + SMESHGUI_EXPORT SObjectList GetMeshesUsingAlgoOrHypothesis( SMESH::SMESH_Hypothesis_ptr ); SMESHGUI_EXPORT diff --git a/src/SMESHGUI/SMESHGUI_MeshDlg.cxx b/src/SMESHGUI/SMESHGUI_MeshDlg.cxx index a1ee4ec9f..787a34469 100644 --- a/src/SMESHGUI/SMESHGUI_MeshDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_MeshDlg.cxx @@ -34,6 +34,7 @@ #include // Qt includes +#include #include #include #include @@ -572,9 +573,12 @@ SMESHGUI_MeshDlg::SMESHGUI_MeshDlg( const bool theToCreate, const bool theIsMesh // mesh type QLabel* anMeshTypeLbl = new QLabel( tr( "MESH_TYPE" ), this ); myMeshType = new QComboBox( this ); - + // groups + myCreateGroupsCheck = new QCheckBox( tr( "CREATE_ALL_GROUPS" ), this ); + myCreateGroupsCheck->setChecked( true ); + // Create tab widget - + myTabWg = new QTabWidget( mainFrame() ); myTabs[ Dim0D ] = new SMESHGUI_MeshTab( myTabWg ); myTabs[ Dim1D ] = new SMESHGUI_MeshTab( myTabWg ); @@ -608,9 +612,10 @@ SMESHGUI_MeshDlg::SMESHGUI_MeshDlg( const bool theToCreate, const bool theIsMesh aLay->addWidget( objectWg( Geom, Control ), 2, 2 ); aLay->addWidget( anMeshTypeLbl, 3, 0 ); aLay->addWidget( myMeshType, 3, 2 ); - aLay->addWidget( myTabWg, 5, 0, 1, 3 ); - aLay->addWidget( myHypoSetButton, 6, 0, 1, 3 ); - aLay->setRowMinimumHeight( 3, 20 ); + aLay->addWidget( myCreateGroupsCheck, 4, 0, 1, 3 ); + aLay->addWidget( myTabWg, 6, 0, 1, 3 ); + aLay->addWidget( myHypoSetButton, 7, 0, 1, 3 ); + aLay->setRowMinimumHeight( 4, 20 ); myMeshType->clear(); @@ -658,7 +663,7 @@ void SMESHGUI_MeshDlg::setTitile( const bool theToCreate, const bool theIsMesh ) { setWindowTitle( tr( theIsMesh ? "EDIT_MESH" : "EDIT_SUBMESH") ); } - + myCreateGroupsCheck-> setVisible( theToCreate && theIsMesh ); } //================================================================================ @@ -739,8 +744,11 @@ void SMESHGUI_MeshDlg::setHypoSets( const QStringList& theSets ) myHypoSetButton->setPopupMode( QToolButton::InstantPopup ); } aHypoSetPopup->clear(); - for ( int i = 0, n = theSets.count(); i < n; i++ ) { - aHypoSetPopup->addAction( theSets[ i ] ); + for ( int i = 0, n = theSets.count(); i < n; i++ ) + { + QAction* action = new QAction( tr( theSets[ i ].toUtf8().data() )); + action->setData( theSets[ i ] ); + aHypoSetPopup->addAction( action ); } myHypoSetButton->setEnabled( !aHypoSetPopup->isEmpty() ); } @@ -755,7 +763,7 @@ void SMESHGUI_MeshDlg::setHypoSets( const QStringList& theSets ) //================================================================================ void SMESHGUI_MeshDlg::onHypoSetPopup( QAction* a ) { - emit hypoSet( a->text() ); + emit hypoSet( a->data().toString() ); } //================================================================================ @@ -916,3 +924,14 @@ void SMESHGUI_MeshDlg::setCurrentMeshType( const int theIndex ) else myMeshType->setCurrentIndex( 0 ); } + +//================================================================================ +/*! + * \brief Return state of "Create all Groups on Geometry" check-box + */ +//================================================================================ + +bool SMESHGUI_MeshDlg::toCreateAllGroups() +{ + return myCreateGroupsCheck->isChecked(); +} diff --git a/src/SMESHGUI/SMESHGUI_MeshDlg.h b/src/SMESHGUI/SMESHGUI_MeshDlg.h index 3dd5b0697..1cfb8762f 100644 --- a/src/SMESHGUI/SMESHGUI_MeshDlg.h +++ b/src/SMESHGUI/SMESHGUI_MeshDlg.h @@ -37,14 +37,15 @@ #include #include -class SMESHGUI_MeshTab; class QAction; +class QCheckBox; class QComboBox; class QListWidget; class QMenu; class QTabWidget; class QToolButton; class QtxToolButton; +class SMESHGUI_MeshTab; /*! * \brief Dialog for mech creation or editing @@ -84,6 +85,8 @@ public: void setCurrentMeshType( const int ); int currentMeshType(); + bool toCreateAllGroups(); + signals: void hypoSet( const QString& ); void geomSelectionByMesh( bool ); @@ -101,6 +104,7 @@ private slots: QToolButton* myHypoSetButton; QMenu* myGeomPopup; QComboBox* myMeshType; + QCheckBox* myCreateGroupsCheck; }; /*! diff --git a/src/SMESHGUI/SMESHGUI_MeshOp.cxx b/src/SMESHGUI/SMESHGUI_MeshOp.cxx index 36b530a39..ed9e8d63c 100644 --- a/src/SMESHGUI/SMESHGUI_MeshOp.cxx +++ b/src/SMESHGUI/SMESHGUI_MeshOp.cxx @@ -27,6 +27,7 @@ #include "SMESHGUI.h" #include "SMESHGUI_GEOMGenUtils.h" +#include "SMESHGUI_GroupOnShapeDlg.h" #include "SMESHGUI_Hypotheses.h" #include "SMESHGUI_HypothesesUtils.h" #include "SMESHGUI_MeshDlg.h" @@ -34,26 +35,30 @@ #include "SMESHGUI_ShapeByMeshDlg.h" #include "SMESHGUI_Utils.h" #include "SMESH_NumberFilter.hxx" +#include "SMESH_TypeDefs.hxx" #include "SMESH_TypeFilter.hxx" +#include CORBA_SERVER_HEADER(SMESH_BasicHypothesis) + // SALOME GEOM includes -#include #include -#include -#include #include +#include +#include +#include // SALOME GUI includes -#include -#include #include #include #include +#include +#include #include #include +#include #include -#include -#include +#include +#include // SALOME KERNEL includes #include @@ -62,16 +67,16 @@ #include // Qt includes -#include -#include #include +#include +#include // OCCT includes -#include -#include -#include -#include #include +#include +#include +#include +#include //================================================================================ /*! @@ -183,6 +188,8 @@ bool SMESHGUI_MeshOp::onApply() SUIT_MessageBox::warning( myDlg, tr( "SMESH_ERROR" ), aMess ); } + myHypoSet = 0; + return aResult; } @@ -257,6 +264,7 @@ void SMESHGUI_MeshOp::startOperation() selectionDone(); + myHypoSet = 0; myHasConcurrentSubBefore = false; myObjectToSelect.clear(); } @@ -286,8 +294,8 @@ void SMESHGUI_MeshOp::commitOperation() //================================================================================ /*! * \brief Creates selection filter - * \param theId - identifier of current selection widget - * \retval SUIT_SelectionFilter* - pointer to the created filter or null + * \param theId - identifier of current selection widget + * \retval SUIT_SelectionFilter* - pointer to the created filter or null * * Creates selection filter in accordance with identifier of current selection widget */ @@ -772,7 +780,7 @@ bool SMESHGUI_MeshOp::isCompatibleToGeometry(HypothesisData* theAlgoData, bool isApplicable = false; if ( myGeomEntry == myLastGeomEntry && !myGeomEntry.isEmpty() ) { - THypLabelIsAppMap::const_iterator lab2isApp = myHypMapIsApplicable.find( theAlgoData->Label ); + THypLabelIsAppMap::const_iterator lab2isApp = myHypMapIsApplicable.find( theAlgoData->TypeName ); if ( lab2isApp != myHypMapIsApplicable.end() ) { isApplicable = lab2isApp.value(); return isApplicable; @@ -783,7 +791,7 @@ bool SMESHGUI_MeshOp::isCompatibleToGeometry(HypothesisData* theAlgoData, toCheckIsApplicableToAll = ( myGeom->GetType() == GEOM_GROUP ); isApplicable = SMESH::IsApplicable( theAlgoData->TypeName, myGeom, toCheckIsApplicableToAll ); - myHypMapIsApplicable.insert( theAlgoData->Label, isApplicable ); + myHypMapIsApplicable.insert( theAlgoData->TypeName, isApplicable ); return isApplicable; } @@ -1022,8 +1030,9 @@ void SMESHGUI_MeshOp::existingHyps( const int theDim, */ //================================================================================ SMESH::SMESH_Hypothesis_var -SMESHGUI_MeshOp::getInitParamsHypothesis( const QString& aHypType, - const QString& aServerLib ) const +SMESHGUI_MeshOp::getInitParamsHypothesis( const QString& aHypType, + const QString& aServerLib, + const SMESH::HypInitParams* aParams ) const { if ( aHypType.isEmpty() || aServerLib.isEmpty() ) return SMESH::SMESH_Hypothesis::_nil(); @@ -1083,18 +1092,48 @@ SMESHGUI_MeshOp::getInitParamsHypothesis( const QString& aHypType, } } - SMESH::SMESH_Hypothesis_var hyp = - SMESHGUI::GetSMESHGen()->GetHypothesisParameterValues( aHypType.toUtf8().data(), - aServerLib.toUtf8().data(), - aMesh, - aGeomVar, - /*byMesh = */isSubMesh); - if ( hyp->_is_nil() && isSubMesh ) + SMESH::HypInitParams initParams; + enum { BY_MESH, BY_GEOM, BY_AVERAGE_LENGTH }; // same as ::SMESH_Hypothesis::InitWay + if ( aParams ) + { + initParams = *aParams; + } + else + { + initParams.way = isSubMesh ? BY_MESH : BY_GEOM; + } + + SMESH::SMESH_Hypothesis_var hyp; + if ( initParams.way == BY_AVERAGE_LENGTH ) + hyp = SMESHGUI::GetSMESHGen()->CreateHypothesisByAverageLength( aHypType.toUtf8().data(), + aServerLib.toUtf8().data(), + initParams.averageLength, + initParams.quadDominated ); + else + hyp = SMESHGUI::GetSMESHGen()->GetHypothesisParameterValues( aHypType.toUtf8().data(), + aServerLib.toUtf8().data(), + aMesh, + aGeomVar, + initParams ); + if ( hyp->_is_nil() && initParams.way == BY_MESH ) + { + initParams.way = BY_GEOM; hyp = SMESHGUI::GetSMESHGen()->GetHypothesisParameterValues( aHypType.toLatin1().data(), aServerLib.toUtf8().data(), aMesh, aGeomVar, - /*byMesh = */false); + initParams ); + } + if ( hyp->_is_nil() && initParams.way == BY_GEOM ) + { + initParams.way = BY_AVERAGE_LENGTH; + initParams.averageLength = 1.; + hyp = SMESHGUI::GetSMESHGen()->GetHypothesisParameterValues( aHypType.toLatin1().data(), + aServerLib.toUtf8().data(), + aMesh, + aGeomVar, + initParams ); + } return hyp; } @@ -1221,25 +1260,14 @@ namespace //================================================================================ /*! - * Create hypothesis and update dialog. - * \param theDim - dimension of hypothesis to be created - * \param theType - hypothesis category (algorithm, hypothesis, additional hypothesis) - * \param theTypeName - specifies hypothesis to be created + * \brief Return names of all existing hypotheses */ //================================================================================ -void SMESHGUI_MeshOp::createHypothesis(const int theDim, - const int theType, - const QString& theTypeName) -{ - HypothesisData* aData = SMESH::GetHypothesisData(theTypeName); - if (!aData) - return; - - myDim = theDim; - myType = theType; - // get a unique hyp name +QStringList SMESHGUI_MeshOp::getHypoNames() +{ QStringList aHypNames; + TDim2Type2HypList::const_iterator aDimIter = myExistingHyps.begin(); for ( ; aDimIter != myExistingHyps.end(); aDimIter++) { const TType2HypList& aType2HypList = aDimIter.value(); @@ -1254,7 +1282,30 @@ void SMESHGUI_MeshOp::createHypothesis(const int theDim, } } } - QString aHypName = GetUniqueName( aHypNames, aData->Label); + return aHypNames; +} + +//================================================================================ +/*! + * Create hypothesis and update dialog. + * \param theDim - dimension of hypothesis to be created + * \param theType - hypothesis category (algorithm, hypothesis, additional hypothesis) + * \param theTypeName - specifies hypothesis to be created + */ +//================================================================================ +void SMESHGUI_MeshOp::createHypothesis(const int theDim, + const int theType, + const QString& theTypeName) +{ + HypothesisData* aData = SMESH::GetHypothesisData(theTypeName); + if (!aData) + return; + + myDim = theDim; + myType = theType; + + // get a unique hyp name + QString aHypName = GetUniqueName( getHypoNames(), aData->Label); // existing hypos bool dialog = false; @@ -1655,6 +1706,179 @@ void SMESHGUI_MeshOp::onAlgoSelected( const int theIndex, return; } +//================================================================================ +/*! + * \brief Create a sub-mesh on internal edges in the case where the global algorithm + * is of type 1D-2D[-3D] so that the internal edges would remain not meshed. + */ +//================================================================================ + +void SMESHGUI_MeshOp::createSubMeshOnInternalEdges( SMESH::SMESH_Mesh_ptr theMesh, + GEOM::GEOM_Object_ptr theMainShape ) +{ + if ( theMesh->_is_nil() || theMainShape->_is_nil() ) + return; + + if ( isAccessibleDim( 1 )) + return; // global 1D algorithm is/can be assigned + + const HypothesesSet::SetType internSet = HypothesesSet::INTERN; + bool toCreate = true; + bool toCreateMandatory = ( myHypoSet && + myAverageSize > 0 && + ( myHypoSet->init( /*algo=*/ true, internSet ), myHypoSet->more()) && + ( myHypoSet->init( /*algo=*/false, internSet ), myHypoSet->more())); + if ( !toCreateMandatory ) // ask the user + toCreate = false; // can't pass both mesh and geometry to Create Submesh operation (so far?) + // toCreate = SUIT_MessageBox::warning( SMESHGUI::desktop(), + // QObject::tr("SMESH_WRN_WARNING"), + // QObject::tr("SMESH_CREATE_SUBMESH_ON_INTERNAL_EDGES"), + // QObject::tr("SMESH_BUT_YES"), + // QObject::tr("SMESH_BUT_NO"), 1, 0); + if ( !toCreate ) + return; + + TopoDS_Shape shape; + if ( !GEOMBase::GetShape( theMainShape, shape )) + return; + + std::vector< TopoDS_Shape > internalEdges; + for ( TopExp_Explorer edge( shape, TopAbs_EDGE, TopAbs_WIRE ); edge.More(); edge.Next() ) + internalEdges.push_back( edge.Current() ); + + if ( internalEdges.empty() ) + return; + + TopTools_IndexedMapOfShape shapeIDs; + TopExp::MapShapes( shape, shapeIDs ); + + std::set< int > intIDSet; + for ( size_t i = 0; i < internalEdges.size(); ++i ) + intIDSet.insert( shapeIDs.FindIndex( internalEdges[ i ])); + + GEOM::GEOM_Gen_var geomGen = theMainShape->GetGen(); + if (geomGen->_is_nil()) return; + + GEOM::GEOM_Object_var edgeGroup; + GEOM::GEOM_IShapesOperations_wrap sOp = geomGen->GetIShapesOperations(); + GEOM::GEOM_IGroupOperations_wrap gOp = geomGen->GetIGroupOperations(); + GEOM::ListOfGO_var geomGroups = sOp->GetExistingSubObjects( theMainShape, + /*groupsOnly=*/true ); + for ( CORBA::ULong i = 0; i < geomGroups->length(); ++i ) + { + GEOM::ListOfLong_var ids = gOp->GetObjects( geomGroups[ i ]); + std::set< int > idSet( & ids[0], & ids[0] + ids->length() ); + if ( idSet == intIDSet ) + { + edgeGroup = geomGroups[ i ]; + break; + } + } + + if ( edgeGroup->_is_nil() ) + { + GEOM::GEOM_Object_var edgeGroup = gOp->CreateGroup( theMainShape, TopAbs_EDGE ); + + GEOM::ListOfLong_var edgeIDs = new GEOM::ListOfLong; + edgeIDs->length( internalEdges.size() ); + std::set< int >::iterator id = intIDSet.begin(); + for ( size_t i = 0; i < intIDSet.size(); ++i, ++id ) + edgeIDs[ i ] = *id; + gOp->UnionIDs( edgeGroup, edgeIDs ); + + SALOMEDS::SObject_wrap so = geomGen->AddInStudy( edgeGroup, "Internal edges", theMainShape ); + } + + if ( !toCreateMandatory ) + { + // show Create Sub-mesh dislog + // _PTR(SObject) aMeshSO = SMESH::FindSObject( theMesh ); + // selectionMgr()->clearFilters(); + // selectObject( pSubmesh ); + // SMESHGUI::GetSMESHGUI()->switchToOperation( SMESHOp::OpEditMeshOrSubMesh ); + return; + } + + // create a sub-mesh using myAverageSize w/o GUI + + SMESH::SMESH_subMesh_var subMesh = theMesh->GetSubMesh( edgeGroup, "" ); + + for ( int isAlgo = 1; isAlgo >= 0; --isAlgo ) + for ( myHypoSet->init( isAlgo, internSet ); myHypoSet->more(); myHypoSet->next() ) + { + QString aHypoTypeName = myHypoSet->current(); + HypothesisData* aHypData = SMESH::GetHypothesisData( aHypoTypeName ); + if ( !aHypData ) + continue; + + myDim = aHypData->Dim[0]; + if ( myDim != 1 ) + continue; + + // create or/and set + SMESH::SMESH_Hypothesis_var newHypo; + if ( isAlgo ) + { + myAvailableHypData[ myDim ][ Algo ].clear(); + myAvailableHypData[ myDim ][ Algo ] << aHypData; + QStringList hypList; hypList << aHypoTypeName; + myDlg->tab( myDim )->setAvailableHyps( Algo, hypList ); + setCurrentHyp( myDim, Algo, 0 ); + newHypo = getAlgo( myDim ); + } + else + { + SMESH::HypInitParams params = { 2, myAverageSize, false }; + newHypo = getInitParamsHypothesis( aHypData->TypeName, aHypData->ServerLibName, & params ); + QString hypName = GetUniqueName( getHypoNames(), aHypData->Label ); + SALOMEDS::SObject_wrap so = + SMESHGUI::GetSMESHGen()->PublishInStudy( SALOMEDS::SObject::_nil(), newHypo, + hypName.toUtf8().data() ); + } + SMESH::AddHypothesisOnSubMesh( subMesh, newHypo ); + } + + return; +} + +//================================================================================ +/*! + * \brief Ask the user to enter an average size which will be used to create + * hypotheses of a hypo-set basing on this size + * \param [out] averageSize - average element size + * \return bool - false if the user canceled the dialog + */ +//================================================================================ + +bool SMESHGUI_MeshOp::getAverageSize( double & averageSize ) +{ + HypothesisData* hypData = SMESH::GetHypothesisData( "MaxLength" ); + if ( !hypData ) + return false; + + SMESH::SMESH_Hypothesis_var hyp = getInitParamsHypothesis( hypData->TypeName, + hypData->ServerLibName ); + if ( hyp->_is_nil() ) + return false; + + SMESHGUI_GenericHypothesisCreator* aCreator = SMESH::GetHypothesisCreator( hypData->TypeName ); + if ( !aCreator ) + return false; + + initHypCreator( aCreator ); + myDlg->setEnabled( false ); + + aCreator->edit( hyp.in(), HypothesesSet::getCommonHypoSetHypoType(), + dlg(), this, SLOT( onHypoEdited( int ))); + + StdMeshers::StdMeshers_MaxLength_var lenHyp = StdMeshers::StdMeshers_MaxLength::_narrow( hyp ); + if ( lenHyp->_is_nil() ) + return false; + + averageSize = lenHyp->GetLength(); + return true; +} + //================================================================================ /*! * \brief Creates and selects hypothesis of hypotheses set @@ -1664,6 +1888,7 @@ void SMESHGUI_MeshOp::onAlgoSelected( const int theIndex, void SMESHGUI_MeshOp::onHypoSet( const QString& theSetName ) { HypothesesSet* aHypoSet = SMESH::GetHypothesesSet(theSetName); + myHypoSet = aHypoSet; if (!aHypoSet) return; @@ -1676,38 +1901,68 @@ void SMESHGUI_MeshOp::onHypoSet( const QString& theSetName ) onAlgoSelected( -1, dim ); } + HypothesesSet::SetType setType = aHypoSet->getPreferredHypType(); + if ( !aHypoSet->getAlgoAvailable( setType )) + { + setType = ( setType == HypothesesSet::ALT ) ? HypothesesSet::MAIN : HypothesesSet::ALT; + if ( !aHypoSet->getAlgoAvailable( setType )) + return; + } + + myAverageSize = -1; + if ( aHypoSet->toUseCommonSize() && !getAverageSize( myAverageSize )) + return; + for ( int isAlgo = 1; isAlgo >= 0; --isAlgo ) - for ( aHypoSet->init( isAlgo ); aHypoSet->more(); aHypoSet->next() ) + for ( aHypoSet->init( isAlgo, setType ); aHypoSet->more(); aHypoSet->next() ) { QString aHypoTypeName = aHypoSet->current(); HypothesisData* aHypData = SMESH::GetHypothesisData( aHypoTypeName ); if (!aHypData) continue; - int aDim = aHypData->Dim[0]; + myDim = aHypData->Dim[0]; // create or/and set if ( isAlgo ) { - int index = myAvailableHypData[aDim][Algo].indexOf( aHypData ); + int index = myAvailableHypData[myDim][Algo].indexOf( aHypData ); if ( index >= 0 ) { - setCurrentHyp( aDim, Algo, index ); - onAlgoSelected( index, aDim ); + setCurrentHyp( myDim, Algo, index ); + onAlgoSelected( index, myDim ); } } else { - bool mainHyp = true; - int index = myAvailableHypData[aDim][MainHyp].indexOf( aHypData ); + myType = MainHyp; + int index = myAvailableHypData[myDim][MainHyp].indexOf( aHypData ); if ( index < 0 ) { - mainHyp = false; - index = myAvailableHypData[aDim][AddHyp].indexOf( aHypData ); + myType = AddHyp; + index = myAvailableHypData[myDim][AddHyp].indexOf( aHypData ); } if ( index >= 0 ) - createHypothesis( aDim, mainHyp ? MainHyp : AddHyp, aHypoTypeName ); + { + if ( myAverageSize > 0 ) + { + SMESH::HypInitParams params = { 2, myAverageSize, aHypoSet->isQuadDominated() }; + SMESH::SMESH_Hypothesis_var hyp = + getInitParamsHypothesis( aHypData->TypeName, aHypData->ServerLibName, & params ); + + QString hypName = GetUniqueName( getHypoNames(), aHypData->Label ); + SALOMEDS::SObject_wrap so = + SMESHGUI::GetSMESHGen()->PublishInStudy( SALOMEDS::SObject::_nil(), hyp, + hypName.toUtf8().data() ); + onHypoCreated(2); + } + else + { + createHypothesis( myDim, myType, aHypoTypeName ); + } + } } } + return; } @@ -1755,7 +2010,7 @@ bool SMESHGUI_MeshOp::createMesh( QString& theMess, QStringList& theEntryList ) namePrefix += "_"; } QStringList::Iterator it = aList.begin(); - for ( int i = 0; it!=aList.end(); it++, ++i ) + for ( int i = 0; it != aList.end(); it++, ++i ) { QString aGeomEntry = *it; _PTR(SObject) pGeom = SMESH::getStudy()->FindObjectID( aGeomEntry.toUtf8().data() ); @@ -1801,7 +2056,36 @@ bool SMESHGUI_MeshOp::createMesh( QString& theMess, QStringList& theEntryList ) if ( !anAlgoVar->_is_nil() ) SMESH::AddHypothesisOnMesh( aMesh, anAlgoVar ); } + + + if ( myDlg->toCreateAllGroups() && !aGeomVar->_is_nil() ) + { + // Create groups on all geom groups + + GEOM::GEOM_Gen_var geomGen = aGeomVar->GetGen(); + GEOM::GEOM_IShapesOperations_wrap op = geomGen->GetIShapesOperations(); + GEOM::ListOfGO_var geomGroups = op->GetExistingSubObjects( aGeomVar, + /*groupsOnly=*/false ); + SMESH::SMESH_GroupOnGeom_var meshGroup; + for ( CORBA::ULong iG = 0; iG < geomGroups->length(); ++iG ) + { + SMESH::ElementType elemType = SMESHGUI_GroupOnShapeOp::ElementType( geomGroups[ iG ] ); + if ( elemType == SMESH::ALL ) + continue; + if ( elemType == SMESH::ELEM0D ) + elemType = SMESH::NODE; + + CORBA::String_var name = geomGroups[ iG ]->GetName(); + meshGroup = aMesh->CreateGroupFromGEOM( elemType, name, geomGroups[ iG ]); + // if ( elemType != SMESH::NODE ) + // meshGroup = aMesh->CreateGroupFromGEOM( SMESH::NODE, name, geomGroups[ iG ]); + } + } + + createSubMeshOnInternalEdges( aMesh, aGeomVar ); + } + return true; } @@ -1854,7 +2138,7 @@ bool SMESHGUI_MeshOp::createSubMesh( QString& theMess, QStringList& theEntryList else if (aGEOMs.count() > 1) { // create a GEOM group - GEOM::GEOM_Gen_var geomGen = SMESH::GetGEOMGen( mainGeom ); + GEOM::GEOM_Gen_var geomGen = mainGeom->GetGen(); if ( !geomGen->_is_nil() ) { GEOM::GEOM_IGroupOperations_ptr op = geomGen->GetIGroupOperations(); if ( !op->_is_nil() ) @@ -2435,6 +2719,12 @@ bool SMESHGUI_MeshOp::editMeshOrSubMesh( QString& theMess ) } } + if ( aSubMeshVar->_is_nil() ) + { + GEOM::GEOM_Object_var mainGeom = aMesh->GetShapeToMesh(); + createSubMeshOnInternalEdges( aMesh, mainGeom ); + } + myHasConcurrentSubBefore = checkSubMeshConcurrency( aMesh, aSubMeshVar, /*askUser=*/!myHasConcurrentSubBefore ); @@ -2635,24 +2925,40 @@ void SMESHGUI_MeshOp::updateHypoSets() for ( ; inHypoSetName != aHypothesesSetsList.end(); ++inHypoSetName ) { HypothesesSet* currentHypoSet = SMESH::GetHypothesesSet( *inHypoSetName ); - bool isAvailable = false; - for ( currentHypoSet->init( true ); currentHypoSet->more(); currentHypoSet->next() ) + HypothesesSet::SetType sType; + for ( sType = HypothesesSet::MAIN; sType <= HypothesesSet::ALT; SMESHUtils::Increment( sType )) { - isAvailable = false; - if ( HypothesisData* algoDataIn = SMESH::GetHypothesisData( currentHypoSet->current() )) { - for (int i = SMESH::DIM_0D; i <= myMaxShapeDim; i++) { - int aCurrentAvailableAlgo = myAvailableHypData[i][Algo].indexOf( algoDataIn ); - if ( aCurrentAvailableAlgo > -1 ) { - isAvailable = true; - break; + bool isAvailable = false; + for ( currentHypoSet->init( true, sType ); currentHypoSet->more(); currentHypoSet->next() ) + { + isAvailable = false; + if ( HypothesisData* algoDataIn = SMESH::GetHypothesisData( currentHypoSet->current() )) { + for ( int dim = SMESH::DIM_0D; dim <= myMaxShapeDim; dim++) { + int aCurrentAvailableAlgo = myAvailableHypData[dim][Algo].indexOf( algoDataIn ); + if ( aCurrentAvailableAlgo > -1 ) { + isAvailable = true; + break; + } } + if ( !isAvailable ) + break; } - if ( !isAvailable ) - break; } + currentHypoSet->setAlgoAvailable( sType, isAvailable ); } - if ( isAvailable ) + if ( currentHypoSet->hasAlgo( HypothesesSet::MAIN ) && + currentHypoSet->hasAlgo( HypothesesSet::ALT )) + { + HypothesesSet::SetType setType = HypothesesSet::getPreferredHypType(); + if ( !currentHypoSet->getAlgoAvailable( setType )) + continue; // not add if a preferred type not available currently + } + + if ( currentHypoSet->getAlgoAvailable( HypothesesSet::MAIN ) || + currentHypoSet->getAlgoAvailable( HypothesesSet::ALT )) + { aFilteredHypothesesSetsList.append( *inHypoSetName ); + } } myDlg->setHypoSets( aFilteredHypothesesSetsList ); } diff --git a/src/SMESHGUI/SMESHGUI_MeshOp.h b/src/SMESHGUI/SMESHGUI_MeshOp.h index d93e4a12e..1a117d53f 100644 --- a/src/SMESHGUI/SMESHGUI_MeshOp.h +++ b/src/SMESHGUI/SMESHGUI_MeshOp.h @@ -121,6 +121,8 @@ private: bool createMesh( QString&, QStringList& ); bool createSubMesh( QString&, QStringList& ); bool editMeshOrSubMesh( QString& ); + void createSubMeshOnInternalEdges( SMESH::SMESH_Mesh_ptr mesh, + GEOM::GEOM_Object_ptr mainShape ); bool checkSubMeshConcurrency( SMESH::SMESH_Mesh_ptr mesh, SMESH::SMESH_subMesh_ptr submesh, bool askUser=false); @@ -137,8 +139,10 @@ private: int find( const SMESH::SMESH_Hypothesis_var&, const THypList& ) const; SMESH::SMESH_Hypothesis_var getInitParamsHypothesis( const QString&, - const QString& ) const; + const QString&, + const SMESH::HypInitParams* prm=0) const; void initHypCreator( SMESHGUI_GenericHypothesisCreator* aCreator ); + bool getAverageSize( double & averageSize ); bool isSubshapeOk() const; char* isSubmeshIgnored() const; _PTR(SObject) getSubmeshByGeom() const; @@ -146,6 +150,7 @@ private: void updateMeshTypeList(); void updateHypoSets(); void setFilteredAlgoData(); + QStringList getHypoNames(); private: @@ -172,6 +177,9 @@ private: bool myIgnoreAlgoSelection; int myDim, myType, myMaxShapeDim; + HypothesesSet* myHypoSet; // applied hypo-set + double myAverageSize; // entered at hypo-set processing + QString myObjectToSelect; }; diff --git a/src/SMESHGUI/SMESHGUI_VTKUtils.cxx b/src/SMESHGUI/SMESHGUI_VTKUtils.cxx index a8564b42e..fe5b138dc 100644 --- a/src/SMESHGUI/SMESHGUI_VTKUtils.cxx +++ b/src/SMESHGUI/SMESHGUI_VTKUtils.cxx @@ -289,6 +289,29 @@ namespace SMESH return; } + //================================================================================ + /*! + * \brief Remove/update actors while module activation + * + * At module activation, groups and sub-meshes can be removed on engine side due + * to modification of meshed geometry, while their actors can remain. + * Here we remove/update SMESH_Actor's of changed objects. State (emptiness) of objects + * is defined by their icons in the Object Browser + */ + //================================================================================ + + void UpdateActorsAfterUpdateStudy() + { + SUIT_Study* study = SMESH::GetActiveStudy(); + if ( SUIT_Desktop* desk = study->application()->desktop() ) + { + QList wndList = desk->windows(); + SUIT_ViewWindow* wnd; + foreach ( wnd, wndList ) + SMESH::UpdateActorsAfterUpdateStudy(wnd); + } + } + //================================================================================ /*! * \brief Notify the user on problems during visualization diff --git a/src/SMESHGUI/SMESHGUI_VTKUtils.h b/src/SMESHGUI/SMESHGUI_VTKUtils.h index ec6057493..8874d1a80 100644 --- a/src/SMESHGUI/SMESHGUI_VTKUtils.h +++ b/src/SMESHGUI/SMESHGUI_VTKUtils.h @@ -219,6 +219,9 @@ SMESHGUI_EXPORT SMESHGUI_EXPORT void UpdateActorsAfterUpdateStudy( SUIT_ViewWindow* wnd ); + + SMESHGUI_EXPORT + void UpdateActorsAfterUpdateStudy(); }; #endif // SMESHGUI_VTKUTILS_H diff --git a/src/SMESHGUI/SMESHGUI_XmlHandler.cxx b/src/SMESHGUI/SMESHGUI_XmlHandler.cxx index 823032fca..3993633be 100644 --- a/src/SMESHGUI/SMESHGUI_XmlHandler.cxx +++ b/src/SMESHGUI/SMESHGUI_XmlHandler.cxx @@ -201,14 +201,26 @@ bool SMESHGUI_XmlHandler::startElement (const QString&, const QString&, { if (atts.value("name") != "") { - QString hypos = atts.value("hypos").remove( ' ' ); - QString algos = atts.value("algos").remove( ' ' ); + bool useCommonSize = ( atts.value("use-common-size") == "true" ); + bool isQuadDominated = ( atts.value("quad-dominated") == "true" ); + QString hypos = atts.value("hypos"); + QString algos = atts.value("algos"); + QString altHypos = atts.value("alt-hypos"); + QString altAlgos = atts.value("alt-algos"); + QString intHypos = atts.value("intern-edge-hypos"); + QString intAlgos = atts.value("intern-edge-algos"); bool badSet = hypos.contains( BAD_HYP_FLAG ) || algos.contains( BAD_HYP_FLAG ); if ( !badSet ) - myListOfHypothesesSets.append( new HypothesesSet ( atts.value("name"), - hypos.split( ',', QString::SkipEmptyParts ), - algos.split( ',', QString::SkipEmptyParts ) ) ); + myListOfHypothesesSets.append + ( new HypothesesSet ( atts.value("name"), + useCommonSize, isQuadDominated, + hypos.split ( ',', QString::SkipEmptyParts ), + algos.split ( ',', QString::SkipEmptyParts ), + altHypos.split( ',', QString::SkipEmptyParts ), + altAlgos.split( ',', QString::SkipEmptyParts ), + intHypos.split( ',', QString::SkipEmptyParts ), + intAlgos.split( ',', QString::SkipEmptyParts ))); } } else if ( qName == "python-wrap" || diff --git a/src/SMESHGUI/SMESH_msg_en.ts b/src/SMESHGUI/SMESH_msg_en.ts index 62e0db990..eba5718ed 100644 --- a/src/SMESHGUI/SMESH_msg_en.ts +++ b/src/SMESHGUI/SMESH_msg_en.ts @@ -4677,6 +4677,10 @@ Please, create VTK viewer and try again PREF_NB_SEGMENTS Default Number of Segments + + PREF_USE_MESHGEMS_HYPOSET + Use MeshGems meshers when assigning set of hypotheses + SMESH_PREF_MESH_LOADING Mesh loading @@ -6520,7 +6524,7 @@ Please specify them and try again HYPOTHESES_SETS - Assign a set of hypotheses + Assign a set of automatic hypotheses MESH @@ -6534,6 +6538,10 @@ Please specify them and try again NAME Name + + CREATE_ALL_GROUPS + Create all Groups on Geometry + SMESHGUI_MeshOp @@ -8498,4 +8506,11 @@ red in the Object Browser. Option value + + SMESHGUI_GenericHypothesisCreator + + AverageLengthForHypoSet + Mean Size + + diff --git a/src/SMESHGUI/SMESH_msg_fr.ts b/src/SMESHGUI/SMESH_msg_fr.ts index 23f5a8d89..f3ecad3be 100644 --- a/src/SMESHGUI/SMESH_msg_fr.ts +++ b/src/SMESHGUI/SMESH_msg_fr.ts @@ -53,7 +53,7 @@ GMF_BINARY_FILES_FILTER - Fichier GMF binaires + Fichiers GMF binaires STL_BIN_FILES_FILTER @@ -109,7 +109,7 @@ MIN_ELEM_EDGE - Longueur arête Minimum + Longueur arête minimum ASPECTRATIO_3D_ELEMENTS @@ -189,7 +189,7 @@ EDITERR_NO_MEDIUM_ON_GEOM - Certain noeuds milieux (affichés en magenta) ne sont pas placés + Certain nœuds milieux (affichés en magenta) ne sont pas placés sur la géométrie pour éviter d'obtenir des élements distordus. @@ -234,7 +234,7 @@ DEFLECTION2D_FACES - Deflection 2D + Déflection 2D LENGTH_EDGES @@ -246,15 +246,15 @@ MAX_ELEMENT_LENGTH_2D - Diamètre d'éléments 2D + Diamètre des éléments 2D MAX_ELEMENT_LENGTH_3D - Diamètre Element 3D + Diamètre des éléments 3D DEFLECTION_2D - Deflection 2D + Déflection 2D MEN_ADD @@ -334,7 +334,7 @@ MEN_CONV_TO_QUAD - Convertir vers/de quadratique + Convertir vers/depuis quadratique MEN_2D_FROM_3D @@ -450,7 +450,7 @@ MEN_0D_ON_ALL_NODES - Eléments 0D sur des noeuds + Eléments 0D sur des nœuds MEN_BALL @@ -1183,7 +1183,7 @@ STB_OVERALL_MESH_QUALITY Qualité du maillage global - + STB_SPLIT_TO_TETRA Eclater en tétraèdres @@ -1803,7 +1803,7 @@ Voulez-vous continuer ? SMESH_EXPORT_MED_VERSION_COLLISION - La version MED du fichier "%1" n'est pas connue + La version MED du fichier "%1" n'est pas connue ou ne correspond pas à la version choisie. Ecraser le fichier ? @@ -1855,8 +1855,7 @@ Voulez-vous continuer ? SMESH_FILE_EXISTS Le fichier "%1" existe déjà. -Voulez-vous le réécrire ou y ajouter -les données exportées ? +Voulez-vous le réécrire ou y ajouter les données exportées ? SMESH_FONT_ARIAL @@ -3154,7 +3153,7 @@ Utilisez le menu "Visualiser une entité" pour les afficher. STB_0D_ON_ALL_NODES - Créer des éléments 0D sur des noeuds + Créer des éléments 0D sur des nœuds STB_ELEMS0D @@ -3846,7 +3845,7 @@ Utilisez le menu "Visualiser une entité" pour les afficher. TOP_0D_ON_ALL_NODES - Créer des éléments 0D sur des noeuds + Créer des éléments 0D sur des nœuds TOP_ELEM0D @@ -4603,6 +4602,10 @@ Ouvrez une fenêtre VTK et essayez de nouveau PREF_SHOW_WARN Affiche un avertissement quand un groupe est exporté + + PREF_ZTOLERANCE + Tolérance sur Z pour l'export en MED + PREF_GROUP_SEGMENT_LENGTH Paramètres automatiques @@ -4615,6 +4618,10 @@ Ouvrez une fenêtre VTK et essayez de nouveau PREF_NB_SEGMENTS Nombre de segments par défaut + + PREF_USE_MESHGEMS_HYPOSET + Utiliser les mailleurs MeshGems pour définir les hypothèses automatiques + SMESH_PREF_MESH_LOADING Chargement de maillage @@ -4703,6 +4710,10 @@ Ouvrez une fenêtre VTK et essayez de nouveau PREF_DISPLAY_MODE Mode de visualisation par défaut + + PREF_FITALL_ON_DISPLAYONLY + Ajuster la vue en cas d'affichage unique + PREF_ELEMENTS Eléments @@ -4967,7 +4978,7 @@ Ouvrez une fenêtre VTK et essayez de nouveau SMESHGUI_Add0DElemsOnAllNodesDlg CAPTION - Créer des éléments 0D sur des noeuds + Créer des éléments 0D sur des nœuds OBJ_BTN @@ -5410,7 +5421,7 @@ Choisissez un groupe et essayez de nouveau EDIT_SELECTED_NODE_GROUP - Editer le groupe sélectionné de noeuds coïncidents + Editer le groupe sélectionné de nœuds coïncidents EDIT_SELECTED_ELEM_GROUP @@ -5434,7 +5445,7 @@ Choisissez un groupe et essayez de nouveau SEPARATE_CORNERS_AND_MEDIUM - Pas de fusion du coin et des noeuds moyens des cellules quadratiques + Pas de fusion du coin et des nœuds moyens des cellules quadratiques AVOID_MAKING_HOLES @@ -5442,7 +5453,7 @@ Choisissez un groupe et essayez de nouveau KEEP_NODES - Les noeuds à conserver pendant la fusion + Les nœuds à conserver pendant la fusion GROUP_SUBMESH @@ -5536,7 +5547,7 @@ Choisissez un groupe et essayez de nouveau SMESHGUI_ExtrusionDlg EXTRUSION_0D - Extrusion de noeuds + Extrusion de nœuds EXTRUSION_1D @@ -5880,7 +5891,7 @@ Vérifiez la validité des informations données NUMBEROFNODESINELEMENT - Nombre de noeuds dans l'élément + Nombre de nœuds dans l'élément COPY_FROM @@ -6448,7 +6459,7 @@ Indiquez-les et essayez de nouveau HYPOTHESES_SETS - Attribuer un jeu d'hypothèses + Définir des hypothèses automatiques MESH @@ -6462,6 +6473,34 @@ Indiquez-les et essayez de nouveau NAME Nom + + CREATE_ALL_GROUPS + Créer tous les groupes définis dans la géométrie + + + 3D: Tetrahedralization + 3D : Tétraèdres + + + 3D: Mapped Hexahedralization + 3D : Hexaèdres réglés + + + 3D: Free Hexahedralization + 3D : Hexaèdres libres + + + 2D: Triangulation + 2D : Triangles + + + 2D: Mapped Quadrangulation + 2D : Quadrangles réglés + + + 2D: Free Quadrangulation + 2D : Quadrangles libres + SMESHGUI_MeshOp @@ -6524,7 +6563,7 @@ Spécifiez-le et essayez de nouveau MT_HEXAHEDRAL - Hexahèdre + Hexaèdre MT_TETRAHEDRAL @@ -6555,7 +6594,7 @@ Sélectionnez un maillage ou un sous-maillage et essayez de nouveau CONCURRENT_SUBMESH_APPEARS - + L'algorithme assigné a la même priorité que celui assigné à un sous-maillage adjacent; ainsi l'algorithme à utiliser pour mailler la frontière partagée par les deux sous-maillages n'est pas défini. @@ -6587,7 +6626,7 @@ Il est probable que le fichier est corrompu ou contient un autre type de motif ERROR_OF_OPENING - Il est impossible d'ouvrir le fichier. + Il est impossible d'ouvrir le fichier. Vérifiez s'il existe et si vous avez l'autorisation @@ -6637,7 +6676,7 @@ Il est impossible de lire les coordonnées des points dans le fichier ERR_READ_TOO_FEW_POINTS - Il est impossible de charger le motif. + Il est impossible de charger le motif. Il y a trop peu de points dans le fichier @@ -8143,7 +8182,7 @@ en raison de leurs types incompatibles: SUBSHAPES_NOT_FOUND_MSG -Some sub-shapes not found in the new geometry. They are listed +Some sub-shapes not found in the new geometry. They are listed below along with dependent mesh objects that are marked with with red in the Object Browser. @@ -8399,4 +8438,11 @@ with red in the Object Browser. Valeur de l'option' + + SMESHGUI_GenericHypothesisCreator + + AverageLengthForHypoSet + Taille moyenne + + diff --git a/src/SMESHUtils/SMESH_Delaunay.cxx b/src/SMESHUtils/SMESH_Delaunay.cxx index e2a4a99b6..92bbc6e3b 100644 --- a/src/SMESHUtils/SMESH_Delaunay.cxx +++ b/src/SMESHUtils/SMESH_Delaunay.cxx @@ -225,11 +225,8 @@ const BRepMesh_Triangle* SMESH_Delaunay::FindTriangle( const gp_XY& gp_XY seg = uv - gc; tria->Edges( linkIDs, ori ); -#if OCC_VERSION_LARGE <= 0x07030000 - int triaID = _triaDS->IndexOf( *tria ); -#else - int triaID = tria - & ( _triaDS->GetElement( 0 )); -#endif + + const BRepMesh_Triangle* prevTria = tria; tria = 0; for ( int i = 0; i < 3; ++i ) @@ -252,7 +249,9 @@ const BRepMesh_Triangle* SMESH_Delaunay::FindTriangle( const gp_XY& double uSeg = ( uv1 - gc ) ^ lin / crossSegLin; if ( 0. <= uSeg && uSeg <= 1. ) { - tria = & _triaDS->GetElement( triIDs.Index( 1 + ( triIDs.Index(1) == triaID ))); + tria = & _triaDS->GetElement( triIDs.Index( 1 )); + if ( tria == prevTria ) + tria = & _triaDS->GetElement( triIDs.Index( 2 )); if ( tria->Movability() != BRepMesh_Deleted ) break; } @@ -388,5 +387,5 @@ void SMESH_Delaunay::ToPython() const file.remove(); file.openForWriting(); file.write( text.c_str(), text.size() ); - cout << "exec(open('" << fileName << "', 'rb').read())"; + std::cout << "exec(open('" << fileName << "', 'rb').read())"; } diff --git a/src/SMESH_I/CMakeLists.txt b/src/SMESH_I/CMakeLists.txt index e274c7728..9bb707929 100644 --- a/src/SMESH_I/CMakeLists.txt +++ b/src/SMESH_I/CMakeLists.txt @@ -23,6 +23,7 @@ INCLUDE_DIRECTORIES( ${OMNIORB_INCLUDE_DIR} ${OpenCASCADE_INCLUDE_DIR} ${HDF5_INCLUDE_DIRS} + ${MEDFILE_INCLUDE_DIRS} ${VTK_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${KERNEL_INCLUDE_DIRS} diff --git a/src/SMESH_I/SMESH_2smeshpy.cxx b/src/SMESH_I/SMESH_2smeshpy.cxx index 10398d8fc..689f49861 100644 --- a/src/SMESH_I/SMESH_2smeshpy.cxx +++ b/src/SMESH_I/SMESH_2smeshpy.cxx @@ -1834,7 +1834,7 @@ _pyMesh::_pyMesh(const Handle(_pyCommand) theCreationCmd, const _pyID& meshId): void _pyMesh::Process( const Handle(_pyCommand)& theCommand ) { - // some methods of SMESH_Mesh interface needs special conversion + // some methods of SMESH_Mesh interface need special conversion // to methods of Mesh python class // // 1. GetSubMesh(geom, name) + AddHypothesis(geom, algo) @@ -1987,7 +1987,7 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand ) // if GetGroups() is just after Compute(), this can mean that the groups // were created by some algorithm and hence Compute() should not be discarded std::list< Handle(_pyCommand) >& cmdList = theGen->GetCommands(); - std::list< Handle(_pyCommand) >::iterator cmd = cmdList.begin(); + std::list< Handle(_pyCommand) >::reverse_iterator cmd = cmdList.rbegin(); while ( (*cmd)->GetMethod() == "GetGroups" ) ++cmd; if ( myLastComputeCmd == (*cmd)) @@ -3165,8 +3165,7 @@ void _pyHypothesis::ComputeDiscarded( const Handle(_pyCommand)& theComputeCmd ) continue; // check if a cmd is a sole command setting its parameter; // don't use method name for search as it can change - map >::iterator - m2cmds = myMeth2Commands.begin(); + map<_AString, list >::iterator m2cmds = myMeth2Commands.begin(); for ( ; m2cmds != myMeth2Commands.end(); ++m2cmds ) { list< Handle(_pyCommand)>& cmds = m2cmds->second; diff --git a/src/SMESH_I/SMESH_Gen_i.cxx b/src/SMESH_I/SMESH_Gen_i.cxx index 6117d4547..ac0b69600 100644 --- a/src/SMESH_I/SMESH_Gen_i.cxx +++ b/src/SMESH_I/SMESH_Gen_i.cxx @@ -829,6 +829,43 @@ SMESH::SMESH_Hypothesis_ptr SMESH_Gen_i::CreateHypothesis( const char* theHypNam return hyp._retn(); } +//================================================================================ +/*! + * \brief Return a hypothesis initialized by given average length. + * \param theHypType - hypothesis type name + * \param theLibName - plugin library name + * \param theAverageLength - average length + * \param theQuadDominated - is quad-dominated flag + * \retval SMESH::SMESH_Hypothesis_ptr - the new hypothesis + */ +//================================================================================ + +SMESH::SMESH_Hypothesis_ptr +SMESH_Gen_i::CreateHypothesisByAverageLength( const char* theHypType, + const char* theLibName, + CORBA::Double theAverageLength, + CORBA::Boolean theQuadDominated) + throw ( SALOME::SALOME_Exception ) +{ + SMESH::HypInitParams initParams = { ::SMESH_Hypothesis::BY_AVERAGE_LENGTH, + theAverageLength, theQuadDominated }; + + SMESH::SMESH_Hypothesis_var hyp = + GetHypothesisParameterValues( theHypType, theLibName, + SMESH::SMESH_Mesh::_nil(), + GEOM::GEOM_Object::_nil(), + initParams ); + SALOMEDS::SObject_wrap so = PublishHypothesis( hyp ); + + TPythonDump() << hyp << " = " << this << ".CreateHypothesisByAverageLength( '" + << theHypType << "', '" + << theLibName << "', " + << theAverageLength << ", " + << theQuadDominated << " )"; + + return hyp._retn(); +} + //================================================================================ /*! * \brief Return a hypothesis holding parameter values corresponding either to the mesh @@ -844,14 +881,16 @@ SMESH::SMESH_Hypothesis_ptr SMESH_Gen_i::CreateHypothesis( const char* theHypNam //================================================================================ SMESH::SMESH_Hypothesis_ptr -SMESH_Gen_i::GetHypothesisParameterValues (const char* theHypType, - const char* theLibName, - SMESH::SMESH_Mesh_ptr theMesh, - GEOM::GEOM_Object_ptr theGeom, - CORBA::Boolean byMesh) +SMESH_Gen_i::GetHypothesisParameterValues( const char* theHypType, + const char* theLibName, + SMESH::SMESH_Mesh_ptr theMesh, + GEOM::GEOM_Object_ptr theGeom, + const SMESH::HypInitParams& theParams) throw ( SALOME::SALOME_Exception ) { Unexpect aCatch(SALOME_SalomeException); + + const bool byMesh = ( theParams.way == ::SMESH_Hypothesis::BY_MESH ); if ( byMesh && CORBA::is_nil( theMesh ) ) return SMESH::SMESH_Hypothesis::_nil(); if ( byMesh && CORBA::is_nil( theGeom ) ) @@ -906,17 +945,24 @@ SMESH_Gen_i::GetHypothesisParameterValues (const char* theHypType, if ( hyp->SetParametersByMesh( mesh, shape )) return SMESH::SMESH_Hypothesis::_duplicate( tmpHyp ); } - else { - double diagonal = 0; - if ( mesh ) - diagonal = mesh->GetShapeDiagonalSize(); - else - diagonal = ::SMESH_Mesh::GetShapeDiagonalSize( shape ); + else + { ::SMESH_Hypothesis::TDefaults dflts; - dflts._elemLength = diagonal / myGen.GetBoundaryBoxSegmentation(); - dflts._nbSegments = myGen.GetDefaultNbSegments(); - dflts._shape = &shape; - // let the temporary hypothesis initialize it's values + dflts._way = ( ::SMESH_Hypothesis::InitWay) theParams.way; + dflts._nbSegments = myGen.GetDefaultNbSegments(); + dflts._elemLength = theParams.averageLength; + dflts._quadDominated = theParams.quadDominated; + if ( theParams.way == ::SMESH_Hypothesis::BY_GEOM ) + { + if ( mesh ) + dflts._diagonal = mesh->GetShapeDiagonalSize(); + else + dflts._diagonal = ::SMESH_Mesh::GetShapeDiagonalSize( shape ); + dflts._elemLength = dflts._diagonal / myGen.GetBoundaryBoxSegmentation(); + dflts._shape = &shape; + } + + // let the hypothesis initialize it's values if ( hyp->SetParametersByDefaults( dflts, mesh )) return SMESH::SMESH_Hypothesis::_duplicate( tmpHyp ); } diff --git a/src/SMESH_I/SMESH_Gen_i.hxx b/src/SMESH_I/SMESH_Gen_i.hxx index 0cb93fbb9..b288eec86 100644 --- a/src/SMESH_I/SMESH_Gen_i.hxx +++ b/src/SMESH_I/SMESH_Gen_i.hxx @@ -170,12 +170,19 @@ public: const char* theLibName) throw ( SALOME::SALOME_Exception ); + SMESH::SMESH_Hypothesis_ptr CreateHypothesisByAverageLength( const char* theHypType, + const char* theLibName, + CORBA::Double theAverageLength, + CORBA::Boolean theQuadDominated) + throw ( SALOME::SALOME_Exception ); + // Return hypothesis of given type holding parameter values of the existing mesh - SMESH::SMESH_Hypothesis_ptr GetHypothesisParameterValues (const char* theHypType, - const char* theLibName, - SMESH::SMESH_Mesh_ptr theMesh, - GEOM::GEOM_Object_ptr theGeom, - CORBA::Boolean byMesh) + SMESH::SMESH_Hypothesis_ptr + GetHypothesisParameterValues (const char* theHypType, + const char* theLibName, + SMESH::SMESH_Mesh_ptr theMesh, + GEOM::GEOM_Object_ptr theGeom, + const SMESH::HypInitParams& theWay) throw ( SALOME::SALOME_Exception ); /* @@ -530,6 +537,7 @@ public: const char* theName = 0); void UpdateIcons(SMESH::SMESH_Mesh_ptr theMesh); void HighLightInvalid(CORBA::Object_ptr theObject, bool isInvalid); + bool IsInvalid(SALOMEDS::SObject_ptr theObject); bool AddHypothesisToShape(SMESH::SMESH_Mesh_ptr theMesh, GEOM::GEOM_Object_ptr theShapeObject, SMESH::SMESH_Hypothesis_ptr theHyp); diff --git a/src/SMESH_I/SMESH_Gen_i_1.cxx b/src/SMESH_I/SMESH_Gen_i_1.cxx index 0b258bf08..580663d46 100644 --- a/src/SMESH_I/SMESH_Gen_i_1.cxx +++ b/src/SMESH_I/SMESH_Gen_i_1.cxx @@ -840,21 +840,25 @@ SALOMEDS::SObject_ptr SMESH_Gen_i::PublishGroup (SMESH::SMESH_Mesh_ptr theMesh, SetName( aRootSO, aRootNames[aType] ); // Add new group to corresponding sub-tree - int isEmpty = false; + int isEmpty = ( theMesh->NbNodes() == 0 ); std::string pm[2] = { "ICON_SMESH_TREE_GROUP", "ICON_SMESH_TREE_MESH_WARN" }; - if ( SMESH::DownCast< SMESH_GroupOnFilter_i* > ( theGroup )) - { - pm[0] = "ICON_SMESH_TREE_GROUP_ON_FILTER"; - } - else if ( SMESH::DownCast< SMESH_Group_i* > ( theGroup )) + if ( !isEmpty ) { - if ( theGroup->GetType() == SMESH::NODE ) - isEmpty = ( theMesh->NbNodes() == 0 ); - else + if ( SMESH::DownCast< SMESH_GroupOnFilter_i* > ( theGroup )) // on filter + { + pm[0] = "ICON_SMESH_TREE_GROUP_ON_FILTER"; + + if ( theGroup->GetType() != SMESH::NODE ) + { + isEmpty = true; + SMESH::array_of_ElementType_var allElemTypes = theMesh->GetTypes(); + for ( size_t i =0; i < allElemTypes->length() && isEmpty; ++i ) + isEmpty = ( allElemTypes[i] != theGroup->GetType() ); + } + } + else // standalone or on geometry { - SMESH::array_of_ElementType_var allElemTypes = theMesh->GetTypes(); - for ( size_t i =0; i < allElemTypes->length() && isEmpty; ++i ) - isEmpty = ( allElemTypes[i] != theGroup->GetType() ); + isEmpty = ( theGroup->Size() == 0 ); } } aGroupSO = publish ( theGroup, aRootSO, 0, pm[isEmpty].c_str() ); @@ -874,14 +878,14 @@ SALOMEDS::SObject_ptr SMESH_Gen_i::PublishGroup (SMESH::SMESH_Mesh_ptr theMesh, //======================================================================= //function : PublishHypothesis -//purpose : +//purpose : //======================================================================= SALOMEDS::SObject_ptr - SMESH_Gen_i::PublishHypothesis (SMESH::SMESH_Hypothesis_ptr theHyp, - const char* theName) +SMESH_Gen_i::PublishHypothesis (SMESH::SMESH_Hypothesis_ptr theHyp, + const char* theName) { - if(MYDEBUG) MESSAGE("PublishHypothesis") + if(MYDEBUG) MESSAGE("PublishHypothesis"); if ( !myIsEnablePublish ) return SALOMEDS::SObject::_nil(); if (theHyp->_is_nil()) @@ -1031,6 +1035,28 @@ void SMESH_Gen_i::highLightInvalid( SALOMEDS::SObject_ptr theSObject, bool isInv } } +//======================================================================= +//function : IsInvalid +//purpose : Check object validity == absence of AttributeTextColor=(178,34,34) +//======================================================================= + +bool SMESH_Gen_i::IsInvalid( SALOMEDS::SObject_ptr theSObject ) +{ + bool isValid = true; + if ( !theSObject->_is_nil() ) + { + SALOMEDS::GenericAttribute_wrap attr; + SALOMEDS::StudyBuilder_var studyBuilder = getStudyServant()->NewBuilder(); + if ( studyBuilder->FindAttribute( theSObject, attr.inout(), "AttributeTextColor" )) + { + SALOMEDS::AttributeTextColor_wrap colorAttr = attr; + SALOMEDS::Color color = colorAttr->TextColor(); + isValid = ( color.R != 178 || color.G != 34 || color.B != 34 ); + } + } + return isValid; +} + //======================================================================= //function : GetMeshOrSubmeshByShape //purpose : diff --git a/src/SMESH_I/SMESH_Group_i.cxx b/src/SMESH_I/SMESH_Group_i.cxx index a2dac404c..a7a7e45eb 100644 --- a/src/SMESH_I/SMESH_Group_i.cxx +++ b/src/SMESH_I/SMESH_Group_i.cxx @@ -171,13 +171,13 @@ char* SMESH_GroupBase_i::GetName() { ::SMESH_Group* aGroup = GetSmeshGroup(); if (aGroup) - return CORBA::string_dup (aGroup->GetName()); + return CORBA::string_dup( aGroup->GetName() ); return CORBA::string_dup( "NO_NAME" ); } //============================================================================= /*! - * + * */ //============================================================================= diff --git a/src/SMESH_I/SMESH_MeshEditor_i.cxx b/src/SMESH_I/SMESH_MeshEditor_i.cxx index 421a0babf..b813fc37b 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.cxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.cxx @@ -1390,8 +1390,11 @@ void SMESH_MeshEditor_i::SetNodeOnEdge(CORBA::Long NodeID, CORBA::Long EdgeID, Standard_Real f,l; BRep_Tool::Range( TopoDS::Edge( shape ), f,l); if ( paramOnEdge < f || paramOnEdge > l ) - THROW_SALOME_CORBA_EXCEPTION("Invalid paramOnEdge", SALOME::BAD_PARAM); - + { + SMESH_Comment txt("Invalid paramOnEdge. It must vary in range [ "); + txt << f << ", " << l << " ]"; + THROW_SALOME_CORBA_EXCEPTION(txt.c_str(), SALOME::BAD_PARAM); + } mesh->SetNodeOnEdge( node, EdgeID, paramOnEdge ); myMesh->SetIsModified( true ); @@ -1434,14 +1437,11 @@ void SMESH_MeshEditor_i::SetNodeOnFace(CORBA::Long NodeID, CORBA::Long FaceID, v > surf.LastVParameter() ); if ( isOut ) { -#ifdef _DEBUG_ - MESSAGE ( "FACE " << FaceID << " (" << u << "," << v << ") out of " - << " u( " << surf.FirstUParameter() - << "," << surf.LastUParameter() - << ") v( " << surf.FirstVParameter() - << "," << surf.LastVParameter() << ")" ); -#endif - THROW_SALOME_CORBA_EXCEPTION("Invalid UV", SALOME::BAD_PARAM); + SMESH_Comment txt("Invalid UV. U must vary in range [ "); + txt << surf.FirstUParameter() << ", " << surf.LastUParameter() << " ], "; + txt << "V must vary in range [ "; + txt << surf.FirstVParameter() << ", " << surf.LastVParameter() << " ]"; + THROW_SALOME_CORBA_EXCEPTION(txt.c_str(), SALOME::BAD_PARAM); } mesh->SetNodeOnFace( node, FaceID, u, v ); diff --git a/src/SMESH_I/SMESH_Mesh_i.cxx b/src/SMESH_I/SMESH_Mesh_i.cxx index 2b831f8c9..d4e396cbd 100644 --- a/src/SMESH_I/SMESH_Mesh_i.cxx +++ b/src/SMESH_I/SMESH_Mesh_i.cxx @@ -114,6 +114,7 @@ SMESH_Mesh_i::SMESH_Mesh_i( PortableServer::POA_ptr thePOA, _impl = NULL; _gen_i = gen_i; _id = _idGenerator++; + _nbInvalidHypos= -1; _editor = NULL; _previewEditor = NULL; _preMeshInfo = NULL; @@ -689,6 +690,8 @@ SMESH_Mesh_i::AddHypothesis(GEOM::GEOM_Object_ptr aSubShape, if ( _preMeshInfo ) _preMeshInfo->ForgetOrLoad(); + const int prevNbMeshEnt = _impl->NbNodes() + _impl->GetMeshDS()->NbElements(); + std::string error; SMESH_Hypothesis::Hypothesis_Status status = addHypothesis( aSubShape, anHyp, &error ); anErrorText = error.c_str(); @@ -697,7 +700,10 @@ SMESH_Mesh_i::AddHypothesis(GEOM::GEOM_Object_ptr aSubShape, if ( !SMESH_Hypothesis::IsStatusFatal(status) ) { _gen_i->AddHypothesisToShape( mesh, aSubShape, anHyp ); - _gen_i->UpdateIcons( mesh ); + + int newNbMeshEnt = _impl->NbNodes() + _impl->GetMeshDS()->NbElements(); + if ( newNbMeshEnt != prevNbMeshEnt ) + _gen_i->UpdateIcons( mesh ); } if(MYDEBUG) MESSAGE( " AddHypothesis(): status = " << status ); @@ -3234,40 +3240,55 @@ namespace SMESH_Mesh_i* _mesh; TCallUp_i(SMESH_Mesh_i* mesh):_mesh(mesh) {} virtual void RemoveGroup (const int theGroupID) { _mesh->removeGroup( theGroupID ); } - virtual void HypothesisModified (int theHypID) { _mesh->onHypothesisModified( theHypID ); } + virtual void HypothesisModified( int hypID, + bool updIcons) { _mesh->onHypothesisModified( hypID, + updIcons ); } virtual void Load () { _mesh->Load(); } + virtual bool IsLoaded() { return _mesh->IsLoaded(); } }; } //================================================================================ /*! - * \brief callback from _impl to forget not loaded mesh data (issue 0021208) + * \brief callback from _impl to + * 1) forget not loaded mesh data (issue 0021208) + * 2) mark hypothesis as valid */ //================================================================================ -void SMESH_Mesh_i::onHypothesisModified(int theHypID) +void SMESH_Mesh_i::onHypothesisModified(int theHypID, bool theUpdateIcons) { if ( _preMeshInfo ) _preMeshInfo->ForgetOrLoad(); - SMESH::SMESH_Mesh_var mesh = _this(); - _gen_i->UpdateIcons( mesh ); + if ( theUpdateIcons ) + { + SMESH::SMESH_Mesh_var mesh = _this(); + _gen_i->UpdateIcons( mesh ); + } - // mark a hypothesis as valid after edition - SALOMEDS::SComponent_wrap smeshComp = _gen_i->PublishComponent(); - SALOMEDS::SObject_wrap hypRoot; - if ( !smeshComp->_is_nil() && - smeshComp->FindSubObject( _gen_i->GetHypothesisRootTag(), hypRoot.inout() )) + if ( _nbInvalidHypos != 0 ) { - SALOMEDS::ChildIterator_wrap anIter = _gen_i->getStudyServant()->NewChildIterator( hypRoot ); - for ( ; anIter->More(); anIter->Next() ) + // mark a hypothesis as valid after edition + int nbInvalid = 0; + SALOMEDS::SComponent_wrap smeshComp = _gen_i->PublishComponent(); + SALOMEDS::SObject_wrap hypRoot; + if ( !smeshComp->_is_nil() && + smeshComp->FindSubObject( _gen_i->GetHypothesisRootTag(), hypRoot.inout() )) { - SALOMEDS::SObject_wrap hypSO = anIter->Value(); - CORBA::Object_var obj = _gen_i->SObjectToObject( hypSO ); - SMESH::SMESH_Hypothesis_var hyp = SMESH::SMESH_Hypothesis::_narrow( obj ); - if ( !hyp->_is_nil() && hyp->GetId() == theHypID ) - _gen_i->HighLightInvalid( hyp, false ); + SALOMEDS::ChildIterator_wrap anIter = _gen_i->getStudyServant()->NewChildIterator( hypRoot ); + for ( ; anIter->More(); anIter->Next() ) + { + SALOMEDS::SObject_wrap hypSO = anIter->Value(); + CORBA::Object_var obj = _gen_i->SObjectToObject( hypSO ); + SMESH::SMESH_Hypothesis_var hyp = SMESH::SMESH_Hypothesis::_narrow( obj ); + if ( !hyp->_is_nil() && hyp->GetId() == theHypID ) + _gen_i->HighLightInvalid( hyp, false ); + else + nbInvalid += _gen_i->IsInvalid( hypSO ); + } } + _nbInvalidHypos = nbInvalid; } } diff --git a/src/SMESH_I/SMESH_Mesh_i.hxx b/src/SMESH_I/SMESH_Mesh_i.hxx index 40e97e4c3..0d79c015d 100644 --- a/src/SMESH_I/SMESH_Mesh_i.hxx +++ b/src/SMESH_I/SMESH_Mesh_i.hxx @@ -455,11 +455,9 @@ public: const std::map& getGroups() { return _mapGroups; } // return existing group objects - void onHypothesisModified(int theHypID); + void onHypothesisModified(int theHypID, bool updateIcons); // callback from _impl to forget not loaded mesh data (issue 0021208) - void checkMeshLoaded(); - /*! * \brief Update data if geometry changes * @@ -733,12 +731,13 @@ private: */ TListOfListOfInt findConcurrentSubMeshes(); -private: + private: static int _idGenerator; ::SMESH_Mesh* _impl; // :: force no namespace here SMESH_Gen_i* _gen_i; int _id; // id given by creator (unique within the creator instance) + int _nbInvalidHypos; std::map _mapSubMeshIor; std::map _mapGroups; std::map _mapHypo; diff --git a/src/SMESH_I/SMESH_PreMeshInfo.cxx b/src/SMESH_I/SMESH_PreMeshInfo.cxx index 58701b123..275acb043 100644 --- a/src/SMESH_I/SMESH_PreMeshInfo.cxx +++ b/src/SMESH_I/SMESH_PreMeshInfo.cxx @@ -479,7 +479,7 @@ bool SMESH_PreMeshInfo::readMeshInfo() MED::PMeshInfo medMeshInfo = aMed->CrMeshInfo(3,3,SMESH_Comment( _meshID )); // read nb nodes - int nbNodes = std::max( 0, aMed->GetNbNodes( medMeshInfo )); + int nbNodes = Max( 0, aMed->GetNbNodes( medMeshInfo )); if ( nbNodes > 0 ) { setNb( SMDSEntity_Node, nbNodes); diff --git a/src/SMESH_I/SMESH_PythonDump.cxx b/src/SMESH_I/SMESH_PythonDump.cxx index 0687ddc0c..6b90f80f5 100644 --- a/src/SMESH_I/SMESH_PythonDump.cxx +++ b/src/SMESH_I/SMESH_PythonDump.cxx @@ -668,7 +668,7 @@ namespace SMESH void printException( const char* text ) { #ifdef _DEBUG_ - cout << "Exception in SMESH_Gen_i::DumpPython(): " << text << endl; + std::cout << "Exception in SMESH_Gen_i::DumpPython(): " << text << std::endl; #endif } @@ -696,7 +696,7 @@ namespace SMESH //function : DumpPython //purpose : //======================================================================= -Engines::TMPFile* SMESH_Gen_i::DumpPython (CORBA::Boolean isPublished, +Engines::TMPFile* SMESH_Gen_i::DumpPython( CORBA::Boolean isPublished, CORBA::Boolean isMultiFile, CORBA::Boolean& isValidScript) { diff --git a/src/SMESH_SWIG/StdMeshersBuilder.py b/src/SMESH_SWIG/StdMeshersBuilder.py index 858820238..8c8a4ced9 100644 --- a/src/SMESH_SWIG/StdMeshersBuilder.py +++ b/src/SMESH_SWIG/StdMeshersBuilder.py @@ -75,6 +75,11 @@ POLYGON = "PolygonPerFace_2D" Algorithm type: Polygon Per Face 2D algorithm, see :class:`~StdMeshersBuilder.StdMeshersBuilder_PolygonPerFace` """ +POLYHEDRON = "PolyhedronPerSolid_3D" +""" +Algorithm type: Polyhedron Per Solid 3D algorithm, see :class:`~StdMeshersBuilder.StdMeshersBuilder_PolyhedronPerSolid` +""" + # import items of enums for e in StdMeshers.QuadType._items: exec('%s = StdMeshers.%s'%(e,e)) for e in StdMeshers.VLExtrusionMethod._items: exec('%s = StdMeshers.%s'%(e,e)) @@ -174,10 +179,11 @@ class StdMeshersBuilder_Segment(Mesh_Algorithm): hyp.SetLength(length) if not UseExisting: # set preestimated length + import SMESH gen = self.mesh.smeshpyD initHyp = gen.GetHypothesisParameterValues("MaxLength", "libStdMeshersEngine.so", self.mesh.GetMesh(), self.mesh.GetShape(), - False) # <- byMesh + SMESH.HypInitParams( 1, 1.0, False )) preHyp = initHyp._narrow(StdMeshers.StdMeshers_MaxLength) if preHyp: hyp.SetPreestimatedLength( preHyp.GetPreestimatedLength() ) @@ -1670,6 +1676,44 @@ class StdMeshersBuilder_PolygonPerFace(Mesh_Algorithm): pass +class StdMeshersBuilder_PolyhedronPerSolid(Mesh_Algorithm): + """ Defines a Polyhedron Per Solid 3D algorithm. + It is created by calling smeshBuilder.Mesh.Polyhedron(geom=0) + """ + + meshMethod = "Polyhedron" + """ + name of the dynamic method in smeshBuilder.Mesh class + """ + algoType = POLYHEDRON + """ + type of algorithm used with helper function in smeshBuilder.Mesh class + """ + isDefault = True + """ + flag pointing whether this algorithm should be used by default in dynamic method + of smeshBuilder.Mesh class + """ + docHelper = "Create polyhedron 3D algorithm for solids" + """ + doc string of the method + """ + + def __init__(self, mesh, geom=0): + """ + Private constructor. + + Parameters: + mesh: parent mesh object algorithm is assigned to + geom: geometry (shape/sub-shape) algorithm is assigned to; + if it is :code:`0` (default), the algorithm is assigned to the main shape + """ + Mesh_Algorithm.__init__(self) + self.Create(mesh, geom, self.algoType) + pass + + pass + class StdMeshersBuilder_UseExistingElements_1D(Mesh_Algorithm): """ Defines a Use Existing Elements 1D algorithm. diff --git a/src/SMESH_SWIG/smeshBuilder.py b/src/SMESH_SWIG/smeshBuilder.py index 696d4f3cc..2a6238966 100644 --- a/src/SMESH_SWIG/smeshBuilder.py +++ b/src/SMESH_SWIG/smeshBuilder.py @@ -1239,6 +1239,27 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): return hyp + def GetHypothesisParameterValues( self, hypType, libName, mesh, shape, initParams ): + """ + Create hypothesis initialized according to parameters + + Parameters: + hypType (string): hypothesis type + libName (string): plug-in library name + mesh: optional mesh by which a hypotheses can initialize self + shape: optional geometry by size of which a hypotheses can initialize self + initParams: structure SMESH.HypInitParams defining how to initialize a hypothesis + + Returns: + created hypothesis instance + """ + if isinstance( mesh, Mesh ): + mesh = mesh.GetMesh() + if isinstance( initParams, (bool,int)): + initParams = SMESH.HypInitParams( not initParams, 1.0, not mesh ) + return SMESH._objref_SMESH_Gen.GetHypothesisParameterValues(self, hypType, libName, + mesh, shape, initParams ) + def GetMeshInfo(self, obj): """ Get the mesh statistic. @@ -2608,7 +2629,7 @@ class Mesh(metaclass = MeshMeta): tgeo = str(shape.GetShapeType()) if tgeo == "VERTEX": typ = NODE - elif tgeo == "EDGE": + elif tgeo == "EDGE" or tgeo == "WIRE": typ = EDGE elif tgeo == "FACE" or tgeo == "SHELL": typ = FACE @@ -7597,7 +7618,7 @@ class genObjUnRegister: if genObj and hasattr( genObj, "UnRegister" ): genObj.UnRegister() -for pluginName in os.environ[ "SMESH_MeshersList" ].split( ":" ): +for pluginName in os.environ[ "SMESH_MeshersList" ].split( os.pathsep ): """ Bind methods creating mesher plug-ins to the Mesh class """ diff --git a/src/SMESH_SWIG/smesh_algorithm.py b/src/SMESH_SWIG/smesh_algorithm.py index be5552d8e..e90d64aa6 100644 --- a/src/SMESH_SWIG/smesh_algorithm.py +++ b/src/SMESH_SWIG/smesh_algorithm.py @@ -290,7 +290,8 @@ class Mesh_Algorithm: return shape.GetStudyEntry() def ViscousLayers(self, thickness, numberOfLayers, stretchFactor, - faces=[], isFacesToIgnore=True, extrMethod=StdMeshers.SURF_OFFSET_SMOOTH ): + faces=[], isFacesToIgnore=True, + extrMethod=StdMeshers.SURF_OFFSET_SMOOTH, groupName=""): """ Defines "ViscousLayers" hypothesis to give parameters of layers of prisms to build near mesh boundary. This hypothesis can be used by several 3D algorithms: @@ -319,8 +320,17 @@ class Mesh_Algorithm: - StdMeshers.NODE_OFFSET method extrudes nodes along average normal of surrounding mesh faces by the layers thickness. Thickness of layers can be limited to avoid creation of invalid prisms. + groupName: name of a group to contain elements of layers. If not provided, + no group is created. The group is created upon mesh generation. + It can be retrieved by calling + :: + + group = mesh.GetGroupByName( groupName, SMESH.VOLUME )[0] + + Returns: + StdMeshers.StdMeshers_ViscousLayers hypothesis """ - + if not isinstance(self.algo, SMESH._objref_SMESH_3D_Algo): raise TypeError("ViscousLayers are supported by 3D algorithms only") if not "ViscousLayers" in self.GetCompatibleHypothesis(): @@ -342,11 +352,12 @@ class Mesh_Algorithm: hyp.SetStretchFactor( stretchFactor ) hyp.SetFaces( faces, isFacesToIgnore ) hyp.SetMethod( extrMethod ) + hyp.SetGroupName( groupName ) self.mesh.AddHypothesis( hyp, self.geom ) return hyp def ViscousLayers2D(self, thickness, numberOfLayers, stretchFactor, - edges=[], isEdgesToIgnore=True ): + edges=[], isEdgesToIgnore=True, groupName="" ): """ Defines "ViscousLayers2D" hypothesis to give parameters of layers of quadrilateral elements to build near mesh boundary. This hypothesis can be used by several 2D algorithms: @@ -361,6 +372,15 @@ class Mesh_Algorithm: the value of **isEdgesToIgnore** parameter. isEdgesToIgnore: if *True*, the Viscous layers are not generated on the edges specified by the previous parameter (**edges**). + groupName: name of a group to contain elements of layers. If not provided, + no group is created. The group is created upon mesh generation. + It can be retrieved by calling + :: + + group = mesh.GetGroupByName( groupName, SMESH.FACE )[0] + + Returns: + StdMeshers.StdMeshers_ViscousLayers2D hypothesis """ if not isinstance(self.algo, SMESH._objref_SMESH_2D_Algo): @@ -383,6 +403,7 @@ class Mesh_Algorithm: hyp.SetNumberLayers(numberOfLayers) hyp.SetStretchFactor(stretchFactor) hyp.SetEdges(edges, isEdgesToIgnore) + hyp.SetGroupName( groupName ) self.mesh.AddHypothesis( hyp, self.geom ) return hyp diff --git a/src/StdMeshers/CMakeLists.txt b/src/StdMeshers/CMakeLists.txt index dfad28a86..df1d95243 100644 --- a/src/StdMeshers/CMakeLists.txt +++ b/src/StdMeshers/CMakeLists.txt @@ -130,6 +130,7 @@ SET(StdMeshers_HEADERS StdMeshers_Cartesian_3D.hxx StdMeshers_QuadFromMedialAxis_1D2D.hxx StdMeshers_PolygonPerFace_2D.hxx + StdMeshers_PolyhedronPerSolid_3D.hxx ) IF(SALOME_SMESH_ENABLE_MEFISTO) @@ -195,6 +196,7 @@ SET(StdMeshers_SOURCES StdMeshers_Adaptive1D.cxx StdMeshers_QuadFromMedialAxis_1D2D.cxx StdMeshers_PolygonPerFace_2D.cxx + StdMeshers_PolyhedronPerSolid_3D.cxx ) IF(SALOME_SMESH_ENABLE_MEFISTO) diff --git a/src/StdMeshers/StdMeshers_CartesianParameters3D.cxx b/src/StdMeshers/StdMeshers_CartesianParameters3D.cxx index 21bc0bbb1..fe479bb1e 100644 --- a/src/StdMeshers/StdMeshers_CartesianParameters3D.cxx +++ b/src/StdMeshers/StdMeshers_CartesianParameters3D.cxx @@ -64,7 +64,10 @@ StdMeshers_CartesianParameters3D::StdMeshers_CartesianParameters3D(int h SMESH_Gen * gen) : SMESH_Hypothesis(hypId, gen), _sizeThreshold( 4.0 ), // default according to the customer specification - _toAddEdges( false ) + _toAddEdges( false ), + _toConsiderInternalFaces( false ), + _toUseThresholdForInternalFaces( false ), + _toCreateFaces( false ) { _name = "CartesianParameters3D"; // used by "Cartesian_3D" _param_algo_dim = 3; // 3D @@ -739,6 +742,48 @@ bool StdMeshers_CartesianParameters3D::GetToAddEdges() const return _toAddEdges; } +//======================================================================= +//function : SetToConsiderInternalFaces +//purpose : Enables treatment of geom faces either shared by solids or internal +//======================================================================= + +void StdMeshers_CartesianParameters3D::SetToConsiderInternalFaces(bool toTreat) +{ + if ( _toConsiderInternalFaces != toTreat ) + { + _toConsiderInternalFaces = toTreat; + NotifySubMeshesHypothesisModification(); + } +} + +//======================================================================= +//function : SetToUseThresholdForInternalFaces +//purpose : Enables applying size threshold to grid cells cut by internal geom faces. +//======================================================================= + +void StdMeshers_CartesianParameters3D::SetToUseThresholdForInternalFaces(bool toUse) +{ + if ( _toUseThresholdForInternalFaces != toUse ) + { + _toUseThresholdForInternalFaces = toUse; + NotifySubMeshesHypothesisModification(); + } +} + +//======================================================================= +//function : SetToCreateFaces +//purpose : Enables creation of mesh faces. +//======================================================================= + +void StdMeshers_CartesianParameters3D::SetToCreateFaces(bool toCreate) +{ + if ( _toCreateFaces != toCreate ) + { + _toCreateFaces = toCreate; + NotifySubMeshesHypothesisModification(); + } +} + //======================================================================= //function : IsDefined //purpose : Return true if parameters are well defined @@ -786,6 +831,10 @@ std::ostream & StdMeshers_CartesianParameters3D::SaveTo(std::ostream & save) for ( int i = 0; i < 3; ++i ) save << _fixedPoint[i] << " "; + save << " " << _toConsiderInternalFaces + << " " << _toUseThresholdForInternalFaces + << " " << _toCreateFaces; + return save; } @@ -844,6 +893,12 @@ std::istream & StdMeshers_CartesianParameters3D::LoadFrom(std::istream & load) for ( int i = 0; i < 3 && ok ; ++i ) ok = static_cast( load >> _fixedPoint[i]); + if ( load >> _toConsiderInternalFaces ) + { + load >> _toUseThresholdForInternalFaces; + load >> _toCreateFaces; + } + return load; } diff --git a/src/StdMeshers/StdMeshers_CartesianParameters3D.hxx b/src/StdMeshers/StdMeshers_CartesianParameters3D.hxx index 089d19f46..fc8ceff4c 100644 --- a/src/StdMeshers/StdMeshers_CartesianParameters3D.hxx +++ b/src/StdMeshers/StdMeshers_CartesianParameters3D.hxx @@ -139,6 +139,25 @@ public: void SetToAddEdges(bool toAdd); bool GetToAddEdges() const; + /*! + * \brief Enables treatment of geom faces either shared by solids or internal. + */ + void SetToConsiderInternalFaces(bool toTreat); + bool GetToConsiderInternalFaces() const { return _toConsiderInternalFaces; } + + /*! + * \brief Enables applying size threshold to grid cells cut by internal geom faces. + */ + void SetToUseThresholdForInternalFaces(bool toUse); + bool GetToUseThresholdForInternalFaces() const { return _toUseThresholdForInternalFaces; } + + /*! + * \brief Enables creation of mesh faces. + */ + void SetToCreateFaces(bool toCreate); + bool GetToCreateFaces() const { return _toCreateFaces; } + + /*! * \brief Return true if parameters are well defined */ @@ -171,6 +190,9 @@ public: double _sizeThreshold; bool _toAddEdges; + bool _toConsiderInternalFaces; + bool _toUseThresholdForInternalFaces; + bool _toCreateFaces; }; #endif diff --git a/src/StdMeshers/StdMeshers_Cartesian_3D.cxx b/src/StdMeshers/StdMeshers_Cartesian_3D.cxx index 85a984c30..78059016f 100644 --- a/src/StdMeshers/StdMeshers_Cartesian_3D.cxx +++ b/src/StdMeshers/StdMeshers_Cartesian_3D.cxx @@ -23,16 +23,22 @@ // Module : SMESH // #include "StdMeshers_Cartesian_3D.hxx" +#include "StdMeshers_CartesianParameters3D.hxx" +#include "ObjectPool.hxx" #include "SMDS_MeshNode.hxx" +#include "SMDS_VolumeTool.hxx" #include "SMESHDS_Mesh.hxx" #include "SMESH_Block.hxx" #include "SMESH_Comment.hxx" +#include "SMESH_ControlsDef.hxx" #include "SMESH_Mesh.hxx" +#include "SMESH_MeshAlgos.hxx" +#include "SMESH_MeshEditor.hxx" #include "SMESH_MesherHelper.hxx" #include "SMESH_subMesh.hxx" #include "SMESH_subMeshEventListener.hxx" -#include "StdMeshers_CartesianParameters3D.hxx" +#include "StdMeshers_FaceSide.hxx" #include #include @@ -89,6 +95,8 @@ #include +#include + //#undef WITH_TBB #ifdef WITH_TBB @@ -97,7 +105,6 @@ // Windows 10 = 0x0A00 #define WINVER 0x0A00 #define _WIN32_WINNT 0x0A00 - #endif #include @@ -105,6 +112,7 @@ #endif using namespace std; +using namespace SMESH; #ifdef _DEBUG_ //#define _MY_DEBUG_ @@ -161,7 +169,7 @@ bool StdMeshers_Cartesian_3D::CheckHypothesis (SMESH_Mesh& aMesh, namespace { - typedef int TGeomID; + typedef int TGeomID; // IDs of sub-shapes //============================================================================= // Definitions of internal utils @@ -170,7 +178,72 @@ namespace Trans_TANGENT = IntCurveSurface_Tangent, Trans_IN = IntCurveSurface_In, Trans_OUT = IntCurveSurface_Out, - Trans_APEX + Trans_APEX, + Trans_INTERNAL // for INTERNAL FACE + }; + // -------------------------------------------------------------------------- + /*! + * \brief Container of IDs of SOLID sub-shapes + */ + class Solid // sole SOLID contains all sub-shapes + { + TGeomID _id; // SOLID id + bool _hasInternalFaces; + public: + virtual ~Solid() {} + virtual bool Contains( TGeomID subID ) const { return true; } + virtual bool ContainsAny( const vector< TGeomID>& subIDs ) const { return true; } + virtual TopAbs_Orientation Orientation( const TopoDS_Shape& s ) const { return s.Orientation(); } + virtual bool IsOutsideOriented( TGeomID faceID ) const { return true; } + void SetID( TGeomID id ) { _id = id; } + TGeomID ID() const { return _id; } + void SetHasInternalFaces( bool has ) { _hasInternalFaces = has; } + bool HasInternalFaces() const { return _hasInternalFaces; } + }; + // -------------------------------------------------------------------------- + class OneOfSolids : public Solid + { + TColStd_MapOfInteger _subIDs; + TopTools_MapOfShape _faces; // keep FACE orientation + TColStd_MapOfInteger _outFaceIDs; // FACEs of shape_to_mesh oriented outside the SOLID + public: + void Init( const TopoDS_Shape& solid, + TopAbs_ShapeEnum subType, + const SMESHDS_Mesh* mesh ); + virtual bool Contains( TGeomID i ) const { return i == ID() || _subIDs.Contains( i ); } + virtual bool ContainsAny( const vector< TGeomID>& subIDs ) const + { + for ( size_t i = 0; i < subIDs.size(); ++i ) if ( Contains( subIDs[ i ])) return true; + return false; + } + virtual TopAbs_Orientation Orientation( const TopoDS_Shape& face ) const + { + const TopoDS_Shape& sInMap = const_cast< OneOfSolids* >(this)->_faces.Added( face ); + return sInMap.Orientation(); + } + virtual bool IsOutsideOriented( TGeomID faceID ) const + { + return faceID == 0 || _outFaceIDs.Contains( faceID ); + } + }; + // -------------------------------------------------------------------------- + /*! + * \brief Geom data + */ + struct Geometry + { + TopoDS_Shape _mainShape; + vector< vector< TGeomID > > _solidIDsByShapeID;// V/E/F ID -> SOLID IDs + Solid _soleSolid; + map< TGeomID, OneOfSolids > _solidByID; + TColStd_MapOfInteger _boundaryFaces; // FACEs on boundary of mesh->ShapeToMesh() + TColStd_MapOfInteger _strangeEdges; // EDGEs shared by strange FACEs + TGeomID _extIntFaceID; // pseudo FACE - extension of INTERNAL FACE + + Controls::ElementsOnShape _edgeClassifier; + Controls::ElementsOnShape _vertexClassifier; + + bool IsOneSolid() const { return _solidByID.size() < 2; } }; // -------------------------------------------------------------------------- /*! @@ -194,6 +267,7 @@ namespace struct F_IntersectPoint : public B_IntersectPoint { double _paramOnLine; + double _u, _v; mutable Transition _transition; mutable size_t _indexOnLine; @@ -207,7 +281,7 @@ namespace { gp_Pnt _point; double _uvw[3]; - TGeomID _shapeID; + TGeomID _shapeID; // ID of EDGE or VERTEX }; // -------------------------------------------------------------------------- /*! @@ -220,7 +294,9 @@ namespace multiset< F_IntersectPoint > _intPoints; void RemoveExcessIntPoints( const double tol ); - bool GetIsOutBefore( multiset< F_IntersectPoint >::iterator ip, bool prevIsOut ); + TGeomID GetSolidIDBefore( multiset< F_IntersectPoint >::iterator ip, + const TGeomID prevID, + const Geometry& geom); }; // -------------------------------------------------------------------------- /*! @@ -249,7 +325,7 @@ namespace { _size[0] = sz1; _size[1] = sz2; _size[2] = sz3; _curInd[0] = _curInd[1] = _curInd[2] = 0; - _iVar1 = iv1; _iVar2 = iv2; _iConst = iConst; + _iVar1 = iv1; _iVar2 = iv2; _iConst = iConst; _name1 = nv1; _name2 = nv2; _nameConst = nConst; } @@ -288,10 +364,18 @@ namespace vector< const SMDS_MeshNode* > _nodes; // mesh nodes at grid nodes vector< const F_IntersectPoint* > _gridIntP; // grid node intersection with geometry - - list< E_IntersectPoint > _edgeIntP; // intersections with EDGEs - TopTools_IndexedMapOfShape _shapes; - + ObjectPool< E_IntersectPoint > _edgeIntPool; // intersections with EDGEs + ObjectPool< F_IntersectPoint > _extIntPool; // intersections with extended INTERNAL FACEs + //list< E_IntersectPoint > _edgeIntP; // intersections with EDGEs + + Geometry _geometry; + bool _toAddEdges; + bool _toCreateFaces; + bool _toConsiderInternalFaces; + bool _toUseThresholdForInternalFaces; + double _sizeThreshold; + + vector< TGeomID > _shapeIDs; // returned by Hexahedron::getSolids() SMESH_MesherHelper* _helper; size_t CellIndex( size_t i, size_t j, size_t k ) const @@ -308,6 +392,43 @@ namespace LineIndexer GetLineIndexer(size_t iDir) const; + E_IntersectPoint* Add( const E_IntersectPoint& ip ) + { + E_IntersectPoint* eip = _edgeIntPool.getNew(); + *eip = ip; + return eip; + } + void Remove( E_IntersectPoint* eip ) { _edgeIntPool.destroy( eip ); } + + TGeomID ShapeID( const TopoDS_Shape& s ) const; + const TopoDS_Shape& Shape( TGeomID id ) const; + TopAbs_ShapeEnum ShapeType( TGeomID id ) const { return Shape(id).ShapeType(); } + void InitGeometry( const TopoDS_Shape& theShape ); + void InitClassifier( const TopoDS_Shape& mainShape, + TopAbs_ShapeEnum shapeType, + Controls::ElementsOnShape& classifier ); + void GetEdgesToImplement( map< TGeomID, vector< TGeomID > > & edge2faceMap, + const TopoDS_Shape& shape, + const vector< TopoDS_Shape >& faces ); + void SetSolidFather( const TopoDS_Shape& s, const TopoDS_Shape& theShapeToMesh ); + bool IsShared( TGeomID faceID ) const; + bool IsAnyShared( const std::vector< TGeomID >& faceIDs ) const; + bool IsInternal( TGeomID faceID ) const { + return ( faceID == PseudoIntExtFaceID() || + Shape( faceID ).Orientation() == TopAbs_INTERNAL ); } + bool IsSolid( TGeomID shapeID ) const { + if ( _geometry.IsOneSolid() ) return _geometry._soleSolid.ID() == shapeID; + else return _geometry._solidByID.count( shapeID ); } + bool IsStrangeEdge( TGeomID id ) const { return _geometry._strangeEdges.Contains( id ); } + TGeomID PseudoIntExtFaceID() const { return _geometry._extIntFaceID; } + Solid* GetSolid( TGeomID solidID = 0 ); + Solid* GetOneOfSolids( TGeomID solidID ); + const vector< TGeomID > & GetSolidIDs( TGeomID subShapeID ) const; + bool IsCorrectTransition( TGeomID faceID, const Solid* solid ); + bool IsBoundaryFace( TGeomID face ) const { return _geometry._boundaryFaces.Contains( face ); } + void SetOnShape( const SMDS_MeshNode* n, const F_IntersectPoint& ip, bool unset=false ); + bool IsToCheckNodePos() const { return !_toAddEdges && _toCreateFaces; } + void SetCoordinates(const vector& xCoords, const vector& yCoords, const vector& zCoords, @@ -317,6 +438,49 @@ namespace void ComputeNodes(SMESH_MesherHelper& helper); }; // -------------------------------------------------------------------------- + /*! + * \brief Return cells sharing a link + */ + struct CellsAroundLink + { + int _dInd[4][3]; + size_t _nbCells[3]; + int _i,_j,_k; + Grid* _grid; + + CellsAroundLink( Grid* grid, int iDir ): + _dInd{ {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0} }, + _nbCells{ grid->_coords[0].size() - 1, + grid->_coords[1].size() - 1, + grid->_coords[2].size() - 1 }, + _grid( grid ) + { + const int iDirOther[3][2] = {{ 1,2 },{ 0,2 },{ 0,1 }}; + _dInd[1][ iDirOther[iDir][0] ] = -1; + _dInd[2][ iDirOther[iDir][1] ] = -1; + _dInd[3][ iDirOther[iDir][0] ] = -1; _dInd[3][ iDirOther[iDir][1] ] = -1; + } + void Init( int i, int j, int k, int link12 = 0 ) + { + int iL = link12 % 4; + _i = i - _dInd[iL][0]; + _j = j - _dInd[iL][1]; + _k = k - _dInd[iL][2]; + } + bool GetCell( int iL, int& i, int& j, int& k, int& cellIndex ) + { + i = _i + _dInd[iL][0]; + j = _j + _dInd[iL][1]; + k = _k + _dInd[iL][2]; + if ( i < 0 || i >= (int)_nbCells[0] || + j < 0 || j >= (int)_nbCells[1] || + k < 0 || k >= (int)_nbCells[2] ) + return false; + cellIndex = _grid->CellIndex( i,j,k ); + return true; + } + }; + // -------------------------------------------------------------------------- /*! * \brief Intersector of TopoDS_Face with all GridLine's */ @@ -336,7 +500,7 @@ namespace { for ( size_t i = 0; i < _intersections.size(); ++i ) { - multiset< F_IntersectPoint >::iterator ip = + multiset< F_IntersectPoint >::iterator ip = _intersections[i].first->_intPoints.insert( _intersections[i].second ); ip->_faceIDs.reserve( 1 ); ip->_faceIDs.push_back( _faceID ); @@ -368,7 +532,7 @@ namespace { double _tol; double _u, _v, _w; // params on the face and the line - Transition _transition; // transition of at intersection (see IntCurveSurface.cdl) + Transition _transition; // transition at intersection (see IntCurveSurface.cdl) Transition _transIn, _transOut; // IN and OUT transitions depending of face orientation gp_Pln _plane; @@ -406,36 +570,31 @@ namespace // -------------------------------------------------------------------------------- struct _Face; struct _Link; + enum IsInternalFlag { IS_NOT_INTERNAL, IS_INTERNAL, IS_CUT_BY_INTERNAL_FACE }; // -------------------------------------------------------------------------------- struct _Node //!< node either at a hexahedron corner or at intersection { const SMDS_MeshNode* _node; // mesh node at hexahedron corner const B_IntersectPoint* _intPoint; const _Face* _usedInFace; + char _isInternalFlags; _Node(const SMDS_MeshNode* n=0, const B_IntersectPoint* ip=0) - :_node(n), _intPoint(ip), _usedInFace(0) {} + :_node(n), _intPoint(ip), _usedInFace(0), _isInternalFlags(0) {} const SMDS_MeshNode* Node() const { return ( _intPoint && _intPoint->_node ) ? _intPoint->_node : _node; } const E_IntersectPoint* EdgeIntPnt() const { return static_cast< const E_IntersectPoint* >( _intPoint ); } + const F_IntersectPoint* FaceIntPnt() const + { return static_cast< const F_IntersectPoint* >( _intPoint ); } + const vector< TGeomID >& faces() const { return _intPoint->_faceIDs; } + TGeomID face(size_t i) const { return _intPoint->_faceIDs[ i ]; } + void SetInternal( IsInternalFlag intFlag ) { _isInternalFlags |= intFlag; } + bool IsCutByInternal() const { return _isInternalFlags & IS_CUT_BY_INTERNAL_FACE; } bool IsUsedInFace( const _Face* polygon = 0 ) { return polygon ? ( _usedInFace == polygon ) : bool( _usedInFace ); } - void Add( const E_IntersectPoint* ip ) - { - if ( !_intPoint ) { - _intPoint = ip; - } - else if ( !_intPoint->_node ) { - ip->Add( _intPoint->_faceIDs ); - _intPoint = ip; - } - else { - _intPoint->Add( ip->_faceIDs ); - } - } TGeomID IsLinked( const B_IntersectPoint* other, TGeomID avoidFace=-1 ) const // returns id of a common face { @@ -448,7 +607,7 @@ namespace gp_Pnt Point() const { if ( const SMDS_MeshNode* n = Node() ) - return SMESH_TNodeXYZ( n ); + return SMESH_NodeXYZ( n ); if ( const E_IntersectPoint* eip = dynamic_cast< const E_IntersectPoint* >( _intPoint )) return eip->_point; @@ -460,6 +619,27 @@ namespace return eip->_shapeID; return 0; } + void Add( const E_IntersectPoint* ip ) + { + // Possible cases before Add(ip): + /// 1) _node != 0 --> _Node at hex corner ( _intPoint == 0 || _intPoint._node == 0 ) + /// 2) _node == 0 && _intPoint._node != 0 --> link intersected by FACE + /// 3) _node == 0 && _intPoint._node == 0 --> _Node at EDGE intersection + // + // If ip is added in cases 1) and 2) _node position must be changed to ip._shapeID + // at creation of elements + // To recognize this case, set _intPoint._node = Node() + const SMDS_MeshNode* node = Node(); + if ( !_intPoint ) { + _intPoint = ip; + } + else { + ip->Add( _intPoint->_faceIDs ); + _intPoint = ip; + } + if ( node ) + _node = _intPoint->_node = node; + } }; // -------------------------------------------------------------------------------- struct _Link // link connecting two _Node's @@ -469,7 +649,7 @@ namespace vector< const F_IntersectPoint* > _fIntPoints; // GridLine intersections with FACEs vector< _Node* > _fIntNodes; // _Node's at _fIntPoints vector< _Link > _splits; - _Link() { _faces[0] = 0; } + _Link(): _faces{ 0, 0 } {} }; // -------------------------------------------------------------------------------- struct _OrientedLink @@ -541,6 +721,43 @@ namespace } }; // -------------------------------------------------------------------------------- + struct _SplitIterator //! set to _hexLinks splits on one side of INTERNAL FACEs + { + struct _Split // data of a link split + { + int _linkID; // hex link ID + _Node* _nodes[2]; + int _iCheckIteration; // iteration where split is tried as Hexahedron split + _Link* _checkedSplit; // split set to hex links + bool _isUsed; // used in a volume + + _Split( _Link & split, int iLink ): + _linkID( iLink ), _nodes{ split._nodes[0], split._nodes[1] }, + _iCheckIteration( 0 ), _isUsed( false ) + {} + bool IsCheckedOrUsed( bool used ) const { return used ? _isUsed : _iCheckIteration > 0; } + }; + _Link* _hexLinks; + std::vector< _Split > _splits; + int _iterationNb; + size_t _nbChecked; + size_t _nbUsed; + std::vector< _Node* > _freeNodes; // nodes reached while composing a split set + + _SplitIterator( _Link* hexLinks ): + _hexLinks( hexLinks ), _iterationNb(0), _nbChecked(0), _nbUsed(0) + { + _freeNodes.reserve( 12 ); + _splits.reserve( 24 ); + for ( int iL = 0; iL < 12; ++iL ) + for ( size_t iS = 0; iS < _hexLinks[ iL ]._splits.size(); ++iS ) + _splits.emplace_back( _hexLinks[ iL ]._splits[ iS ], iL ); + Next(); + } + bool More() const { return _nbUsed < _splits.size(); } + bool Next(); + }; + // -------------------------------------------------------------------------------- struct _Face { vector< _OrientedLink > _links; // links on GridLine's @@ -573,14 +790,37 @@ namespace // -------------------------------------------------------------------------------- struct _volumeDef // holder of nodes of a volume mesh element { - vector< _Node* > _nodes; - vector< int > _quantities; - typedef boost::shared_ptr<_volumeDef> Ptr; - void set( const vector< _Node* >& nodes, - const vector< int >& quant = vector< int >() ) - { _nodes = nodes; _quantities = quant; } - void set( _Node** nodes, int nb ) + struct _nodeDef + { + const SMDS_MeshNode* _node; // mesh node at hexahedron corner + const B_IntersectPoint* _intPoint; + + _nodeDef( _Node* n ): _node( n->_node), _intPoint( n->_intPoint ) {} + const SMDS_MeshNode* Node() const + { return ( _intPoint && _intPoint->_node ) ? _intPoint->_node : _node; } + const E_IntersectPoint* EdgeIntPnt() const + { return static_cast< const E_IntersectPoint* >( _intPoint ); } + }; + vector< _nodeDef > _nodes; + vector< int > _quantities; + _volumeDef* _next; // to store several _volumeDefs in a chain + TGeomID _solidID; + const SMDS_MeshElement* _volume; // new volume + + _volumeDef(): _next(0), _solidID(0), _volume(0) {} + ~_volumeDef() { delete _next; } + _volumeDef( _volumeDef& other ): + _next(0), _solidID( other._solidID ), _volume( other._volume ) + { _nodes.swap( other._nodes ); _quantities.swap( other._quantities ); other._volume = 0; } + + void Set( const vector< _Node* >& nodes, const vector< int >& quant = vector< int >() ) + { _nodes.assign( nodes.begin(), nodes.end() ); _quantities = quant; } + + void Set( _Node** nodes, int nb ) { _nodes.assign( nodes, nodes + nb ); } + + void SetNext( _volumeDef* vd ) + { if ( _next ) { _next->SetNext( vd ); } else { _next = vd; }} }; // topology of a hexahedron @@ -602,26 +842,33 @@ namespace vector< _Node* > _vIntNodes; // computed volume elements - //vector< _volumeDef::Ptr > _volumeDefs; _volumeDef _volumeDefs; Grid* _grid; - double _sizeThreshold, _sideLength[3]; + double _sideLength[3]; int _nbCornerNodes, _nbFaceIntNodes, _nbBndNodes; int _origNodeInd; // index of _hexNodes[0] node within the _grid size_t _i,_j,_k; + bool _hasTooSmall; + +#ifdef _DEBUG_ + int _cellID; +#endif public: - Hexahedron(const double sizeThreshold, Grid* grid); + Hexahedron(Grid* grid); int MakeElements(SMESH_MesherHelper& helper, const map< TGeomID, vector< TGeomID > >& edge2faceIDsMap); - void ComputeElements(); - void Init() { init( _i, _j, _k ); } + void ComputeElements( const Solid* solid = 0, int solidIndex = -1 ); private: - Hexahedron(const Hexahedron& other ); - void init( size_t i, size_t j, size_t k ); + Hexahedron(const Hexahedron& other, size_t i, size_t j, size_t k, int cellID ); + void init( size_t i, size_t j, size_t k, const Solid* solid=0 ); void init( size_t i ); + void setIJK( size_t i ); + bool compute( const Solid* solid, const IsInternalFlag intFlag ); + const vector< TGeomID >& getSolids(); + bool isCutByInternalFace( IsInternalFlag & maxFlag ); void addEdges(SMESH_MesherHelper& helper, vector< Hexahedron* >& intersectedHex, const map< TGeomID, vector< TGeomID > >& edge2faceIDsMap); @@ -629,7 +876,7 @@ namespace double proj, BRepAdaptor_Curve& curve, const gp_XYZ& axis, const gp_XYZ& origin ); int getEntity( const E_IntersectPoint* ip, int* facets, int& sub ); - bool addIntersection( const E_IntersectPoint& ip, + bool addIntersection( const E_IntersectPoint* ip, vector< Hexahedron* >& hexes, int ijk[], int dIJK[] ); bool findChain( _Node* n1, _Node* n2, _Face& quad, vector<_Node*>& chainNodes ); @@ -640,11 +887,22 @@ namespace size_t & iS, _Face& quad, vector<_Node*>& chn); - int addElements(SMESH_MesherHelper& helper); - bool isOutPoint( _Link& link, int iP, SMESH_MesherHelper& helper ) const; + int addVolumes(SMESH_MesherHelper& helper ); + void addFaces( SMESH_MesherHelper& helper, + const vector< const SMDS_MeshElement* > & boundaryVolumes ); + void addSegments( SMESH_MesherHelper& helper, + const map< TGeomID, vector< TGeomID > >& edge2faceIDsMap ); + void getVolumes( vector< const SMDS_MeshElement* > & volumes ); + void getBoundaryElems( vector< const SMDS_MeshElement* > & boundaryVolumes ); + TGeomID getAnyFace() const; + void cutByExtendedInternal( std::vector< Hexahedron* >& hexes, + const TColStd_MapOfInteger& intEdgeIDs ); + gp_Pnt mostDistantInternalPnt( int hexIndex, const gp_Pnt& p1, const gp_Pnt& p2 ); + bool isOutPoint( _Link& link, int iP, SMESH_MesherHelper& helper, const Solid* solid ) const; void sortVertexNodes(vector<_Node*>& nodes, _Node* curNode, TGeomID face); bool isInHole() const; - bool checkPolyhedronSize() const; + bool hasStrangeEdge() const; + bool checkPolyhedronSize( bool isCutByInternalFace ) const; bool addHexa (); bool addTetra(); bool addPenta(); @@ -660,8 +918,16 @@ namespace return nodes[i]; return 0; } - bool isImplementEdges() const { return !_grid->_edgeIntP.empty(); } + bool isImplementEdges() const { return _grid->_edgeIntPool.nbElements(); } bool isOutParam(const double uvw[3]) const; + + typedef boost::container::flat_map< TGeomID, size_t > TID2Nb; + static void insertAndIncrement( TGeomID id, TID2Nb& id2nbMap ) + { + TID2Nb::value_type s0( id, 0 ); + TID2Nb::iterator id2nb = id2nbMap.insert( s0 ).first; + id2nb->second++; + } }; #ifdef WITH_TBB @@ -756,29 +1022,72 @@ namespace } //================================================================================ /* - * Return "is OUT" state for nodes before the given intersection point + * Return ID of SOLID for nodes before the given intersection point */ - bool GridLine::GetIsOutBefore( multiset< F_IntersectPoint >::iterator ip, bool prevIsOut ) + TGeomID GridLine::GetSolidIDBefore( multiset< F_IntersectPoint >::iterator ip, + const TGeomID prevID, + const Geometry& geom ) { - if ( ip->_transition == Trans_IN ) - return true; - if ( ip->_transition == Trans_OUT ) - return false; - if ( ip->_transition == Trans_APEX ) + if ( ip == _intPoints.begin() ) + return 0; + + if ( geom.IsOneSolid() ) { - // singularity point (apex of a cone) - if ( _intPoints.size() == 1 || ip == _intPoints.begin() ) - return true; - multiset< F_IntersectPoint >::iterator ipBef = ip, ipAft = ++ip; - if ( ipAft == _intPoints.end() ) - return false; - --ipBef; - if ( ipBef->_transition != ipAft->_transition ) - return ( ipBef->_transition == Trans_OUT ); - return ( ipBef->_transition != Trans_OUT ); + bool isOut = true; + switch ( ip->_transition ) { + case Trans_IN: isOut = true; break; + case Trans_OUT: isOut = false; break; + case Trans_TANGENT: isOut = ( prevID == 0 ); break; + case Trans_APEX: + { + // singularity point (apex of a cone) + multiset< F_IntersectPoint >::iterator ipBef = ip, ipAft = ++ip; + if ( ipAft == _intPoints.end() ) + isOut = false; + else + { + --ipBef; + if ( ipBef->_transition != ipAft->_transition ) + isOut = ( ipBef->_transition == Trans_OUT ); + else + isOut = ( ipBef->_transition != Trans_OUT ); + } + break; + } + case Trans_INTERNAL: isOut = false; + default:; + } + return isOut ? 0 : geom._soleSolid.ID(); + } + + const vector< TGeomID >& solids = geom._solidIDsByShapeID[ ip->_faceIDs[ 0 ]]; + + --ip; + if ( ip->_transition == Trans_INTERNAL ) + return prevID; + + const vector< TGeomID >& solidsBef = geom._solidIDsByShapeID[ ip->_faceIDs[ 0 ]]; + + if ( ip->_transition == Trans_IN || + ip->_transition == Trans_OUT ) + { + if ( solidsBef.size() == 1 ) + return ( solidsBef[0] == prevID ) ? 0 : solidsBef[0]; + + return solidsBef[ solidsBef[0] == prevID ]; + } + + if ( solidsBef.size() == 1 ) + return solidsBef[0]; + + for ( size_t i = 0; i < solids.size(); ++i ) + { + vector< TGeomID >::const_iterator it = + std::find( solidsBef.begin(), solidsBef.end(), solids[i] ); + if ( it != solidsBef.end() ) + return solids[i]; } - // _transition == Trans_TANGENT - return !prevIsOut; + return 0; } //================================================================================ /* @@ -824,6 +1133,35 @@ namespace return ( it != _faceIDs.end() ); } //================================================================================ + /* + * OneOfSolids initialization + */ + void OneOfSolids::Init( const TopoDS_Shape& solid, + TopAbs_ShapeEnum subType, + const SMESHDS_Mesh* mesh ) + { + SetID( mesh->ShapeToIndex( solid )); + + if ( subType == TopAbs_FACE ) + SetHasInternalFaces( false ); + + for ( TopExp_Explorer sub( solid, subType ); sub.More(); sub.Next() ) + { + _subIDs.Add( mesh->ShapeToIndex( sub.Current() )); + if ( subType == TopAbs_FACE ) + { + _faces.Add( sub.Current() ); + if ( sub.Current().Orientation() == TopAbs_INTERNAL ) + SetHasInternalFaces( true ); + + TGeomID faceID = mesh->ShapeToIndex( sub.Current() ); + if ( sub.Current().Orientation() == TopAbs_INTERNAL || + sub.Current().Orientation() == mesh->IndexToShape( faceID ).Orientation() ) + _outFaceIDs.Add( faceID ); + } + } + } + //================================================================================ /* * Return an iterator on GridLine's in a given direction */ @@ -928,6 +1266,290 @@ namespace } } } + //================================================================================ + /* + * Return local ID of shape + */ + TGeomID Grid::ShapeID( const TopoDS_Shape& s ) const + { + return _helper->GetMeshDS()->ShapeToIndex( s ); + } + //================================================================================ + /* + * Return a shape by its local ID + */ + const TopoDS_Shape& Grid::Shape( TGeomID id ) const + { + return _helper->GetMeshDS()->IndexToShape( id ); + } + //================================================================================ + /* + * Initialize _geometry + */ + void Grid::InitGeometry( const TopoDS_Shape& theShapeToMesh ) + { + SMESH_Mesh* mesh = _helper->GetMesh(); + + _geometry._mainShape = theShapeToMesh; + _geometry._extIntFaceID = mesh->GetMeshDS()->MaxShapeIndex() * 100; + _geometry._soleSolid.SetID( 0 ); + _geometry._soleSolid.SetHasInternalFaces( false ); + + InitClassifier( theShapeToMesh, TopAbs_VERTEX, _geometry._vertexClassifier ); + InitClassifier( theShapeToMesh, TopAbs_EDGE , _geometry._edgeClassifier ); + + TopExp_Explorer solidExp( theShapeToMesh, TopAbs_SOLID ); + + bool isSeveralSolids = false; + if ( _toConsiderInternalFaces ) // check nb SOLIDs + { + solidExp.Next(); + isSeveralSolids = solidExp.More(); + _toConsiderInternalFaces = isSeveralSolids; + solidExp.ReInit(); + + if ( !isSeveralSolids ) // look for an internal FACE + { + TopExp_Explorer fExp( theShapeToMesh, TopAbs_FACE ); + for ( ; fExp.More() && !_toConsiderInternalFaces; fExp.Next() ) + _toConsiderInternalFaces = ( fExp.Current().Orientation() == TopAbs_INTERNAL ); + + _geometry._soleSolid.SetHasInternalFaces( _toConsiderInternalFaces ); + _geometry._soleSolid.SetID( ShapeID( solidExp.Current() )); + } + else // fill Geometry::_solidByID + { + for ( ; solidExp.More(); solidExp.Next() ) + { + OneOfSolids & solid = _geometry._solidByID[ ShapeID( solidExp.Current() )]; + solid.Init( solidExp.Current(), TopAbs_FACE, mesh->GetMeshDS() ); + solid.Init( solidExp.Current(), TopAbs_EDGE, mesh->GetMeshDS() ); + solid.Init( solidExp.Current(), TopAbs_VERTEX, mesh->GetMeshDS() ); + } + } + } + else + { + _geometry._soleSolid.SetID( ShapeID( solidExp.Current() )); + } + + if ( !_toCreateFaces ) + { + int nbSolidsGlobal = _helper->Count( mesh->GetShapeToMesh(), TopAbs_SOLID, false ); + int nbSolidsLocal = _helper->Count( theShapeToMesh, TopAbs_SOLID, false ); + _toCreateFaces = ( nbSolidsLocal < nbSolidsGlobal ); + } + + TopTools_IndexedMapOfShape faces; + if ( _toCreateFaces || isSeveralSolids ) + TopExp::MapShapes( theShapeToMesh, TopAbs_FACE, faces ); + + // find boundary FACEs on boundary of mesh->ShapeToMesh() + if ( _toCreateFaces ) + for ( int i = 1; i <= faces.Size(); ++i ) + if ( faces(i).Orientation() != TopAbs_INTERNAL && + _helper->NbAncestors( faces(i), *mesh, TopAbs_SOLID ) == 1 ) + { + _geometry._boundaryFaces.Add( ShapeID( faces(i) )); + } + + if ( isSeveralSolids ) + for ( int i = 1; i <= faces.Size(); ++i ) + { + SetSolidFather( faces(i), theShapeToMesh ); + for ( TopExp_Explorer eExp( faces(i), TopAbs_EDGE ); eExp.More(); eExp.Next() ) + { + const TopoDS_Edge& edge = TopoDS::Edge( eExp.Current() ); + SetSolidFather( edge, theShapeToMesh ); + SetSolidFather( _helper->IthVertex( 0, edge ), theShapeToMesh ); + SetSolidFather( _helper->IthVertex( 1, edge ), theShapeToMesh ); + } + } + return; + } + //================================================================================ + /* + * Store ID of SOLID as father of its child shape ID + */ + void Grid::SetSolidFather( const TopoDS_Shape& s, const TopoDS_Shape& theShapeToMesh ) + { + if ( _geometry._solidIDsByShapeID.empty() ) + _geometry._solidIDsByShapeID.resize( _helper->GetMeshDS()->MaxShapeIndex() + 1 ); + + vector< TGeomID > & solidIDs = _geometry._solidIDsByShapeID[ ShapeID( s )]; + if ( !solidIDs.empty() ) + return; + solidIDs.reserve(2); + PShapeIteratorPtr solidIt = _helper->GetAncestors( s, + *_helper->GetMesh(), + TopAbs_SOLID, + & theShapeToMesh ); + while ( const TopoDS_Shape* solid = solidIt->next() ) + solidIDs.push_back( ShapeID( *solid )); + } + //================================================================================ + /* + * Return IDs of solids given sub-shape belongs to + */ + const vector< TGeomID > & Grid::GetSolidIDs( TGeomID subShapeID ) const + { + return _geometry._solidIDsByShapeID[ subShapeID ]; + } + //================================================================================ + /* + * Check if a sub-shape belongs to several SOLIDs + */ + bool Grid::IsShared( TGeomID shapeID ) const + { + return !_geometry.IsOneSolid() && ( _geometry._solidIDsByShapeID[ shapeID ].size() > 1 ); + } + //================================================================================ + /* + * Check if any of FACEs belongs to several SOLIDs + */ + bool Grid::IsAnyShared( const std::vector< TGeomID >& faceIDs ) const + { + for ( size_t i = 0; i < faceIDs.size(); ++i ) + if ( IsShared( faceIDs[ i ])) + return true; + return false; + } + //================================================================================ + /* + * Return Solid by ID + */ + Solid* Grid::GetSolid( TGeomID solidID ) + { + if ( !solidID || _geometry.IsOneSolid() || _geometry._solidByID.empty() ) + return & _geometry._soleSolid; + + return & _geometry._solidByID[ solidID ]; + } + //================================================================================ + /* + * Return OneOfSolids by ID + */ + Solid* Grid::GetOneOfSolids( TGeomID solidID ) + { + map< TGeomID, OneOfSolids >::iterator is2s = _geometry._solidByID.find( solidID ); + if ( is2s != _geometry._solidByID.end() ) + return & is2s->second; + + return & _geometry._soleSolid; + } + //================================================================================ + /* + * Check if transition on given FACE is correct for a given SOLID + */ + bool Grid::IsCorrectTransition( TGeomID faceID, const Solid* solid ) + { + if ( _geometry.IsOneSolid() ) + return true; + + const vector< TGeomID >& solidIDs = _geometry._solidIDsByShapeID[ faceID ]; + return solidIDs[0] == solid->ID(); + } + + //================================================================================ + /* + * Assign to geometry a node at FACE intersection + */ + void Grid::SetOnShape( const SMDS_MeshNode* n, const F_IntersectPoint& ip, bool unset ) + { + TopoDS_Shape s; + SMESHDS_Mesh* mesh = _helper->GetMeshDS(); + if ( ip._faceIDs.size() == 1 ) + { + mesh->SetNodeOnFace( n, ip._faceIDs[0], ip._u, ip._v ); + } + else if ( _geometry._vertexClassifier.IsSatisfy( n, &s )) + { + if ( unset ) mesh->UnSetNodeOnShape( n ); + mesh->SetNodeOnVertex( n, TopoDS::Vertex( s )); + } + else if ( _geometry._edgeClassifier.IsSatisfy( n, &s )) + { + if ( unset ) mesh->UnSetNodeOnShape( n ); + mesh->SetNodeOnEdge( n, TopoDS::Edge( s )); + } + else if ( ip._faceIDs.size() > 0 ) + { + mesh->SetNodeOnFace( n, ip._faceIDs[0], ip._u, ip._v ); + } + else if ( !unset && _geometry.IsOneSolid() ) + { + mesh->SetNodeInVolume( n, _geometry._soleSolid.ID() ); + } + } + //================================================================================ + /* + * Initialize a classifier + */ + void Grid::InitClassifier( const TopoDS_Shape& mainShape, + TopAbs_ShapeEnum shapeType, + Controls::ElementsOnShape& classifier ) + { + TopTools_IndexedMapOfShape shapes; + TopExp::MapShapes( mainShape, shapeType, shapes ); + + TopoDS_Compound compound; BRep_Builder builder; + builder.MakeCompound( compound ); + for ( int i = 1; i <= shapes.Size(); ++i ) + builder.Add( compound, shapes(i) ); + + classifier.SetMesh( _helper->GetMeshDS() ); + //classifier.SetTolerance( _tol ); // _tol is not initialised + classifier.SetShape( compound, SMDSAbs_Node ); + } + + //================================================================================ + /* + * Return EDGEs with FACEs to implement into the mesh + */ + void Grid::GetEdgesToImplement( map< TGeomID, vector< TGeomID > > & edge2faceIDsMap, + const TopoDS_Shape& shape, + const vector< TopoDS_Shape >& faces ) + { + // check if there are strange EDGEs + TopTools_IndexedMapOfShape faceMap; + TopExp::MapShapes( _helper->GetMesh()->GetShapeToMesh(), TopAbs_FACE, faceMap ); + int nbFacesGlobal = faceMap.Size(); + faceMap.Clear( false ); + TopExp::MapShapes( shape, TopAbs_FACE, faceMap ); + int nbFacesLocal = faceMap.Size(); + bool hasStrangeEdges = ( nbFacesGlobal > nbFacesLocal ); + if ( !_toAddEdges && !hasStrangeEdges ) + return; // no FACEs in contact with those meshed by other algo + + for ( size_t i = 0; i < faces.size(); ++i ) + { + _helper->SetSubShape( faces[i] ); + for ( TopExp_Explorer eExp( faces[i], TopAbs_EDGE ); eExp.More(); eExp.Next() ) + { + const TopoDS_Edge& edge = TopoDS::Edge( eExp.Current() ); + if ( hasStrangeEdges ) + { + bool hasStrangeFace = false; + PShapeIteratorPtr faceIt = _helper->GetAncestors( edge, *_helper->GetMesh(), TopAbs_FACE); + while ( const TopoDS_Shape* face = faceIt->next() ) + if (( hasStrangeFace = !faceMap.Contains( *face ))) + break; + if ( !hasStrangeFace && !_toAddEdges ) + continue; + _geometry._strangeEdges.Add( ShapeID( edge )); + _geometry._strangeEdges.Add( ShapeID( _helper->IthVertex( 0, edge ))); + _geometry._strangeEdges.Add( ShapeID( _helper->IthVertex( 1, edge ))); + } + if ( !SMESH_Algo::isDegenerated( edge ) && + !_helper->IsRealSeam( edge )) + { + edge2faceIDsMap[ ShapeID( edge )].push_back( ShapeID( faces[i] )); + } + } + } + return; + } + //================================================================================ /* * Computes coordinates of a point in the grid CS @@ -945,10 +1567,13 @@ namespace { // state of each node of the grid relative to the geometry const size_t nbGridNodes = _coords[0].size() * _coords[1].size() * _coords[2].size(); - vector< bool > isNodeOut( nbGridNodes, false ); + const TGeomID undefID = 1e+9; + vector< TGeomID > shapeIDVec( nbGridNodes, undefID ); _nodes.resize( nbGridNodes, 0 ); _gridIntP.resize( nbGridNodes, NULL ); + SMESHDS_Mesh* mesh = helper.GetMeshDS(); + for ( int iDir = 0; iDir < 3; ++iDir ) // loop on 3 line directions { LineIndexer li = GetLineIndexer( iDir ); @@ -968,26 +1593,30 @@ namespace GridLine& line = _lines[ iDir ][ li.LineIndex() ]; const gp_XYZ lineLoc = line._line.Location().XYZ(); const gp_XYZ lineDir = line._line.Direction().XYZ(); + line.RemoveExcessIntPoints( _tol ); - multiset< F_IntersectPoint >& intPnts = line._intPoints; + multiset< F_IntersectPoint >& intPnts = line._intPoints; multiset< F_IntersectPoint >::iterator ip = intPnts.begin(); - bool isOut = true; + // Create mesh nodes at intersections with geometry + // and set OUT state of nodes between intersections + + TGeomID solidID = 0; const double* nodeCoord = & coords[0]; const double* coord0 = nodeCoord; const double* coordEnd = coord0 + coords.size(); double nodeParam = 0; for ( ; ip != intPnts.end(); ++ip ) { + solidID = line.GetSolidIDBefore( ip, solidID, _geometry ); + // set OUT state or just skip IN nodes before ip if ( nodeParam < ip->_paramOnLine - _tol ) { - isOut = line.GetIsOutBefore( ip, isOut ); - while ( nodeParam < ip->_paramOnLine - _tol ) { - if ( isOut ) - isNodeOut[ nIndex0 + nShift * ( nodeCoord-coord0 ) ] = isOut; + TGeomID & nodeShapeID = shapeIDVec[ nIndex0 + nShift * ( nodeCoord-coord0 ) ]; + nodeShapeID = Min( solidID, nodeShapeID ); if ( ++nodeCoord < coordEnd ) nodeParam = *nodeCoord - *coord0; else @@ -998,24 +1627,21 @@ namespace // create a mesh node on a GridLine at ip if it does not coincide with a grid node if ( nodeParam > ip->_paramOnLine + _tol ) { - // li.SetIndexOnLine( 0 ); - // double xyz[3] = { _coords[0][ li.I() ], _coords[1][ li.J() ], _coords[2][ li.K() ]}; - // xyz[ li._iConst ] += ip->_paramOnLine; gp_XYZ xyz = lineLoc + ip->_paramOnLine * lineDir; - ip->_node = helper.AddNode( xyz.X(), xyz.Y(), xyz.Z() ); + ip->_node = mesh->AddNode( xyz.X(), xyz.Y(), xyz.Z() ); ip->_indexOnLine = nodeCoord-coord0-1; + SetOnShape( ip->_node, *ip ); } - // create a mesh node at ip concident with a grid node + // create a mesh node at ip coincident with a grid node else { int nodeIndex = nIndex0 + nShift * ( nodeCoord-coord0 ); if ( !_nodes[ nodeIndex ] ) { - //li.SetIndexOnLine( nodeCoord-coord0 ); - //double xyz[3] = { _coords[0][ li.I() ], _coords[1][ li.J() ], _coords[2][ li.K() ]}; gp_XYZ xyz = lineLoc + nodeParam * lineDir; - _nodes [ nodeIndex ] = helper.AddNode( xyz.X(), xyz.Y(), xyz.Z() ); - _gridIntP[ nodeIndex ] = & * ip; + _nodes [ nodeIndex ] = mesh->AddNode( xyz.X(), xyz.Y(), xyz.Z() ); + //_gridIntP[ nodeIndex ] = & * ip; + //SetOnShape( _nodes[ nodeIndex ], *ip ); } if ( _gridIntP[ nodeIndex ] ) _gridIntP[ nodeIndex ]->Add( ip->_faceIDs ); @@ -1029,7 +1655,7 @@ namespace } // set OUT state to nodes after the last ip for ( ; nodeCoord < coordEnd; ++nodeCoord ) - isNodeOut[ nIndex0 + nShift * ( nodeCoord-coord0 ) ] = true; + shapeIDVec[ nIndex0 + nShift * ( nodeCoord-coord0 ) ] = 0; } } @@ -1040,13 +1666,19 @@ namespace for ( size_t x = 0; x < _coords[0].size(); ++x ) { size_t nodeIndex = NodeIndex( x, y, z ); - if ( !isNodeOut[ nodeIndex ] && !_nodes[ nodeIndex] ) + if ( !_nodes[ nodeIndex ] && + 0 < shapeIDVec[ nodeIndex ] && shapeIDVec[ nodeIndex ] < undefID ) { - //_nodes[ nodeIndex ] = helper.AddNode( _coords[0][x], _coords[1][y], _coords[2][z] ); gp_XYZ xyz = ( _coords[0][x] * _axes[0] + _coords[1][y] * _axes[1] + _coords[2][z] * _axes[2] ); - _nodes[ nodeIndex ] = helper.AddNode( xyz.X(), xyz.Y(), xyz.Z() ); + _nodes[ nodeIndex ] = mesh->AddNode( xyz.X(), xyz.Y(), xyz.Z() ); + mesh->SetNodeInVolume( _nodes[ nodeIndex ], shapeIDVec[ nodeIndex ]); + } + else if ( _nodes[ nodeIndex ] && _gridIntP[ nodeIndex ] /*&& + !_nodes[ nodeIndex]->GetShapeID()*/ ) + { + SetOnShape( _nodes[ nodeIndex ], *_gridIntP[ nodeIndex ]); } } @@ -1174,6 +1806,17 @@ namespace _intersections.push_back( make_pair( &gridLine, intersector._intPoints[i] )); } } + + if ( _face.Orientation() == TopAbs_INTERNAL ) + { + for ( size_t i = 0; i < _intersections.size(); ++i ) + if ( _intersections[i].second._transition == Trans_IN || + _intersections[i].second._transition == Trans_OUT ) + { + _intersections[i].second._transition = Trans_INTERNAL; + } + } + return; } //================================================================================ /* @@ -1194,6 +1837,8 @@ namespace { F_IntersectPoint p; p._paramOnLine = _w; + p._u = _u; + p._v = _v; p._transition = _transition; _intPoints.push_back( p ); } @@ -1428,8 +2073,8 @@ namespace /*! * \brief Creates topology of the hexahedron */ - Hexahedron::Hexahedron(const double sizeThreshold, Grid* grid) - : _grid( grid ), _sizeThreshold( sizeThreshold ), _nbFaceIntNodes(0) + Hexahedron::Hexahedron(Grid* grid) + : _grid( grid ), _nbFaceIntNodes(0), _hasTooSmall( false ) { _polygons.reserve(100); // to avoid reallocation; @@ -1491,11 +2136,12 @@ namespace /*! * \brief Copy constructor */ - Hexahedron::Hexahedron( const Hexahedron& other ) - :_grid( other._grid ), _sizeThreshold( other._sizeThreshold ), _nbFaceIntNodes(0) + Hexahedron::Hexahedron( const Hexahedron& other, size_t i, size_t j, size_t k, int cellID ) + :_grid( other._grid ), _nbFaceIntNodes(0), _i( i ), _j( j ), _k( k ), _hasTooSmall( false ) { _polygons.reserve(100); // to avoid reallocation; + // copy topology for ( int i = 0; i < 8; ++i ) _nodeShift[i] = other._nodeShift[i]; @@ -1520,23 +2166,198 @@ namespace tgtLink._link = _hexLinks + ( srcLink._link - other._hexLinks ); } } +#ifdef _DEBUG_ + _cellID = cellID; +#endif + } + + //================================================================================ + /*! + * \brief Return IDs of SOLIDs interfering with this Hexahedron + */ + const vector< TGeomID >& Hexahedron::getSolids() + { + _grid->_shapeIDs.clear(); + if ( _grid->_geometry.IsOneSolid() ) + { + _grid->_shapeIDs.push_back( _grid->GetSolid()->ID() ); + return _grid->_shapeIDs; + } + // count intersection points belonging to each SOLID + TID2Nb id2NbPoints; + id2NbPoints.reserve( 3 ); + + _origNodeInd = _grid->NodeIndex( _i,_j,_k ); + for ( int iN = 0; iN < 8; ++iN ) + { + _hexNodes[iN]._node = _grid->_nodes [ _origNodeInd + _nodeShift[iN] ]; + _hexNodes[iN]._intPoint = _grid->_gridIntP[ _origNodeInd + _nodeShift[iN] ]; + + if ( _hexNodes[iN]._intPoint ) // intersection with a FACE + { + for ( size_t iF = 0; iF < _hexNodes[iN]._intPoint->_faceIDs.size(); ++iF ) + { + const vector< TGeomID > & solidIDs = + _grid->GetSolidIDs( _hexNodes[iN]._intPoint->_faceIDs[iF] ); + for ( size_t i = 0; i < solidIDs.size(); ++i ) + insertAndIncrement( solidIDs[i], id2NbPoints ); + } + } + else if ( _hexNodes[iN]._node ) // node inside a SOLID + { + insertAndIncrement( _hexNodes[iN]._node->GetShapeID(), id2NbPoints ); + } + } + + for ( int iL = 0; iL < 12; ++iL ) + { + const _Link& link = _hexLinks[ iL ]; + for ( size_t iP = 0; iP < link._fIntPoints.size(); ++iP ) + { + for ( size_t iF = 0; iF < link._fIntPoints[iP]->_faceIDs.size(); ++iF ) + { + const vector< TGeomID > & solidIDs = + _grid->GetSolidIDs( link._fIntPoints[iP]->_faceIDs[iF] ); + for ( size_t i = 0; i < solidIDs.size(); ++i ) + insertAndIncrement( solidIDs[i], id2NbPoints ); + } + } + } + + for ( size_t iP = 0; iP < _eIntPoints.size(); ++iP ) + { + const vector< TGeomID > & solidIDs = _grid->GetSolidIDs( _eIntPoints[iP]->_shapeID ); + for ( size_t i = 0; i < solidIDs.size(); ++i ) + insertAndIncrement( solidIDs[i], id2NbPoints ); + } + + _grid->_shapeIDs.reserve( id2NbPoints.size() ); + for ( TID2Nb::iterator id2nb = id2NbPoints.begin(); id2nb != id2NbPoints.end(); ++id2nb ) + if ( id2nb->second >= 3 ) + _grid->_shapeIDs.push_back( id2nb->first ); + + return _grid->_shapeIDs; + } + + //================================================================================ + /*! + * \brief Count cuts by INTERNAL FACEs and set _Node::_isInternalFlags + */ + bool Hexahedron::isCutByInternalFace( IsInternalFlag & maxFlag ) + { + TID2Nb id2NbPoints; + id2NbPoints.reserve( 3 ); + + for ( size_t iN = 0; iN < _intNodes.size(); ++iN ) + for ( size_t iF = 0; iF < _intNodes[iN]._intPoint->_faceIDs.size(); ++iF ) + { + if ( _grid->IsInternal( _intNodes[iN]._intPoint->_faceIDs[iF])) + insertAndIncrement( _intNodes[iN]._intPoint->_faceIDs[iF], id2NbPoints ); + } + for ( size_t iN = 0; iN < 8; ++iN ) + if ( _hexNodes[iN]._intPoint ) + for ( size_t iF = 0; iF < _hexNodes[iN]._intPoint->_faceIDs.size(); ++iF ) + { + if ( _grid->IsInternal( _hexNodes[iN]._intPoint->_faceIDs[iF])) + insertAndIncrement( _hexNodes[iN]._intPoint->_faceIDs[iF], id2NbPoints ); + } + + maxFlag = IS_NOT_INTERNAL; + for ( TID2Nb::iterator id2nb = id2NbPoints.begin(); id2nb != id2NbPoints.end(); ++id2nb ) + { + TGeomID intFace = id2nb->first; + IsInternalFlag intFlag = ( id2nb->second >= 3 ? IS_CUT_BY_INTERNAL_FACE : IS_INTERNAL ); + if ( intFlag > maxFlag ) + maxFlag = intFlag; + + for ( size_t iN = 0; iN < _intNodes.size(); ++iN ) + if ( _intNodes[iN].IsOnFace( intFace )) + _intNodes[iN].SetInternal( intFlag ); + + for ( size_t iN = 0; iN < 8; ++iN ) + if ( _hexNodes[iN].IsOnFace( intFace )) + _hexNodes[iN].SetInternal( intFlag ); + } + + return maxFlag; + } + + //================================================================================ + /*! + * \brief Return any FACE interfering with this Hexahedron + */ + TGeomID Hexahedron::getAnyFace() const + { + TID2Nb id2NbPoints; + id2NbPoints.reserve( 3 ); + + for ( size_t iN = 0; iN < _intNodes.size(); ++iN ) + for ( size_t iF = 0; iF < _intNodes[iN]._intPoint->_faceIDs.size(); ++iF ) + insertAndIncrement( _intNodes[iN]._intPoint->_faceIDs[iF], id2NbPoints ); + + for ( size_t iN = 0; iN < 8; ++iN ) + if ( _hexNodes[iN]._intPoint ) + for ( size_t iF = 0; iF < _hexNodes[iN]._intPoint->_faceIDs.size(); ++iF ) + insertAndIncrement( _hexNodes[iN]._intPoint->_faceIDs[iF], id2NbPoints ); + + for ( unsigned int minNb = 3; minNb > 0; --minNb ) + for ( TID2Nb::iterator id2nb = id2NbPoints.begin(); id2nb != id2NbPoints.end(); ++id2nb ) + if ( id2nb->second >= minNb ) + return id2nb->first; + + return 0; + } + + //================================================================================ + /*! + * \brief Initializes IJK by Hexahedron index + */ + void Hexahedron::setIJK( size_t iCell ) + { + size_t iNbCell = _grid->_coords[0].size() - 1; + size_t jNbCell = _grid->_coords[1].size() - 1; + _i = iCell % iNbCell; + _j = ( iCell % ( iNbCell * jNbCell )) / iNbCell; + _k = iCell / iNbCell / jNbCell; + } + + //================================================================================ + /*! + * \brief Initializes its data by given grid cell (countered from zero) + */ + void Hexahedron::init( size_t iCell ) + { + setIJK( iCell ); + init( _i, _j, _k ); } //================================================================================ /*! - * \brief Initializes its data by given grid cell + * \brief Initializes its data by given grid cell nodes and intersections */ - void Hexahedron::init( size_t i, size_t j, size_t k ) + void Hexahedron::init( size_t i, size_t j, size_t k, const Solid* solid ) { _i = i; _j = j; _k = k; + + if ( !solid ) + solid = _grid->GetSolid(); + // set nodes of grid to nodes of the hexahedron and // count nodes at hexahedron corners located IN and ON geometry _nbCornerNodes = _nbBndNodes = 0; _origNodeInd = _grid->NodeIndex( i,j,k ); for ( int iN = 0; iN < 8; ++iN ) { + _hexNodes[iN]._isInternalFlags = 0; + _hexNodes[iN]._node = _grid->_nodes [ _origNodeInd + _nodeShift[iN] ]; _hexNodes[iN]._intPoint = _grid->_gridIntP[ _origNodeInd + _nodeShift[iN] ]; + + if ( _hexNodes[iN]._node && !solid->Contains( _hexNodes[iN]._node->GetShapeID() )) + _hexNodes[iN]._node = 0; + if ( _hexNodes[iN]._intPoint && !solid->ContainsAny( _hexNodes[iN]._intPoint->_faceIDs )) + _hexNodes[iN]._intPoint = 0; + _nbCornerNodes += bool( _hexNodes[iN]._node ); _nbBndNodes += bool( _hexNodes[iN]._intPoint ); } @@ -1547,25 +2368,28 @@ namespace _intNodes.clear(); _vIntNodes.clear(); - if ( _nbFaceIntNodes + _eIntPoints.size() > 0 && - _nbFaceIntNodes + _nbCornerNodes + _eIntPoints.size() > 3) + if ( _nbFaceIntNodes + _eIntPoints.size() > 0 && + _nbFaceIntNodes + _eIntPoints.size() + _nbCornerNodes > 3) { _intNodes.reserve( 3 * _nbBndNodes + _nbFaceIntNodes + _eIntPoints.size() ); // this method can be called in parallel, so use own helper SMESH_MesherHelper helper( *_grid->_helper->GetMesh() ); - // create sub-links (_splits) by splitting links with _fIntPoints + // Create sub-links (_Link::_splits) by splitting links with _Link::_fIntPoints + // --------------------------------------------------------------- _Link split; for ( int iLink = 0; iLink < 12; ++iLink ) { _Link& link = _hexLinks[ iLink ]; - link._fIntNodes.resize( link._fIntPoints.size() ); + link._fIntNodes.clear(); + link._fIntNodes.reserve( link._fIntPoints.size() ); for ( size_t i = 0; i < link._fIntPoints.size(); ++i ) - { - _intNodes.push_back( _Node( 0, link._fIntPoints[i] )); - link._fIntNodes[ i ] = & _intNodes.back(); - } + if ( solid->ContainsAny( link._fIntPoints[i]->_faceIDs )) + { + _intNodes.push_back( _Node( 0, link._fIntPoints[i] )); + link._fIntNodes.push_back( & _intNodes.back() ); + } link._splits.clear(); split._nodes[ 0 ] = link._nodes[0]; @@ -1590,15 +2414,21 @@ namespace } if ( checkTransition ) { - if ( link._fIntPoints[i]->_faceIDs.size() > 1 || _eIntPoints.size() > 0 ) - isOut = isOutPoint( link, i, helper ); + const vector< TGeomID >& faceIDs = link._fIntNodes[i]->_intPoint->_faceIDs; + if ( _grid->IsInternal( faceIDs.back() )) + isOut = false; + else if ( faceIDs.size() > 1 || _eIntPoints.size() > 0 ) + isOut = isOutPoint( link, i, helper, solid ); else - switch ( link._fIntPoints[i]->_transition ) { - case Trans_OUT: isOut = true; break; - case Trans_IN : isOut = false; break; + { + bool okTransi = _grid->IsCorrectTransition( faceIDs[0], solid ); + switch ( link._fIntNodes[i]->FaceIntPnt()->_transition ) { + case Trans_OUT: isOut = okTransi; break; + case Trans_IN : isOut = !okTransi; break; default: - isOut = isOutPoint( link, i, helper ); + isOut = isOutPoint( link, i, helper, solid ); } + } } } if ( link._nodes[ 1 ]->Node() && split._nodes[ 0 ]->Node() && !isOut ) @@ -1609,12 +2439,20 @@ namespace } // Create _Node's at intersections with EDGEs. - + // -------------------------------------------- + // 1) add this->_eIntPoints to _Face::_eIntNodes + // 2) fill _intNodes and _vIntNodes + // const double tol2 = _grid->_tol * _grid->_tol; int facets[3], nbFacets, subEntity; + for ( int iF = 0; iF < 6; ++iF ) + _hexQuads[ iF ]._eIntNodes.clear(); + for ( size_t iP = 0; iP < _eIntPoints.size(); ++iP ) { + if ( !solid->ContainsAny( _eIntPoints[iP]->_faceIDs )) + continue; nbFacets = getEntity( _eIntPoints[iP], facets, subEntity ); _Node* equalNode = 0; switch( nbFacets ) { @@ -1639,10 +2477,16 @@ namespace equalNode = findEqualNode( link._fIntNodes, _eIntPoints[ iP ], tol2 ); if ( equalNode ) equalNode->Add( _eIntPoints[ iP ] ); + else if ( link._splits.size() == 1 && + link._splits[0]._nodes[0] && + link._splits[0]._nodes[1] ) + link._splits.clear(); // hex edge is divided by _eIntPoints[iP] } - else + //else + if ( !equalNode ) { _intNodes.push_back( _Node( 0, _eIntPoints[ iP ])); + bool newNodeUsed = false; for ( int iF = 0; iF < 2; ++iF ) { _Face& quad = _hexQuads[ facets[iF] - SMESH_Block::ID_FirstF ]; @@ -1652,8 +2496,11 @@ namespace } else { quad._eIntNodes.push_back( & _intNodes.back() ); + newNodeUsed = true; } } + if ( !newNodeUsed ) + _intNodes.pop_back(); } break; } @@ -1685,7 +2532,7 @@ namespace } // switch( nbFacets ) if ( nbFacets == 0 || - _grid->_shapes( _eIntPoints[ iP ]->_shapeID ).ShapeType() == TopAbs_VERTEX ) + _grid->ShapeType( _eIntPoints[ iP ]->_shapeID ) == TopAbs_VERTEX ) { equalNode = findEqualNode( _vIntNodes, _eIntPoints[ iP ], tol2 ); if ( equalNode ) { @@ -1699,6 +2546,7 @@ namespace } } // loop on _eIntPoints } + else if ( 3 < _nbCornerNodes && _nbCornerNodes < 8 ) // _nbFaceIntNodes == 0 { _Link split; @@ -1715,40 +2563,76 @@ namespace } } } + return; - } - //================================================================================ - /*! - * \brief Initializes its data by given grid cell (countered from zero) - */ - void Hexahedron::init( size_t iCell ) - { - size_t iNbCell = _grid->_coords[0].size() - 1; - size_t jNbCell = _grid->_coords[1].size() - 1; - _i = iCell % iNbCell; - _j = ( iCell % ( iNbCell * jNbCell )) / iNbCell; - _k = iCell / iNbCell / jNbCell; - init( _i, _j, _k ); - } + } // init( _i, _j, _k ) //================================================================================ /*! * \brief Compute mesh volumes resulted from intersection of the Hexahedron */ - void Hexahedron::ComputeElements() + void Hexahedron::ComputeElements( const Solid* solid, int solidIndex ) { - Init(); + if ( !solid ) + { + solid = _grid->GetSolid(); + if ( !_grid->_geometry.IsOneSolid() ) + { + const vector< TGeomID >& solidIDs = getSolids(); + if ( solidIDs.size() > 1 ) + { + for ( size_t i = 0; i < solidIDs.size(); ++i ) + { + solid = _grid->GetSolid( solidIDs[i] ); + ComputeElements( solid, i ); + if ( !_volumeDefs._nodes.empty() && i < solidIDs.size() - 1 ) + _volumeDefs.SetNext( new _volumeDef( _volumeDefs )); + } + return; + } + solid = _grid->GetSolid( solidIDs[0] ); + } + } + + init( _i, _j, _k, solid ); // get nodes and intersections from grid nodes and split links int nbIntersections = _nbFaceIntNodes + _eIntPoints.size(); if ( _nbCornerNodes + nbIntersections < 4 ) return; if ( _nbBndNodes == _nbCornerNodes && nbIntersections == 0 && isInHole() ) - return; + return; // cell is in a hole + + IsInternalFlag intFlag = IS_NOT_INTERNAL; + if ( solid->HasInternalFaces() && this->isCutByInternalFace( intFlag )) + { + for ( _SplitIterator it( _hexLinks ); it.More(); it.Next() ) + { + if ( compute( solid, intFlag )) + _volumeDefs.SetNext( new _volumeDef( _volumeDefs )); + } + } + else + { + if ( solidIndex >= 0 ) + intFlag = IS_CUT_BY_INTERNAL_FACE; + + compute( solid, intFlag ); + } + } + //================================================================================ + /*! + * \brief Compute mesh volumes resulted from intersection of the Hexahedron + */ + bool Hexahedron::compute( const Solid* solid, const IsInternalFlag intFlag ) + { _polygons.clear(); _polygons.reserve( 20 ); + for ( int iN = 0; iN < 8; ++iN ) + _hexNodes[iN]._usedInFace = 0; + // Create polygons from quadrangles // -------------------------------- @@ -1778,14 +2662,13 @@ namespace if (( nbSplits == 1 ) && ( quad._eIntNodes.empty() || splits[0].FirstNode()->IsLinked( splits[0].LastNode()->_intPoint ))) - //( quad._eIntNodes.empty() || _nbCornerNodes + nbIntersections > 6 )) + //( quad._eIntNodes.empty() || _nbCornerNodes + nbIntersections > 6 )) nbSplits = 0; -#ifdef _DEBUG_ for ( size_t iP = 0; iP < quad._eIntNodes.size(); ++iP ) if ( quad._eIntNodes[ iP ]->IsUsedInFace( polygon )) quad._eIntNodes[ iP ]->_usedInFace = 0; -#endif + size_t nbUsedEdgeNodes = 0; _Face* prevPolyg = 0; // polygon previously created from this quad @@ -1815,16 +2698,20 @@ namespace n1 = split.FirstNode(); if ( n1 == n2 && n1->_intPoint && - n1->_intPoint->_faceIDs.size() > 1 ) + (( n1->_intPoint->_faceIDs.size() > 1 && isImplementEdges() ) || + ( n1->_isInternalFlags ))) { // n1 is at intersection with EDGE if ( findChainOnEdge( splits, polygon->_links.back(), split, iS, quad, chainNodes )) { for ( size_t i = 1; i < chainNodes.size(); ++i ) polygon->AddPolyLink( chainNodes[i-1], chainNodes[i], prevPolyg ); - prevPolyg = polygon; - n2 = chainNodes.back(); - continue; + if ( chainNodes.back() != n1 ) // not a partial cut by INTERNAL FACE + { + prevPolyg = polygon; + n2 = chainNodes.back(); + continue; + } } } else if ( n1 != n2 ) @@ -1940,7 +2827,7 @@ namespace freeLinks.push_back( & polygon._links[ iL ]); } int nbFreeLinks = freeLinks.size(); - if ( nbFreeLinks == 1 ) return; + if ( nbFreeLinks == 1 ) return false; // put not used intersection nodes to _vIntNodes int nbVertexNodes = 0; // nb not used vertex nodes @@ -2106,7 +2993,8 @@ namespace _vIntNodes[ iN ]->_usedInFace = &polygon; chainNodes.push_back( _vIntNodes[ iN ] ); } - if ( chainNodes.size() > 1 ) + if ( chainNodes.size() > 1 && + curFace != _grid->PseudoIntExtFaceID() ) /////// TODO { sortVertexNodes( chainNodes, curNode, curFace ); } @@ -2130,7 +3018,7 @@ namespace if ( polygon._links.size() < 2 || polygon._links[0].LastNode() != polygon._links.back().FirstNode() ) - return; // closed polygon not found -> invalid polyhedron + return false; // closed polygon not found -> invalid polyhedron if ( polygon._links.size() == 2 ) { @@ -2251,15 +3139,16 @@ namespace } // end of case ( polygon._links.size() > 2 ) } // while ( nbFreeLinks > 0 ) - if ( ! checkPolyhedronSize() ) - { - return; - } + // check volume size + _hasTooSmall = ! checkPolyhedronSize( intFlag & IS_CUT_BY_INTERNAL_FACE ); for ( size_t i = 0; i < 8; ++i ) if ( _hexNodes[ i ]._intPoint == &ipTmp ) _hexNodes[ i ]._intPoint = 0; + if ( _hasTooSmall ) + return false; // too small volume + // create a classic cell if possible int nbPolygons = 0; @@ -2292,6 +3181,9 @@ namespace _volumeDefs._nodes.push_back( _polygons[ iF ]._links[ iL ].FirstNode() ); } } + _volumeDefs._solidID = solid->ID(); + + return !_volumeDefs._nodes.empty(); } //================================================================================ /*! @@ -2302,23 +3194,18 @@ namespace { SMESHDS_Mesh* mesh = helper.GetMeshDS(); - size_t nbCells[3] = { _grid->_coords[0].size() - 1, - _grid->_coords[1].size() - 1, - _grid->_coords[2].size() - 1 }; - const size_t nbGridCells = nbCells[0] * nbCells[1] * nbCells[2]; + CellsAroundLink c( _grid, 0 ); + const size_t nbGridCells = c._nbCells[0] * c._nbCells[1] * c._nbCells[2]; vector< Hexahedron* > allHexa( nbGridCells, 0 ); int nbIntHex = 0; // set intersection nodes from GridLine's to links of allHexa - int i,j,k, iDirOther[3][2] = {{ 1,2 },{ 0,2 },{ 0,1 }}; + int i,j,k, cellIndex; for ( int iDir = 0; iDir < 3; ++iDir ) { - int dInd[4][3] = { {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0} }; - dInd[1][ iDirOther[iDir][0] ] = -1; - dInd[2][ iDirOther[iDir][1] ] = -1; - dInd[3][ iDirOther[iDir][0] ] = -1; dInd[3][ iDirOther[iDir][1] ] = -1; // loop on GridLine's parallel to iDir LineIndexer lineInd = _grid->GetLineIndexer( iDir ); + CellsAroundLink fourCells( _grid, iDir ); for ( ; lineInd.More(); ++lineInd ) { GridLine& line = _grid->_lines[ iDir ][ lineInd.LineIndex() ]; @@ -2327,23 +3214,15 @@ namespace { // if ( !ip->_node ) continue; // intersection at a grid node lineInd.SetIndexOnLine( ip->_indexOnLine ); + fourCells.Init( lineInd.I(), lineInd.J(), lineInd.K() ); for ( int iL = 0; iL < 4; ++iL ) // loop on 4 cells sharing a link { - i = int(lineInd.I()) + dInd[iL][0]; - j = int(lineInd.J()) + dInd[iL][1]; - k = int(lineInd.K()) + dInd[iL][2]; - if ( i < 0 || i >= (int) nbCells[0] || - j < 0 || j >= (int) nbCells[1] || - k < 0 || k >= (int) nbCells[2] ) continue; - - const size_t hexIndex = _grid->CellIndex( i,j,k ); - Hexahedron *& hex = allHexa[ hexIndex ]; + if ( !fourCells.GetCell( iL, i,j,k, cellIndex )) + continue; + Hexahedron *& hex = allHexa[ cellIndex ]; if ( !hex) { - hex = new Hexahedron( *this ); - hex->_i = i; - hex->_j = j; - hex->_k = k; + hex = new Hexahedron( *this, i, j, k, cellIndex ); ++nbIntHex; } const int iLink = iL + iDir * 4; @@ -2357,22 +3236,24 @@ namespace // implement geom edges into the mesh addEdges( helper, allHexa, edge2faceIDsMap ); - // add not split hexadrons to the mesh + // add not split hexahedra to the mesh int nbAdded = 0; - vector< Hexahedron* > intHexa( nbIntHex, (Hexahedron*) NULL ); + vector< Hexahedron* > intHexa; intHexa.reserve( nbIntHex ); + vector< const SMDS_MeshElement* > boundaryVolumes; boundaryVolumes.reserve( nbIntHex * 1.1 ); for ( size_t i = 0; i < allHexa.size(); ++i ) { + // initialize this by not cut allHexa[ i ] Hexahedron * & hex = allHexa[ i ]; - if ( hex ) + if ( hex ) // split hexahedron { intHexa.push_back( hex ); if ( hex->_nbFaceIntNodes > 0 || hex->_eIntPoints.size() > 0 ) - continue; // treat intersected hex later + continue; // treat intersected hex later in parallel this->init( hex->_i, hex->_j, hex->_k ); } else - { - this->init( i ); + { + this->init( i ); // == init(i,j,k) } if (( _nbCornerNodes == 8 ) && ( _nbBndNodes < _nbCornerNodes || !isInHole() )) @@ -2383,18 +3264,31 @@ namespace _hexNodes[3].Node(), _hexNodes[1].Node(), _hexNodes[4].Node(), _hexNodes[6].Node(), _hexNodes[7].Node(), _hexNodes[5].Node() ); - mesh->SetMeshElementOnShape( el, helper.GetSubShapeID() ); + TGeomID solidID = 0; + if ( _nbBndNodes < _nbCornerNodes ) + { + for ( int iN = 0; iN < 8 && !solidID; ++iN ) + if ( !_hexNodes[iN]._intPoint ) // no intersection + solidID = _hexNodes[iN].Node()->GetShapeID(); + } + else + { + solidID = getSolids()[0]; + } + mesh->SetMeshElementOnShape( el, solidID ); ++nbAdded; if ( hex ) intHexa.pop_back(); + if ( _grid->_toCreateFaces && _nbBndNodes >= 3 ) + { + boundaryVolumes.push_back( el ); + el->setIsMarked( true ); + } } - else if ( _nbCornerNodes > 3 && !hex ) + else if ( _nbCornerNodes > 3 && !hex ) { // all intersection of hex with geometry are at grid nodes - hex = new Hexahedron( *this ); - hex->_i = _i; - hex->_j = _j; - hex->_k = _k; + hex = new Hexahedron( *this, _i, _j, _k, i ); intHexa.push_back( hex ); } } @@ -2406,16 +3300,30 @@ namespace tbb::simple_partitioner()); // ComputeElements() is called here for ( size_t i = 0; i < intHexa.size(); ++i ) if ( Hexahedron * hex = intHexa[ i ] ) - nbAdded += hex->addElements( helper ); + nbAdded += hex->addVolumes( helper ); #else for ( size_t i = 0; i < intHexa.size(); ++i ) if ( Hexahedron * hex = intHexa[ i ] ) { hex->ComputeElements(); - nbAdded += hex->addElements( helper ); + nbAdded += hex->addVolumes( helper ); } #endif + // fill boundaryVolumes with volumes neighboring too small skipped volumes + if ( _grid->_toCreateFaces ) + { + for ( size_t i = 0; i < intHexa.size(); ++i ) + if ( Hexahedron * hex = intHexa[ i ] ) + hex->getBoundaryElems( boundaryVolumes ); + } + + // create boundary mesh faces + addFaces( helper, boundaryVolumes ); + + // create mesh edges + addSegments( helper, edge2faceIDsMap ); + for ( size_t i = 0; i < allHexa.size(); ++i ) if ( allHexa[ i ] ) delete allHexa[ i ]; @@ -2456,25 +3364,36 @@ namespace const double tol = _grid->_tol; E_IntersectPoint ip; + TColStd_MapOfInteger intEdgeIDs; // IDs of not shared INTERNAL EDGES + // Intersect EDGEs with the planes map< TGeomID, vector< TGeomID > >::const_iterator e2fIt = edge2faceIDsMap.begin(); for ( ; e2fIt != edge2faceIDsMap.end(); ++e2fIt ) { const TGeomID edgeID = e2fIt->first; - const TopoDS_Edge & E = TopoDS::Edge( _grid->_shapes( edgeID )); + const TopoDS_Edge & E = TopoDS::Edge( _grid->Shape( edgeID )); BRepAdaptor_Curve curve( E ); - TopoDS_Vertex v1 = helper.IthVertex( 0, E, false ); - TopoDS_Vertex v2 = helper.IthVertex( 1, E, false ); + TopoDS_Vertex v1 = helper.IthVertex( 0, E, false ); + TopoDS_Vertex v2 = helper.IthVertex( 1, E, false ); ip._faceIDs = e2fIt->second; ip._shapeID = edgeID; + bool isInternal = ( ip._faceIDs.size() == 1 && _grid->IsInternal( edgeID )); + if ( isInternal ) + { + intEdgeIDs.Add( edgeID ); + intEdgeIDs.Add( _grid->ShapeID( v1 )); + intEdgeIDs.Add( _grid->ShapeID( v2 )); + } + // discretize the EDGE GCPnts_UniformDeflection discret( curve, deflection, true ); if ( !discret.IsDone() || discret.NbPoints() < 2 ) continue; // perform intersection + E_IntersectPoint* eip, *vip; for ( int iDirZ = 0; iDirZ < 3; ++iDirZ ) { GridPlanes& planes = pln[ iDirZ ]; @@ -2501,7 +3420,7 @@ namespace locateValue( iY1, ip._uvw[iDirY], _grid->_coords[ iDirY ], dIJK[ iDirY ], tol ); locateValue( iZ1, ip._uvw[iDirZ], _grid->_coords[ iDirZ ], dIJK[ iDirZ ], tol ); - int ijk[3]; // grid index where a segment intersect a plane + int ijk[3]; // grid index where a segment intersects a plane ijk[ iDirX ] = iX1; ijk[ iDirY ] = iY1; ijk[ iDirZ ] = iZ1; @@ -2510,10 +3429,12 @@ namespace if ( iDirZ == 0 ) { ip._point = p1; - ip._shapeID = _grid->_shapes.Add( v1 ); - _grid->_edgeIntP.push_back( ip ); - if ( !addIntersection( _grid->_edgeIntP.back(), hexes, ijk, d000 )) - _grid->_edgeIntP.pop_back(); + ip._shapeID = _grid->ShapeID( v1 ); + vip = _grid->Add( ip ); + if ( isInternal ) + vip->_faceIDs.push_back( _grid->PseudoIntExtFaceID() ); + if ( !addIntersection( vip, hexes, ijk, d000 )) + _grid->Remove( vip ); ip._shapeID = edgeID; } for ( int iP = 2; iP <= discret.NbPoints(); ++iP ) @@ -2541,15 +3462,17 @@ namespace ijk[ iDirZ ] = iZ; // add ip to hex "above" the plane - _grid->_edgeIntP.push_back( ip ); + eip = _grid->Add( ip ); + if ( isInternal ) + eip->_faceIDs.push_back( _grid->PseudoIntExtFaceID() ); dIJK[ iDirZ ] = 0; - bool added = addIntersection(_grid->_edgeIntP.back(), hexes, ijk, dIJK); + bool added = addIntersection( eip, hexes, ijk, dIJK); // add ip to hex "below" the plane ijk[ iDirZ ] = iZ-1; - if ( !addIntersection( _grid->_edgeIntP.back(), hexes, ijk, dIJK ) && - !added) - _grid->_edgeIntP.pop_back(); + if ( !addIntersection( eip, hexes, ijk, dIJK ) && + !added ) + _grid->Remove( eip ); } } iZ1 = iZ2; @@ -2560,62 +3483,292 @@ namespace // add the 2nd vertex point to a hexahedron if ( iDirZ == 0 ) { - ip._shapeID = _grid->_shapes.Add( v2 ); - ip._point = p1; + ip._point = p1; + ip._shapeID = _grid->ShapeID( v2 ); _grid->ComputeUVW( p1, ip._uvw ); locateValue( ijk[iDirX], ip._uvw[iDirX], _grid->_coords[iDirX], dIJK[iDirX], tol ); locateValue( ijk[iDirY], ip._uvw[iDirY], _grid->_coords[iDirY], dIJK[iDirY], tol ); ijk[ iDirZ ] = iZ1; - _grid->_edgeIntP.push_back( ip ); - if ( !addIntersection( _grid->_edgeIntP.back(), hexes, ijk, d000 )) - _grid->_edgeIntP.pop_back(); + bool sameV = ( v1.IsSame( v2 )); + if ( !sameV ) + vip = _grid->Add( ip ); + if ( isInternal && !sameV ) + vip->_faceIDs.push_back( _grid->PseudoIntExtFaceID() ); + if ( !addIntersection( vip, hexes, ijk, d000 ) && !sameV ) + _grid->Remove( vip ); ip._shapeID = edgeID; } } // loop on 3 grid directions } // loop on EDGEs + + if ( intEdgeIDs.Size() > 0 ) + cutByExtendedInternal( hexes, intEdgeIDs ); + + return; } //================================================================================ /*! - * \brief Finds intersection of a curve with a plane - * \param [in] u1 - parameter of one curve point - * \param [in] proj1 - projection of the curve point to the plane normal - * \param [in] u2 - parameter of another curve point - * \param [in] proj2 - projection of the other curve point to the plane normal - * \param [in] proj - projection of a point where the curve intersects the plane - * \param [in] curve - the curve - * \param [in] axis - the plane normal - * \param [in] origin - the plane origin - * \return gp_Pnt - the found intersection point + * \brief Fully cut hexes that are partially cut by INTERNAL FACE. + * Cut them by extended INTERNAL FACE. */ - gp_Pnt Hexahedron::findIntPoint( double u1, double proj1, - double u2, double proj2, - double proj, - BRepAdaptor_Curve& curve, - const gp_XYZ& axis, - const gp_XYZ& origin) + void Hexahedron::cutByExtendedInternal( std::vector< Hexahedron* >& hexes, + const TColStd_MapOfInteger& intEdgeIDs ) { - double r = (( proj - proj1 ) / ( proj2 - proj1 )); - double u = u1 * ( 1 - r ) + u2 * r; - gp_Pnt p = curve.Value( u ); - double newProj = axis * ( p.XYZ() - origin ); - if ( Abs( proj - newProj ) > _grid->_tol / 10. ) + IntAna_IntConicQuad intersection; + SMESHDS_Mesh* meshDS = _grid->_helper->GetMeshDS(); + const double tol2 = _grid->_tol * _grid->_tol; + + for ( size_t iH = 0; iH < hexes.size(); ++iH ) { - if ( r > 0.5 ) - return findIntPoint( u2, proj2, u, newProj, proj, curve, axis, origin ); - else - return findIntPoint( u1, proj2, u, newProj, proj, curve, axis, origin ); - } - return p; + Hexahedron* hex = hexes[ iH ]; + if ( !hex || hex->_eIntPoints.size() < 2 ) + continue; + if ( !intEdgeIDs.Contains( hex->_eIntPoints.back()->_shapeID )) + continue; + + // get 3 points on INTERNAL FACE to construct a cutting plane + gp_Pnt p1 = hex->_eIntPoints[0]->_point; + gp_Pnt p2 = hex->_eIntPoints[1]->_point; + gp_Pnt p3 = hex->mostDistantInternalPnt( iH, p1, p2 ); + + gp_Vec norm = gp_Vec( p1, p2 ) ^ gp_Vec( p1, p3 ); + gp_Pln pln; + try { + pln = gp_Pln( p1, norm ); + } + catch(...) + { + continue; + } + + TGeomID intFaceID = hex->_eIntPoints.back()->_faceIDs.front(); // FACE being "extended" + TGeomID solidID = _grid->GetSolid( intFaceID )->ID(); + + // cut links by the plane + //bool isCut = false; + for ( int iLink = 0; iLink < 12; ++iLink ) + { + _Link& link = hex->_hexLinks[ iLink ]; + if ( !link._fIntPoints.empty() ) + { + // if ( link._fIntPoints[0]->_faceIDs.back() == _grid->PseudoIntExtFaceID() ) + // isCut = true; + continue; // already cut link + } + if ( !link._nodes[0]->Node() || + !link._nodes[1]->Node() ) + continue; // outside link + + if ( link._nodes[0]->IsOnFace( intFaceID )) + { + if ( link._nodes[0]->_intPoint->_faceIDs.back() != _grid->PseudoIntExtFaceID() ) + if ( p1.SquareDistance( link._nodes[0]->Point() ) < tol2 || + p2.SquareDistance( link._nodes[0]->Point() ) < tol2 ) + link._nodes[0]->_intPoint->_faceIDs.push_back( _grid->PseudoIntExtFaceID() ); + continue; // link is cut by FACE being "extended" + } + if ( link._nodes[1]->IsOnFace( intFaceID )) + { + if ( link._nodes[1]->_intPoint->_faceIDs.back() != _grid->PseudoIntExtFaceID() ) + if ( p1.SquareDistance( link._nodes[1]->Point() ) < tol2 || + p2.SquareDistance( link._nodes[1]->Point() ) < tol2 ) + link._nodes[1]->_intPoint->_faceIDs.push_back( _grid->PseudoIntExtFaceID() ); + continue; // link is cut by FACE being "extended" + } + gp_Pnt p4 = link._nodes[0]->Point(); + gp_Pnt p5 = link._nodes[1]->Point(); + gp_Lin line( p4, gp_Vec( p4, p5 )); + + intersection.Perform( line, pln ); + if ( !intersection.IsDone() || + intersection.IsInQuadric() || + intersection.IsParallel() || + intersection.NbPoints() < 1 ) + continue; + + double u = intersection.ParamOnConic(1); + if ( u + _grid->_tol < 0 ) + continue; + int iDir = iLink / 4; + int index = (&hex->_i)[iDir]; + double linkLen = _grid->_coords[iDir][index+1] - _grid->_coords[iDir][index]; + if ( u - _grid->_tol > linkLen ) + continue; + + if ( u < _grid->_tol || + u > linkLen - _grid->_tol ) // intersection at grid node + { + int i = ! ( u < _grid->_tol ); // [0,1] + int iN = link._nodes[ i ] - hex->_hexNodes; // [0-7] + + const F_IntersectPoint * & ip = _grid->_gridIntP[ hex->_origNodeInd + _nodeShift[iN] ]; + if ( !ip ) + { + ip = _grid->_extIntPool.getNew(); + ip->_faceIDs.push_back( _grid->PseudoIntExtFaceID() ); + //ip->_transition = Trans_INTERNAL; + } + else if ( ip->_faceIDs.back() != _grid->PseudoIntExtFaceID() ) + { + ip->_faceIDs.push_back( _grid->PseudoIntExtFaceID() ); + } + hex->_nbFaceIntNodes++; + //isCut = true; + } + else + { + const gp_Pnt& p = intersection.Point( 1 ); + F_IntersectPoint* ip = _grid->_extIntPool.getNew(); + ip->_node = meshDS->AddNode( p.X(), p.Y(), p.Z() ); + ip->_faceIDs.push_back( _grid->PseudoIntExtFaceID() ); + ip->_transition = Trans_INTERNAL; + meshDS->SetNodeInVolume( ip->_node, solidID ); + + CellsAroundLink fourCells( _grid, iDir ); + fourCells.Init( hex->_i, hex->_j, hex->_k, iLink ); + int i,j,k, cellIndex; + for ( int iC = 0; iC < 4; ++iC ) // loop on 4 cells sharing the link + { + if ( !fourCells.GetCell( iC, i,j,k, cellIndex )) + continue; + Hexahedron * h = hexes[ cellIndex ]; + if ( !h ) + h = hexes[ cellIndex ] = new Hexahedron( *this, i, j, k, cellIndex ); + const int iL = iC + iDir * 4; + h->_hexLinks[iL]._fIntPoints.push_back( ip ); + h->_nbFaceIntNodes++; + //isCut = true; + } + } + } + + // if ( isCut ) + // for ( size_t i = 0; i < hex->_eIntPoints.size(); ++i ) + // { + // if ( _grid->IsInternal( hex->_eIntPoints[i]->_shapeID ) && + // ! hex->_eIntPoints[i]->IsOnFace( _grid->PseudoIntExtFaceID() )) + // hex->_eIntPoints[i]->_faceIDs.push_back( _grid->PseudoIntExtFaceID() ); + // } + continue; + + } // loop on all hexes + return; } //================================================================================ /*! - * \brief Returns indices of a hexahedron sub-entities holding a point - * \param [in] ip - intersection point - * \param [out] facets - 0-3 facets holding a point - * \param [out] sub - index of a vertex or an edge holding a point + * \brief Return intersection point on INTERNAL FACE most distant from given ones + */ + gp_Pnt Hexahedron::mostDistantInternalPnt( int hexIndex, const gp_Pnt& p1, const gp_Pnt& p2 ) + { + gp_Pnt resultPnt = p1; + + double maxDist2 = 0; + for ( int iLink = 0; iLink < 12; ++iLink ) // check links + { + _Link& link = _hexLinks[ iLink ]; + for ( size_t i = 0; i < link._fIntPoints.size(); ++i ) + if ( _grid->PseudoIntExtFaceID() != link._fIntPoints[i]->_faceIDs[0] && + _grid->IsInternal( link._fIntPoints[i]->_faceIDs[0] ) && + link._fIntPoints[i]->_node ) + { + gp_Pnt p = SMESH_NodeXYZ( link._fIntPoints[i]->_node ); + double d = p1.SquareDistance( p ); + if ( d > maxDist2 ) + { + resultPnt = p; + maxDist2 = d; + } + else + { + d = p2.SquareDistance( p ); + if ( d > maxDist2 ) + { + resultPnt = p; + maxDist2 = d; + } + } + } + } + setIJK( hexIndex ); + _origNodeInd = _grid->NodeIndex( _i,_j,_k ); + + for ( size_t iN = 0; iN < 8; ++iN ) // check corners + { + _hexNodes[iN]._node = _grid->_nodes [ _origNodeInd + _nodeShift[iN] ]; + _hexNodes[iN]._intPoint = _grid->_gridIntP[ _origNodeInd + _nodeShift[iN] ]; + if ( _hexNodes[iN]._intPoint ) + for ( size_t iF = 0; iF < _hexNodes[iN]._intPoint->_faceIDs.size(); ++iF ) + { + if ( _grid->IsInternal( _hexNodes[iN]._intPoint->_faceIDs[iF])) + { + gp_Pnt p = SMESH_NodeXYZ( _hexNodes[iN]._node ); + double d = p1.SquareDistance( p ); + if ( d > maxDist2 ) + { + resultPnt = p; + maxDist2 = d; + } + else + { + d = p2.SquareDistance( p ); + if ( d > maxDist2 ) + { + resultPnt = p; + maxDist2 = d; + } + } + } + } + } + if ( maxDist2 < _grid->_tol * _grid->_tol ) + return p1; + + return resultPnt; + } + + //================================================================================ + /*! + * \brief Finds intersection of a curve with a plane + * \param [in] u1 - parameter of one curve point + * \param [in] proj1 - projection of the curve point to the plane normal + * \param [in] u2 - parameter of another curve point + * \param [in] proj2 - projection of the other curve point to the plane normal + * \param [in] proj - projection of a point where the curve intersects the plane + * \param [in] curve - the curve + * \param [in] axis - the plane normal + * \param [in] origin - the plane origin + * \return gp_Pnt - the found intersection point + */ + gp_Pnt Hexahedron::findIntPoint( double u1, double proj1, + double u2, double proj2, + double proj, + BRepAdaptor_Curve& curve, + const gp_XYZ& axis, + const gp_XYZ& origin) + { + double r = (( proj - proj1 ) / ( proj2 - proj1 )); + double u = u1 * ( 1 - r ) + u2 * r; + gp_Pnt p = curve.Value( u ); + double newProj = axis * ( p.XYZ() - origin ); + if ( Abs( proj - newProj ) > _grid->_tol / 10. ) + { + if ( r > 0.5 ) + return findIntPoint( u2, proj2, u, newProj, proj, curve, axis, origin ); + else + return findIntPoint( u1, proj2, u, newProj, proj, curve, axis, origin ); + } + return p; + } + + //================================================================================ + /*! + * \brief Returns indices of a hexahedron sub-entities holding a point + * \param [in] ip - intersection point + * \param [out] facets - 0-3 facets holding a point + * \param [out] sub - index of a vertex or an edge holding a point * \return int - number of facets holding a point */ int Hexahedron::getEntity( const E_IntersectPoint* ip, int* facets, int& sub ) @@ -2683,7 +3836,7 @@ namespace /*! * \brief Adds intersection with an EDGE */ - bool Hexahedron::addIntersection( const E_IntersectPoint& ip, + bool Hexahedron::addIntersection( const E_IntersectPoint* ip, vector< Hexahedron* >& hexes, int ijk[], int dIJK[] ) { @@ -2697,16 +3850,17 @@ namespace }; for ( int i = 0; i < 4; ++i ) { - if ( /*0 <= hexIndex[i] &&*/ hexIndex[i] < hexes.size() && hexes[ hexIndex[i] ] ) + if ( hexIndex[i] < hexes.size() && hexes[ hexIndex[i] ] ) { Hexahedron* h = hexes[ hexIndex[i] ]; - // check if ip is really inside the hex + h->_eIntPoints.reserve(2); + h->_eIntPoints.push_back( ip ); + added = true; #ifdef _DEBUG_ - if ( h->isOutParam( ip._uvw )) + // check if ip is really inside the hex + if ( h->isOutParam( ip->_uvw )) throw SALOME_Exception("ip outside a hex"); #endif - h->_eIntPoints.push_back( & ip ); - added = true; } } return added; @@ -2798,8 +3952,10 @@ namespace /*! * \brief Finds nodes on the same EDGE as the first node of avoidSplit. * - * This function is for a case where an EDGE lies on a quad which lies on a FACE - * so that a part of quad in ON and another part in IN + * This function is for + * 1) a case where an EDGE lies on a quad which lies on a FACE + * so that a part of quad in ON and another part is IN + * 2) INTERNAL FACE passes through the 1st node of avoidSplit */ bool Hexahedron::findChainOnEdge( const vector< _OrientedLink >& splits, const _OrientedLink& prevSplit, @@ -2808,19 +3964,16 @@ namespace _Face& quad, vector<_Node*>& chn ) { - if ( !isImplementEdges() ) - return false; - _Node* pn1 = prevSplit.FirstNode(); _Node* pn2 = prevSplit.LastNode(); int avoidFace = pn1->IsLinked( pn2->_intPoint ); // FACE under the quad if ( avoidFace < 1 && pn1->_intPoint ) return false; - _Node* n, *stopNode = avoidSplit.LastNode(); + _Node* n = 0, *stopNode = avoidSplit.LastNode(); chn.clear(); - if ( !quad._eIntNodes.empty() ) + if ( !quad._eIntNodes.empty() ) // connect pn2 with EDGE intersections { chn.push_back( pn2 ); bool found; @@ -2841,7 +3994,7 @@ namespace } int i; - for ( i = splits.size()-1; i >= 0; --i ) + for ( i = splits.size()-1; i >= 0; --i ) // connect new pn2 (at _eIntNodes) with a split { if ( !splits[i] ) continue; @@ -2862,7 +4015,7 @@ namespace break; n = 0; } - if ( n && n != stopNode) + if ( n && n != stopNode ) { if ( chn.empty() ) chn.push_back( pn2 ); @@ -2870,17 +4023,29 @@ namespace iS = i-1; return true; } + else if ( !chn.empty() && chn.back()->_isInternalFlags ) + { + // INTERNAL FACE partially cuts the quad + for ( int i = chn.size() - 2; i >= 0; --i ) + chn.push_back( chn[ i ]); + return true; + } return false; } //================================================================================ /*! * \brief Checks transition at the ginen intersection node of a link */ - bool Hexahedron::isOutPoint( _Link& link, int iP, SMESH_MesherHelper& helper ) const + bool Hexahedron::isOutPoint( _Link& link, int iP, + SMESH_MesherHelper& helper, const Solid* solid ) const { bool isOut = false; - const bool moreIntPoints = ( iP+1 < (int) link._fIntPoints.size() ); + if ( link._fIntNodes[iP]->faces().size() == 1 && + _grid->IsInternal( link._fIntNodes[iP]->face(0) )) + return false; + + const bool moreIntPoints = ( iP+1 < (int) link._fIntNodes.size() ); // get 2 _Node's _Node* n1 = link._fIntNodes[ iP ]; @@ -2894,16 +4059,16 @@ namespace // get all FACEs under n1 and n2 set< TGeomID > faceIDs; - if ( moreIntPoints ) faceIDs.insert( link._fIntPoints[iP+1]->_faceIDs.begin(), - link._fIntPoints[iP+1]->_faceIDs.end() ); + if ( moreIntPoints ) faceIDs.insert( link._fIntNodes[iP+1]->faces().begin(), + link._fIntNodes[iP+1]->faces().end() ); if ( n2->_intPoint ) faceIDs.insert( n2->_intPoint->_faceIDs.begin(), n2->_intPoint->_faceIDs.end() ); if ( faceIDs.empty() ) return false; // n2 is inside if ( n1->_intPoint ) faceIDs.insert( n1->_intPoint->_faceIDs.begin(), n1->_intPoint->_faceIDs.end() ); - faceIDs.insert( link._fIntPoints[iP]->_faceIDs.begin(), - link._fIntPoints[iP]->_faceIDs.end() ); + faceIDs.insert( link._fIntNodes[iP]->faces().begin(), + link._fIntNodes[iP]->faces().end() ); // get a point between 2 nodes gp_Pnt p1 = n1->Point(); @@ -2916,10 +4081,9 @@ namespace for ( ; faceID != faceIDs.end(); ++faceID ) { // project pOnLink on a FACE - if ( *faceID < 1 ) continue; - const TopoDS_Face& face = TopoDS::Face( _grid->_shapes( *faceID )); - GeomAPI_ProjectPointOnSurf& proj = - helper.GetProjector( face, loc, 0.1*_grid->_tol ); + if ( *faceID < 1 || !solid->Contains( *faceID )) continue; + const TopoDS_Face& face = TopoDS::Face( _grid->Shape( *faceID )); + GeomAPI_ProjectPointOnSurf& proj = helper.GetProjector( face, loc, 0.1*_grid->_tol ); gp_Pnt testPnt = pOnLink.Transformed( loc.Transformation().Inverted() ); proj.Perform( testPnt ); if ( proj.IsDone() && proj.NbPoints() > 0 ) @@ -2940,7 +4104,7 @@ namespace 0.1*_grid->_tol, normal ) < 3 ) { - if ( face.Orientation() == TopAbs_REVERSED ) + if ( solid->Orientation( face ) == TopAbs_REVERSED ) normal.Reverse(); gp_Vec v( proj.NearestPoint(), testPnt ); isOut = ( v * normal > 0 ); @@ -2980,7 +4144,7 @@ namespace return; // get shapes of the FACE - const TopoDS_Face& face = TopoDS::Face( _grid->_shapes( faceID )); + const TopoDS_Face& face = TopoDS::Face( _grid->Shape( faceID )); list< TopoDS_Edge > edges; list< int > nbEdges; int nbW = SMESH_Block::GetOrderedEdges (face, edges, nbEdges); @@ -2995,8 +4159,8 @@ namespace for ( int i = 0; i < 2; ++i ) { TGeomID id = i==0 ? - _grid->_shapes.FindIndex( *e ) : - _grid->_shapes.FindIndex( SMESH_MesherHelper::IthVertex( 0, *e )); + _grid->ShapeID( *e ) : + _grid->ShapeID( SMESH_MesherHelper::IthVertex( 0, *e )); if (( id > 0 ) && ( std::find( &nShapeIds[0], nShapeIdsEnd, id ) != nShapeIdsEnd )) { @@ -3015,7 +4179,7 @@ namespace list< TopoDS_Edge >::iterator e = edges.begin(), eMidOut = edges.end(); for ( ; e != edges.end(); ++e ) { - if ( !_grid->_shapes.FindIndex( *e )) + if ( !_grid->ShapeID( *e )) continue; bool isOut = false; gp_Pnt p; @@ -3063,14 +4227,14 @@ namespace TGeomID id, *pID = 0; for ( e = edges.begin(); e != edges.end(); ++e ) { - if (( id = _grid->_shapes.FindIndex( SMESH_MesherHelper::IthVertex( 0, *e ))) && + if (( id = _grid->ShapeID( SMESH_MesherHelper::IthVertex( 0, *e ))) && (( pID = std::find( &nShapeIds[0], nShapeIdsEnd, id )) != nShapeIdsEnd )) { //orderShapeIDs[ nbN ] = id; orderNodes [ nbN++ ] = nodes[ pID - &nShapeIds[0] ]; *pID = -1; } - if (( id = _grid->_shapes.FindIndex( *e )) && + if (( id = _grid->ShapeID( *e )) && (( pID = std::find( &nShapeIds[0], nShapeIdsEnd, id )) != nShapeIdsEnd )) { //orderShapeIDs[ nbN ] = id; @@ -3092,46 +4256,81 @@ namespace /*! * \brief Adds computed elements to the mesh */ - int Hexahedron::addElements(SMESH_MesherHelper& helper) + int Hexahedron::addVolumes( SMESH_MesherHelper& helper ) { + F_IntersectPoint noIntPnt; + const bool toCheckNodePos = _grid->IsToCheckNodePos(); + int nbAdded = 0; // add elements resulted from hexahedron intersection - //for ( size_t i = 0; i < _volumeDefs.size(); ++i ) + for ( _volumeDef* volDef = &_volumeDefs; volDef; volDef = volDef->_next ) { - vector< const SMDS_MeshNode* > nodes( _volumeDefs._nodes.size() ); + vector< const SMDS_MeshNode* > nodes( volDef->_nodes.size() ); for ( size_t iN = 0; iN < nodes.size(); ++iN ) - if ( !( nodes[iN] = _volumeDefs._nodes[iN]->Node() )) + { + if ( !( nodes[iN] = volDef->_nodes[iN].Node() )) { - if ( const E_IntersectPoint* eip = _volumeDefs._nodes[iN]->EdgeIntPnt() ) - nodes[iN] = _volumeDefs._nodes[iN]->_intPoint->_node = + if ( const E_IntersectPoint* eip = volDef->_nodes[iN].EdgeIntPnt() ) + { + nodes[iN] = volDef->_nodes[iN]._intPoint->_node = helper.AddNode( eip->_point.X(), eip->_point.Y(), eip->_point.Z() ); + if ( _grid->ShapeType( eip->_shapeID ) == TopAbs_VERTEX ) + helper.GetMeshDS()->SetNodeOnVertex( nodes[iN], eip->_shapeID ); + else + helper.GetMeshDS()->SetNodeOnEdge( nodes[iN], eip->_shapeID ); + } else throw SALOME_Exception("Bug: no node at intersection point"); } + else if ( volDef->_nodes[iN]._intPoint && + volDef->_nodes[iN]._intPoint->_node == volDef->_nodes[iN]._node ) + { + // Update position of node at EDGE intersection; + // see comment to _Node::Add( E_IntersectPoint ) + SMESHDS_Mesh* mesh = helper.GetMeshDS(); + TGeomID shapeID = volDef->_nodes[iN].EdgeIntPnt()->_shapeID; + mesh->UnSetNodeOnShape( nodes[iN] ); + if ( _grid->ShapeType( shapeID ) == TopAbs_VERTEX ) + mesh->SetNodeOnVertex( nodes[iN], shapeID ); + else + mesh->SetNodeOnEdge( nodes[iN], shapeID ); + } + else if ( toCheckNodePos && + !nodes[iN]->isMarked() && + _grid->ShapeType( nodes[iN]->GetShapeID() ) == TopAbs_FACE ) + { + _grid->SetOnShape( nodes[iN], noIntPnt, /*unset=*/true ); + nodes[iN]->setIsMarked( true ); + } + } - if ( !_volumeDefs._quantities.empty() ) + const SMDS_MeshElement* v = 0; + if ( !volDef->_quantities.empty() ) { - helper.AddPolyhedralVolume( nodes, _volumeDefs._quantities ); + v = helper.AddPolyhedralVolume( nodes, volDef->_quantities ); } else { switch ( nodes.size() ) { - case 8: helper.AddVolume( nodes[0],nodes[1],nodes[2],nodes[3], - nodes[4],nodes[5],nodes[6],nodes[7] ); + case 8: v = helper.AddVolume( nodes[0],nodes[1],nodes[2],nodes[3], + nodes[4],nodes[5],nodes[6],nodes[7] ); break; - case 4: helper.AddVolume( nodes[0],nodes[1],nodes[2],nodes[3] ); + case 4: v = helper.AddVolume( nodes[0],nodes[1],nodes[2],nodes[3] ); break; - case 6: helper.AddVolume( nodes[0],nodes[1],nodes[2],nodes[3], nodes[4],nodes[5] ); + case 6: v = helper.AddVolume( nodes[0],nodes[1],nodes[2],nodes[3],nodes[4],nodes[5] ); break; - case 5: - helper.AddVolume( nodes[0],nodes[1],nodes[2],nodes[3],nodes[4] ); + case 5: v = helper.AddVolume( nodes[0],nodes[1],nodes[2],nodes[3],nodes[4] ); break; } } - nbAdded += int ( _volumeDefs._nodes.size() > 0 ); + if (( volDef->_volume = v )) + { + helper.GetMeshDS()->SetMeshElementOnShape( v, volDef->_solidID ); + ++nbAdded; + } } return nbAdded; @@ -3182,7 +4381,8 @@ namespace if ( firstIntPnt ) { hasLinks = true; - allLinksOut = ( firstIntPnt->_transition == Trans_OUT ); + allLinksOut = ( firstIntPnt->_transition == Trans_OUT && + !_grid->IsShared( firstIntPnt->_faceIDs[0] )); } } if ( hasLinks && allLinksOut ) @@ -3191,12 +4391,68 @@ namespace return false; } + //================================================================================ + /*! + * \brief Check if a polyherdon has an edge lying on EDGE shared by strange FACE + * that will be meshed by other algo + */ + bool Hexahedron::hasStrangeEdge() const + { + if ( _eIntPoints.size() < 2 ) + return false; + + TopTools_MapOfShape edges; + for ( size_t i = 0; i < _eIntPoints.size(); ++i ) + { + if ( !_grid->IsStrangeEdge( _eIntPoints[i]->_shapeID )) + continue; + const TopoDS_Shape& s = _grid->Shape( _eIntPoints[i]->_shapeID ); + if ( s.ShapeType() == TopAbs_EDGE ) + { + if ( ! edges.Add( s )) + return true; // an EDGE encounters twice + } + else + { + PShapeIteratorPtr edgeIt = _grid->_helper->GetAncestors( s, + *_grid->_helper->GetMesh(), + TopAbs_EDGE ); + while ( const TopoDS_Shape* edge = edgeIt->next() ) + if ( ! edges.Add( *edge )) + return true; // an EDGE encounters twice + } + } + return false; + } + //================================================================================ /*! * \brief Return true if a polyhedron passes _sizeThreshold criterion */ - bool Hexahedron::checkPolyhedronSize() const + bool Hexahedron::checkPolyhedronSize( bool cutByInternalFace ) const { + if ( cutByInternalFace && !_grid->_toUseThresholdForInternalFaces ) + { + // check if any polygon fully lies on shared/internal FACEs + for ( size_t iP = 0; iP < _polygons.size(); ++iP ) + { + const _Face& polygon = _polygons[iP]; + if ( polygon._links.empty() ) + continue; + bool allNodesInternal = true; + for ( size_t iL = 0; iL < polygon._links.size() && allNodesInternal; ++iL ) + { + _Node* n = polygon._links[ iL ].FirstNode(); + allNodesInternal = (( n->IsCutByInternal() ) || + ( n->_intPoint && _grid->IsAnyShared( n->_intPoint->_faceIDs ))); + } + if ( allNodesInternal ) + return true; + } + } + if ( this->hasStrangeEdge() ) + return true; + double volume = 0; for ( size_t iP = 0; iP < _polygons.size(); ++iP ) { @@ -3217,7 +4473,7 @@ namespace double initVolume = _sideLength[0] * _sideLength[1] * _sideLength[2]; - return volume > initVolume / _sizeThreshold; + return volume > initVolume / _grid->_sizeThreshold; } //================================================================================ /*! @@ -3263,7 +4519,7 @@ namespace } } if ( nbN == 8 ) - _volumeDefs.set( &nodes[0], 8 ); + _volumeDefs.Set( &nodes[0], 8 ); return nbN == 8; } @@ -3295,7 +4551,7 @@ namespace if ( tria->_links[i]._link == link ) { nodes[3] = tria->_links[(i+1)%3].LastNode(); - _volumeDefs.set( &nodes[0], 4 ); + _volumeDefs.Set( &nodes[0], 4 ); return true; } @@ -3340,7 +4596,7 @@ namespace } } if ( nbN == 6 ) - _volumeDefs.set( &nodes[0], 6 ); + _volumeDefs.Set( &nodes[0], 6 ); return ( nbN == 6 ); } @@ -3375,7 +4631,7 @@ namespace if ( tria->_links[i]._link == link ) { nodes[4] = tria->_links[(i+1)%3].LastNode(); - _volumeDefs.set( &nodes[0], 5 ); + _volumeDefs.Set( &nodes[0], 5 ); return true; } @@ -3408,6 +4664,467 @@ namespace ( _grid->_coords[2][ _k ] - _grid->_tol > uvw[2] ) || ( _grid->_coords[2][ _k+1 ] + _grid->_tol < uvw[2] )); } + //================================================================================ + /*! + * \brief Divide a polygon into triangles and modify accordingly an adjacent polyhedron + */ + void splitPolygon( const SMDS_MeshElement* polygon, + SMDS_VolumeTool & volume, + const int facetIndex, + const TGeomID faceID, + const TGeomID solidID, + SMESH_MeshEditor::ElemFeatures& face, + SMESH_MeshEditor& editor, + const bool reinitVolume) + { + SMESH_MeshAlgos::Triangulate divider(/*optimize=*/false); + int nbTrias = divider.GetTriangles( polygon, face.myNodes ); + face.myNodes.resize( nbTrias * 3 ); + + SMESH_MeshEditor::ElemFeatures newVolumeDef; + newVolumeDef.Init( volume.Element() ); + newVolumeDef.SetID( volume.Element()->GetID() ); + + newVolumeDef.myPolyhedQuantities.reserve( volume.NbFaces() + nbTrias ); + newVolumeDef.myNodes.reserve( volume.NbNodes() + nbTrias * 3 ); + + SMESHDS_Mesh* meshDS = editor.GetMeshDS(); + SMDS_MeshElement* newTriangle; + for ( int iF = 0, nF = volume.NbFaces(); iF < nF; iF++ ) + { + if ( iF == facetIndex ) + { + newVolumeDef.myPolyhedQuantities.push_back( 3 ); + newVolumeDef.myNodes.insert( newVolumeDef.myNodes.end(), + face.myNodes.begin(), + face.myNodes.begin() + 3 ); + meshDS->RemoveFreeElement( polygon, 0, false ); + newTriangle = meshDS->AddFace( face.myNodes[0], face.myNodes[1], face.myNodes[2] ); + meshDS->SetMeshElementOnShape( newTriangle, faceID ); + } + else + { + const SMDS_MeshNode** nn = volume.GetFaceNodes( iF ); + const size_t nbFaceNodes = volume.NbFaceNodes ( iF ); + newVolumeDef.myPolyhedQuantities.push_back( nbFaceNodes ); + newVolumeDef.myNodes.insert( newVolumeDef.myNodes.end(), nn, nn + nbFaceNodes ); + } + } + + for ( size_t iN = 3; iN < face.myNodes.size(); iN += 3 ) + { + newVolumeDef.myPolyhedQuantities.push_back( 3 ); + newVolumeDef.myNodes.insert( newVolumeDef.myNodes.end(), + face.myNodes.begin() + iN, + face.myNodes.begin() + iN + 3 ); + newTriangle = meshDS->AddFace( face.myNodes[iN], face.myNodes[iN+1], face.myNodes[iN+2] ); + meshDS->SetMeshElementOnShape( newTriangle, faceID ); + } + + meshDS->RemoveFreeElement( volume.Element(), 0, false ); + SMDS_MeshElement* newVolume = editor.AddElement( newVolumeDef.myNodes, newVolumeDef ); + meshDS->SetMeshElementOnShape( newVolume, solidID ); + + if ( reinitVolume ) + { + volume.Set( 0 ); + volume.Set( newVolume ); + } + return; + } + //================================================================================ + /*! + * \brief Create mesh faces at free facets + */ + void Hexahedron::addFaces( SMESH_MesherHelper& helper, + const vector< const SMDS_MeshElement* > & boundaryVolumes ) + { + if ( !_grid->_toCreateFaces ) + return; + + SMDS_VolumeTool vTool; + vector bndFacets; + SMESH_MeshEditor editor( helper.GetMesh() ); + SMESH_MeshEditor::ElemFeatures face( SMDSAbs_Face ); + SMESHDS_Mesh* meshDS = helper.GetMeshDS(); + + // check if there are internal or shared FACEs + bool hasInternal = ( !_grid->_geometry.IsOneSolid() || + _grid->_geometry._soleSolid.HasInternalFaces() ); + + for ( size_t iV = 0; iV < boundaryVolumes.size(); ++iV ) + { + if ( !vTool.Set( boundaryVolumes[ iV ])) + continue; + + TGeomID solidID = vTool.Element()->GetShapeID(); + Solid * solid = _grid->GetOneOfSolids( solidID ); + + // find boundary facets + + bndFacets.clear(); + for ( int iF = 0, n = vTool.NbFaces(); iF < n; iF++ ) + { + bool isBoundary = vTool.IsFreeFace( iF ); + if ( isBoundary ) + { + bndFacets.push_back( iF ); + } + else if ( hasInternal ) + { + // check if all nodes are on internal/shared FACEs + isBoundary = true; + const SMDS_MeshNode** nn = vTool.GetFaceNodes( iF ); + const size_t nbFaceNodes = vTool.NbFaceNodes ( iF ); + for ( size_t iN = 0; iN < nbFaceNodes && isBoundary; ++iN ) + isBoundary = ( nn[ iN ]->GetShapeID() != solidID ); + if ( isBoundary ) + bndFacets.push_back( -( iF+1 )); // !!! minus ==> to check the FACE + } + } + if ( bndFacets.empty() ) + continue; + + // create faces + + if ( !vTool.IsPoly() ) + vTool.SetExternalNormal(); + for ( size_t i = 0; i < bndFacets.size(); ++i ) // loop on boundary facets + { + const bool isBoundary = ( bndFacets[i] >= 0 ); + const int iFacet = isBoundary ? bndFacets[i] : -bndFacets[i]-1; + const SMDS_MeshNode** nn = vTool.GetFaceNodes( iFacet ); + const size_t nbFaceNodes = vTool.NbFaceNodes ( iFacet ); + face.myNodes.assign( nn, nn + nbFaceNodes ); + + TGeomID faceID = 0; + const SMDS_MeshElement* existFace = 0, *newFace = 0; + + if (( existFace = meshDS->FindElement( face.myNodes, SMDSAbs_Face ))) + { + if ( existFace->isMarked() ) + continue; // created by this method + faceID = existFace->GetShapeID(); + } + else + { + // look for a supporting FACE + for ( size_t iN = 0; iN < nbFaceNodes && !faceID; ++iN ) // look for a node on FACE + { + if ( nn[ iN ]->GetPosition()->GetDim() == 2 ) + faceID = nn[ iN ]->GetShapeID(); + } + for ( size_t iN = 0; iN < nbFaceNodes && !faceID; ++iN ) + { + // look for a father FACE of EDGEs and VERTEXes + const TopoDS_Shape& s1 = _grid->Shape( nn[ iN ]->GetShapeID() ); + const TopoDS_Shape& s2 = _grid->Shape( nn[ iN+1 ]->GetShapeID() ); + if ( s1 != s2 && s1.ShapeType() == TopAbs_EDGE && s2.ShapeType() == TopAbs_EDGE ) + { + TopoDS_Shape f = helper.GetCommonAncestor( s1, s2, *helper.GetMesh(), TopAbs_FACE ); + if ( !f.IsNull() ) + faceID = _grid->ShapeID( f ); + } + } + + bool toCheckFace = faceID && (( !isBoundary ) || + ( hasInternal && _grid->_toUseThresholdForInternalFaces )); + if ( toCheckFace ) // check if all nodes are on the found FACE + { + SMESH_subMesh* faceSM = helper.GetMesh()->GetSubMeshContaining( faceID ); + for ( size_t iN = 0; iN < nbFaceNodes && faceID; ++iN ) + { + TGeomID subID = nn[ iN ]->GetShapeID(); + if ( subID != faceID && !faceSM->DependsOn( subID )) + faceID = 0; + } + if ( !faceID && !isBoundary ) + continue; + } + } + // orient a new face according to supporting FACE orientation in shape_to_mesh + if ( !solid->IsOutsideOriented( faceID )) + { + if ( existFace ) + editor.Reorient( existFace ); + else + std::reverse( face.myNodes.begin(), face.myNodes.end() ); + } + + if ( ! ( newFace = existFace )) + { + face.SetPoly( nbFaceNodes > 4 ); + newFace = editor.AddElement( face.myNodes, face ); + if ( !newFace ) + continue; + newFace->setIsMarked( true ); // to distinguish from face created in getBoundaryElems() + } + + if ( faceID && _grid->IsBoundaryFace( faceID )) // face is not shared + { + // set newFace to the found FACE provided that it fully lies on the FACE + for ( size_t iN = 0; iN < nbFaceNodes && faceID; ++iN ) + if ( nn[iN]->GetShapeID() == solidID ) + { + if ( existFace ) + meshDS->UnSetMeshElementOnShape( existFace, _grid->Shape( faceID )); + faceID = 0; + } + } + + // split a polygon that will be used by other 3D algorithm + if ( faceID && nbFaceNodes > 4 && + !_grid->IsInternal( faceID ) && + !_grid->IsShared( faceID ) && + !_grid->IsBoundaryFace( faceID )) + { + splitPolygon( newFace, vTool, iFacet, faceID, solidID, + face, editor, i+1 < bndFacets.size() ); + } + else + { + if ( faceID ) + meshDS->SetMeshElementOnShape( newFace, faceID ); + else + meshDS->SetMeshElementOnShape( newFace, solidID ); + } + } // loop on bndFacets + } // loop on boundaryVolumes + + + // Orient coherently mesh faces on INTERNAL FACEs + + if ( hasInternal ) + { + TopExp_Explorer faceExp( _grid->_geometry._mainShape, TopAbs_FACE ); + for ( ; faceExp.More(); faceExp.Next() ) + { + if ( faceExp.Current().Orientation() != TopAbs_INTERNAL ) + continue; + + SMESHDS_SubMesh* sm = meshDS->MeshElements( faceExp.Current() ); + if ( !sm ) continue; + + TIDSortedElemSet facesToOrient; + for ( SMDS_ElemIteratorPtr fIt = sm->GetElements(); fIt->more(); ) + facesToOrient.insert( facesToOrient.end(), fIt->next() ); + if ( facesToOrient.size() < 2 ) + continue; + + gp_Dir direction(1,0,0); + const SMDS_MeshElement* anyFace = *facesToOrient.begin(); + editor.Reorient2D( facesToOrient, direction, anyFace ); + } + } + return; + } + + //================================================================================ + /*! + * \brief Create mesh segments. + */ + void Hexahedron::addSegments( SMESH_MesherHelper& helper, + const map< TGeomID, vector< TGeomID > >& edge2faceIDsMap ) + { + SMESHDS_Mesh* mesh = helper.GetMeshDS(); + + std::vector nodes; + std::vector elems; + map< TGeomID, vector< TGeomID > >::const_iterator e2ff = edge2faceIDsMap.begin(); + for ( ; e2ff != edge2faceIDsMap.end(); ++e2ff ) + { + const TopoDS_Edge& edge = TopoDS::Edge( _grid->Shape( e2ff->first )); + const TopoDS_Face& face = TopoDS::Face( _grid->Shape( e2ff->second[0] )); + StdMeshers_FaceSide side( face, edge, helper.GetMesh(), /*isFwd=*/true, /*skipMed=*/true ); + nodes = side.GetOrderedNodes(); + + elems.clear(); + if ( nodes.size() == 2 ) + // check that there is an element connecting two nodes + if ( !mesh->GetElementsByNodes( nodes, elems )) + continue; + + for ( size_t i = 1; i < nodes.size(); i++ ) + { + SMDS_MeshElement* segment = mesh->AddEdge( nodes[i-1], nodes[i] ); + mesh->SetMeshElementOnShape( segment, e2ff->first ); + } + } + return; + } + + //================================================================================ + /*! + * \brief Return created volumes and volumes that can have free facet because of + * skipped small volume. Also create mesh faces on free facets + * of adjacent not-cut volumes id the result volume is too small. + */ + void Hexahedron::getBoundaryElems( vector< const SMDS_MeshElement* > & boundaryElems ) + { + if ( _hasTooSmall /*|| _volumeDefs.IsEmpty()*/ ) + { + // create faces around a missing small volume + TGeomID faceID = 0; + SMESH_MeshEditor editor( _grid->_helper->GetMesh() ); + SMESH_MeshEditor::ElemFeatures polygon( SMDSAbs_Face ); + SMESHDS_Mesh* meshDS = _grid->_helper->GetMeshDS(); + std::vector adjVolumes(2); + for ( size_t iF = 0; iF < _polygons.size(); ++iF ) + { + const size_t nbLinks = _polygons[ iF ]._links.size(); + if ( nbLinks != 4 ) continue; + polygon.myNodes.resize( nbLinks ); + polygon.myNodes.back() = 0; + for ( size_t iL = 0, iN = nbLinks - 1; iL < nbLinks; ++iL, --iN ) + if ( ! ( polygon.myNodes[iN] = _polygons[ iF ]._links[ iL ].FirstNode()->Node() )) + break; + if ( !polygon.myNodes.back() ) + continue; + + meshDS->GetElementsByNodes( polygon.myNodes, adjVolumes, SMDSAbs_Volume ); + if ( adjVolumes.size() != 1 ) + continue; + if ( !adjVolumes[0]->isMarked() ) + { + boundaryElems.push_back( adjVolumes[0] ); + adjVolumes[0]->setIsMarked( true ); + } + + bool sameShape = true; + TGeomID shapeID = polygon.myNodes[0]->GetShapeID(); + for ( size_t i = 1; i < polygon.myNodes.size() && sameShape; ++i ) + sameShape = ( shapeID == polygon.myNodes[i]->GetShapeID() ); + + if ( !sameShape || !_grid->IsSolid( shapeID )) + continue; // some of shapes must be FACE + + if ( !faceID ) + { + faceID = getAnyFace(); + if ( !faceID ) + break; + if ( _grid->IsInternal( faceID ) || + _grid->IsShared( faceID ) || + _grid->IsBoundaryFace( faceID )) + break; // create only if a new face will be used by other 3D algo + } + + Solid * solid = _grid->GetOneOfSolids( adjVolumes[0]->GetShapeID() ); + if ( !solid->IsOutsideOriented( faceID )) + std::reverse( polygon.myNodes.begin(), polygon.myNodes.end() ); + + //polygon.SetPoly( polygon.myNodes.size() > 4 ); + const SMDS_MeshElement* newFace = editor.AddElement( polygon.myNodes, polygon ); + meshDS->SetMeshElementOnShape( newFace, faceID ); + } + } + + // return created volumes + for ( _volumeDef* volDef = &_volumeDefs; volDef; volDef = volDef->_next ) + { + if ( volDef->_volume && !volDef->_volume->isMarked() ) + { + volDef->_volume->setIsMarked( true ); + boundaryElems.push_back( volDef->_volume ); + + if ( _grid->IsToCheckNodePos() ) // un-mark nodes marked in addVolumes() + for ( size_t iN = 0; iN < volDef->_nodes.size(); ++iN ) + volDef->_nodes[iN].Node()->setIsMarked( false ); + } + } + } + + //================================================================================ + /*! + * \brief Set to _hexLinks a next portion of splits located on one side of INTERNAL FACEs + */ + bool Hexahedron::_SplitIterator::Next() + { + if ( _iterationNb > 0 ) + // count used splits + for ( size_t i = 0; i < _splits.size(); ++i ) + { + if ( _splits[i]._iCheckIteration == _iterationNb ) + { + _splits[i]._isUsed = _splits[i]._checkedSplit->_faces[1]; + _nbUsed += _splits[i]._isUsed; + } + if ( !More() ) + return false; + } + + ++_iterationNb; + + bool toTestUsed = ( _nbChecked >= _splits.size() ); + if ( toTestUsed ) + { + // all splits are checked; find all not used splits + for ( size_t i = 0; i < _splits.size(); ++i ) + if ( !_splits[i].IsCheckedOrUsed( toTestUsed )) + _splits[i]._iCheckIteration = _iterationNb; + + _nbUsed = _splits.size(); // to stop iteration + } + else + { + // get any not used/checked split to start from + _freeNodes.clear(); + for ( size_t i = 0; i < _splits.size(); ++i ) + { + if ( !_splits[i].IsCheckedOrUsed( toTestUsed )) + { + _freeNodes.push_back( _splits[i]._nodes[0] ); + _freeNodes.push_back( _splits[i]._nodes[1] ); + _splits[i]._iCheckIteration = _iterationNb; + break; + } + } + // find splits connected to the start one via _freeNodes + for ( size_t iN = 0; iN < _freeNodes.size(); ++iN ) + { + for ( size_t iS = 0; iS < _splits.size(); ++iS ) + { + if ( _splits[iS].IsCheckedOrUsed( toTestUsed )) + continue; + int iN2 = -1; + if ( _freeNodes[iN] == _splits[iS]._nodes[0] ) + iN2 = 1; + else if ( _freeNodes[iN] == _splits[iS]._nodes[1] ) + iN2 = 0; + else + continue; + if ( _freeNodes[iN]->_isInternalFlags > 0 ) + { + if ( _splits[iS]._nodes[ iN2 ]->_isInternalFlags == 0 ) + continue; + if ( !_splits[iS]._nodes[ iN2 ]->IsLinked( _freeNodes[iN]->_intPoint )) + continue; + } + _splits[iS]._iCheckIteration = _iterationNb; + _freeNodes.push_back( _splits[iS]._nodes[ iN2 ]); + } + } + } + // set splits to hex links + + for ( int iL = 0; iL < 12; ++iL ) + _hexLinks[ iL ]._splits.clear(); + + _Link split; + for ( size_t i = 0; i < _splits.size(); ++i ) + { + if ( _splits[i]._iCheckIteration == _iterationNb ) + { + split._nodes[0] = _splits[i]._nodes[0]; + split._nodes[1] = _splits[i]._nodes[1]; + _Link & hexLink = _hexLinks[ _splits[i]._linkID ]; + hexLink._splits.push_back( split ); + _splits[i]._checkedSplit = & hexLink._splits.back(); + ++_nbChecked; + } + } + return More(); + } //================================================================================ /*! @@ -3524,50 +5241,46 @@ bool StdMeshers_Cartesian_3D::Compute(SMESH_Mesh & theMesh, _computeCanceled = false; SMESH_MesherHelper helper( theMesh ); + SMESHDS_Mesh* meshDS = theMesh.GetMeshDS(); try { Grid grid; - grid._helper = &helper; + grid._helper = &helper; + grid._toAddEdges = _hyp->GetToAddEdges(); + grid._toCreateFaces = _hyp->GetToCreateFaces(); + grid._toConsiderInternalFaces = _hyp->GetToConsiderInternalFaces(); + grid._toUseThresholdForInternalFaces = _hyp->GetToUseThresholdForInternalFaces(); + grid._sizeThreshold = _hyp->GetSizeThreshold(); + grid.InitGeometry( theShape ); vector< TopoDS_Shape > faceVec; { TopTools_MapOfShape faceMap; TopExp_Explorer fExp; for ( fExp.Init( theShape, TopAbs_FACE ); fExp.More(); fExp.Next() ) - if ( !faceMap.Add( fExp.Current() )) - faceMap.Remove( fExp.Current() ); // remove a face shared by two solids - - for ( fExp.ReInit(); fExp.More(); fExp.Next() ) - if ( faceMap.Contains( fExp.Current() )) - faceVec.push_back( fExp.Current() ); + { + bool isNewFace = faceMap.Add( fExp.Current() ); + if ( !grid._toConsiderInternalFaces ) + if ( !isNewFace || fExp.Current().Orientation() == TopAbs_INTERNAL ) + // remove an internal face + faceMap.Remove( fExp.Current() ); + } + faceVec.reserve( faceMap.Extent() ); + faceVec.assign( faceMap.cbegin(), faceMap.cend() ); } vector facesItersectors( faceVec.size() ); - map< TGeomID, vector< TGeomID > > edge2faceIDsMap; - TopExp_Explorer eExp; Bnd_Box shapeBox; for ( size_t i = 0; i < faceVec.size(); ++i ) { - facesItersectors[i]._face = TopoDS::Face ( faceVec[i] ); - facesItersectors[i]._faceID = grid._shapes.Add( faceVec[i] ); + facesItersectors[i]._face = TopoDS::Face( faceVec[i] ); + facesItersectors[i]._faceID = grid.ShapeID( faceVec[i] ); facesItersectors[i]._grid = &grid; shapeBox.Add( facesItersectors[i].GetFaceBndBox() ); - - if ( _hyp->GetToAddEdges() ) - { - helper.SetSubShape( faceVec[i] ); - for ( eExp.Init( faceVec[i], TopAbs_EDGE ); eExp.More(); eExp.Next() ) - { - const TopoDS_Edge& edge = TopoDS::Edge( eExp.Current() ); - if ( !SMESH_Algo::isDegenerated( edge ) && - !helper.IsRealSeam( edge )) - edge2faceIDsMap[ grid._shapes.Add( edge )].push_back( facesItersectors[i]._faceID ); - } - } } - getExactBndBox( faceVec, _hyp->GetAxisDirs(), shapeBox ); + vector xCoords, yCoords, zCoords; _hyp->GetCoordinates( xCoords, yCoords, zCoords, shapeBox ); @@ -3581,7 +5294,7 @@ bool StdMeshers_Cartesian_3D::Compute(SMESH_Mesh & theMesh, BRepBuilderAPI_Copy copier; for ( size_t i = 0; i < facesItersectors.size(); ++i ) { - if ( !facesItersectors[i].IsThreadSafe(tshapes) ) + if ( !facesItersectors[i].IsThreadSafe( tshapes )) { copier.Perform( facesItersectors[i]._face ); facesItersectors[i]._face = TopoDS::Face( copier ); @@ -3603,33 +5316,36 @@ bool StdMeshers_Cartesian_3D::Compute(SMESH_Mesh & theMesh, for ( size_t i = 0; i < facesItersectors.size(); ++i ) facesItersectors[i].StoreIntersections(); - TopExp_Explorer solidExp (theShape, TopAbs_SOLID); - helper.SetSubShape( solidExp.Current() ); - helper.SetElementsOnShape( true ); - if ( _computeCanceled ) return false; // create nodes on the geometry - grid.ComputeNodes(helper); + grid.ComputeNodes( helper ); if ( _computeCanceled ) return false; + // get EDGEs to take into account + map< TGeomID, vector< TGeomID > > edge2faceIDsMap; + grid.GetEdgesToImplement( edge2faceIDsMap, theShape, faceVec ); + // create volume elements - Hexahedron hex( _hyp->GetSizeThreshold(), &grid ); + Hexahedron hex( &grid ); int nbAdded = hex.MakeElements( helper, edge2faceIDsMap ); - SMESHDS_Mesh* meshDS = theMesh.GetMeshDS(); if ( nbAdded > 0 ) { - // make all SOLIDs computed - if ( SMESHDS_SubMesh* sm1 = meshDS->MeshElements( solidExp.Current()) ) + if ( !grid._toConsiderInternalFaces ) { - SMDS_ElemIteratorPtr volIt = sm1->GetElements(); - for ( ; solidExp.More() && volIt->more(); solidExp.Next() ) + // make all SOLIDs computed + TopExp_Explorer solidExp( theShape, TopAbs_SOLID ); + if ( SMESHDS_SubMesh* sm1 = meshDS->MeshElements( solidExp.Current()) ) { - const SMDS_MeshElement* vol = volIt->next(); - sm1->RemoveElement( vol ); - meshDS->SetMeshElementOnShape( vol, solidExp.Current() ); + SMDS_ElemIteratorPtr volIt = sm1->GetElements(); + for ( ; solidExp.More() && volIt->more(); solidExp.Next() ) + { + const SMDS_MeshElement* vol = volIt->next(); + sm1->RemoveElement( vol ); + meshDS->SetMeshElementOnShape( vol, solidExp.Current() ); + } } } // make other sub-shapes computed @@ -3637,9 +5353,9 @@ bool StdMeshers_Cartesian_3D::Compute(SMESH_Mesh & theMesh, } // remove free nodes - if ( SMESHDS_SubMesh * smDS = meshDS->MeshElements( helper.GetSubShapeID() )) + //if ( SMESHDS_SubMesh * smDS = meshDS->MeshElements( helper.GetSubShapeID() )) { - TIDSortedNodeSet nodesToRemove; + std::vector< const SMDS_MeshNode* > nodesToRemove; // get intersection nodes for ( int iDir = 0; iDir < 3; ++iDir ) { @@ -3648,19 +5364,25 @@ bool StdMeshers_Cartesian_3D::Compute(SMESH_Mesh & theMesh, { multiset< F_IntersectPoint >::iterator ip = lines[i]._intPoints.begin(); for ( ; ip != lines[i]._intPoints.end(); ++ip ) - if ( ip->_node && ip->_node->NbInverseElements() == 0 ) - nodesToRemove.insert( nodesToRemove.end(), ip->_node ); + if ( ip->_node && ip->_node->NbInverseElements() == 0 && !ip->_node->isMarked() ) + { + nodesToRemove.push_back( ip->_node ); + ip->_node->setIsMarked( true ); + } } } // get grid nodes for ( size_t i = 0; i < grid._nodes.size(); ++i ) - if ( grid._nodes[i] && grid._nodes[i]->NbInverseElements() == 0 ) - nodesToRemove.insert( nodesToRemove.end(), grid._nodes[i] ); + if ( grid._nodes[i] && grid._nodes[i]->NbInverseElements() == 0 && + !grid._nodes[i]->isMarked() ) + { + nodesToRemove.push_back( grid._nodes[i] ); + grid._nodes[i]->setIsMarked( true ); + } // do remove - TIDSortedNodeSet::iterator n = nodesToRemove.begin(); - for ( ; n != nodesToRemove.end(); ++n ) - meshDS->RemoveFreeNode( *n, smDS, /*fromGroups=*/false ); + for ( size_t i = 0; i < nodesToRemove.size(); ++i ) + meshDS->RemoveFreeNode( nodesToRemove[i], /*smD=*/0, /*fromGroups=*/false ); } return nbAdded; @@ -3795,4 +5517,3 @@ void StdMeshers_Cartesian_3D::setSubmeshesComputed(SMESH_Mesh& theMesh, for ( TopExp_Explorer soExp( theShape, TopAbs_SOLID ); soExp.More(); soExp.Next() ) _EventListener::setAlwaysComputed( true, theMesh.GetSubMesh( soExp.Current() )); } - diff --git a/src/StdMeshers/StdMeshers_FaceSide.cxx b/src/StdMeshers/StdMeshers_FaceSide.cxx index 455af191c..6c6d4c2be 100644 --- a/src/StdMeshers/StdMeshers_FaceSide.cxx +++ b/src/StdMeshers/StdMeshers_FaceSide.cxx @@ -665,7 +665,7 @@ std::vector StdMeshers_FaceSide::GetOrderedNodes(int theEd iE = theEdgeInd % NbEdges(); iEnd = iE + 1; } - for ( iE = 0; iE < iEnd; ++iE ) + for ( ; iE < iEnd; ++iE ) { double prevNormPar = ( iE == 0 ? 0 : myNormPar[ iE-1 ]); // normalized param diff --git a/src/StdMeshers/StdMeshers_Geometric1D.cxx b/src/StdMeshers/StdMeshers_Geometric1D.cxx index 8de8c92d2..e8d9eaea6 100644 --- a/src/StdMeshers/StdMeshers_Geometric1D.cxx +++ b/src/StdMeshers/StdMeshers_Geometric1D.cxx @@ -114,7 +114,7 @@ double StdMeshers_Geometric1D::GetCommonRatio() const */ //============================================================================= -ostream & StdMeshers_Geometric1D::SaveTo(ostream & save) +std::ostream & StdMeshers_Geometric1D::SaveTo(std::ostream & save) { save << _begLength << " " << _ratio << " "; @@ -129,7 +129,7 @@ ostream & StdMeshers_Geometric1D::SaveTo(ostream & save) */ //============================================================================= -istream & StdMeshers_Geometric1D::LoadFrom(istream & load) +std::istream & StdMeshers_Geometric1D::LoadFrom(std::istream & load) { bool isOK = true; isOK = static_cast(load >> _begLength); diff --git a/src/StdMeshers/StdMeshers_PolygonPerFace_2D.cxx b/src/StdMeshers/StdMeshers_PolygonPerFace_2D.cxx index c8d203d12..76afc6a0c 100644 --- a/src/StdMeshers/StdMeshers_PolygonPerFace_2D.cxx +++ b/src/StdMeshers/StdMeshers_PolygonPerFace_2D.cxx @@ -37,15 +37,15 @@ #include #include +#include #include -#include using namespace std; //======================================================================= //function : StdMeshers_PolygonPerFace_2D -//purpose : +//purpose : //======================================================================= StdMeshers_PolygonPerFace_2D::StdMeshers_PolygonPerFace_2D(int hypId, diff --git a/src/StdMeshers/StdMeshers_PolyhedronPerSolid_3D.cxx b/src/StdMeshers/StdMeshers_PolyhedronPerSolid_3D.cxx new file mode 100644 index 000000000..6695eea7b --- /dev/null +++ b/src/StdMeshers/StdMeshers_PolyhedronPerSolid_3D.cxx @@ -0,0 +1,618 @@ +// Copyright (C) 2007-2019 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// File : StdMeshers_PolyhedronPerSolid_3D.cxx +// Module : SMESH +// Created : Fri Oct 20 11:37:07 2006 +// Author : Edward AGAPOV (eap) +// +#include "StdMeshers_PolyhedronPerSolid_3D.hxx" + +#include "SMESHDS_Mesh.hxx" +#include "SMESH_ControlsDef.hxx" +#include "SMESH_Gen.hxx" +#include "SMESH_Mesh.hxx" +#include "SMESH_MeshAlgos.hxx" +#include "SMESH_MeshEditor.hxx" +#include "SMESH_MesherHelper.hxx" +#include "SMESH_ProxyMesh.hxx" +#include "SMESH_subMesh.hxx" +#include "StdMeshers_PolygonPerFace_2D.hxx" +#include "StdMeshers_Regular_1D.hxx" +#include "StdMeshers_ViscousLayers.hxx" + +#include + +#include +#include + +namespace +{ + struct _EdgeMesher : public StdMeshers_Regular_1D + { + _EdgeMesher( int hypId, SMESH_Gen* gen ) + : StdMeshers_Regular_1D( hypId, gen ) + { + _hypType = NB_SEGMENTS; + _ivalue[ NB_SEGMENTS_IND ] = 1; + } + }; + + //======================================================================= + //function : addHexa + //purpose : + //======================================================================= + + const SMDS_MeshElement* addHexa( std::vector< const SMDS_MeshElement* >& faces, + const std::vector< int > & quantities, + SMESH_MesherHelper & helper ) + { + const SMDS_MeshElement* newHexa = 0; + + // check nb of nodes in faces + for ( size_t i = 0; i < quantities.size(); ++i ) + if ( quantities[ i ] != 4 ) + return newHexa; + + // look for a top face + const SMDS_MeshElement* topFace = 0; + const SMDS_MeshElement* botFace = faces[0]; + std::vector< const SMDS_MeshNode* > nodes( 16 ); // last 8 is a working buffer + nodes.assign( botFace->begin_nodes(), botFace->end_nodes() ); + for ( size_t iF = 1; iF < faces.size() && !topFace; ++iF ) + { + bool hasCommonNode = false; + for ( int iN = 0; iN < quantities[ 0 ] && !hasCommonNode; ++iN ) + hasCommonNode = ( faces[ iF ]->GetNodeIndex( nodes[ iN ]) >= 0 ); + + if ( !hasCommonNode ) + topFace = faces[ iF ]; + } + + nodes.resize( 8 ); // set top nodes after hexa nodes - [8-11] + nodes.insert( nodes.end(), topFace->begin_nodes(), topFace->end_nodes() ); + nodes.resize( 12 ); + nodes.insert( nodes.end(), nodes.begin() + 8, nodes.begin() + 12 ); + + // find corresponding nodes of top and bottom by finding a side face including 2 node of each + SMESHDS_Mesh* mesh = helper.GetMeshDS(); + const SMDS_MeshElement* sideFace = 0; + size_t i; + for ( i = 8; i < nodes.size()-1 && !sideFace; ++i ) + { + sideFace = mesh->FindFace( nodes[0], nodes[1], nodes[ i ], nodes[ i + 1 ]); + } + if ( !sideFace ) + return newHexa; + + --i; // restore after ++i in the loop + bool botOriRight = SMESH_MeshAlgos::IsRightOrder( sideFace, nodes[ 0 ], nodes[ 1 ] ); + bool topOriRight = SMESH_MeshAlgos::IsRightOrder( sideFace, nodes[ i ], nodes[ i + 1 ] ); + if ( botOriRight == topOriRight ) + { + nodes[ 4 ] = nodes[ i + 1 ]; + nodes[ 5 ] = nodes[ i + 0 ]; + nodes[ 6 ] = nodes[ i + 3 ]; + nodes[ 7 ] = nodes[ i + 2 ]; + } + else + { + nodes[ 4 ] = nodes[ i + 0 ]; + nodes[ 5 ] = nodes[ i + 1 ]; + nodes[ 6 ] = nodes[ i + 2 ]; + nodes[ 7 ] = nodes[ i + 3 ]; + } + + newHexa = helper.AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ], + nodes[ 4 ], nodes[ 5 ], nodes[ 6 ], nodes[ 7 ]); + + return newHexa; + } + + //======================================================================= + //function : addTetra + //purpose : + //======================================================================= + + const SMDS_MeshElement* addTetra( std::vector< const SMDS_MeshElement* >& faces, + const std::vector< int > & quantities, + SMESH_MesherHelper & helper ) + { + const SMDS_MeshElement* newTetra = 0; + + // check nb of nodes in faces + for ( size_t i = 0; i < quantities.size(); ++i ) + if ( quantities[ i ] != 3 ) + return newTetra; + + const SMDS_MeshElement* botFace = faces[0]; + + std::vector< const SMDS_MeshNode* > nodes( 6 ); + nodes.assign( botFace->begin_nodes(), botFace->end_nodes() ); + nodes.resize( 3 ); + + const SMDS_MeshNode* topNode = 0; + for ( size_t i = 0; i < 3 && !topNode; ++i ) + { + topNode = faces[ 1 ]->GetNode( i ); + if ( botFace->GetNodeIndex( topNode ) >= 0 ) + topNode = 0; + } + if ( !topNode ) + return newTetra; + + nodes.push_back( topNode ); + + newTetra = helper.AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]); + + return newTetra; + } + + //======================================================================= + //function : addPenta + //purpose : + //======================================================================= + + const SMDS_MeshElement* addPenta( std::vector< const SMDS_MeshElement* >& faces, + const std::vector< int > & quantities, + SMESH_MesherHelper & helper ) + { + const SMDS_MeshElement* newPenta = 0; + + // check nb of nodes in faces and find triangle faces + int trias[2] = { -1, -1 }; + for ( size_t i = 0; i < quantities.size(); ++i ) + if ( quantities[ i ] != 4 ) + { + if ( quantities[ i ] != 3 ) + return newPenta; + int iTria = ( trias[0] != -1 ); + if ( trias[ iTria ] != -1 ) + return newPenta; + trias[ iTria ] = i; + } + if ( trias[1] == -1 ) + return newPenta; + + int iSide = trias[0] + 1; + if ( iSide == trias[1] ) + ++iSide; + + const SMDS_MeshElement* botFace = faces[ trias[0]]; + const SMDS_MeshElement* topFace = faces[ trias[1]]; + const SMDS_MeshElement* sideFace = faces[ iSide ]; + const SMDS_MeshNode* nodes[ 6 ] = { 0,0,0,0,0,0 }; + for ( int i = 0 ; i < 3; ++i ) + { + const SMDS_MeshNode* botNode = botFace->GetNode( i ); + if ( sideFace->GetNodeIndex( botNode ) < 0 ) + nodes[2] = botNode; + else + nodes[ bool( nodes[0] )] = botNode; + + const SMDS_MeshNode* topNode = topFace->GetNode( i ); + if ( sideFace->GetNodeIndex( topNode ) < 0 ) + nodes[5] = topNode; + else + nodes[ 3 + bool( nodes[3]) ] = topNode; + } + bool botOriRight = SMESH_MeshAlgos::IsRightOrder( sideFace, nodes[ 0 ], nodes[ 1 ]); + bool topOriRight = SMESH_MeshAlgos::IsRightOrder( sideFace, nodes[ 3 ], nodes[ 4 ]); + if ( botOriRight == topOriRight ) + std::swap( nodes[ 3 ], nodes[ 4 ]); + + newPenta = helper.AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], + nodes[ 3 ], nodes[ 4 ], nodes[ 5 ]); + + return newPenta; + } + + //======================================================================= + //function : addPyra + //purpose : + //======================================================================= + + const SMDS_MeshElement* addPyra( std::vector< const SMDS_MeshElement* >& faces, + const std::vector< int > & quantities, + SMESH_MesherHelper & helper ) + { + const SMDS_MeshElement* newPyra = 0; + + // check nb of nodes in faces + int iBot = -1; + for ( size_t i = 0; i < quantities.size(); ++i ) + if ( quantities[ i ] != 3 ) + { + if ( quantities[ i ] != 4 || iBot != -1 ) + return newPyra; + iBot = i; + } + + const SMDS_MeshElement* botFace = faces[ iBot ]; + + std::vector< const SMDS_MeshNode* > nodes( 8 ); + nodes.assign( botFace->begin_nodes(), botFace->end_nodes() ); + nodes.resize( 4 ); + + const SMDS_MeshNode* topNode = 0; + for ( size_t i = 0; i < 4 && !topNode; ++i ) + { + topNode = faces[ 1 ]->GetNode( i ); + if ( botFace->GetNodeIndex( topNode ) >= 0 ) + topNode = 0; + } + if ( !topNode ) + return newPyra; + + nodes.push_back( topNode ); + + newPyra = helper.AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ], nodes[4] ); + + return newPyra; + } + + //======================================================================= + //function : addHPrism + //purpose : add hexagonal prism + //======================================================================= + + const SMDS_MeshElement* addHPrism( std::vector< const SMDS_MeshElement* >& faces, + const std::vector< int > & quantities, + SMESH_MesherHelper & helper ) + { + const SMDS_MeshElement* newHexPrism = 0; + + // check nb of nodes in faces and find hexagons + int hexa[2] = { -1, -1 }; + for ( size_t i = 0; i < quantities.size(); ++i ) + if ( quantities[ i ] != 4 ) + { + if ( quantities[ i ] != 6 ) + return newHexPrism; + int iHex = ( hexa[0] != -1 ); + if ( hexa[ iHex ] != -1 ) + return newHexPrism; + hexa[ iHex ] = i; + } + if ( hexa[1] == -1 ) + return newHexPrism; + + int iSide = hexa[0] + 1; + if ( iSide == hexa[1] ) + ++iSide; + + const SMDS_MeshElement* botFace = faces[ hexa[ 0 ]]; + const SMDS_MeshElement* topFace = faces[ hexa[ 1 ]]; + std::vector< const SMDS_MeshNode* > nodes( 24 ); // last 12 is a working buffer + + nodes.assign( botFace->begin_nodes(), botFace->end_nodes() ); + nodes.resize( 12 ); // set top nodes after hexa nodes - [12-17] + nodes.insert( nodes.end(), topFace->begin_nodes(), topFace->end_nodes() ); + nodes.resize( 18 ); + nodes.insert( nodes.end(), nodes.begin() + 12, nodes.begin() + 18 ); + + // find corresponding nodes of top and bottom by finding a side face including 2 node of each + SMESHDS_Mesh* mesh = helper.GetMeshDS(); + const SMDS_MeshElement* sideFace = 0; + size_t i; + for ( i = 12; i < nodes.size()-1 && !sideFace; ++i ) + { + sideFace = mesh->FindFace( nodes[0], nodes[1], nodes[ i ], nodes[ i + 1 ]); + } + if ( !sideFace ) + return newHexPrism; + + --i; // restore after ++i in the loop + bool botOriRight = SMESH_MeshAlgos::IsRightOrder( sideFace, nodes[ 0 ], nodes[ 1 ] ); + bool topOriRight = SMESH_MeshAlgos::IsRightOrder( sideFace, nodes[ i ], nodes[ i + 1 ] ); + if ( botOriRight == topOriRight ) + { + nodes[ 6 ] = nodes[ i + 1 ]; + nodes[ 7 ] = nodes[ i + 0 ]; + nodes[ 8 ] = nodes[ i + 5 ]; + nodes[ 9 ] = nodes[ i + 4 ]; + nodes[ 10 ] = nodes[ i + 3 ]; + nodes[ 11 ] = nodes[ i + 2 ]; + } + else + { + nodes[ 6 ] = nodes[ i + 0 ]; + nodes[ 7 ] = nodes[ i + 1 ]; + nodes[ 8 ] = nodes[ i + 2 ]; + nodes[ 9 ] = nodes[ i + 3 ]; + nodes[ 10 ] = nodes[ i + 4 ]; + nodes[ 11 ] = nodes[ i + 5 ]; + } + + newHexPrism = helper.AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], + nodes[ 3 ], nodes[ 4 ], nodes[ 5 ], + nodes[ 6 ], nodes[ 7 ], nodes[ 8 ], + nodes[ 9 ], nodes[10 ], nodes[11 ]); + + return newHexPrism; + } + + //======================================================================= + //function : addPoly + //purpose : + //======================================================================= + + const SMDS_MeshElement* addPoly( std::vector< const SMDS_MeshElement* >& faces, + const std::vector< int > & quantities, + SMESH_MesherHelper & helper ) + { + const SMDS_MeshElement* newPoly = 0; + + std::vector< const SMDS_MeshNode* > nodes; + for ( size_t iF = 0; iF < faces.size(); ++iF ) + nodes.insert( nodes.end(), faces[iF]->begin_nodes(), faces[iF]->end_nodes() ); + + newPoly = helper.AddPolyhedralVolume( nodes, quantities ); + + return newPoly; + } + +} // namespace + +//======================================================================= +//function : StdMeshers_PolyhedronPerSolid_3D +//purpose : +//======================================================================= + +StdMeshers_PolyhedronPerSolid_3D::StdMeshers_PolyhedronPerSolid_3D(int hypId, + SMESH_Gen* gen) + :SMESH_3D_Algo(hypId, gen), + myEdgeMesher( new _EdgeMesher( gen->GetANewId(), gen )), + myFaceMesher( new StdMeshers_PolygonPerFace_2D( gen->GetANewId(), gen )) +{ + _name = "PolyhedronPerSolid_3D"; + _requireDiscreteBoundary = false; + _supportSubmeshes = true; + _compatibleHypothesis.push_back("ViscousLayers"); + _neededLowerHyps[0] = _neededLowerHyps[1] = _neededLowerHyps[2] = true; +} + +//======================================================================= +//function : ~StdMeshers_PolyhedronPerSolid_3D +//purpose : +//======================================================================= + +StdMeshers_PolyhedronPerSolid_3D::~StdMeshers_PolyhedronPerSolid_3D() +{ + delete myEdgeMesher; + delete myFaceMesher; +} + +//======================================================================= +//function : CheckHypothesis +//purpose : +//======================================================================= + +bool StdMeshers_PolyhedronPerSolid_3D::CheckHypothesis(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape, + Hypothesis_Status& theStatus) +{ + myViscousLayersHyp = NULL; + + const std::list& hyps = + GetUsedHypothesis( theMesh, theShape, /*ignoreAuxiliary=*/false); + std::list ::const_iterator h = hyps.begin(); + if ( h == hyps.end()) + { + theStatus = SMESH_Hypothesis::HYP_OK; + return true; + } + + // only StdMeshers_ViscousLayers can be used + theStatus = HYP_OK; + for ( ; h != hyps.end(); ++h ) + { + if ( !(myViscousLayersHyp = dynamic_cast< const StdMeshers_ViscousLayers*> ( *h ))) + break; + } + if ( !myViscousLayersHyp ) + theStatus = HYP_INCOMPATIBLE; + else + error( myViscousLayersHyp->CheckHypothesis( theMesh, theShape, theStatus )); + + return theStatus == HYP_OK; +} + +//======================================================================= +//function : Compute +//purpose : +//======================================================================= + +bool StdMeshers_PolyhedronPerSolid_3D::Compute(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape) +{ + const SMDS_MeshElement* newVolume = 0; + + SMESH_subMesh* sm = theMesh.GetSubMesh( theShape ); + SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator( /*includeSelf=*/true, + /*complexFirst=*/false); + while ( smIt->more() ) + { + sm = smIt->next(); + if ( !sm->IsEmpty() ) + continue; + + const TopoDS_Shape & shape = sm->GetSubShape(); + switch ( shape.ShapeType() ) + { + case TopAbs_VERTEX: + sm->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + break; + + case TopAbs_EDGE: + sm->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + if ( sm->IsEmpty() ) + myEdgeMesher->Compute( theMesh, shape ); + break; + + case TopAbs_FACE: + sm->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + if ( sm->IsEmpty() && !myFaceMesher->Compute( theMesh, shape )) + { + sm->GetComputeError() = myFaceMesher->GetComputeError(); + sm->GetComputeError()->myAlgo = myFaceMesher; + return false; + } + break; + + case TopAbs_SOLID: + { + SMESH_MesherHelper helper( theMesh ); + helper.SetElementsOnShape( true ); + _quadraticMesh = helper.IsQuadraticSubMesh( shape ); + + SMESH_ProxyMesh::Ptr proxymesh( new SMESH_ProxyMesh( theMesh )); + if ( myViscousLayersHyp ) + { + proxymesh = myViscousLayersHyp->Compute( theMesh, theShape ); + if ( !proxymesh ) + return false; + } + + std::vector< const SMDS_MeshElement* > faces; + faces.reserve( 20 ); + + for ( TopExp_Explorer faceEx( shape, TopAbs_FACE ); faceEx.More(); faceEx.Next() ) + { + const SMESHDS_SubMesh* smDS = proxymesh->GetSubMesh( faceEx.Current() ); + for ( SMDS_ElemIteratorPtr faceIt = smDS->GetElements(); faceIt->more(); ) + faces.push_back( faceIt->next() ); + } + + bool useMediumNodes = false; + if ( !_quadraticMesh && theMesh.GetMeshDS()->GetMeshInfo().NbFaces( ORDER_QUADRATIC )) + for ( size_t i = 0; i < faces.size() && !useMediumNodes ; ++i ) + useMediumNodes = faces[ i ]->IsQuadratic(); + + std::vector< int > quantities( faces.size() ); + std::set< const SMDS_MeshNode* > nodes; + for ( size_t i = 0; i < faces.size(); ++i ) + { + quantities[ i ] = useMediumNodes ? faces[ i ]->NbNodes() : faces[ i ]->NbCornerNodes(); + for ( int iN = 0; iN < quantities[ i ]; ++iN ) + nodes.insert( faces[ i ]->GetNode( iN )); + } + + const size_t nbNodes = nodes.size(), nbFaces = faces.size(); + if ( nbNodes == 8 && nbFaces == 6 ) newVolume = addHexa ( faces, quantities, helper ); + else if ( nbNodes == 4 && nbFaces == 4 ) newVolume = addTetra ( faces, quantities, helper ); + else if ( nbNodes == 6 && nbFaces == 5 ) newVolume = addPenta ( faces, quantities, helper ); + else if ( nbNodes == 5 && nbFaces == 5 ) newVolume = addPyra ( faces, quantities, helper ); + else if ( nbNodes == 12 && nbFaces == 8 ) newVolume = addHPrism( faces, quantities, helper ); + if ( !newVolume ) + newVolume = addPoly ( faces, quantities, helper ); + + if ( newVolume ) + { + SMESH::Controls::BadOrientedVolume checker; + checker.SetMesh( theMesh.GetMeshDS() ); + if ( checker.IsSatisfy( newVolume->GetID() )) + { + SMESH_MeshEditor editor( &theMesh ); + editor.Reorient( newVolume ); + } + } + } + default:; + + } // switch ( shape.ShapeType() ) + } // loop on sub-meshes + + return newVolume; +} + +//======================================================================= +//function : Evaluate +//purpose : +//======================================================================= + +bool StdMeshers_PolyhedronPerSolid_3D::Evaluate(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape, + MapShapeNbElems& theResMap) +{ + _quadraticMesh = false; + + SMESH_subMesh* sm = theMesh.GetSubMesh( theShape ); + SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator( /*includeSelf=*/true, + /*complexFirst=*/false); + while ( smIt->more() ) + { + sm = smIt->next(); + + MapShapeNbElems::iterator sm2vec = theResMap.find( sm ); + if ( sm2vec != theResMap.end() && !sm2vec->second.empty() ) + continue; + + const TopoDS_Shape & shape = sm->GetSubShape(); + switch ( shape.ShapeType() ) + { + case TopAbs_EDGE: + myEdgeMesher->Evaluate( theMesh, shape, theResMap ); + break; + + case TopAbs_FACE: + { + myFaceMesher->Evaluate( theMesh, shape, theResMap ); + std::vector & quantities = theResMap[ sm ]; + _quadraticMesh = ( !quantities.empty() && + ( quantities[ SMDSEntity_Quad_Triangle ] + + quantities[ SMDSEntity_Quad_Quadrangle ] + + quantities[ SMDSEntity_Quad_Polygon ])); + break; + } + + case TopAbs_SOLID: + { + std::vector & quantities = theResMap[ sm ]; + quantities.resize( SMDSEntity_Last, 0 ); + + SMESH_MesherHelper helper( theMesh ); + const int nbNodes = helper.Count( shape, TopAbs_VERTEX, /*ignoreSame=*/true ); + const int nbFaces = helper.Count( shape, TopAbs_FACE, /*ignoreSame=*/false ); + + if ( nbNodes == 8 && nbFaces == 6 ) + quantities[ _quadraticMesh ? SMDSEntity_Quad_Hexa : SMDSEntity_Hexa ] = 1; + else if ( nbNodes == 4 && nbFaces == 4 ) + quantities[ _quadraticMesh ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ] = 1; + else if ( nbNodes == 6 && nbFaces == 5 ) + quantities[ _quadraticMesh ? SMDSEntity_Quad_Penta : SMDSEntity_Penta ] = 1; + else if ( nbNodes == 5 && nbFaces == 5 ) + quantities[ _quadraticMesh ? SMDSEntity_Quad_Pyramid : SMDSEntity_Pyramid ] = 1; + else if ( nbNodes == 12 && nbFaces == 8 ) + quantities[ /*_quadraticMesh ? SMDSEntity_Quad_Pyramid :*/ SMDSEntity_Hexagonal_Prism ] = 1; + else + quantities[ /*_quadraticMesh ? SMDSEntity_Quad_Polyhedra : */SMDSEntity_Polyhedra ] = 1; + + return true; + } + default:; + + } // switch ( shape.ShapeType() ) + } // loop on sub-meshes + + return false; +} diff --git a/src/StdMeshers/StdMeshers_PolyhedronPerSolid_3D.hxx b/src/StdMeshers/StdMeshers_PolyhedronPerSolid_3D.hxx new file mode 100644 index 000000000..f6296aa18 --- /dev/null +++ b/src/StdMeshers/StdMeshers_PolyhedronPerSolid_3D.hxx @@ -0,0 +1,58 @@ +// Copyright (C) 2007-2019 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// File : StdMeshers_PolyhedronPerSolid_3D.hxx +// Module : SMESH +// +#ifndef _SMESH_PolyhedronPerSolid_3D_HXX_ +#define _SMESH_PolyhedronPerSolid_3D_HXX_ + +#include "SMESH_StdMeshers.hxx" +#include "SMESH_Algo.hxx" + +class StdMeshers_Regular_1D; +class StdMeshers_PolygonPerFace_2D; +class StdMeshers_ViscousLayers; + +class STDMESHERS_EXPORT StdMeshers_PolyhedronPerSolid_3D: public SMESH_3D_Algo +{ + public: + StdMeshers_PolyhedronPerSolid_3D(int hypId, SMESH_Gen* gen); + ~StdMeshers_PolyhedronPerSolid_3D(); + + virtual bool CheckHypothesis(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + SMESH_Hypothesis::Hypothesis_Status& aStatus); + + virtual bool Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape); + + virtual bool Evaluate(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, + MapShapeNbElems& aResMap); + + private: + + StdMeshers_Regular_1D* myEdgeMesher; + StdMeshers_PolygonPerFace_2D* myFaceMesher; + const StdMeshers_ViscousLayers* myViscousLayersHyp; +}; + +#endif diff --git a/src/StdMeshers/StdMeshers_Regular_1D.cxx b/src/StdMeshers/StdMeshers_Regular_1D.cxx index 12619c94f..45e1c25b6 100644 --- a/src/StdMeshers/StdMeshers_Regular_1D.cxx +++ b/src/StdMeshers/StdMeshers_Regular_1D.cxx @@ -974,6 +974,8 @@ bool StdMeshers_Regular_1D::computeInternalParameters(SMESH_Mesh & theMesh, an = eltSize; eltSize *= q; ++nbParams; + if ( q < 1. && eltSize < 1e-100 ) + return error("Too small common ratio causes too many segments"); } if ( nbParams > 1 ) { diff --git a/src/StdMeshers/StdMeshers_ViscousLayers.cxx b/src/StdMeshers/StdMeshers_ViscousLayers.cxx index 31669f15c..270330be4 100644 --- a/src/StdMeshers/StdMeshers_ViscousLayers.cxx +++ b/src/StdMeshers/StdMeshers_ViscousLayers.cxx @@ -23,6 +23,7 @@ #include "StdMeshers_ViscousLayers.hxx" +#include "ObjectPool.hxx" #include "SMDS_EdgePosition.hxx" #include "SMDS_FaceOfNodes.hxx" #include "SMDS_FacePosition.hxx" @@ -33,6 +34,7 @@ #include "SMESHDS_Hypothesis.hxx" #include "SMESHDS_Mesh.hxx" #include "SMESH_Algo.hxx" +#include "SMESH_Block.hxx" #include "SMESH_ComputeError.hxx" #include "SMESH_ControlsDef.hxx" #include "SMESH_Gen.hxx" @@ -40,12 +42,13 @@ #include "SMESH_HypoFilter.hxx" #include "SMESH_Mesh.hxx" #include "SMESH_MeshAlgos.hxx" +#include "SMESH_MeshEditor.hxx" #include "SMESH_MesherHelper.hxx" #include "SMESH_ProxyMesh.hxx" #include "SMESH_subMesh.hxx" -#include "SMESH_MeshEditor.hxx" #include "SMESH_subMeshEventListener.hxx" #include "StdMeshers_FaceSide.hxx" +#include "StdMeshers_ProjectionUtils.hxx" #include "StdMeshers_ViscousLayers2D.hxx" #include @@ -372,22 +375,7 @@ namespace VISCOUS_3D double _h2lenRatio; // avgNormProj / (2*avgDist) gp_Pnt2d _uv; // UV used in putOnOffsetSurface() public: - static _Curvature* New( double avgNormProj, double avgDist ) - { - _Curvature* c = 0; - if ( fabs( avgNormProj / avgDist ) > 1./200 ) - { - c = new _Curvature; - c->_r = avgDist * avgDist / avgNormProj; - c->_k = avgDist * avgDist / c->_r / c->_r; - //c->_k = avgNormProj / c->_r; - c->_k *= ( c->_r < 0 ? 1/1.1 : 1.1 ); // not to be too restrictive - c->_h2lenRatio = avgNormProj / ( avgDist + avgDist ); - - c->_uv.SetCoord( 0., 0. ); - } - return c; - } + static _Curvature* New( double avgNormProj, double avgDist ); double lenDelta(double len) const { return _k * ( _r + len ); } double lenDeltaByDist(double dist) const { return dist * _h2lenRatio; } }; @@ -583,6 +571,7 @@ namespace VISCOUS_3D gp_XYZ* _plnNorm; _2NearEdges() { _edges[0]=_edges[1]=0; _plnNorm = 0; } + ~_2NearEdges(){ delete _plnNorm; } const SMDS_MeshNode* tgtNode(bool is2nd) { return _edges[is2nd] ? _edges[is2nd]->_nodes.back() : 0; } @@ -623,12 +612,16 @@ namespace VISCOUS_3D _thickness = Max( _thickness, hyp->GetTotalThickness() ); _stretchFactor += hyp->GetStretchFactor(); _method = hyp->GetMethod(); + if ( _groupName.empty() ) + _groupName = hyp->GetGroupName(); } } double GetTotalThickness() const { return _thickness; /*_nbHyps ? _thickness / _nbHyps : 0;*/ } double GetStretchFactor() const { return _nbHyps ? _stretchFactor / _nbHyps : 0; } int GetNumberLayers() const { return _nbLayers; } int GetMethod() const { return _method; } + bool ToCreateGroup() const { return !_groupName.empty(); } + const std::string& GetGroupName() const { return _groupName; } bool UseSurfaceNormal() const { return _method == StdMeshers_ViscousLayers::SURF_OFFSET_SMOOTH; } @@ -637,9 +630,19 @@ namespace VISCOUS_3D bool IsOffsetMethod() const { return _method == StdMeshers_ViscousLayers::FACE_OFFSET; } + bool operator==( const AverageHyp& other ) const + { + return ( _nbLayers == other._nbLayers && + _method == other._method && + Equals( GetTotalThickness(), other.GetTotalThickness() ) && + Equals( GetStretchFactor(), other.GetStretchFactor() )); + } + static bool Equals( double v1, double v2 ) { return Abs( v1 - v2 ) < 0.01 * ( v1 + v2 ); } + private: - int _nbLayers, _nbHyps, _method; - double _thickness, _stretchFactor; + int _nbLayers, _nbHyps, _method; + double _thickness, _stretchFactor; + std::string _groupName; }; //-------------------------------------------------------------------------------- @@ -684,6 +687,7 @@ namespace VISCOUS_3D _SolidData& GetData() const { return *_data; } _EdgesOnShape(): _shapeID(-1), _subMesh(0), _toSmooth(false), _edgeSmoother(0) {} + ~_EdgesOnShape(); }; //-------------------------------------------------------------------------------- @@ -743,6 +747,7 @@ namespace VISCOUS_3D TopTools_MapOfShape _before; // SOLIDs to be computed before _solid TGeomID _index; // SOLID id _MeshOfSolid* _proxyMesh; + bool _done; list< THyp > _hyps; list< TopoDS_Shape > _hypShapes; map< TGeomID, THyp > _face2hyp; // filled if _hyps.size() > 1 @@ -759,7 +764,7 @@ namespace VISCOUS_3D // _LayerEdge's with underlying shapes vector< _EdgesOnShape > _edgesOnShape; - // key: an id of shape (EDGE or VERTEX) shared by a FACE with + // key: an ID of shape (EDGE or VERTEX) shared by a FACE with // layers and a FACE w/o layers // value: the shape (FACE or EDGE) to shrink mesh on. // _LayerEdge's basing on nodes on key shape are inflated along the value shape @@ -786,8 +791,8 @@ namespace VISCOUS_3D _SolidData(const TopoDS_Shape& s=TopoDS_Shape(), _MeshOfSolid* m=0) - :_solid(s), _proxyMesh(m), _helper(0) {} - ~_SolidData(); + :_solid(s), _proxyMesh(m), _done(false),_helper(0) {} + ~_SolidData() { delete _helper; _helper = 0; } void SortOnEdge( const TopoDS_Edge& E, vector< _LayerEdge* >& edges); void Sort2NeiborsOnEdge( vector< _LayerEdge* >& edges ); @@ -888,6 +893,7 @@ namespace VISCOUS_3D const double refSign ); }; struct PyDump; + struct Periodicity; //-------------------------------------------------------------------------------- /*! * \brief Builder of viscous layers @@ -914,10 +920,12 @@ namespace VISCOUS_3D bool findSolidsWithLayers(); bool setBefore( _SolidData& solidBefore, _SolidData& solidAfter ); bool findFacesWithLayers(const bool onlyWith=false); + void findPeriodicFaces(); void getIgnoreFaces(const TopoDS_Shape& solid, const StdMeshers_ViscousLayers* hyp, const TopoDS_Shape& hypShape, set& ignoreFaces); + void makeEdgesOnShape(); bool makeLayer(_SolidData& data); void setShapeData( _EdgesOnShape& eos, SMESH_subMesh* sm, _SolidData& data ); bool setEdgeData( _LayerEdge& edge, _EdgesOnShape& eos, @@ -1000,15 +1008,16 @@ namespace VISCOUS_3D // debug void makeGroupOfLE(); - SMESH_Mesh* _mesh; - SMESH_ComputeErrorPtr _error; + SMESH_Mesh* _mesh; + SMESH_ComputeErrorPtr _error; - vector< _SolidData > _sdVec; - TopTools_IndexedMapOfShape _solids; // to find _SolidData by a solid - TopTools_MapOfShape _shrinkedFaces; + vector< _SolidData > _sdVec; + TopTools_IndexedMapOfShape _solids; // to find _SolidData by a solid + TopTools_MapOfShape _shrunkFaces; + std::unique_ptr _periodicity; - int _tmpFaceID; - PyDump* _pyDump; + int _tmpFaceID; + PyDump* _pyDump; }; //-------------------------------------------------------------------------------- /*! @@ -1212,6 +1221,27 @@ namespace VISCOUS_3D ( dot * dot ) / l1 / l2 >= ( cos * cos )); } + class _Factory + { + ObjectPool< _LayerEdge > _edgePool; + ObjectPool< _Curvature > _curvaturePool; + ObjectPool< _2NearEdges > _nearEdgesPool; + + static _Factory* & me() + { + static _Factory* theFactory = 0; + return theFactory; + } + public: + + _Factory() { me() = this; } + ~_Factory() { me() = 0; } + + static _LayerEdge* NewLayerEdge() { return me()->_edgePool.getNew(); } + static _Curvature * NewCurvature() { return me()->_curvaturePool.getNew(); } + static _2NearEdges* NewNearEdges() { return me()->_nearEdgesPool.getNew(); } + }; + } // namespace VISCOUS_3D @@ -1222,7 +1252,8 @@ namespace VISCOUS_3D StdMeshers_ViscousLayers::StdMeshers_ViscousLayers(int hypId, SMESH_Gen* gen) :SMESH_Hypothesis(hypId, gen), _isToIgnoreShapes(1), _nbLayers(1), _thickness(1), _stretchFactor(1), - _method( SURF_OFFSET_SMOOTH ) + _method( SURF_OFFSET_SMOOTH ), + _groupName("") { _name = StdMeshers_ViscousLayers::GetHypType(); _param_algo_dim = -3; // auxiliary hyp used by 3D algos @@ -1254,6 +1285,15 @@ void StdMeshers_ViscousLayers::SetMethod( ExtrusionMethod method ) if ( _method != method ) _method = method, NotifySubMeshesHypothesisModification(); } // -------------------------------------------------------------------------------- +void StdMeshers_ViscousLayers::SetGroupName(const std::string& name) +{ + if ( _groupName != name ) + { + _groupName = name; + if ( !_groupName.empty() ) + NotifySubMeshesHypothesisModification(); + } +} // -------------------------------------------------------------------------------- SMESH_ProxyMesh::Ptr StdMeshers_ViscousLayers::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theShape, @@ -1308,6 +1348,9 @@ std::ostream & StdMeshers_ViscousLayers::SaveTo(std::ostream & save) save << " " << _shapeIds[i]; save << " " << !_isToIgnoreShapes; // negate to keep the behavior in old studies. save << " " << _method; + save << " " << _groupName.size(); + if ( !_groupName.empty() ) + save << " " << _groupName; return save; } // -------------------------------------------------------------------------------- std::istream & StdMeshers_ViscousLayers::LoadFrom(std::istream & load) @@ -1320,6 +1363,13 @@ std::istream & StdMeshers_ViscousLayers::LoadFrom(std::istream & load) _isToIgnoreShapes = !shapeToTreat; if ( load >> method ) _method = (ExtrusionMethod) method; + int nameSize = 0; + if ( load >> nameSize && nameSize > 0 ) + { + _groupName.resize( nameSize ); + load.get( _groupName[0] ); // remove a white-space + load.getline( &_groupName[0], nameSize + 1 ); + } } else { _isToIgnoreShapes = true; // old behavior @@ -1353,6 +1403,36 @@ bool StdMeshers_ViscousLayers::IsShapeWithLayers(int shapeIndex) const ( std::find( _shapeIds.begin(), _shapeIds.end(), shapeIndex ) != _shapeIds.end() ); return IsToIgnoreShapes() ? !isIn : isIn; } + +// -------------------------------------------------------------------------------- +SMDS_MeshGroup* StdMeshers_ViscousLayers::CreateGroup( const std::string& theName, + SMESH_Mesh& theMesh, + SMDSAbs_ElementType theType) +{ + SMESH_Group* group = 0; + SMDS_MeshGroup* groupDS = 0; + + if ( theName.empty() ) + return groupDS; + + if ( SMESH_Mesh::GroupIteratorPtr grIt = theMesh.GetGroups() ) + while( grIt->more() && !group ) + { + group = grIt->next(); + if ( !group || + group->GetGroupDS()->GetType() != theType || + group->GetName() != theName || + !dynamic_cast< SMESHDS_Group* >( group->GetGroupDS() )) + group = 0; + } + if ( !group ) + group = theMesh.AddGroup( theType, theName.c_str() ); + + groupDS = & dynamic_cast< SMESHDS_Group* >( group->GetGroupDS() )->SMDSGroup(); + + return groupDS; +} + // END StdMeshers_ViscousLayers hypothesis //================================================================================ @@ -1873,6 +1953,8 @@ SMESH_ComputeErrorPtr _ViscousBuilder::Compute(SMESH_Mesh& theMesh, { _mesh = & theMesh; + _Factory factory; + // check if proxy mesh already computed TopExp_Explorer exp( theShape, TopAbs_SOLID ); if ( !exp.More() ) @@ -1884,20 +1966,30 @@ SMESH_ComputeErrorPtr _ViscousBuilder::Compute(SMESH_Mesh& theMesh, PyDump debugDump( theMesh ); _pyDump = &debugDump; - // TODO: ignore already computed SOLIDs + // TODO: ignore already computed SOLIDs if ( !findSolidsWithLayers()) return _error; if ( !findFacesWithLayers() ) return _error; + // for ( size_t i = 0; i < _sdVec.size(); ++i ) + // { + // if ( ! makeLayer( _sdVec[ i ])) // create _LayerEdge's + // return _error; + // } + + makeEdgesOnShape(); + + findPeriodicFaces(); + for ( size_t i = 0; i < _sdVec.size(); ++i ) { size_t iSD = 0; for ( iSD = 0; iSD < _sdVec.size(); ++iSD ) // find next SOLID to compute if ( _sdVec[iSD]._before.IsEmpty() && !_sdVec[iSD]._solid.IsNull() && - _sdVec[iSD]._n2eMap.empty() ) + !_sdVec[iSD]._done ) break; if ( ! makeLayer(_sdVec[iSD]) ) // create _LayerEdge's @@ -1920,6 +2012,8 @@ SMESH_ComputeErrorPtr _ViscousBuilder::Compute(SMESH_Mesh& theMesh, addBoundaryElements(_sdVec[iSD]); // create quadrangles on prism bare sides + _sdVec[iSD]._done = true; + const TopoDS_Shape& solid = _sdVec[iSD]._solid; for ( iSD = 0; iSD < _sdVec.size(); ++iSD ) _sdVec[iSD]._before.Remove( solid ); @@ -2146,7 +2240,7 @@ bool _ViscousBuilder::findFacesWithLayers(const bool onlyWith) for ( ; exp.More(); exp.Next() ) { const TopoDS_Face& face = TopoDS::Face( exp.Current() ); - const TGeomID faceID = getMeshDS()->ShapeToIndex( face ); + const TGeomID faceID = getMeshDS()->ShapeToIndex( face ); if ( //!sdVec[i]._ignoreFaceIds.count( faceID ) && helper.NbAncestors( face, *_mesh, TopAbs_SOLID ) > 1 && helper.IsReversedSubMesh( face )) @@ -2182,7 +2276,7 @@ bool _ViscousBuilder::findFacesWithLayers(const bool onlyWith) ignore[j] = _sdVec[i]._ignoreFaceIds.count( getMeshDS()->ShapeToIndex( FF[j] )); if ( ignore[0] == ignore[1] ) continue; // nothing interesting - TopoDS_Shape fWOL = FF[ ignore[0] ? 0 : 1 ]; + TopoDS_Shape fWOL = FF[ ignore[0] ? 0 : 1 ]; // FACE w/o layers // add EDGE to maps if ( !fWOL.IsNull()) @@ -2262,7 +2356,7 @@ bool _ViscousBuilder::findFacesWithLayers(const bool onlyWith) } } - // Add to _noShrinkShapes sub-shapes of FACE's that can't be shrinked since + // Add to _noShrinkShapes sub-shapes of FACE's that can't be shrunk since // the algo of the SOLID sharing the FACE does not support it or for other reasons set< string > notSupportAlgos; notSupportAlgos.insert( structAlgoName ); for ( size_t i = 0; i < _sdVec.size(); ++i ) @@ -2487,17 +2581,6 @@ void _ViscousBuilder::getIgnoreFaces(const TopoDS_Shape& solid, bool _ViscousBuilder::makeLayer(_SolidData& data) { - // get all sub-shapes to make layers on - set subIds, faceIds; - subIds = data._noShrinkShapes; - TopExp_Explorer exp( data._solid, TopAbs_FACE ); - for ( ; exp.More(); exp.Next() ) - { - SMESH_subMesh* fSubM = _mesh->GetSubMesh( exp.Current() ); - if ( ! data._ignoreFaceIds.count( fSubM->GetId() )) - faceIds.insert( fSubM->GetId() ); - } - // make a map to find new nodes on sub-shapes shared with other SOLID map< TGeomID, TNode2Edge* >::iterator s2ne; map< TGeomID, TopoDS_Shape >::iterator s2s = data._shrinkShape2Shape.begin(); @@ -2521,6 +2604,8 @@ bool _ViscousBuilder::makeLayer(_SolidData& data) dumpFunction(SMESH_Comment("makeLayers_")<& edgesByGeom = data._edgesOnShape; + data._stepSize = Precision::Infinite(); data._stepSizeNodes[0] = 0; @@ -2531,34 +2616,19 @@ bool _ViscousBuilder::makeLayer(_SolidData& data) vector< const SMDS_MeshNode*> newNodes; // of a mesh face TNode2Edge::iterator n2e2; - // collect _LayerEdge's of shapes they are based on - vector< _EdgesOnShape >& edgesByGeom = data._edgesOnShape; - const int nbShapes = getMeshDS()->MaxShapeIndex(); - edgesByGeom.resize( nbShapes+1 ); - - // set data of _EdgesOnShape's - if ( SMESH_subMesh* sm = _mesh->GetSubMesh( data._solid )) - { - SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(/*includeSelf=*/false); - while ( smIt->more() ) - { - sm = smIt->next(); - if ( sm->GetSubShape().ShapeType() == TopAbs_FACE && - !faceIds.count( sm->GetId() )) - continue; - setShapeData( edgesByGeom[ sm->GetId() ], sm, data ); - } - } // make _LayerEdge's - for ( set::iterator id = faceIds.begin(); id != faceIds.end(); ++id ) + for ( TopExp_Explorer exp( data._solid, TopAbs_FACE ); exp.More(); exp.Next() ) { - const TopoDS_Face& F = TopoDS::Face( getMeshDS()->IndexToShape( *id )); - SMESH_subMesh* sm = _mesh->GetSubMesh( F ); + const TopoDS_Face& F = TopoDS::Face( exp.Current() ); + SMESH_subMesh* sm = _mesh->GetSubMesh( F ); + const TGeomID id = sm->GetId(); + if ( edgesByGeom[ id ]._shape.IsNull() ) + continue; // no layers SMESH_ProxyMesh::SubMesh* proxySub = data._proxyMesh->getFaceSubM( F, /*create=*/true); SMESHDS_SubMesh* smDS = sm->GetSubMeshDS(); - if ( !smDS ) return error(SMESH_Comment("Not meshed face ") << *id, data._index ); + if ( !smDS ) return error(SMESH_Comment("Not meshed face ") << id, data._index ); SMDS_ElemIteratorPtr eIt = smDS->GetElements(); while ( eIt->more() ) @@ -2596,7 +2666,7 @@ bool _ViscousBuilder::makeLayer(_SolidData& data) if ( !(*n2e).second ) { // add a _LayerEdge - _LayerEdge* edge = new _LayerEdge(); + _LayerEdge* edge = _Factory::NewLayerEdge(); edge->_nodes.push_back( n ); n2e->second = edge; edgesByGeom[ shapeID ]._edges.push_back( edge ); @@ -3249,6 +3319,39 @@ bool _ViscousBuilder::findShapesToSmooth( _SolidData& data ) return ok; } +//================================================================================ +/*! + * \brief Set up _SolidData::_edgesOnShape + */ +//================================================================================ + +void _ViscousBuilder::makeEdgesOnShape() +{ + const int nbShapes = getMeshDS()->MaxShapeIndex(); + + for ( size_t i = 0; i < _sdVec.size(); ++i ) + { + _SolidData& data = _sdVec[ i ]; + vector< _EdgesOnShape >& edgesByGeom = data._edgesOnShape; + edgesByGeom.resize( nbShapes+1 ); + + // set data of _EdgesOnShape's + if ( SMESH_subMesh* sm = _mesh->GetSubMesh( data._solid )) + { + SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(/*includeSelf=*/false); + while ( smIt->more() ) + { + sm = smIt->next(); + if ( sm->GetSubShape().ShapeType() == TopAbs_FACE && + data._ignoreFaceIds.count( sm->GetId() )) + continue; + + setShapeData( edgesByGeom[ sm->GetId() ], sm, data ); + } + } + } +} + //================================================================================ /*! * \brief initialize data of _EdgesOnShape @@ -3383,6 +3486,16 @@ bool _EdgesOnShape::GetNormal( const SMDS_MeshElement* face, gp_Vec& norm ) return ok; } +//================================================================================ +/*! + * \brief EdgesOnShape destructor + */ +//================================================================================ + +_EdgesOnShape::~_EdgesOnShape() +{ + delete _edgeSmoother; +} //================================================================================ /*! @@ -3397,12 +3510,13 @@ bool _ViscousBuilder::setEdgeData(_LayerEdge& edge, { const SMDS_MeshNode* node = edge._nodes[0]; // source node - edge._len = 0; - edge._maxLen = Precision::Infinite(); - edge._minAngle = 0; - edge._2neibors = 0; - edge._curvature = 0; - edge._flags = 0; + edge._len = 0; + edge._maxLen = Precision::Infinite(); + edge._minAngle = 0; + edge._2neibors = 0; + edge._curvature = 0; + edge._flags = 0; + edge._smooFunction = 0; // -------------------------- // Compute _normal and _cosin @@ -3675,7 +3789,7 @@ bool _ViscousBuilder::setEdgeData(_LayerEdge& edge, if ( eos.ShapeType() == TopAbs_EDGE /*|| ( onShrinkShape && posType == SMDS_TOP_VERTEX && fabs( edge._cosin ) < 1e-10 )*/) { - edge._2neibors = new _2NearEdges; + edge._2neibors = _Factory::NewNearEdges(); // target nodes instead of source ones will be set later } @@ -4134,6 +4248,34 @@ bool _ViscousBuilder::findNeiborsOnEdge(const _LayerEdge* edge, return true; } +//================================================================================ +/*! + * \brief Create _Curvature + */ +//================================================================================ + +_Curvature* _Curvature::New( double avgNormProj, double avgDist ) +{ + // double _r; // radius + // double _k; // factor to correct node smoothed position + // double _h2lenRatio; // avgNormProj / (2*avgDist) + // gp_Pnt2d _uv; // UV used in putOnOffsetSurface() + + _Curvature* c = 0; + if ( fabs( avgNormProj / avgDist ) > 1./200 ) + { + c = _Factory::NewCurvature(); + c->_r = avgDist * avgDist / avgNormProj; + c->_k = avgDist * avgDist / c->_r / c->_r; + //c->_k = avgNormProj / c->_r; + c->_k *= ( c->_r < 0 ? 1/1.1 : 1.1 ); // not to be too restrictive + c->_h2lenRatio = avgNormProj / ( avgDist + avgDist ); + + c->_uv.SetCoord( 0., 0. ); + } + return c; +} + //================================================================================ /*! * \brief Set _curvature and _2neibors->_plnNorm by 2 neighbor nodes residing the same EDGE @@ -4161,7 +4303,6 @@ void _LayerEdge::SetDataByNeighbors( const SMDS_MeshNode* n1, _2neibors->_wgt[1] = 1 - vec2.Modulus() / sumLen; double avgNormProj = 0.5 * ( _normal * vec1 + _normal * vec2 ); double avgLen = 0.5 * ( vec1.Modulus() + vec2.Modulus() ); - if ( _curvature ) delete _curvature; _curvature = _Curvature::New( avgNormProj, avgLen ); // if ( _curvature ) // debugMsg( _nodes[0]->GetID() @@ -4205,8 +4346,11 @@ gp_XYZ _LayerEdge::Copy( _LayerEdge& other, _lenFactor = other._lenFactor; _cosin = other._cosin; _2neibors = other._2neibors; - _curvature = 0; std::swap( _curvature, other._curvature ); - _2neibors = 0; std::swap( _2neibors, other._2neibors ); + _curvature = other._curvature; + _2neibors = other._2neibors; + _maxLen = Precision::Infinite();//other._maxLen; + _flags = 0; + _smooFunction = 0; gp_XYZ lastPos( 0,0,0 ); if ( eos.SWOLType() == TopAbs_EDGE ) @@ -6927,7 +7071,7 @@ void _ViscousBuilder::findEdgesToUpdateNormalNearConvexFace( _ConvexFace & if ( dist < 0.95 * ledge->_maxLen ) { ledge->Set( _LayerEdge::UPD_NORMAL_CONV ); - if ( !ledge->_curvature ) ledge->_curvature = new _Curvature; + if ( !ledge->_curvature ) ledge->_curvature = _Factory::NewCurvature(); ledge->_curvature->_uv.SetCoord( uv.X(), uv.Y() ); edgesToUpdateFound = true; } @@ -8269,7 +8413,7 @@ void _LayerEdge::MoveNearConcaVer( const _EdgesOnShape* eov, if ( !edgeF->_curvature ) if (( fPos = edgeF->_nodes[0]->GetPosition() )) { - edgeF->_curvature = new _Curvature; + edgeF->_curvature = _Factory::NewCurvature(); edgeF->_curvature->_r = 0; edgeF->_curvature->_k = 0; edgeF->_curvature->_h2lenRatio = 0; @@ -10141,6 +10285,11 @@ bool _ViscousBuilder::refine(_SolidData& data) const TGeomID faceID = getMeshDS()->ShapeToIndex( exp.Current() ); if ( data._ignoreFaceIds.count( faceID )) continue; + _EdgesOnShape* eos = data.GetShapeEdges( faceID ); + SMDS_MeshGroup* group = StdMeshers_ViscousLayers::CreateGroup( eos->_hyp.GetGroupName(), + *helper.GetMesh(), + SMDSAbs_Volume ); + std::vector< const SMDS_MeshElement* > vols; const bool isReversedFace = data._reversedFaceIds.count( faceID ); SMESHDS_SubMesh* fSubM = getMeshDS()->MeshElements( exp.Current() ); SMDS_ElemIteratorPtr fIt = fSubM->GetElements(); @@ -10171,14 +10320,20 @@ bool _ViscousBuilder::refine(_SolidData& data) if ( 0 < nnSet.size() && nnSet.size() < 3 ) continue; + vols.clear(); + const SMDS_MeshElement* vol; + switch ( nbNodes ) { case 3: // TRIA { // PENTA for ( size_t iZ = 1; iZ < minZ; ++iZ ) - helper.AddVolume( (*nnVec[0])[iZ-1], (*nnVec[1])[iZ-1], (*nnVec[2])[iZ-1], - (*nnVec[0])[iZ], (*nnVec[1])[iZ], (*nnVec[2])[iZ]); + { + vol = helper.AddVolume( (*nnVec[0])[iZ-1], (*nnVec[1])[iZ-1], (*nnVec[2])[iZ-1], + (*nnVec[0])[iZ], (*nnVec[1])[iZ], (*nnVec[2])[iZ]); + vols.push_back( vol ); + } for ( size_t iZ = minZ; iZ < maxZ; ++iZ ) { @@ -10191,16 +10346,18 @@ bool _ViscousBuilder::refine(_SolidData& data) int i2 = *degenEdgeInd.begin(); int i0 = helper.WrapIndex( i2 - 1, nbNodes ); int i1 = helper.WrapIndex( i2 + 1, nbNodes ); - helper.AddVolume( (*nnVec[i0])[iZ-1], (*nnVec[i1])[iZ-1], - (*nnVec[i1])[iZ ], (*nnVec[i0])[iZ ], (*nnVec[i2]).back()); + vol = helper.AddVolume( (*nnVec[i0])[iZ-1], (*nnVec[i1])[iZ-1], + (*nnVec[i1])[iZ ], (*nnVec[i0])[iZ ], (*nnVec[i2]).back()); + vols.push_back( vol ); } else // TETRA { int i3 = !degenEdgeInd.count(0) ? 0 : !degenEdgeInd.count(1) ? 1 : 2; - helper.AddVolume( (*nnVec[ 0 ])[ i3 == 0 ? iZ-1 : nnVec[0]->size()-1 ], - (*nnVec[ 1 ])[ i3 == 1 ? iZ-1 : nnVec[1]->size()-1 ], - (*nnVec[ 2 ])[ i3 == 2 ? iZ-1 : nnVec[2]->size()-1 ], - (*nnVec[ i3 ])[ iZ ]); + vol = helper.AddVolume( (*nnVec[ 0 ])[ i3 == 0 ? iZ-1 : nnVec[0]->size()-1 ], + (*nnVec[ 1 ])[ i3 == 1 ? iZ-1 : nnVec[1]->size()-1 ], + (*nnVec[ 2 ])[ i3 == 2 ? iZ-1 : nnVec[2]->size()-1 ], + (*nnVec[ i3 ])[ iZ ]); + vols.push_back( vol ); } } break; // TRIA @@ -10209,10 +10366,13 @@ bool _ViscousBuilder::refine(_SolidData& data) { // HEX for ( size_t iZ = 1; iZ < minZ; ++iZ ) - helper.AddVolume( (*nnVec[0])[iZ-1], (*nnVec[1])[iZ-1], - (*nnVec[2])[iZ-1], (*nnVec[3])[iZ-1], - (*nnVec[0])[iZ], (*nnVec[1])[iZ], - (*nnVec[2])[iZ], (*nnVec[3])[iZ]); + { + vol = helper.AddVolume( (*nnVec[0])[iZ-1], (*nnVec[1])[iZ-1], + (*nnVec[2])[iZ-1], (*nnVec[3])[iZ-1], + (*nnVec[0])[iZ], (*nnVec[1])[iZ], + (*nnVec[2])[iZ], (*nnVec[3])[iZ]); + vols.push_back( vol ); + } for ( size_t iZ = minZ; iZ < maxZ; ++iZ ) { @@ -10231,9 +10391,9 @@ bool _ViscousBuilder::refine(_SolidData& data) int i0 = helper.WrapIndex( i3 + 1, nbNodes ); int i1 = helper.WrapIndex( i0 + 1, nbNodes ); - const SMDS_MeshElement* vol = - helper.AddVolume( nnVec[i3]->back(), (*nnVec[i0])[iZ], (*nnVec[i0])[iZ-1], - nnVec[i2]->back(), (*nnVec[i1])[iZ], (*nnVec[i1])[iZ-1]); + vol = helper.AddVolume( nnVec[i3]->back(), (*nnVec[i0])[iZ], (*nnVec[i0])[iZ-1], + nnVec[i2]->back(), (*nnVec[i1])[iZ], (*nnVec[i1])[iZ-1]); + vols.push_back( vol ); if ( !ok && vol ) degenVols.push_back( vol ); } @@ -10241,15 +10401,15 @@ bool _ViscousBuilder::refine(_SolidData& data) default: // degen HEX { - const SMDS_MeshElement* vol = - helper.AddVolume( nnVec[0]->size() > iZ-1 ? (*nnVec[0])[iZ-1] : nnVec[0]->back(), - nnVec[1]->size() > iZ-1 ? (*nnVec[1])[iZ-1] : nnVec[1]->back(), - nnVec[2]->size() > iZ-1 ? (*nnVec[2])[iZ-1] : nnVec[2]->back(), - nnVec[3]->size() > iZ-1 ? (*nnVec[3])[iZ-1] : nnVec[3]->back(), - nnVec[0]->size() > iZ ? (*nnVec[0])[iZ] : nnVec[0]->back(), - nnVec[1]->size() > iZ ? (*nnVec[1])[iZ] : nnVec[1]->back(), - nnVec[2]->size() > iZ ? (*nnVec[2])[iZ] : nnVec[2]->back(), - nnVec[3]->size() > iZ ? (*nnVec[3])[iZ] : nnVec[3]->back()); + vol = helper.AddVolume( nnVec[0]->size() > iZ-1 ? (*nnVec[0])[iZ-1] : nnVec[0]->back(), + nnVec[1]->size() > iZ-1 ? (*nnVec[1])[iZ-1] : nnVec[1]->back(), + nnVec[2]->size() > iZ-1 ? (*nnVec[2])[iZ-1] : nnVec[2]->back(), + nnVec[3]->size() > iZ-1 ? (*nnVec[3])[iZ-1] : nnVec[3]->back(), + nnVec[0]->size() > iZ ? (*nnVec[0])[iZ] : nnVec[0]->back(), + nnVec[1]->size() > iZ ? (*nnVec[1])[iZ] : nnVec[1]->back(), + nnVec[2]->size() > iZ ? (*nnVec[2])[iZ] : nnVec[2]->back(), + nnVec[3]->size() > iZ ? (*nnVec[3])[iZ] : nnVec[3]->back()); + vols.push_back( vol ); degenVols.push_back( vol ); } } @@ -10260,6 +10420,11 @@ bool _ViscousBuilder::refine(_SolidData& data) return error("Not supported type of element", data._index); } // switch ( nbNodes ) + + if ( group ) + for ( size_t i = 0; i < vols.size(); ++i ) + group->Add( vols[ i ]); + } // while ( fIt->more() ) } // loop on FACEs @@ -10279,6 +10444,440 @@ bool _ViscousBuilder::refine(_SolidData& data) return true; } +namespace VISCOUS_3D +{ + struct ShrinkFace; + //-------------------------------------------------------------------------------- + /*! + * \brief Pair of periodic FACEs + */ + struct PeriodicFaces + { + typedef StdMeshers_ProjectionUtils::TrsfFinder3D Trsf; + + ShrinkFace* _shriFace[2]; + TNodeNodeMap _nnMap; + Trsf _trsf; + + PeriodicFaces( ShrinkFace* sf1, ShrinkFace* sf2 ): _shriFace{ sf1, sf2 } {} + bool IncludeShrunk( const TopoDS_Face& face, const TopTools_MapOfShape& shrunkFaces ) const; + bool MoveNodes( const TopoDS_Face& tgtFace ); + }; + + //-------------------------------------------------------------------------------- + /*! + * \brief Shrink FACE data used to find periodic FACEs + */ + struct ShrinkFace + { + // ................................................................................ + struct BndPart //!< part of FACE boundary, either shrink or no-shrink + { + bool _isShrink, _isReverse; + int _nbSegments; + AverageHyp* _hyp; + std::vector< SMESH_NodeXYZ > _nodes; + TopAbs_ShapeEnum _vertSWOLType[2]; // shrink part includes VERTEXes + AverageHyp* _vertHyp[2]; + + BndPart(): + _isShrink(0), _isReverse(0), _nbSegments(0), _hyp(0), + _vertSWOLType{ TopAbs_WIRE, TopAbs_WIRE }, _vertHyp{ 0, 0 } + {} + + bool operator==( const BndPart& other ) const + { + return ( _isShrink == other._isShrink && + _nbSegments == other._nbSegments && + _nodes.size() == other._nodes.size() && + vertSWOLType1() == other.vertSWOLType1() && + vertSWOLType2() == other.vertSWOLType2() && + (( !_isShrink ) || + ( *_hyp == *other._hyp && + vertHyp1() == other.vertHyp1() && + vertHyp2() == other.vertHyp2() )) + ); + } + bool CanAppend( const BndPart& other ) + { + return ( _isShrink == other._isShrink && + (( !_isShrink ) || + ( *_hyp == *other._hyp && + *_hyp == vertHyp2() && + vertHyp2() == other.vertHyp1() )) + ); + } + void Append( const BndPart& other ) + { + _nbSegments += other._nbSegments; + bool hasCommonNode = ( _nodes.back()->GetID() == other._nodes.front()->GetID() ); + _nodes.insert( _nodes.end(), other._nodes.begin() + hasCommonNode, other._nodes.end() ); + _vertSWOLType[1] = other._vertSWOLType[1]; + if ( _isShrink ) + _vertHyp[1] = other._vertHyp[1]; + } + const SMDS_MeshNode* Node(size_t i) const + { + return _nodes[ _isReverse ? ( _nodes.size() - 1 - i ) : i ]._node; + } + void Reverse() { _isReverse = !_isReverse; } + const TopAbs_ShapeEnum& vertSWOLType1() const { return _vertSWOLType[ _isReverse ]; } + const TopAbs_ShapeEnum& vertSWOLType2() const { return _vertSWOLType[ !_isReverse ]; } + const AverageHyp& vertHyp1() const { return *(_vertHyp[ _isReverse ]); } + const AverageHyp& vertHyp2() const { return *(_vertHyp[ !_isReverse ]); } + }; + // ................................................................................ + + SMESH_subMesh* _subMesh; + _SolidData* _data1; + _SolidData* _data2; + //bool _isPeriodic; + + std::list< BndPart > _boundary; + int _boundarySize, _nbBoundaryParts; + + void Init( SMESH_subMesh* sm, _SolidData* sd1, _SolidData* sd2 ) + { + _subMesh = sm; _data1 = sd1; _data2 = sd2; //_isPeriodic = false; + } + bool IsSame( const TopoDS_Face& face ) const + { + return _subMesh->GetSubShape().IsSame( face ); + } + bool IsShrunk( const TopTools_MapOfShape& shrunkFaces ) const + { + return shrunkFaces.Contains( _subMesh->GetSubShape() ); + } + + //================================================================================ + /*! + * Check if meshes on two FACEs are equal + */ + bool IsPeriodic( ShrinkFace& other, PeriodicFaces& periodic ) + { + if ( !IsSameNbElements( other )) + return false; + + this->SetBoundary(); + other.SetBoundary(); + if ( this->_boundarySize != other._boundarySize || + this->_nbBoundaryParts != other._nbBoundaryParts ) + return false; + + for ( int isReverse = 0; isReverse < 2; ++isReverse ) + { + if ( isReverse ) + Reverse( _boundary ); + + // check boundaries + bool equalBoundary = false; + for ( int iP = 0; iP < _nbBoundaryParts && !equalBoundary; ++iP ) + { + if ( ! ( equalBoundary = ( this->_boundary == other._boundary ))) + // set first part at end + _boundary.splice( _boundary.end(), _boundary, _boundary.begin() ); + } + if ( !equalBoundary ) + continue; + + // check connectivity + std::set elemsThis, elemsOther; + this->GetElements( elemsThis ); + other.GetElements( elemsOther ); + SMESH_MeshEditor::Sew_Error err = + SMESH_MeshEditor::FindMatchingNodes( elemsThis, elemsOther, + this->_boundary.front().Node(0), + other._boundary.front().Node(0), + this->_boundary.front().Node(1), + other._boundary.front().Node(1), + periodic._nnMap ); + if ( err != SMESH_MeshEditor::SEW_OK ) + continue; + + // check node positions + std::vector< gp_XYZ > srcPnts, tgtPnts; + this->GetBoundaryPoints( srcPnts ); + other.GetBoundaryPoints( tgtPnts ); + if ( !periodic._trsf.Solve( srcPnts, tgtPnts )) { + continue; + } + double tol = std::numeric_limits::max(); + for ( size_t i = 1; i < srcPnts.size(); ++i ) { + tol = Min( tol, ( srcPnts[i-1] - srcPnts[i] ).SquareModulus() ); + } + tol = 0.01 * Sqrt( tol ); + bool nodeCoincide = true; + TNodeNodeMap::iterator n2n = periodic._nnMap.begin(); + for ( ; n2n != periodic._nnMap.end() && nodeCoincide; ++n2n ) + { + SMESH_NodeXYZ nSrc = n2n->first; + SMESH_NodeXYZ nTgt = n2n->second; + gp_XYZ pTgt = periodic._trsf.Transform( nSrc ); + nodeCoincide = (( pTgt - nTgt ).SquareModulus() < tol ); + } + if ( nodeCoincide ) + return true; + } + return false; + } + + bool IsSameNbElements( ShrinkFace& other ) // check number of mesh faces + { + SMESHDS_SubMesh* sm1 = this->_subMesh->GetSubMeshDS(); + SMESHDS_SubMesh* sm2 = other._subMesh->GetSubMeshDS(); + return ( sm1->NbElements() == sm2->NbElements() && + sm1->NbNodes() == sm2->NbNodes() ); + } + + void Reverse( std::list< BndPart >& boundary ) + { + boundary.reverse(); + for ( std::list< BndPart >::iterator part = boundary.begin(); part != boundary.end(); ++part ) + part->Reverse(); + } + + void SetBoundary() + { + if ( !_boundary.empty() ) + return; + + TopoDS_Face F = TopoDS::Face( _subMesh->GetSubShape() ); + if ( F.Orientation() >= TopAbs_INTERNAL ) F.Orientation( TopAbs_FORWARD ); + std::list< TopoDS_Edge > edges; + std::list< int > nbEdgesInWire; + /*int nbWires =*/ SMESH_Block::GetOrderedEdges (F, edges, nbEdgesInWire); + + // std::list< TopoDS_Edge >::iterator edgesEnd = edges.end(); + // if ( nbWires > 1 ) { + // edgesEnd = edges.begin(); + // std::advance( edgesEnd, nbEdgesInWire.front() ); + // } + StdMeshers_FaceSide fSide( F, edges, _subMesh->GetFather(), + /*fwd=*/true, /*skipMedium=*/true ); + _boundarySize = fSide.NbSegments(); + + //TopoDS_Vertex vv[2]; + //std::list< TopoDS_Edge >::iterator edgeIt = edges.begin(); + for ( int iE = 0; iE < nbEdgesInWire.front(); ++iE ) + { + BndPart bndPart; + _EdgesOnShape* eos = _data1->GetShapeEdges( fSide.EdgeID( iE )); + + bndPart._isShrink = ( eos->SWOLType() == TopAbs_FACE ); + if ( bndPart._isShrink ) + if (( _data1->_noShrinkShapes.count( eos->_shapeID )) || + ( _data2 && _data2->_noShrinkShapes.count( eos->_shapeID ))) + bndPart._isShrink = false; + + if ( bndPart._isShrink ) + { + bndPart._hyp = & eos->_hyp; + _EdgesOnShape* eov[2] = { _data1->GetShapeEdges( fSide.FirstVertex( iE )), + _data1->GetShapeEdges( fSide.LastVertex ( iE )) }; + for ( int iV = 0; iV < 2; ++iV ) + { + bndPart._vertHyp [iV] = & eov[iV]->_hyp; + bndPart._vertSWOLType[iV] = eov[iV]->SWOLType(); + if ( _data1->_noShrinkShapes.count( eov[iV]->_shapeID )) + bndPart._vertSWOLType[iV] = TopAbs_SHAPE; + if ( _data2 && bndPart._vertSWOLType[iV] != TopAbs_SHAPE ) + { + eov[iV] = _data2->GetShapeEdges( iV ? fSide.LastVertex(iE) : fSide.FirstVertex(iE )); + if ( _data2->_noShrinkShapes.count( eov[iV]->_shapeID )) + bndPart._vertSWOLType[iV] = TopAbs_SHAPE; + else if ( eov[iV]->SWOLType() > bndPart._vertSWOLType[iV] ) + bndPart._vertSWOLType[iV] = eov[iV]->SWOLType(); + } + } + } + std::vector nodes = fSide.GetOrderedNodes( iE ); + bndPart._nodes.assign( nodes.begin(), nodes.end() ); + bndPart._nbSegments = bndPart._nodes.size() - 1; + + if ( _boundary.empty() || ! _boundary.back().CanAppend( bndPart )) + _boundary.push_back( bndPart ); + else + _boundary.back().Append( bndPart ); + } + + _nbBoundaryParts = _boundary.size(); + if ( _nbBoundaryParts > 1 && _boundary.front()._isShrink == _boundary.back()._isShrink ) + { + _boundary.back().Append( _boundary.front() ); + _boundary.pop_front(); + --_nbBoundaryParts; + } + } + + void GetElements( std::set& theElems) + { + if ( SMESHDS_SubMesh* sm = _subMesh->GetSubMeshDS() ) + for ( SMDS_ElemIteratorPtr fIt = sm->GetElements(); fIt->more(); ) + theElems.insert( theElems.end(), fIt->next() ); + + return ; + } + + void GetBoundaryPoints( std::vector< gp_XYZ >& points ) + { + points.reserve( _boundarySize ); + size_t nb = _boundary.rbegin()->_nodes.size(); + int lastID = _boundary.rbegin()->Node( nb - 1 )->GetID(); + std::list< BndPart >::const_iterator part = _boundary.begin(); + for ( ; part != _boundary.end(); ++part ) + { + size_t nb = part->_nodes.size(); + size_t iF = 0; + size_t iR = nb - 1; + size_t* i = part->_isReverse ? &iR : &iF; + if ( part->_nodes[ *i ]->GetID() == lastID ) + ++iF, --iR; + for ( ; iF < nb; ++iF, --iR ) + points.push_back( part->_nodes[ *i ]); + --iF, ++iR; + lastID = part->_nodes[ *i ]->GetID(); + } + } + }; // struct ShrinkFace + + //-------------------------------------------------------------------------------- + /*! + * \brief Periodic FACEs + */ + struct Periodicity + { + std::vector< ShrinkFace > _shrinkFaces; + std::vector< PeriodicFaces > _periodicFaces; + + PeriodicFaces* GetPeriodic( const TopoDS_Face& face, const TopTools_MapOfShape& shrunkFaces ) + { + for ( size_t i = 0; i < _periodicFaces.size(); ++i ) + if ( _periodicFaces[ i ].IncludeShrunk( face, shrunkFaces )) + return & _periodicFaces[ i ]; + return 0; + } + }; + + //================================================================================ + /*! + * Check if a pair includes the given FACE and the other FACE is already shrunk + */ + bool PeriodicFaces::IncludeShrunk( const TopoDS_Face& face, + const TopTools_MapOfShape& shrunkFaces ) const + { + return (( _shriFace[0]->IsSame( face ) && _shriFace[1]->IsShrunk( shrunkFaces )) || + ( _shriFace[1]->IsSame( face ) && _shriFace[0]->IsShrunk( shrunkFaces ))); + } + + //================================================================================ + /*! + * Make equal meshes on periodic faces by moving corresponding nodes + */ + bool PeriodicFaces::MoveNodes( const TopoDS_Face& tgtFace ) + { + int iTgt = _shriFace[1]->IsSame( tgtFace ); + int iSrc = 1 - iTgt; + + _SolidData* dataSrc = _shriFace[iSrc]->_data1; + _SolidData* dataTgt = _shriFace[iTgt]->_data1; + + Trsf * trsf = & _trsf, trsfInverse; + if ( iSrc != 0 ) + { + trsfInverse = _trsf; + trsfInverse.Invert(); + trsf = &trsfInverse; + } + SMESHDS_Mesh* meshDS = dataSrc->GetHelper().GetMeshDS(); + + TNode2Edge::iterator n2e; + TNodeNodeMap::iterator n2n = _nnMap.begin(); + for ( ; n2n != _nnMap.end(); ++n2n ) + { + const SMDS_MeshNode* const* nn = & n2n->first; + const SMDS_MeshNode* nSrc = nn[ iSrc ]; + const SMDS_MeshNode* nTgt = nn[ iTgt ]; + + if (( nSrc->GetPosition()->GetDim() == 2 ) || + (( n2e = dataSrc->_n2eMap.find( nSrc )) == dataSrc->_n2eMap.end() )) + { + SMESH_NodeXYZ pSrc = nSrc; + gp_XYZ pTgt = trsf->Transform( pSrc ); + meshDS->MoveNode( nTgt, pTgt.X(), pTgt.Y(), pTgt.Z() ); + } + else + { + _LayerEdge* leSrc = n2e->second; + n2e = dataTgt->_n2eMap.find( nTgt ); + if ( n2e == dataTgt->_n2eMap.end() ) + break; + _LayerEdge* leTgt = n2e->second; + if ( leSrc->_nodes.size() != leTgt->_nodes.size() ) + break; + for ( size_t iN = 1; iN < leSrc->_nodes.size(); ++iN ) + { + SMESH_NodeXYZ pSrc = leSrc->_nodes[ iN ]; + gp_XYZ pTgt = trsf->Transform( pSrc ); + meshDS->MoveNode( leTgt->_nodes[ iN ], pTgt.X(), pTgt.Y(), pTgt.Z() ); + } + } + } + bool done = ( n2n == _nnMap.end() ); + // cout << "MMMMMMMOOOOOOOOOOVVVVVVVVVVVEEEEEEEE " + // << _shriFace[iSrc]->_subMesh->GetId() << " -> " + // << _shriFace[iTgt]->_subMesh->GetId() << " -- " + // << ( done ? "DONE" : "FAIL") << endl; + + return done; + } +} // namespace VISCOUS_3D; Periodicity part + + +//================================================================================ +/*! + * \brief Find FACEs to shrink, that are equally meshed before shrink (i.e. periodic) + * and should remain equal after shrink + */ +//================================================================================ + +void _ViscousBuilder::findPeriodicFaces() +{ + // make map of (ids of FACEs to shrink mesh on) to (list of _SolidData containing + // _LayerEdge's inflated along FACE or EDGE) + std::map< TGeomID, std::list< _SolidData* > > id2sdMap; + for ( size_t i = 0 ; i < _sdVec.size(); ++i ) + { + _SolidData& data = _sdVec[i]; + std::map< TGeomID, TopoDS_Shape >::iterator s2s = data._shrinkShape2Shape.begin(); + for (; s2s != data._shrinkShape2Shape.end(); ++s2s ) + if ( s2s->second.ShapeType() == TopAbs_FACE ) + id2sdMap[ getMeshDS()->ShapeToIndex( s2s->second )].push_back( &data ); + } + + _periodicity.reset( new Periodicity ); + _periodicity->_shrinkFaces.resize( id2sdMap.size() ); + + std::map< TGeomID, std::list< _SolidData* > >::iterator id2sdIt = id2sdMap.begin(); + for ( size_t i = 0; i < id2sdMap.size(); ++i, ++id2sdIt ) + { + _SolidData* sd1 = id2sdIt->second.front(); + _SolidData* sd2 = id2sdIt->second.back(); + _periodicity->_shrinkFaces[ i ].Init( _mesh->GetSubMeshContaining( id2sdIt->first ), sd1, sd2 ); + } + + for ( size_t i1 = 0; i1 < _periodicity->_shrinkFaces.size(); ++i1 ) + for ( size_t i2 = i1 + 1; i2 < _periodicity->_shrinkFaces.size(); ++i2 ) + { + PeriodicFaces pf( & _periodicity->_shrinkFaces[ i1 ], + & _periodicity->_shrinkFaces[ i2 ]); + if ( pf._shriFace[0]->IsPeriodic( *pf._shriFace[1], pf )) + { + _periodicity->_periodicFaces.push_back( pf ); + } + } + return; +} + //================================================================================ /*! * \brief Shrink 2D mesh on faces to let space for inflated layers @@ -10295,11 +10894,11 @@ bool _ViscousBuilder::shrink(_SolidData& theData) _SolidData& data = _sdVec[i]; map< TGeomID, TopoDS_Shape >::iterator s2s = data._shrinkShape2Shape.begin(); for (; s2s != data._shrinkShape2Shape.end(); ++s2s ) - if ( s2s->second.ShapeType() == TopAbs_FACE && !_shrinkedFaces.Contains( s2s->second )) + if ( s2s->second.ShapeType() == TopAbs_FACE && !_shrunkFaces.Contains( s2s->second )) { f2sdMap[ getMeshDS()->ShapeToIndex( s2s->second )].push_back( &data ); - // Put mesh faces on the shrinked FACE to the proxy sub-mesh to avoid + // Put mesh faces on the shrunk FACE to the proxy sub-mesh to avoid // usage of mesh faces made in addBoundaryElements() by the 3D algo or // by StdMeshers_QuadToTriaAdaptor if ( SMESHDS_SubMesh* smDS = getMeshDS()->MeshElements( s2s->second )) @@ -10358,15 +10957,24 @@ bool _ViscousBuilder::shrink(_SolidData& theData) Handle(Geom_Surface) surface = BRep_Tool::Surface( F ); - _shrinkedFaces.Add( F ); + _shrunkFaces.Add( F ); helper.SetSubShape( F ); + // ============================== + // Use periodicity to move nodes + // ============================== + + PeriodicFaces* periodic = _periodicity->GetPeriodic( F, _shrunkFaces ); + bool movedByPeriod = ( periodic && periodic->MoveNodes( F )); + // =========================== // Prepare data for shrinking // =========================== // Collect nodes to smooth (they are marked at the beginning of this method) vector < const SMDS_MeshNode* > smoothNodes; + + if ( !movedByPeriod ) { SMDS_NodeIteratorPtr nIt = smDS->GetNodes(); while ( nIt->more() ) @@ -10412,11 +11020,12 @@ bool _ViscousBuilder::shrink(_SolidData& theData) } subEOS.push_back( eos ); - for ( size_t i = 0; i < eos->_edges.size(); ++i ) - { - lEdges.push_back( eos->_edges[ i ] ); - prepareEdgeToShrink( *eos->_edges[ i ], *eos, helper, smDS ); - } + if ( !movedByPeriod ) + for ( size_t i = 0; i < eos->_edges.size(); ++i ) + { + lEdges.push_back( eos->_edges[ i ] ); + prepareEdgeToShrink( *eos->_edges[ i ], *eos, helper, smDS ); + } } } @@ -10488,13 +11097,16 @@ bool _ViscousBuilder::shrink(_SolidData& theData) if ( eos.SWOLType() == TopAbs_EDGE ) { SMESH_subMesh* edgeSM = _mesh->GetSubMesh( eos._sWOL ); - _Shrinker1D& shrinker = e2shrMap[ edgeSM->GetId() ]; - eShri1D.insert( & shrinker ); - shrinker.AddEdge( eos._edges[0], eos, helper ); VISCOUS_3D::ToClearSubWithMain( edgeSM, data._solid ); - // restore params of nodes on EDGE if the EDGE has been already - // shrinked while shrinking other FACE - shrinker.RestoreParams(); + if ( !movedByPeriod ) + { + _Shrinker1D& shrinker = e2shrMap[ edgeSM->GetId() ]; + eShri1D.insert( & shrinker ); + shrinker.AddEdge( eos._edges[0], eos, helper ); + // restore params of nodes on EDGE if the EDGE has been already + // shrunk while shrinking other FACE + shrinker.RestoreParams(); + } } for ( size_t i = 0; i < eos._edges.size(); ++i ) { @@ -10509,7 +11121,7 @@ bool _ViscousBuilder::shrink(_SolidData& theData) } bool toFixTria = false; // to improve quality of trias by diagonal swap - if ( isConcaveFace ) + if ( isConcaveFace && !movedByPeriod ) { const bool hasTria = _mesh->NbTriangles(), hasQuad = _mesh->NbQuadrangles(); if ( hasTria != hasQuad ) { @@ -10528,24 +11140,24 @@ bool _ViscousBuilder::shrink(_SolidData& theData) // Perform shrinking // ================== - bool shrinked = true; + bool shrunk = !movedByPeriod; int nbBad, shriStep=0, smooStep=0; _SmoothNode::SmoothType smoothType = isConcaveFace ? _SmoothNode::ANGULAR : _SmoothNode::LAPLACIAN; SMESH_Comment errMsg; - while ( shrinked ) + while ( shrunk ) { shriStep++; // Move boundary nodes (actually just set new UV) // ----------------------------------------------- dumpFunction(SMESH_Comment("moveBoundaryOnF")<first<<"_st"<SetNewLength2d( surface, F, eos, helper ); + shrunk |= eos._edges[i]->SetNewLength2d( surface, F, eos, helper ); } } dumpFunctionEnd(); @@ -10636,7 +11248,7 @@ bool _ViscousBuilder::shrink(_SolidData& theData) // } // } - } // while ( shrinked ) + } // while ( shrunk ) if ( !errMsg.empty() ) // Try to re-compute the shrink FACE { @@ -10800,7 +11412,7 @@ bool _ViscousBuilder::shrink(_SolidData& theData) return error( errMsg ); } // end of re-meshing in case of failed smoothing - else + else if ( !movedByPeriod ) { // No wrongly shaped faces remain; final smooth. Set node XYZ. bool isStructuredFixed = false; @@ -10844,7 +11456,7 @@ bool _ViscousBuilder::shrink(_SolidData& theData) } // loop on FACES to shrink mesh on - // Replace source nodes by target nodes in shrinked mesh edges + // Replace source nodes by target nodes in shrunk mesh edges map< int, _Shrinker1D >::iterator e2shr = e2shrMap.begin(); for ( ; e2shr != e2shrMap.end(); ++e2shr ) @@ -11408,34 +12020,6 @@ gp_XY _SmoothNode::computeAngularPos(vector& uv, return newPos; } -//================================================================================ -/*! - * \brief Delete _SolidData - */ -//================================================================================ - -_SolidData::~_SolidData() -{ - TNode2Edge::iterator n2e = _n2eMap.begin(); - for ( ; n2e != _n2eMap.end(); ++n2e ) - { - _LayerEdge* & e = n2e->second; - if ( e ) - { - delete e->_curvature; - if ( e->_2neibors ) - delete e->_2neibors->_plnNorm; - delete e->_2neibors; - } - delete e; - e = 0; - } - _n2eMap.clear(); - - delete _helper; - _helper = 0; -} - //================================================================================ /*! * \brief Keep a _LayerEdge inflated along the EDGE @@ -11601,7 +12185,7 @@ void _Shrinker1D::RestoreParams() //================================================================================ /*! - * \brief Replace source nodes by target nodes in shrinked mesh edges + * \brief Replace source nodes by target nodes in shrunk mesh edges */ //================================================================================ diff --git a/src/StdMeshers/StdMeshers_ViscousLayers.hxx b/src/StdMeshers/StdMeshers_ViscousLayers.hxx index 142f35b01..7d7e362fd 100644 --- a/src/StdMeshers/StdMeshers_ViscousLayers.hxx +++ b/src/StdMeshers/StdMeshers_ViscousLayers.hxx @@ -32,6 +32,8 @@ #include +class SMDS_MeshGroup; + /*! * \brief Hypothesis defining parameters of viscous layers */ @@ -73,6 +75,13 @@ public: void SetMethod( ExtrusionMethod how ); ExtrusionMethod GetMethod() const { return _method; } + // name of a group to create + void SetGroupName(const std::string& name); + const std::string& GetGroupName() const { return _groupName; } + static SMDS_MeshGroup* CreateGroup( const std::string& theName, + SMESH_Mesh& theMesh, + SMDSAbs_ElementType theType); + // Computes temporary 2D mesh to be used by 3D algorithm. // Return SMESH_ProxyMesh for each SOLID in theShape SMESH_ProxyMesh::Ptr Compute(SMESH_Mesh& theMesh, @@ -116,6 +125,7 @@ public: double _thickness; double _stretchFactor; ExtrusionMethod _method; + std::string _groupName; }; class SMESH_subMesh; diff --git a/src/StdMeshers/StdMeshers_ViscousLayers2D.cxx b/src/StdMeshers/StdMeshers_ViscousLayers2D.cxx index 6248200a7..a0da0d527 100644 --- a/src/StdMeshers/StdMeshers_ViscousLayers2D.cxx +++ b/src/StdMeshers/StdMeshers_ViscousLayers2D.cxx @@ -2402,6 +2402,17 @@ bool _ViscousBuilder2D::refine() outerNodes.swap( innerNodes ); } + // Add faces to a group + SMDS_MeshGroup* group = StdMeshers_ViscousLayers::CreateGroup( hyp->GetGroupName(), + *_helper.GetMesh(), + SMDSAbs_Face ); + if ( group ) + { + TIDSortedElemSet::iterator fIt = L._newFaces.begin(); + for ( ; fIt != L._newFaces.end(); ++fIt ) + group->Add( *fIt ); + } + // faces between not shared _LayerEdge's (at concave VERTEX) for ( int isR = 0; isR < 2; ++isR ) { @@ -2413,15 +2424,22 @@ bool _ViscousBuilder2D::refine() if ( lNodes.empty() || rNodes.empty() || lNodes.size() != rNodes.size() ) continue; + const SMDS_MeshElement* face = 0; for ( size_t i = 1; i < lNodes.size(); ++i ) - _helper.AddFace( lNodes[ i+prev ], rNodes[ i+prev ], - rNodes[ i+cur ], lNodes[ i+cur ]); + { + face = _helper.AddFace( lNodes[ i+prev ], rNodes[ i+prev ], + rNodes[ i+cur ], lNodes[ i+cur ]); + if ( group ) + group->Add( face ); + } const UVPtStruct& ptOnVertex = points[ isR ? L._lastPntInd : L._firstPntInd ]; if ( isReverse ) - _helper.AddFace( ptOnVertex.node, lNodes[ 0 ], rNodes[ 0 ]); + face = _helper.AddFace( ptOnVertex.node, lNodes[ 0 ], rNodes[ 0 ]); else - _helper.AddFace( ptOnVertex.node, rNodes[ 0 ], lNodes[ 0 ]); + face = _helper.AddFace( ptOnVertex.node, rNodes[ 0 ], lNodes[ 0 ]); + if ( group ) + group->Add( face ); } // Fill the _ProxyMeshOfFace diff --git a/src/StdMeshersGUI/CMakeLists.txt b/src/StdMeshersGUI/CMakeLists.txt index 0b8834730..4393778db 100644 --- a/src/StdMeshersGUI/CMakeLists.txt +++ b/src/StdMeshersGUI/CMakeLists.txt @@ -82,6 +82,7 @@ SET(_moc_HEADERS StdMeshersGUI_CartesianParamCreator.h StdMeshersGUI_RadioButtonsGrpWdg.h StdMeshersGUI_PropagationHelperWdg.h + StdMeshersGUI_NameCheckableGrpWdg.h ) IF(SALOME_USE_PLOT2DVIEWER) @@ -117,6 +118,7 @@ SET(_other_SOURCES StdMeshersGUI_CartesianParamCreator.cxx StdMeshersGUI_RadioButtonsGrpWdg.cxx StdMeshersGUI_PropagationHelperWdg.cxx + StdMeshersGUI_NameCheckableGrpWdg.cxx ) IF(SALOME_USE_PLOT2DVIEWER) diff --git a/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.cxx b/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.cxx index b70d05091..f1271c105 100644 --- a/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.cxx +++ b/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.cxx @@ -204,8 +204,8 @@ namespace StdMeshersGUI axisTabLayout->setSpacing( SPACING ); axisTabLayout->addWidget( modeBox , 0, 0, 1, 3 ); - axisTabLayout->addWidget( myInsertBtn , 1, 0, 1, 2 ); - axisTabLayout->addWidget( myDeleteBtn , 2, 0, 1, 2 ); + axisTabLayout->addWidget( myInsertBtn, 1, 0, 1, 2 ); + axisTabLayout->addWidget( myDeleteBtn, 2, 0, 1, 2 ); axisTabLayout->addWidget( myStepLabel, 3, 0 ); axisTabLayout->addWidget( myStepSpin , 3, 1 ); axisTabLayout->addWidget( csFrame , 1, 2, 4, 1 ); @@ -821,6 +821,15 @@ QFrame* StdMeshersGUI_CartesianParamCreator::buildFrame() myAddEdges = new QCheckBox( tr("ADD_EDGES"), GroupC1 ); argGroupLayout->addWidget( myAddEdges, row, 0, 1, 2 ); row++; + myCreateFaces = new QCheckBox( tr("CREATE_FACES"), GroupC1 ); + argGroupLayout->addWidget( myCreateFaces, row, 0, 1, 2 ); + row++; + myConsiderInternalFaces = new QCheckBox( tr("CONSIDER_INTERNAL_FACES"), GroupC1 ); + argGroupLayout->addWidget( myConsiderInternalFaces, row, 0, 1, 2 ); + row++; + myUseThresholdForInternalFaces = new QCheckBox( tr("USE_THRESHOLD_FOR_INTERNAL_FACES"), GroupC1 ); + argGroupLayout->addWidget( myUseThresholdForInternalFaces, row, 0, 1, 2 ); + row++; // 3) Grid definition QTabWidget* tabWdg = new QTabWidget( fr ); @@ -924,6 +933,8 @@ QFrame* StdMeshersGUI_CartesianParamCreator::buildFrame() connect( myOrthogonalChk, SIGNAL( toggled(bool)), SLOT( onOrthogonalAxes(bool))); connect( optimBtn, SIGNAL( clicked(bool)), SLOT( onOptimalAxes(bool))); connect( resetBtn, SIGNAL( clicked(bool)), SLOT( onResetAxes(bool))); + connect( myConsiderInternalFaces, SIGNAL( toggled(bool)), + myUseThresholdForInternalFaces, SLOT( setEnabled(bool))); for ( int i = 0; i < 3; ++i ) { connect( myXDirSpin[i], SIGNAL(valueChanged (const QString&)), @@ -999,6 +1010,9 @@ void StdMeshersGUI_CartesianParamCreator::retrieveParams() const myThreshold->setText( varName ); myAddEdges->setChecked( h->GetToAddEdges() ); + myCreateFaces->setChecked( h->GetToCreateFaces() ); + myConsiderInternalFaces->setChecked( h->GetToConsiderInternalFaces() ); + myUseThresholdForInternalFaces->setChecked( h->GetToUseThresholdForInternalFaces() ); // grid definition for ( int ax = 0; ax < 3; ++ax ) @@ -1086,6 +1100,9 @@ QString StdMeshersGUI_CartesianParamCreator::storeParams() const h->SetVarParameter( myThreshold->text().toLatin1().constData(), "SetSizeThreshold" ); h->SetSizeThreshold( myThreshold->text().toDouble() ); h->SetToAddEdges( myAddEdges->isChecked() ); + h->SetToCreateFaces( myCreateFaces->isChecked() ); + h->SetToConsiderInternalFaces( myConsiderInternalFaces->isChecked() ); + h->SetToUseThresholdForInternalFaces( myUseThresholdForInternalFaces->isChecked() ); // grid for ( int ax = 0; ax < 3; ++ax ) diff --git a/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.h b/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.h index 9ae66b9d8..f72b1e531 100644 --- a/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.h +++ b/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.h @@ -152,6 +152,9 @@ private: QLineEdit* myName; SMESHGUI_SpinBox* myThreshold; QCheckBox* myAddEdges; + QCheckBox* myCreateFaces; + QCheckBox* myConsiderInternalFaces; + QCheckBox* myUseThresholdForInternalFaces; StdMeshersGUI::GridAxisTab* myAxisTabs[3]; QGroupBox* myFixedPointGrp; diff --git a/src/StdMeshersGUI/StdMeshersGUI_NameCheckableGrpWdg.cxx b/src/StdMeshersGUI/StdMeshersGUI_NameCheckableGrpWdg.cxx new file mode 100644 index 000000000..5ea084b43 --- /dev/null +++ b/src/StdMeshersGUI/StdMeshersGUI_NameCheckableGrpWdg.cxx @@ -0,0 +1,68 @@ +// Copyright (C) 2007-2019 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, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +#include "StdMeshersGUI_NameCheckableGrpWdg.h" + +#include +#include +#include + +#define SPACING 6 +#define MARGIN 11 + +//================================================================================ +/*! + * \brief Creates a QGroupBox with a given title + */ +//================================================================================ + +StdMeshersGUI_NameCheckableGrpWdg::StdMeshersGUI_NameCheckableGrpWdg( const QString& groupTitle, + const QString& nameLabel ) + : QGroupBox( groupTitle ), + myNameLineEdit( new QLineEdit( this )) +{ + setCheckable( true ); + + QLabel* label = new QLabel( nameLabel ); + + QGridLayout* layout = new QGridLayout( this ); + layout->setSpacing(SPACING); + layout->setMargin(MARGIN); + + layout->addWidget( label, 0, 0 ); + layout->addWidget( myNameLineEdit, 0, 1 ); + + connect( this, SIGNAL( toggled( bool )), myNameLineEdit, SLOT( setEnabled( bool ))); +} + +QString StdMeshersGUI_NameCheckableGrpWdg::getName() +{ + return isChecked() ? myNameLineEdit->text() : QString(); +} + +void StdMeshersGUI_NameCheckableGrpWdg::setName( CORBA::String_var name ) +{ + myNameLineEdit->setText( name.in() ); + setChecked( ! myNameLineEdit->text().isEmpty() ); +} + +void StdMeshersGUI_NameCheckableGrpWdg::setDefaultName( QString name ) +{ + myNameLineEdit->setText( name ); + setChecked( ! myNameLineEdit->text().isEmpty() ); +} diff --git a/src/StdMeshersGUI/StdMeshersGUI_NameCheckableGrpWdg.h b/src/StdMeshersGUI/StdMeshersGUI_NameCheckableGrpWdg.h new file mode 100644 index 000000000..334df51b8 --- /dev/null +++ b/src/StdMeshersGUI/StdMeshersGUI_NameCheckableGrpWdg.h @@ -0,0 +1,53 @@ +// Copyright (C) 2007-2019 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, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +#ifndef STDMESHERSGUI_NameCheckableGrpWdg_H +#define STDMESHERSGUI_NameCheckableGrpWdg_H + +// SMESH includes +#include "SMESH_StdMeshersGUI.hxx" + +// Qt includes +#include + +#include + +class QButtonGroup; +class QLineEdit; + +/*! + * \brief A QGroupBox holding several radio buttons + */ +class STDMESHERSGUI_EXPORT StdMeshersGUI_NameCheckableGrpWdg : public QGroupBox +{ + Q_OBJECT + +public: + StdMeshersGUI_NameCheckableGrpWdg(const QString& groupTitle, + const QString& nameLabel); + + QString getName(); + + void setName( CORBA::String_var name ); + void setDefaultName( QString name ); + +private: + QLineEdit* myNameLineEdit; +}; + +#endif // STDMESHERSGUI_NameCheckableGrpWdg_H diff --git a/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx b/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx index f52914bd4..8dc3f1349 100644 --- a/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx +++ b/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx @@ -39,6 +39,7 @@ #include "StdMeshersGUI_PropagationHelperWdg.h" #include "StdMeshersGUI_QuadrangleParamWdg.h" #include "StdMeshersGUI_RadioButtonsGrpWdg.h" +#include "StdMeshersGUI_NameCheckableGrpWdg.h" #include "StdMeshersGUI_SubShapeSelectorWdg.h" #include @@ -377,10 +378,51 @@ namespace { } } +//================================================================================ +/*! + * \brief Remove a group, whose name is stored by hypothesis, upon group name modification + * \param [in] oldName - old group name + * \param [in] newName - new group name + * \param [in] type - group type + */ +//================================================================================ + +void StdMeshersGUI_StdHypothesisCreator:: +removeOldGroup(const char* oldName, const char* newName, SMESH::ElementType type) const +{ + if ( !oldName || !oldName[0] ) + return; // old name undefined + if ( newName && strcmp( oldName, newName ) == 0 ) + return; // same name + + SMESH::SMESH_Hypothesis_var h = hypothesis(); + SMESH::SObjectList listSOmesh = SMESH::GetMeshesUsingAlgoOrHypothesis( h ); + for ( size_t i = 0; i < listSOmesh.size(); i++ ) + { + _PTR(SObject) submSO = listSOmesh[i]; + SMESH::SMESH_Mesh_var mesh = SMESH::SObjectToInterface( submSO ); + SMESH::SMESH_subMesh_var subMesh = SMESH::SObjectToInterface( submSO ); + if( !subMesh->_is_nil() ) + mesh = subMesh->GetFather(); + if ( mesh->_is_nil() ) + continue; + SMESH::ListOfGroups_var groups = mesh->GetGroups(); + for ( CORBA::ULong iG = 0; iG < groups->length(); iG++ ) + { + if ( groups[iG]->GetType() != type ) + continue; + CORBA::String_var name = groups[iG]->GetName(); + if ( strcmp( name.in(), oldName )) + continue; + mesh->RemoveGroup( groups[iG] ); + } + } +} + //================================================================================ /*! * \brief Check parameter values before accept() - * \retval bool - true if OK + * \retval bool - true if OK */ //================================================================================ @@ -728,6 +770,15 @@ QString StdMeshersGUI_StdHypothesisCreator::storeParams() const { h->SetFaces( idsWg->GetListOfIDs(), params[4].myValue.toInt() ); } + + if ( StdMeshersGUI_NameCheckableGrpWdg* nameWg = + widget< StdMeshersGUI_NameCheckableGrpWdg >( 6 )) + { + CORBA::String_var oldName = h->GetGroupName(); + h->SetGroupName( nameWg->getName().toUtf8().data() ); + CORBA::String_var newName = h->GetGroupName(); + removeOldGroup( oldName, newName, SMESH::VOLUME ); + } } else if( hypType()=="ViscousLayers2D" ) { @@ -746,6 +797,15 @@ QString StdMeshersGUI_StdHypothesisCreator::storeParams() const { h->SetEdges( idsWg->GetListOfIDs(), params[3].myValue.toInt() ); } + + if ( StdMeshersGUI_NameCheckableGrpWdg* nameWg = + widget< StdMeshersGUI_NameCheckableGrpWdg >( 5 )) + { + CORBA::String_var oldName = h->GetGroupName(); + h->SetGroupName( nameWg->getName().toUtf8().data() ); + CORBA::String_var newName = h->GetGroupName(); + removeOldGroup( oldName, newName, SMESH::FACE ); + } } // else if( hypType()=="QuadrangleParams" ) // { @@ -841,7 +901,7 @@ bool StdMeshersGUI_StdHypothesisCreator::stdParams( ListOfStdParams& p ) const item.myName = tr("SMESH_USE_PREESTIMATED_LENGTH"); p.append( item ); QCheckBox* aQCheckBox = new QCheckBox(dlg()); - if ( !noPreestimatedAtEdition && h->HavePreestimatedLength() ) { + if ( h->HavePreestimatedLength() ) { aQCheckBox->setChecked( h->GetUsePreestimatedLength() ); connect( aQCheckBox, SIGNAL( stateChanged(int) ), this, SLOT( onValueChanged() ) ); } @@ -1250,6 +1310,19 @@ bool StdMeshersGUI_StdHypothesisCreator::stdParams( ListOfStdParams& p ) const } customWidgets()->append ( idsWg ); } + + item.setNoName(); + p.append( item ); + StdMeshersGUI_NameCheckableGrpWdg* nameWdg = + new StdMeshersGUI_NameCheckableGrpWdg( tr( "CREATE_GROUPS_FROM_LAYERS" ), + tr( "GROUP_NAME" )); + nameWdg->setName( h->GetGroupName() ); + if ( nameWdg->getName().isEmpty() ) + { + nameWdg->setDefaultName( type() ); + nameWdg->setChecked( false ); + } + customWidgets()->append ( nameWdg ); } else if( hypType()=="ViscousLayers2D" ) { @@ -1308,6 +1381,19 @@ bool StdMeshersGUI_StdHypothesisCreator::stdParams( ListOfStdParams& p ) const } customWidgets()->append ( idsWg ); } + + item.setNoName(); + p.append( item ); + StdMeshersGUI_NameCheckableGrpWdg* nameWdg = + new StdMeshersGUI_NameCheckableGrpWdg( tr( "CREATE_GROUPS_FROM_LAYERS" ), + tr( "GROUP_NAME" )); + nameWdg->setName( h->GetGroupName() ); + if ( nameWdg->getName().isEmpty() ) + { + nameWdg->setDefaultName( type() ); + nameWdg->setChecked( false ); + } + customWidgets()->append ( nameWdg ); } else res = false; @@ -1574,6 +1660,10 @@ bool StdMeshersGUI_StdHypothesisCreator::getParamFromCustomWidget( StdParam & pa param.myValue = w->checkedId(); return true; } + if ( widget->inherits( "StdMeshersGUI_NameCheckableGrpWdg" )) + { + return true; + } return false; } diff --git a/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.h b/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.h index 7e382ed3d..0e984e4d2 100644 --- a/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.h +++ b/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.h @@ -66,6 +66,9 @@ protected: bool initVariableName(SMESH::SMESH_Hypothesis_var theHyp, StdParam& theParams, const char* theMethod) const; QWidget* makeReverseEdgesWdg( SMESH::long_array_var edgeIDs, CORBA::String_var shapeEntry) const; + void removeOldGroup(const char* oldName, + const char* newName, + SMESH::ElementType type) const; diff --git a/src/StdMeshersGUI/StdMeshers_images.ts b/src/StdMeshersGUI/StdMeshers_images.ts index 36489516b..681bf7bed 100644 --- a/src/StdMeshersGUI/StdMeshers_images.ts +++ b/src/StdMeshersGUI/StdMeshers_images.ts @@ -183,6 +183,14 @@ ICON_SMESH_TREE_HYPO_Geometric1D mesh_tree_hypo_length.png + + ICON_SMESH_TREE_HYPO_ImportSource1D + mesh_tree_hypo_import_source_1d.png + + + ICON_SMESH_TREE_HYPO_ImportSource2D + mesh_tree_hypo_import_source_2d.png + ICON_SMESH_TREE_HYPO_AutomaticLength mesh_tree_hypo_length.png @@ -191,6 +199,10 @@ ICON_SMESH_TREE_HYPO_Deflection1D mesh_tree_hypo_length.png + + ICON_SMESH_TREE_HYPO_FixedPoints1D + mesh_tree_hypo_length.png + ICON_SMESH_TREE_HYPO_Adaptive1D mesh_tree_hypo_length.png @@ -199,6 +211,10 @@ ICON_SMESH_TREE_HYPO_LayerDistribution mesh_tree_hypo_layers_distribution.png + + ICON_SMESH_TREE_HYPO_LayerDistribution2D + mesh_tree_hypo_layers_distribution_2d.png + ICON_SMESH_TREE_HYPO_LengthFromEdges mesh_tree_hypo_area.png @@ -229,7 +245,7 @@ ICON_SMESH_TREE_HYPO_NumberOfLayers2D - mesh_tree_hypo_layers_distribution.png + mesh_tree_hypo_layers_distribution_2d.png ICON_SMESH_TREE_HYPO_NumberOfSegments diff --git a/src/StdMeshersGUI/StdMeshers_msg_en.ts b/src/StdMeshersGUI/StdMeshers_msg_en.ts index 351aed8f4..0c0509f19 100644 --- a/src/StdMeshersGUI/StdMeshers_msg_en.ts +++ b/src/StdMeshersGUI/StdMeshers_msg_en.ts @@ -59,6 +59,14 @@ this one for this mesh/sub-mesh. EXTMETH_FACE_OFFSET Face offset + + CREATE_GROUPS_FROM_LAYERS + Create groups from layers + + + GROUP_NAME + Group name + @default @@ -572,6 +580,18 @@ this one for this mesh/sub-mesh. ADD_EDGES Implement Edges + + CREATE_FACES + Create Faces + + + CONSIDER_INTERNAL_FACES + Consider Shared and Internal Faces + + + USE_THRESHOLD_FOR_INTERNAL_FACES + Apply Threshold to Shared / Internal Faces + AXIS_X Axis X diff --git a/src/StdMeshers_I/CMakeLists.txt b/src/StdMeshers_I/CMakeLists.txt index ceed790b4..4b1c390ba 100644 --- a/src/StdMeshers_I/CMakeLists.txt +++ b/src/StdMeshers_I/CMakeLists.txt @@ -119,6 +119,7 @@ SET(StdMeshersEngine_HEADERS StdMeshers_CartesianParameters3D_i.hxx StdMeshers_Cartesian_3D_i.hxx StdMeshers_PolygonPerFace_2D_i.hxx + StdMeshers_PolyhedronPerSolid_3D_i.hxx ) IF(SALOME_SMESH_ENABLE_MEFISTO) SET(StdMeshersEngine_HEADERS ${StdMeshersEngine_HEADERS} StdMeshers_MEFISTO_2D_i.hxx) @@ -174,6 +175,7 @@ SET(StdMeshersEngine_SOURCES StdMeshers_Cartesian_3D_i.cxx StdMeshers_Adaptive1D_i.cxx StdMeshers_PolygonPerFace_2D_i.cxx + StdMeshers_PolyhedronPerSolid_3D_i.cxx ) IF(SALOME_SMESH_ENABLE_MEFISTO) diff --git a/src/StdMeshers_I/StdMeshers_CartesianParameters3D_i.cxx b/src/StdMeshers_I/StdMeshers_CartesianParameters3D_i.cxx index ec36baf67..fa1cadfcb 100644 --- a/src/StdMeshers_I/StdMeshers_CartesianParameters3D_i.cxx +++ b/src/StdMeshers_I/StdMeshers_CartesianParameters3D_i.cxx @@ -240,6 +240,14 @@ void StdMeshers_CartesianParameters3D_i::SetAxesDirs(const SMESH::DirStruct& xDi coords[6] = zDir.PS.x; coords[7] = zDir.PS.y; coords[8] = zDir.PS.z; + + const double* oldCoords = GetImpl()->GetAxisDirs(); + bool isSame = true; + for ( int i = 0; i < 9 && isSame; ++i ) + isSame = ( oldCoords[i] == coords[i] ); + if ( isSame ) + return; + try { this->GetImpl()->SetAxisDirs(coords); @@ -283,6 +291,11 @@ void StdMeshers_CartesianParameters3D_i::GetAxesDirs(SMESH::DirStruct& xDir, void StdMeshers_CartesianParameters3D_i::SetFixedPoint(const SMESH::PointStruct& ps, CORBA::Boolean toUnset) { + SMESH::PointStruct oldPS; + GetFixedPoint( oldPS ); + if ( oldPS.x == ps.x && oldPS.y == ps.y && oldPS.z == ps.z ) + return; + double p[3] = { ps.x, ps.y, ps.z }; GetImpl()->SetFixedPoint( p, toUnset ); @@ -335,6 +348,76 @@ CORBA::Boolean StdMeshers_CartesianParameters3D_i::GetToAddEdges() return GetImpl()->GetToAddEdges(); } +//======================================================================= +//function : SetToConsiderInternalFaces +//purpose : Enables treatment of geom faces, either shared by solids or internal. +//======================================================================= + +void StdMeshers_CartesianParameters3D_i::SetToConsiderInternalFaces(CORBA::Boolean toTreat) +{ + if ( GetToConsiderInternalFaces() == toTreat ) + return; + GetImpl()->SetToConsiderInternalFaces( toTreat ); + SMESH::TPythonDump() << _this() << ".SetToConsiderInternalFaces( " << toTreat << " )"; +} + +//======================================================================= +//function : GetToConsiderInternalFaces +//purpose : Return true if treatment of internal geom faces is enabled +//======================================================================= + +CORBA::Boolean StdMeshers_CartesianParameters3D_i::GetToConsiderInternalFaces() +{ + return GetImpl()->GetToConsiderInternalFaces(); +} + +//======================================================================= +//function : SetToUseThresholdForInternalFaces +//purpose : Enables applying size threshold to grid cells cut by internal geom faces. +//======================================================================= + +void StdMeshers_CartesianParameters3D_i::SetToUseThresholdForInternalFaces(CORBA::Boolean toUse) +{ + if ( GetToUseThresholdForInternalFaces() == toUse ) + return; + GetImpl()->SetToUseThresholdForInternalFaces( toUse ); + SMESH::TPythonDump() << _this() << ".SetToUseThresholdForInternalFaces( " << toUse << " )"; +} + +//======================================================================= +//function : GetToUseThresholdForInternalFaces +//purpose : Return true if applying size threshold to grid cells cut by +// internal geom faces is enabled +//======================================================================= + +CORBA::Boolean StdMeshers_CartesianParameters3D_i::GetToUseThresholdForInternalFaces() +{ + return GetImpl()->GetToUseThresholdForInternalFaces(); +} + +//======================================================================= +//function : SetToCreateFaces +//purpose : Enables creation of mesh faces. +//======================================================================= + +void StdMeshers_CartesianParameters3D_i::SetToCreateFaces(CORBA::Boolean toCreate) +{ + if ( GetToCreateFaces() == toCreate ) + return; + GetImpl()->SetToCreateFaces( toCreate ); + SMESH::TPythonDump() << _this() << ".SetToCreateFaces( " << toCreate << " )"; +} + +//======================================================================= +//function : GetToCreateFaces +//purpose : Check if creation of mesh faces enabled +//======================================================================= + +CORBA::Boolean StdMeshers_CartesianParameters3D_i::GetToCreateFaces() +{ + return GetImpl()->GetToCreateFaces(); +} + //======================================================================= //function : IsGridBySpacing //purpose : Return true if the grid is defined by spacing functions and diff --git a/src/StdMeshers_I/StdMeshers_CartesianParameters3D_i.hxx b/src/StdMeshers_I/StdMeshers_CartesianParameters3D_i.hxx index 03dad0cfb..1b273ce77 100644 --- a/src/StdMeshers_I/StdMeshers_CartesianParameters3D_i.hxx +++ b/src/StdMeshers_I/StdMeshers_CartesianParameters3D_i.hxx @@ -100,7 +100,7 @@ class STDMESHERS_I_EXPORT StdMeshers_CartesianParameters3D_i: /*! - * \brief Enables implementation of geometrical edges into the mesh. If this feature + * \brief Enable implementation of geometrical edges into the mesh. If this feature * is disabled, sharp edges of the shape are lost ("smoothed") in the mesh if * they don't coincide with the grid lines */ @@ -108,13 +108,32 @@ class STDMESHERS_I_EXPORT StdMeshers_CartesianParameters3D_i: CORBA::Boolean GetToAddEdges(); /*! - * \brief Return true if the grid is defined by spacing functions and + * Enable treatment of geom faces, either shared by solids or internal. + */ + void SetToConsiderInternalFaces(CORBA::Boolean toTreat); + CORBA::Boolean GetToConsiderInternalFaces(); + + /*! + * Enable applying size threshold to grid cells cut by internal geom faces. + */ + void SetToUseThresholdForInternalFaces(CORBA::Boolean toUse); + CORBA::Boolean GetToUseThresholdForInternalFaces(); + + /*! + * Enable creation of mesh faces. + */ + void SetToCreateFaces(CORBA::Boolean toCreate); + CORBA::Boolean GetToCreateFaces(); + + + /*! + * \brief Return true if the grid is defined by spacing functions and * not by node coordinates */ CORBA::Boolean IsGridBySpacing(CORBA::Short axis); /*! - * Returns axes at which number of hexahedra is maximal + * Return axes at which number of hexahedra is maximal */ void ComputeOptimalAxesDirs(GEOM::GEOM_Object_ptr shape, CORBA::Boolean isOrthogonal, @@ -122,7 +141,7 @@ class STDMESHERS_I_EXPORT StdMeshers_CartesianParameters3D_i: SMESH::DirStruct& y, SMESH::DirStruct& z) throw (SALOME::SALOME_Exception); /*! - * \brief Computes node coordinates by spacing functions + * \brief Compute node coordinates by spacing functions * \param x0 - lower coordinate * \param x1 - upper coordinate * \param spaceFuns - space functions diff --git a/src/StdMeshers_I/StdMeshers_PolyhedronPerSolid_3D_i.cxx b/src/StdMeshers_I/StdMeshers_PolyhedronPerSolid_3D_i.cxx new file mode 100644 index 000000000..94d5648ce --- /dev/null +++ b/src/StdMeshers_I/StdMeshers_PolyhedronPerSolid_3D_i.cxx @@ -0,0 +1,57 @@ +// Copyright (C) 2007-2019 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// File : StdMeshers_PolyhedronPerSolid_3D_i.cxx +// Module : SMESH +// + +#include "StdMeshers_PolyhedronPerSolid_3D_i.hxx" + +#include "SMESH_Gen.hxx" +#include "StdMeshers_PolyhedronPerSolid_3D.hxx" + +//============================================================================= +/*! + * Constructor + */ +//============================================================================= + +StdMeshers_PolyhedronPerSolid_3D_i::StdMeshers_PolyhedronPerSolid_3D_i( PortableServer::POA_ptr thePOA, + ::SMESH_Gen* theGenImpl ) + : SALOME::GenericObj_i( thePOA ), + SMESH_Hypothesis_i( thePOA ), + SMESH_Algo_i( thePOA ), + SMESH_3D_Algo_i( thePOA ) +{ + myBaseImpl = new ::StdMeshers_PolyhedronPerSolid_3D( theGenImpl->GetANewId(), + theGenImpl ); +} + +//============================================================================= +/*! + * Destructor + */ +//============================================================================= + +StdMeshers_PolyhedronPerSolid_3D_i::~StdMeshers_PolyhedronPerSolid_3D_i() +{ +} diff --git a/src/StdMeshers_I/StdMeshers_PolyhedronPerSolid_3D_i.hxx b/src/StdMeshers_I/StdMeshers_PolyhedronPerSolid_3D_i.hxx new file mode 100644 index 000000000..26bdffc8d --- /dev/null +++ b/src/StdMeshers_I/StdMeshers_PolyhedronPerSolid_3D_i.hxx @@ -0,0 +1,53 @@ +// Copyright (C) 2007-2019 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// File : StdMeshers_PolyhedronPerSolid_3D_i.hxx +// Module : SMESH +// +#ifndef _SMESH_PolyhedronPerSolid_3D_I_HXX_ +#define _SMESH_PolyhedronPerSolid_3D_I_HXX_ + +#include "SMESH_StdMeshers_I.hxx" + +#include +#include CORBA_SERVER_HEADER(SMESH_BasicHypothesis) + +#include "SMESH_3D_Algo_i.hxx" + +class SMESH_Gen; + +// ====================================================== +// Polyhedron Per Solid 3D algorithm +// ====================================================== +class STDMESHERS_I_EXPORT StdMeshers_PolyhedronPerSolid_3D_i: + public virtual POA_StdMeshers::StdMeshers_PolyhedronPerSolid_3D, + public virtual SMESH_3D_Algo_i +{ + public: + // Constructor + StdMeshers_PolyhedronPerSolid_3D_i( PortableServer::POA_ptr thePOA, + ::SMESH_Gen* theGenImpl ); + // Destructor + virtual ~StdMeshers_PolyhedronPerSolid_3D_i(); +}; + +#endif diff --git a/src/StdMeshers_I/StdMeshers_ViscousLayers2D_i.cxx b/src/StdMeshers_I/StdMeshers_ViscousLayers2D_i.cxx index 376f156b0..0e03a4b1f 100644 --- a/src/StdMeshers_I/StdMeshers_ViscousLayers2D_i.cxx +++ b/src/StdMeshers_I/StdMeshers_ViscousLayers2D_i.cxx @@ -222,6 +222,33 @@ throw ( SALOME::SALOME_Exception ) return GetImpl()->GetStretchFactor(); } +//================================================================================ +/*! + * \brief Set name of a group of layers elements + */ +//================================================================================ + +void StdMeshers_ViscousLayers2D_i::SetGroupName(const char* name) +{ + if ( GetImpl()->GetGroupName() != name ) + { + GetImpl()->SetGroupName( name ); + SMESH::TPythonDump() << _this() << ".SetGroupName( '" << name << "' )"; + } +} + +//================================================================================ +/*! + * \brief Return name of a group of layers elements + */ +//================================================================================ + +char* StdMeshers_ViscousLayers2D_i::GetGroupName() +{ + return CORBA::string_dup( GetImpl()->GetGroupName().c_str() ); +} + + //============================================================================= /*! * Get implementation diff --git a/src/StdMeshers_I/StdMeshers_ViscousLayers2D_i.hxx b/src/StdMeshers_I/StdMeshers_ViscousLayers2D_i.hxx index 49dc69c8e..56f557c38 100644 --- a/src/StdMeshers_I/StdMeshers_ViscousLayers2D_i.hxx +++ b/src/StdMeshers_I/StdMeshers_ViscousLayers2D_i.hxx @@ -64,6 +64,10 @@ class STDMESHERS_I_EXPORT StdMeshers_ViscousLayers2D_i: void SetStretchFactor(::CORBA::Double factor) throw ( SALOME::SALOME_Exception ); ::CORBA::Double GetStretchFactor(); + void SetGroupName(const char* name); + char* GetGroupName(); + + // Get implementation ::StdMeshers_ViscousLayers2D* GetImpl(); diff --git a/src/StdMeshers_I/StdMeshers_ViscousLayers_i.cxx b/src/StdMeshers_I/StdMeshers_ViscousLayers_i.cxx index 603ef55c3..ab47e1725 100644 --- a/src/StdMeshers_I/StdMeshers_ViscousLayers_i.cxx +++ b/src/StdMeshers_I/StdMeshers_ViscousLayers_i.cxx @@ -253,6 +253,32 @@ void StdMeshers_ViscousLayers_i::SetMethod( ::StdMeshers::VLExtrusionMethod how return (::StdMeshers::VLExtrusionMethod) GetImpl()->GetMethod(); } +//================================================================================ +/*! + * \brief Set name of a group of layers elements + */ +//================================================================================ + +void StdMeshers_ViscousLayers_i::SetGroupName(const char* name) +{ + if ( GetImpl()->GetGroupName() != name ) + { + GetImpl()->SetGroupName( name ); + SMESH::TPythonDump() << _this() << ".SetGroupName( '" << name << "' )"; + } +} + +//================================================================================ +/*! + * \brief Return name of a group of layers elements + */ +//================================================================================ + +char* StdMeshers_ViscousLayers_i::GetGroupName() +{ + return CORBA::string_dup( GetImpl()->GetGroupName().c_str() ); +} + //============================================================================= /*! * Get implementation diff --git a/src/StdMeshers_I/StdMeshers_ViscousLayers_i.hxx b/src/StdMeshers_I/StdMeshers_ViscousLayers_i.hxx index ac5f0e1ae..47200ce72 100644 --- a/src/StdMeshers_I/StdMeshers_ViscousLayers_i.hxx +++ b/src/StdMeshers_I/StdMeshers_ViscousLayers_i.hxx @@ -67,10 +67,14 @@ class STDMESHERS_I_EXPORT StdMeshers_ViscousLayers_i: void SetMethod( ::StdMeshers::VLExtrusionMethod how ); ::StdMeshers::VLExtrusionMethod GetMethod(); + void SetGroupName(const char* name); + char* GetGroupName(); + + // Get implementation ::StdMeshers_ViscousLayers* GetImpl(); - // Verify whether hypothesis supports given entity type + // Verify whether hypothesis supports given entity type CORBA::Boolean IsDimSupported( SMESH::Dimension type ); // Methods for copying mesh definition to other geometry diff --git a/src/StdMeshers_I/StdMeshers_i.cxx b/src/StdMeshers_I/StdMeshers_i.cxx index 602b00ae2..676de466d 100644 --- a/src/StdMeshers_I/StdMeshers_i.cxx +++ b/src/StdMeshers_I/StdMeshers_i.cxx @@ -57,6 +57,7 @@ #include "StdMeshers_NumberOfLayers_i.hxx" #include "StdMeshers_NumberOfSegments_i.hxx" #include "StdMeshers_PolygonPerFace_2D_i.hxx" +#include "StdMeshers_PolyhedronPerSolid_3D_i.hxx" #include "StdMeshers_Prism_3D_i.hxx" #include "StdMeshers_ProjectionSource1D_i.hxx" #include "StdMeshers_ProjectionSource2D_i.hxx" @@ -250,6 +251,8 @@ STDMESHERS_I_EXPORT aCreator = new StdHypothesisCreator_i; else if (strcmp(aHypName, "PolygonPerFace_2D") == 0) aCreator = new StdHypothesisCreator_i; + else if (strcmp(aHypName, "PolyhedronPerSolid_3D") == 0) + aCreator = new StdHypothesisCreator_i; else ; return aCreator; diff --git a/src/Tools/MeshCut/MeshCut_DC.cxx b/src/Tools/MeshCut/MeshCut_DC.cxx index fb80f4696..224667f60 100644 --- a/src/Tools/MeshCut/MeshCut_DC.cxx +++ b/src/Tools/MeshCut/MeshCut_DC.cxx @@ -211,7 +211,7 @@ int main(int argc, char *argv[]) { bool plus = false; bool moins = false; - int *offset = MAILLAGE1->CNX[TETRA4] + 4 * it4; + med_int *offset = MAILLAGE1->CNX[TETRA4] + 4 * it4; for (int is = 0; is < 4; is++) { int ng = *(offset + is); @@ -1065,7 +1065,7 @@ int main(int argc, char *argv[]) // cout << "Legacy " << tm << " effectif " << MAILLAGE1->EFFECTIFS_TYPES[tm] << endl; int tailleType = Nnoeuds(tm); - MAILLAGE2->CNX[tm] = (int*) malloc(sizeof(int) * tailleType * (MAILLAGE1->EFFECTIFS_TYPES[tm] + MAILLAGE2->CNX[tm] = (med_int*) malloc(sizeof(med_int) * tailleType * (MAILLAGE1->EFFECTIFS_TYPES[tm] + cptNouvellesMailles[tm])); for (int i = 0; i < MAILLAGE1->EFFECTIFS_TYPES[tm]; i++) for (int j = 0; j < tailleType; j++) diff --git a/src/Tools/MeshCut/MeshCut_Fonctions.cxx b/src/Tools/MeshCut/MeshCut_Fonctions.cxx index ba8284d0d..e99da4fc5 100644 --- a/src/Tools/MeshCut/MeshCut_Fonctions.cxx +++ b/src/Tools/MeshCut/MeshCut_Fonctions.cxx @@ -89,7 +89,7 @@ int MESHCUT::intersectionSegmentPlan(int it4, int na) float A[3], B[3]; // Détermination des ng des extrémités de l'arête passée en argument na - int * offset = MAILLAGE1->CNX[TETRA4] + 4 * it4; + med_int * offset = MAILLAGE1->CNX[TETRA4] + 4 * it4; if (na == 0) { ngA = *(offset + 0); diff --git a/src/Tools/MeshCut/MeshCut_Maillage.cxx b/src/Tools/MeshCut/MeshCut_Maillage.cxx index c6cc137dd..d7e41ccb6 100644 --- a/src/Tools/MeshCut/MeshCut_Maillage.cxx +++ b/src/Tools/MeshCut/MeshCut_Maillage.cxx @@ -66,7 +66,7 @@ void Maillage::afficheMailles(TYPE_MAILLE tm) { cout << "\tMaille " << i << " :" << endl; //Boucle sur les noeuds de la maille de numéro local i dans le type tm - int * offset = CNX[tm] + nnoeuds * i; + med_int * offset = CNX[tm] + nnoeuds * i; for (int j = 0; j < nnoeuds; j++) { int ngnoeud = *(offset + j); @@ -868,7 +868,7 @@ void Maillage::acquisitionTYPE_inputMED(TYPE_MAILLE TYPE, int nTYPE, med_idt fid med_int *famTYPE = (med_int*) malloc(sizeof(med_int) * nTYPE); //med_int *conTYPE = (med_int*) malloc(sizeof(med_int)*tTYPE*nTYPE); - CNX[TYPE] = (int*) malloc(sizeof(int) * tTYPE * nTYPE); + CNX[TYPE] = (med_int*) malloc(sizeof(med_int) * tTYPE * nTYPE); med_bool inomTYPE, inumTYPE, ifamTYPE; med_geometry_type typeBanaliseMED = InstanceMGE(TYPE); @@ -1705,10 +1705,10 @@ void Maillage::eliminationMailles(TYPE_MAILLE tm, vector listeMaillesSuppr) // ************* Modification de la connectivité du type concerné - int* CNX2; + med_int* CNX2; int nNoeudsType = Nnoeuds(tm); int tailleCNX2 = nNoeudsType * (EFFECTIFS_TYPES[tm] - listeMaillesSuppr.size()); - CNX2 = (int*) malloc(sizeof(int) * tailleCNX2); + CNX2 = (med_int*) malloc(sizeof(med_int) * tailleCNX2); // Recopie sélective des connectivités int isuppr = 0; // indice dans listeMaillesSuppr int ih2 = 0; // nouveau numéro local ( remarque: ih2 = ih1 - isuppr ) diff --git a/src/Tools/MeshCut/MeshCut_Maillage.hxx b/src/Tools/MeshCut/MeshCut_Maillage.hxx index 7ec14de78..6f984dd09 100644 --- a/src/Tools/MeshCut/MeshCut_Maillage.hxx +++ b/src/Tools/MeshCut/MeshCut_Maillage.hxx @@ -75,7 +75,7 @@ namespace MESHCUT // Le numéro global du j-ième noeud de la maille de numéro global i est stocké à l'adresse // CNX[tm]+t*(i-1)+(j-1) // (t = taille du type, i.e. nombre de noeuds de l'élément) - std::map CNX; // ****** MED-OBLIGATOIRE ****** + std::map CNX; // ****** MED-OBLIGATOIRE ****** // Enveloppes cubiques std::map EC; diff --git a/src/Tools/MeshCut/MeshCut_Utils.cxx b/src/Tools/MeshCut/MeshCut_Utils.cxx index 5aa78dbb6..059ca3c8b 100644 --- a/src/Tools/MeshCut/MeshCut_Utils.cxx +++ b/src/Tools/MeshCut/MeshCut_Utils.cxx @@ -1035,7 +1035,7 @@ float MESHCUT::distance2(float x1, float y1, float z1, float x2, float y2, float /*! * Conversion HL-MED d'une table de connectivités */ -void MESHCUT::conversionCNX(int *CNXtm, TYPE_MAILLE tm, int N) +void MESHCUT::conversionCNX(med_int *CNXtm, TYPE_MAILLE tm, int N) { int n = Nnoeuds(tm); diff --git a/src/Tools/MeshCut/MeshCut_Utils.hxx b/src/Tools/MeshCut/MeshCut_Utils.hxx index 94b3eb968..72b9bfd4e 100644 --- a/src/Tools/MeshCut/MeshCut_Utils.hxx +++ b/src/Tools/MeshCut/MeshCut_Utils.hxx @@ -71,7 +71,7 @@ namespace MESHCUT std::string nomMaille(TYPE_MAILLE tm, int nl); bool appartientVN(int n, std::vector V); float distance2(float x1, float y1, float z1, float x2, float y2, float z2); - void conversionCNX(int *CNXtm, TYPE_MAILLE tm, int N); + void conversionCNX(med_int *CNXtm, TYPE_MAILLE tm, int N); }