diff --git a/CMakeLists.txt b/CMakeLists.txt index 249c3c09d..a88f8c23a 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,10 +29,10 @@ STRING(TOUPPER ${PROJECT_NAME} PROJECT_NAME_UC) SET(${PROJECT_NAME_UC}_MAJOR_VERSION 7) SET(${PROJECT_NAME_UC}_MINOR_VERSION 4) -SET(${PROJECT_NAME_UC}_PATCH_VERSION 0) +SET(${PROJECT_NAME_UC}_PATCH_VERSION 1) SET(${PROJECT_NAME_UC}_VERSION ${${PROJECT_NAME_UC}_MAJOR_VERSION}.${${PROJECT_NAME_UC}_MINOR_VERSION}.${${PROJECT_NAME_UC}_PATCH_VERSION}) -SET(${PROJECT_NAME_UC}_VERSION_DEV 0) +SET(${PROJECT_NAME_UC}_VERSION_DEV 1) # Find KERNEL # =========== @@ -162,7 +162,7 @@ ENDIF(EXISTS ${GEOM_ROOT_DIR}) ## # VTK is obligatiry for the SMESH -FIND_PACKAGE(SalomeVTK 6.1 REQUIRED) +FIND_PACKAGE(SalomeVTK REQUIRED) FIND_PACKAGE(SalomeCAS REQUIRED) diff --git a/doc/salome/examples/CMakeLists.txt b/doc/salome/examples/CMakeLists.txt index 227764998..7aa063689 100644 --- a/doc/salome/examples/CMakeLists.txt +++ b/doc/salome/examples/CMakeLists.txt @@ -17,8 +17,10 @@ # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # +# examples that cant be used for testing because they use external mesher plug-ins SET(BAD_TESTS 3dmesh.py + a3DmeshOnModified2Dmesh.py creating_meshes_ex01.py creating_meshes_ex03.py creating_meshes_ex05.py @@ -39,14 +41,14 @@ SET(BAD_TESTS quality_controls_ex20.py quality_controls_ex21.py quality_controls_ex22.py - viewing_meshes_ex01.py -) + viewing_meshes_ex01.py + ) SET(GOOD_TESTS - cartesian_algo.py - creating_meshes_ex02.py - creating_meshes_ex04.py - creating_meshes_ex06.py + cartesian_algo.py + creating_meshes_ex02.py + creating_meshes_ex04.py + creating_meshes_ex06.py creating_meshes_ex07.py creating_meshes_ex08.py defining_hypotheses_ex01.py diff --git a/doc/salome/examples/a3DmeshOnModified2Dmesh.py b/doc/salome/examples/a3DmeshOnModified2Dmesh.py new file mode 100644 index 000000000..7fcdcaca8 --- /dev/null +++ b/doc/salome/examples/a3DmeshOnModified2Dmesh.py @@ -0,0 +1,62 @@ +import salome +salome.salome_init() + +from salome.geom import geomBuilder +geompy = geomBuilder.New(salome.myStudy) + +# This script demonstrates generation of 3D mesh basing on a modified 2D mesh +# +# Purpose is to get a tetrahedral mesh in a sphere cut by a cube. +# The requirement is to have a surface mesh on the cube comprised of +# triangles of exactly the same size arranged in a grid pattern. +# +# To fulfill this requirement we mesh the box using Quadrangle (Mapping) +# meshing algorithm, split quadrangles into triangles and then generate +# tetrahedrons. + + +# Make the geometry + +Box_1 = geompy.MakeBox(-100,-100,-100, 100, 100, 100) +Sphere_1 = geompy.MakeSphereR( 300 ) +Cut_1 = geompy.MakeCut(Sphere_1, Box_1, theName="Cut_1") +# get a spherical face +Sph_Face = geompy.ExtractShapes( Sphere_1, geompy.ShapeType["FACE"] )[0] + +# get the shape Sph_Face turned into during MakeCut() +Sph_Face = geompy.GetInPlace(Cut_1, Sph_Face, isNewImplementation=True, theName="Sphere_1") + + +# 1) Define a mesh with 1D and 2D meshers + +import SMESH +from salome.smesh import smeshBuilder +smesh = smeshBuilder.New(salome.myStudy) + +Mesh_1 = smesh.Mesh(Cut_1) + +# "global" meshers (assigned to Cut_1) that will be used for the box +Regular_1D = Mesh_1.Segment() +Local_Length_1 = Regular_1D.LocalLength(20) +Quadrangle_2D = Mesh_1.Quadrangle() + +# a "local" mesher (assigned to a sub-mesh on Sphere_1) to mesh the sphere +algo_2D = Mesh_1.Triangle( smeshBuilder.NETGEN_1D2D, Sph_Face ) +algo_2D.SetMaxSize( 70. ) +algo_2D.SetFineness( smeshBuilder.Moderate ) +algo_2D.SetMinSize( 7. ) + +# 2) Compute 2D mesh +isDone = Mesh_1.Compute() + +# 3) Split quadrangles into triangles +isDone = Mesh_1.SplitQuadObject( Mesh_1, Diag13=True ) + +# 4) Define a 3D mesher +Mesh_1.Tetrahedron() + +# 5) Compute 3D mesh +Mesh_1.Compute() + +if salome.sg.hasDesktop(): + salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/creating_meshes_ex08.py b/doc/salome/examples/creating_meshes_ex08.py index 18f9dad01..e8f43eee6 100644 --- a/doc/salome/examples/creating_meshes_ex08.py +++ b/doc/salome/examples/creating_meshes_ex08.py @@ -32,8 +32,8 @@ newMesh = smesh.CopyMesh( mesh, "whole mesh copy") # 2. copy a group of 2D elements along with groups newMesh = smesh.CopyMesh( fGroup, "face group copy with groups",toCopyGroups=True) -# 3. copy a group of nodes with preseving their ids -newMesh = smesh.CopyMesh( nGroup, "node group copy", toKeepIDs=True) +# 3. copy a group of nodes +newMesh = smesh.CopyMesh( nGroup, "node group copy") # 4. copy some faces faceIds = fGroup.GetIDs()[-10:] diff --git a/doc/salome/examples/prism_3d_algo.py b/doc/salome/examples/prism_3d_algo.py index df18d0fcb..7be0a29d3 100644 --- a/doc/salome/examples/prism_3d_algo.py +++ b/doc/salome/examples/prism_3d_algo.py @@ -1,9 +1,14 @@ # Use 3D extrusion meshing algorithm -import salome, smesh, SMESH, geompy - +import salome salome.salome_init() -smesh.SetCurrentStudy( salome.myStudy ) + +from salome.geom import geomBuilder +geompy = geomBuilder.New(salome.myStudy) + +import SMESH +from salome.smesh import smeshBuilder +smesh = smeshBuilder.New(salome.myStudy) OX = geompy.MakeVectorDXDYDZ(1,0,0) OY = geompy.MakeVectorDXDYDZ(0,1,0) diff --git a/doc/salome/gui/SMESH/images/copy_mesh_dlg.png b/doc/salome/gui/SMESH/images/copy_mesh_dlg.png index db9c929b5..c959e680f 100644 Binary files a/doc/salome/gui/SMESH/images/copy_mesh_dlg.png and b/doc/salome/gui/SMESH/images/copy_mesh_dlg.png differ diff --git a/doc/salome/gui/SMESH/images/display_entity_choose_item.png b/doc/salome/gui/SMESH/images/display_entity_choose_item.png new file mode 100644 index 000000000..d09961822 Binary files /dev/null and b/doc/salome/gui/SMESH/images/display_entity_choose_item.png differ diff --git a/doc/salome/gui/SMESH/images/display_entity_dlg.png b/doc/salome/gui/SMESH/images/display_entity_dlg.png new file mode 100644 index 000000000..d0f4fa0ca Binary files /dev/null and b/doc/salome/gui/SMESH/images/display_entity_dlg.png differ diff --git a/doc/salome/gui/SMESH/images/extrusionalongaline1.png b/doc/salome/gui/SMESH/images/extrusionalongaline1.png old mode 100755 new mode 100644 index 95a26ca90..0cc13d518 Binary files a/doc/salome/gui/SMESH/images/extrusionalongaline1.png and b/doc/salome/gui/SMESH/images/extrusionalongaline1.png differ diff --git a/doc/salome/gui/SMESH/images/extrusionalongaline2.png b/doc/salome/gui/SMESH/images/extrusionalongaline2.png old mode 100755 new mode 100644 index 8c1662396..987a66c61 Binary files a/doc/salome/gui/SMESH/images/extrusionalongaline2.png and b/doc/salome/gui/SMESH/images/extrusionalongaline2.png differ diff --git a/doc/salome/gui/SMESH/input/1d_meshing_hypo.doc b/doc/salome/gui/SMESH/input/1d_meshing_hypo.doc index 7a9228b68..8c38c8ddf 100644 --- a/doc/salome/gui/SMESH/input/1d_meshing_hypo.doc +++ b/doc/salome/gui/SMESH/input/1d_meshing_hypo.doc @@ -257,15 +257,14 @@ hypothesis operation. \anchor automatic_length_anchor

Automatic Length

-This hypothesis is automatically applied when you select Assign a -set of hypotheses option in Create Mesh menu. - -\image html automaticlength.png - The dialog box prompts you to define the quality of the future mesh by only one parameter, which is \b Fineness, ranging from 0 (coarse mesh, low number of elements) to 1 (extremely fine mesh, great number of -elements). Compare one and the same object (sphere) meshed with +elements). + +\image html automaticlength.png + +Compare one and the same object (sphere) meshed with minimum and maximum value of this parameter. \image html image147.gif "Example of a very rough mesh. Automatic Length works for 0." diff --git a/doc/salome/gui/SMESH/input/2d_meshing_hypo.doc b/doc/salome/gui/SMESH/input/2d_meshing_hypo.doc index 0ccb902e0..05b8d5a39 100644 --- a/doc/salome/gui/SMESH/input/2d_meshing_hypo.doc +++ b/doc/salome/gui/SMESH/input/2d_meshing_hypo.doc @@ -113,10 +113,9 @@ of the enforced nodes. projected to the meshed face and located close enough to the meshed face will be used to create the enforced nodes. +\note Enforced nodes can't be created at \b Reduced transition type. Let us see how the algorithm works: - - -

Connections

- -Each mesh entity bounds 0 or more mesh entities of higher -dimension. In the same way each mesh entity is bounded by 0 or more -mesh entities of lower dimension: - - - -You can notice that there are two types of connections: \b inverse and -\b direct connections. - -

Inverse connections

- -This relationship has a particularity that the order of bounded -entities has not a direct meaning. Also the number of bounded entities -is not fixed. - -\b Example: The edges surrounding a node. The 3rd edge has no more -sense that the 5th one. - -

Direct connections

- -This relationship has a particularity that the order of bounding -entities is meaningful. The number of bounding entities is fixed and -depends on the type of the entity (hexahedron, tetrahedron,?). - -\b Example: An edge is composed of two nodes. A face is composed of 3 -or 4 edges depending if we are dealing with triangles or quadrangles. - -The connections are not only restricted to entities of one dimension -higher or lower. For example some algorithms may be interested to -retrieve all the faces surrounding a node. - */ diff --git a/doc/salome/gui/SMESH/input/basic_meshing_algos.doc b/doc/salome/gui/SMESH/input/basic_meshing_algos.doc index ee632b282..977b505db 100644 --- a/doc/salome/gui/SMESH/input/basic_meshing_algos.doc +++ b/doc/salome/gui/SMESH/input/basic_meshing_algos.doc @@ -52,15 +52,15 @@ geometrical objects. There is also a number of more specific algorithms: \ref constructing_meshes_page "Constructing meshes" page describes in diff --git a/doc/salome/gui/SMESH/input/constructing_meshes.doc b/doc/salome/gui/SMESH/input/constructing_meshes.doc index 232d4f524..5d26cae6c 100644 --- a/doc/salome/gui/SMESH/input/constructing_meshes.doc +++ b/doc/salome/gui/SMESH/input/constructing_meshes.doc @@ -9,6 +9,7 @@
  • \ref preview_anchor "Previewing the mesh" (optional)
  • \ref submesh_order_anchor "Changing sub-mesh priority" (optional)
  • \ref compute_anchor "Computing the mesh"
  • +
  • \ref edit_anchor "Editing the mesh" (optional)
  • \anchor create_mesh_anchor @@ -357,8 +358,29 @@ computation reporting. There are the following possibilities: always show the information box, show only if an error occurs or never. By default, the information box is always shown after mesh computation operation. -

    +

    +\anchor edit_anchor +

    Editing the mesh

    +It is possible to \ref modifying_meshes_page "edit the mesh" of +lower dimension before generation of mesh of higher dimension. +For example you can generate 2D mesh, modify it using e.g. +\ref pattern_mapping_page, and then generate 3D mesh basing on the +modified 2D mesh. The workflow is following: +- Define 1D and 2D meshing algorithms. +- Compute the mesh. 2D mesh is generated. +- Apply \ref pattern_mapping_page. +- Define 3D meshing algorithms without modifying 1D and 2D algorithms +and hypotheses. +- Compute the mesh. 3D mesh is generated. + +\note Nodes and elements added \ref adding_nodes_and_elements_page +"manually" can't be used in this workflow because the manually created +entities are not attached to any geometry and thus (usually) can't be +found by a mesher paving some geometry. + +See Also a sample TUI Script demonstrates the possibility of +\ref tui_editing_while_meshing "Intermediate edition while meshing" */ diff --git a/doc/salome/gui/SMESH/input/constructing_submeshes.doc b/doc/salome/gui/SMESH/input/constructing_submeshes.doc index 230903449..782b5662e 100644 --- a/doc/salome/gui/SMESH/input/constructing_submeshes.doc +++ b/doc/salome/gui/SMESH/input/constructing_submeshes.doc @@ -2,9 +2,21 @@ \page constructing_submeshes_page Constructing sub-meshes -Sub-mesh is a mesh on a geometrical sub-object created with meshing algorithms -and/or hypotheses other than the algorithms and hypotheses assigned to -the parent mesh on the parent geometrical object. +Sub-mesh is a mesh on a geometrical sub-object (sub-shape) used to assign +different meshing algorithms and/or hypotheses than the algorithms and +hypotheses assigned to the parent mesh on the parent geometrical +object, that allows getting a local mesh refinement. + +A sub-shape to create a sub-mesh on should be retrieved from the shape +of the parent mesh one of the following ways: If a geometrical sub-object belongs to several geometrical objects having different meshes or sub-meshes, it will be meshed with the @@ -56,6 +68,7 @@ sub-mesh. You can select meshing algorithms and hypotheses in the same way as in \ref constructing_meshes_page "Create mesh" menu. \par +\anchor subshape_by_mesh_elem If the parent mesh is already computed, then you can define the \b Geometry by picking mesh elements computed on a sub-shape of interest in the 3D Viewer, i.e. you do not have to extract this sub-shape @@ -77,12 +90,13 @@ Browser. \image html find_geom_by_mesh_elem.png \par -In this dialog, Element Type defines kind of element to pick in the -Viewer. +In this dialog, Element Type defines a kind of element to pick in the +Viewer. Instead of picking an element in the Viewer, you can type its ID in Element ID field. - Geometry name field allows defining a name of the sub-shape. - + Geometry name field allows defining a name of the sub-shape +with which the sub-shape will appear in the Object Browser (if not yet +there). \par In the Object Browser the structure of the new sub-mesh will be diff --git a/doc/salome/gui/SMESH/input/copy_mesh.doc b/doc/salome/gui/SMESH/input/copy_mesh.doc index 2c65ab8d0..15bf2d129 100644 --- a/doc/salome/gui/SMESH/input/copy_mesh.doc +++ b/doc/salome/gui/SMESH/input/copy_mesh.doc @@ -42,9 +42,6 @@ selection_filter_library_page "Selection filter library" page. diff --git a/doc/salome/gui/SMESH/input/display_entity.doc b/doc/salome/gui/SMESH/input/display_entity.doc index 570674017..ccd0043ef 100644 --- a/doc/salome/gui/SMESH/input/display_entity.doc +++ b/doc/salome/gui/SMESH/input/display_entity.doc @@ -9,4 +9,13 @@ edges or combine them. \image html image58.gif Only Edges +If the mesh contains a lot of elements, select Choose... item, + +\image html display_entity_choose_item.png Item to call 'Display Entity' dialog box + +and Display Entity dialog box will provide a way to display only some entities at first display instead of displaying all entities long time. + +\image html display_entity_dlg.png 'Display Entity' dialog allows to select entities before displaying + +\note This menu item is available from popup menu in both Object browser and 3D viewer. */ \ No newline at end of file diff --git a/doc/salome/gui/SMESH/input/extrusion.doc b/doc/salome/gui/SMESH/input/extrusion.doc index 4813eee5c..a28af48d4 100644 --- a/doc/salome/gui/SMESH/input/extrusion.doc +++ b/doc/salome/gui/SMESH/input/extrusion.doc @@ -6,12 +6,12 @@ dimension than the input ones. Any node, segment or 2D element can be extruded. Each type of elements has a corresponding type of extruded elements: - - - - - - + + + + + +
    Extruded element Result elements
    Node Segments
    Segment Quadrilaterals
    Triangle Pentahedrons
    Quadrilateral Hexahedrons
    Polygon Polyhedrons
    Extruded element Result element
    Node Segment
    Segment Quadrilateral
    Triangle Pentahedron
    Quadrilateral Hexahedron
    Polygon Polyhedron
    Hexagonal polygon Hexagonal prism
    @@ -35,7 +35,8 @@ The following dialog common for line and planar elements will appear:
  • In this dialog:
  • Click \b Apply or Apply and Close button to confirm the operation.
  • diff --git a/doc/salome/gui/SMESH/input/modifying_meshes.doc b/doc/salome/gui/SMESH/input/modifying_meshes.doc index 9006ddcd0..f09ab21d4 100755 --- a/doc/salome/gui/SMESH/input/modifying_meshes.doc +++ b/doc/salome/gui/SMESH/input/modifying_meshes.doc @@ -12,8 +12,6 @@ nodes to polyhedrons at an arbitrary place in the mesh. elements (used in quadratic meshes) from quadratic nodes to quadratic polyhedrons at an arbitrary place in the mesh.
  • \subpage removing_nodes_and_elements_page "Remove" any existing mesh elements.
  • -
  • \subpage renumbering_nodes_and_elements_page "Renumber" nodes and -elements of the mesh.
  • \subpage translation_page "Translate" in the indicated direction the mesh or some of its elements.
  • \subpage rotation_page "Rotate" by the indicated axis and angle @@ -53,6 +51,11 @@ or vice versa.
  • \subpage cut_mesh_by_plane_page "Cut a tetrahedron mesh by a plane".
  • +It is possible to \ref edit_anchor "modify the mesh" of lower +dimension before generation of mesh of higher dimension. + +


    + \note It is possible to use the variables defined in the SALOME \b NoteBook to specify the numerical parameters used for modification of any object. diff --git a/doc/salome/gui/SMESH/input/pattern_mapping.doc b/doc/salome/gui/SMESH/input/pattern_mapping.doc index ef7f8ba66..969b9fc5e 100644 --- a/doc/salome/gui/SMESH/input/pattern_mapping.doc +++ b/doc/salome/gui/SMESH/input/pattern_mapping.doc @@ -14,7 +14,7 @@ The smp file contains 4 sections: -# The first line indicates the total number of pattern nodes (N). -# The next N lines describe nodes coordinates. Each line contains 2 -node coordinates for a 2D pattern or 3 node cordinates for a 3D pattern. +node coordinates for a 2D pattern or 3 node coordinates for a 3D pattern. Note, that node coordinates of a 3D pattern can be defined only by relative values in range [0;1]. -# The key-points line contains the indices of the nodes to be mapped on geometrical vertices (for a 2D pattern only). Index n refers to the node described @@ -89,7 +89,7 @@ An example of a simple 3D pattern smp file:

    Application of pattern mapping

    -To apply pattern mapping to a geometrical object: +To apply pattern mapping to a geometrical object or mesh elements: From the \b Modification menu choose the Pattern Mapping item or click "Pattern mapping" button in the toolbar. @@ -113,16 +113,17 @@ created manually or generated automatically from an existing mesh or submesh.
  • \b Vertex to which the first key-point should be mapped;
  • + Alternatively, it is possible to select Refine selected mesh elements -checkbox and apply the pattern to +check-box and apply the pattern to +Additionally it is possible to: \n For a 3D pattern @@ -133,21 +134,27 @@ In this dialog you should specify: Alternatively, it is possible to select Refine selected mesh elements checkbox and apply the pattern to + Additionally it is possible to: + -\n Automatic Generation +
    +

    Automatic Generation

    -To generate a pattern automatically from an existing mesh or submesh, +To generate a pattern automatically from an existing mesh or sub-mesh, click \b New button. The following dialog box will appear: diff --git a/doc/salome/gui/SMESH/input/selection_filter_library.doc b/doc/salome/gui/SMESH/input/selection_filter_library.doc index c06fb6ec5..02d39a541 100644 --- a/doc/salome/gui/SMESH/input/selection_filter_library.doc +++ b/doc/salome/gui/SMESH/input/selection_filter_library.doc @@ -237,7 +237,7 @@ See also \ref filter_double_elements "Double Elements quality control". Bad oriented volume selects mesh volumes, which are incorrectly oriented from the point of view of MED convention.
  • -Over-constrained volumes selects mesh volumes having only one border shared +Over-constrained volumes selects mesh volumes having only one facet shared with other volumes. See also \ref over_constrained_volumes_page "Over-constrained volumes quality control".
  • diff --git a/doc/salome/gui/SMESH/input/tui_creating_meshes.doc b/doc/salome/gui/SMESH/input/tui_creating_meshes.doc index f1b12e4c4..984616457 100644 --- a/doc/salome/gui/SMESH/input/tui_creating_meshes.doc +++ b/doc/salome/gui/SMESH/input/tui_creating_meshes.doc @@ -18,6 +18,11 @@

    Change priority of submeshes in Mesh

    \tui_script{creating_meshes_ex03.py} +
    +\anchor tui_editing_while_meshing +

    Intermediate edition while meshing

    +\tui_script{a3DmeshOnModified2Dmesh.py} +
    \anchor tui_editing_mesh

    Editing a mesh

    diff --git a/doc/salome/gui/SMESH/input/viewing_meshes_overview.doc b/doc/salome/gui/SMESH/input/viewing_meshes_overview.doc index 376da99b0..248685579 100644 --- a/doc/salome/gui/SMESH/input/viewing_meshes_overview.doc +++ b/doc/salome/gui/SMESH/input/viewing_meshes_overview.doc @@ -33,7 +33,7 @@ viewer.
  • \subpage display_mode_page "Display Mode" - allows to select between Wireframe, Shading and Nodes presentation.
  • \subpage display_entity_page "Display Entity" - allows to display -Faces, Edges or both.
  • +entities by types (Faces, Edges, Volumes etc.).
  • 2D Quadratic - allows to select between the representation of quadratic edges as broken lines or as arcs
  • Orientation of faces - shows vectors of orientation of diff --git a/resources/CMakeLists.txt b/resources/CMakeLists.txt index 4ffa049b7..46ca05a36 100755 --- a/resources/CMakeLists.txt +++ b/resources/CMakeLists.txt @@ -34,6 +34,8 @@ SET(SMESH_RESOURCES_FILES mesh_aspect_3d.png mesh_biquad_quadrangle.png mesh_biquad_triangle.png + mesh_choose.png + mesh_choose_all.png mesh_clear.png mesh_compute.png mesh_diagonal.png diff --git a/resources/SalomeApp.xml.in b/resources/SalomeApp.xml.in index 618692c76..c49059d3a 100644 --- a/resources/SalomeApp.xml.in +++ b/resources/SalomeApp.xml.in @@ -130,9 +130,9 @@
    - +
    - +
    diff --git a/resources/mesh_choose.png b/resources/mesh_choose.png new file mode 100644 index 000000000..b5a40bacb Binary files /dev/null and b/resources/mesh_choose.png differ diff --git a/resources/mesh_choose_all.png b/resources/mesh_choose_all.png new file mode 100644 index 000000000..5387c8416 Binary files /dev/null and b/resources/mesh_choose_all.png differ diff --git a/src/Controls/SMESH_Controls.cxx b/src/Controls/SMESH_Controls.cxx index 213dc236d..6311da713 100644 --- a/src/Controls/SMESH_Controls.cxx +++ b/src/Controls/SMESH_Controls.cxx @@ -1954,6 +1954,7 @@ bool MultiConnection2D::Value::operator<(const MultiConnection2D::Value& x) cons } void MultiConnection2D::GetValues(MValues& theValues){ + if ( !myMesh ) return; SMDS_FaceIteratorPtr anIter = myMesh->facesIterator(); for(; anIter->more(); ){ const SMDS_MeshFace* anElem = anIter->next(); @@ -3134,11 +3135,14 @@ bool RangeOfIds::SetRangeStr( const TCollection_AsciiString& theStr ) myIds.Clear(); TCollection_AsciiString aStr = theStr; - aStr.RemoveAll( ' ' ); - aStr.RemoveAll( '\t' ); + //aStr.RemoveAll( ' ' ); + //aStr.RemoveAll( '\t' ); + for ( int i = 1; i <= aStr.Length(); ++i ) + if ( isspace( aStr.Value( i ))) + aStr.SetValue( i, ','); for ( int aPos = aStr.Search( ",," ); aPos != -1; aPos = aStr.Search( ",," ) ) - aStr.Remove( aPos, 2 ); + aStr.Remove( aPos, 1 ); TCollection_AsciiString tmpStr = aStr.Token( ",", 1 ); int i = 1; @@ -4247,11 +4251,11 @@ void BelongToGeom::init() myIsSubshape = IsSubShape(aMap, myShape); } - if (!myIsSubshape) + //if (!myIsSubshape) // to be always ready to check an element not bound to geometry { myElementsOnShapePtr.reset(new ElementsOnShape()); myElementsOnShapePtr->SetTolerance(myTolerance); - myElementsOnShapePtr->SetAllNodes(true); // belong, while false means "lays on" + myElementsOnShapePtr->SetAllNodes(true); // "belong", while false means "lays on" myElementsOnShapePtr->SetMesh(myMeshDS); myElementsOnShapePtr->SetShape(myShape, myType); } @@ -4292,36 +4296,43 @@ bool BelongToGeom::IsSatisfy (long theId) { if( const SMDS_MeshNode* aNode = myMeshDS->FindNode( theId ) ) { + if ( aNode->getshapeId() < 1 ) + return myElementsOnShapePtr->IsSatisfy(theId); + const SMDS_PositionPtr& aPosition = aNode->GetPosition(); SMDS_TypeOfPosition aTypeOfPosition = aPosition->GetTypeOfPosition(); switch( aTypeOfPosition ) { - case SMDS_TOP_VERTEX : return IsContains( myMeshDS,myShape,aNode,TopAbs_VERTEX ); - case SMDS_TOP_EDGE : return IsContains( myMeshDS,myShape,aNode,TopAbs_EDGE ); - case SMDS_TOP_FACE : return IsContains( myMeshDS,myShape,aNode,TopAbs_FACE ); - case SMDS_TOP_3DSPACE: return IsContains( myMeshDS,myShape,aNode,TopAbs_SHELL ); + case SMDS_TOP_VERTEX : return ( IsContains( myMeshDS,myShape,aNode,TopAbs_VERTEX )); + case SMDS_TOP_EDGE : return ( IsContains( myMeshDS,myShape,aNode,TopAbs_EDGE )); + case SMDS_TOP_FACE : return ( IsContains( myMeshDS,myShape,aNode,TopAbs_FACE )); + case SMDS_TOP_3DSPACE: return ( IsContains( myMeshDS,myShape,aNode,TopAbs_SOLID ) || + IsContains( myMeshDS,myShape,aNode,TopAbs_SHELL )); } } } else { - if( const SMDS_MeshElement* anElem = myMeshDS->FindElement( theId ) ) + if ( const SMDS_MeshElement* anElem = myMeshDS->FindElement( theId )) { + if ( anElem->getshapeId() < 1 ) + return myElementsOnShapePtr->IsSatisfy(theId); + if( myType == SMDSAbs_All ) { - return IsContains( myMeshDS,myShape,anElem,TopAbs_EDGE ) || - IsContains( myMeshDS,myShape,anElem,TopAbs_FACE ) || - IsContains( myMeshDS,myShape,anElem,TopAbs_SHELL )|| - IsContains( myMeshDS,myShape,anElem,TopAbs_SOLID ); + return ( IsContains( myMeshDS,myShape,anElem,TopAbs_EDGE ) || + IsContains( myMeshDS,myShape,anElem,TopAbs_FACE ) || + IsContains( myMeshDS,myShape,anElem,TopAbs_SOLID )|| + IsContains( myMeshDS,myShape,anElem,TopAbs_SHELL )); } else if( myType == anElem->GetType() ) { switch( myType ) { - case SMDSAbs_Edge : return IsContains( myMeshDS,myShape,anElem,TopAbs_EDGE ); - case SMDSAbs_Face : return IsContains( myMeshDS,myShape,anElem,TopAbs_FACE ); - case SMDSAbs_Volume: return IsContains( myMeshDS,myShape,anElem,TopAbs_SHELL )|| - IsContains( myMeshDS,myShape,anElem,TopAbs_SOLID ); + case SMDSAbs_Edge : return ( IsContains( myMeshDS,myShape,anElem,TopAbs_EDGE )); + case SMDSAbs_Face : return ( IsContains( myMeshDS,myShape,anElem,TopAbs_FACE )); + case SMDSAbs_Volume: return ( IsContains( myMeshDS,myShape,anElem,TopAbs_SOLID )|| + IsContains( myMeshDS,myShape,anElem,TopAbs_SHELL )); } } } diff --git a/src/PluginUtils/GeomSelectionTools.cxx b/src/PluginUtils/GeomSelectionTools.cxx index d57f2a210..c248771a4 100644 --- a/src/PluginUtils/GeomSelectionTools.cxx +++ b/src/PluginUtils/GeomSelectionTools.cxx @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include #include @@ -96,7 +96,7 @@ LightApp_SelectionMgr* GeomSelectionTools::selectionMgr() */ SALOME_ListIO* GeomSelectionTools::getSelectedSalomeObjects() { - SALOME_ListIO* selected; + SALOME_ListIO* selected = new SALOME_ListIO; LightApp_SelectionMgr* aSel = selectionMgr(); aSel->selectedObjects( *selected, NULL, false ); return selected; diff --git a/src/SMESH/CMakeLists.txt b/src/SMESH/CMakeLists.txt index 17e8d7b9c..a23c8c468 100644 --- a/src/SMESH/CMakeLists.txt +++ b/src/SMESH/CMakeLists.txt @@ -58,6 +58,7 @@ SET(_link_LIBRARIES ${CAS_TKG2d} ${CAS_TKCDF} ${GEOM_NMTTools} + ${GEOM_GEOMUtils} ${Boost_LIBRARIES} SMESHDS SMESHControls diff --git a/src/SMESH/SMESH_Algo.cxx b/src/SMESH/SMESH_Algo.cxx index 732c3e64a..5ec1240b0 100644 --- a/src/SMESH/SMESH_Algo.cxx +++ b/src/SMESH/SMESH_Algo.cxx @@ -522,9 +522,7 @@ GeomAbs_Shape SMESH_Algo::Continuity(TopoDS_Edge E1, Standard_Real tol = BRep_Tool::Tolerance( V ); Standard_Real angTol = 2e-3; try { -#if OCC_VERSION_LARGE > 0x06010000 OCC_CATCH_SIGNALS; -#endif return BRepLProp::Continuity(C1, C2, u1, u2, tol, angTol); } catch (Standard_Failure) { diff --git a/src/SMESH/SMESH_HypoFilter.cxx b/src/SMESH/SMESH_HypoFilter.cxx index e5d167064..d0125d1e5 100644 --- a/src/SMESH/SMESH_HypoFilter.cxx +++ b/src/SMESH/SMESH_HypoFilter.cxx @@ -157,8 +157,9 @@ void SMESH_HypoFilter::IsMoreLocalThanPredicate::findPreferable() bool SMESH_HypoFilter::IsMoreLocalThanPredicate::IsOk(const SMESH_Hypothesis* aHyp, const TopoDS_Shape& aShape) const { - if ( aShape.IsSame( _mesh.GetShapeToMesh() )) - return false; // aHyp is global + if ( aShape.IsSame( _mesh.GetShapeToMesh() ) || // aHyp is global + aShape.IsSame( _shape )) + return false; if ( SMESH_MesherHelper::IsSubShape( aShape, /*mainShape=*/_shape )) return true; diff --git a/src/SMESH/SMESH_Mesh.cxx b/src/SMESH/SMESH_Mesh.cxx index 7692f9f0e..72d7ef193 100644 --- a/src/SMESH/SMESH_Mesh.cxx +++ b/src/SMESH/SMESH_Mesh.cxx @@ -55,8 +55,10 @@ #include "DriverCGNS_Write.hxx" #endif +#include + #undef _Precision_HeaderFile -#include +//#include #include #include #include @@ -226,7 +228,7 @@ SMESH_Mesh::~SMESH_Mesh() bool SMESH_Mesh::MeshExists( int meshId ) const { - return _myDocument ? _myDocument->GetMesh( meshId ) : false; + return _myDocument ? bool( _myDocument->GetMesh( meshId )) : false; } //============================================================================= @@ -327,8 +329,9 @@ double SMESH_Mesh::GetShapeDiagonalSize(const TopoDS_Shape & aShape) { if ( !aShape.IsNull() ) { Bnd_Box Box; - BRepBndLib::Add(aShape, Box); - return sqrt( Box.SquareExtent() ); + GEOMUtils::PreciseBoundingBox(aShape, Box); + if ( !Box.IsVoid() ) + return sqrt( Box.SquareExtent() ); } return 0; } diff --git a/src/SMESH/SMESH_Mesh.hxx b/src/SMESH/SMESH_Mesh.hxx index 0cf3e0949..c603c6a41 100644 --- a/src/SMESH/SMESH_Mesh.hxx +++ b/src/SMESH/SMESH_Mesh.hxx @@ -63,15 +63,15 @@ typedef std::list TListOfListOfInt; class SMESH_EXPORT SMESH_Mesh { -public: - SMESH_Mesh(int theLocalId, - int theStudyId, + public: + SMESH_Mesh(int theLocalId, + int theStudyId, SMESH_Gen* theGen, bool theIsEmbeddedMode, SMESHDS_Document* theDocument); - + virtual ~SMESH_Mesh(); - + /*! * \brief Set geometry to be meshed */ diff --git a/src/SMESH/SMESH_MeshEditor.cxx b/src/SMESH/SMESH_MeshEditor.cxx index e216b2e74..08cc1d9c2 100644 --- a/src/SMESH/SMESH_MeshEditor.cxx +++ b/src/SMESH/SMESH_MeshEditor.cxx @@ -3701,13 +3701,8 @@ static bool getClosestUV (Extrema_GenExtPS& projector, if ( projector.IsDone() ) { double u, v, minVal = DBL_MAX; for ( int i = projector.NbExt(); i > 0; i-- ) -#if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1 if ( projector.SquareDistance( i ) < minVal ) { minVal = projector.SquareDistance( i ); -#else - if ( projector.Value( i ) < minVal ) { - minVal = projector.Value( i ); -#endif projector.Point( i ).Parameter( u, v ); } result.SetCoord( u, v ); @@ -10397,15 +10392,12 @@ namespace { } void Perform(const gp_Pnt& aPnt, double theTol) { + theTol *= theTol; _state = TopAbs_OUT; _extremum.Perform(aPnt); if ( _extremum.IsDone() ) for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol) -#if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1 _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT ); -#else - _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT ); -#endif } TopAbs_State State() const { diff --git a/src/SMESH/SMESH_MesherHelper.cxx b/src/SMESH/SMESH_MesherHelper.cxx index bdd358451..c6c51ab37 100644 --- a/src/SMESH/SMESH_MesherHelper.cxx +++ b/src/SMESH/SMESH_MesherHelper.cxx @@ -242,40 +242,68 @@ void SMESH_MesherHelper::SetSubShape(const TopoDS_Shape& aSh) for ( TopExp_Explorer eF( aSh, TopAbs_FACE ); eF.More(); eF.Next() ) { const TopoDS_Face& face = TopoDS::Face( eF.Current() ); + BRepAdaptor_Surface surf( face, false ); + if ( surf.IsUPeriodic() || surf.IsUClosed() ) { + myParIndex |= U_periodic; + myPar1[0] = surf.FirstUParameter(); + myPar2[0] = surf.LastUParameter(); + } + if ( surf.IsVPeriodic() || surf.IsVClosed() ) { + myParIndex |= V_periodic; + myPar1[1] = surf.FirstVParameter(); + myPar2[1] = surf.LastVParameter(); + } - // if ( surface->IsUPeriodic() || surface->IsVPeriodic() || - // surface->IsUClosed() || surface->IsVClosed() ) + gp_Pnt2d uv1, uv2; + for (TopExp_Explorer exp( face, TopAbs_EDGE ); exp.More(); exp.Next()) { - //while ( surface->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface ))) - //surface = Handle(Geom_RectangularTrimmedSurface)::DownCast( surface )->BasisSurface(); - - for (TopExp_Explorer exp( face, TopAbs_EDGE ); exp.More(); exp.Next()) + // look for a "seam" edge, a real seam or an edge on period boundary + TopoDS_Edge edge = TopoDS::Edge( exp.Current() ); + if ( myParIndex ) { - // look for a seam edge - TopoDS_Edge edge = TopoDS::Edge( exp.Current() ); - if ( BRep_Tool::IsClosed( edge, face )) { - // initialize myPar1, myPar2 and myParIndex - gp_Pnt2d uv1, uv2; - BRep_Tool::UVPoints( edge, face, uv1, uv2 ); - if ( Abs( uv1.Coord(1) - uv2.Coord(1) ) < Abs( uv1.Coord(2) - uv2.Coord(2) )) + BRep_Tool::UVPoints( edge, face, uv1, uv2 ); + const double du = Abs( uv1.Coord(1) - uv2.Coord(1) ); + const double dv = Abs( uv1.Coord(2) - uv2.Coord(2) ); + + bool isSeam = BRep_Tool::IsClosed( edge, face ); + if ( isSeam ) // real seam - having two pcurves on face + { + // pcurve can lie not on pediod boundary (22582, mesh_Quadratic_01/C9) + if ( du < dv ) { double u1 = uv1.Coord(1); edge.Reverse(); BRep_Tool::UVPoints( edge, face, uv1, uv2 ); double u2 = uv1.Coord(1); - myParIndex |= U_periodic; myPar1[0] = Min( u1, u2 ); myPar2[0] = Max( u1, u2 ); } - else { + else + { double v1 = uv1.Coord(2); edge.Reverse(); BRep_Tool::UVPoints( edge, face, uv1, uv2 ); double v2 = uv1.Coord(2); - myParIndex |= V_periodic; myPar1[1] = Min( v1, v2 ); myPar2[1] = Max( v1, v2 ); } + } + else //if ( !isSeam ) + { + // one pcurve but on period boundary (22772, mesh_Quadratic_01/D1) + if (( myParIndex & U_periodic ) && du < Precision::PConfusion() ) + { + isSeam = ( Abs( uv1.Coord(1) - myPar1[0] ) < Precision::PConfusion() || + Abs( uv1.Coord(1) - myPar2[0] ) < Precision::PConfusion() ); + } + else if (( myParIndex & V_periodic ) && dv < Precision::PConfusion() ) + { + isSeam = ( Abs( uv1.Coord(2) - myPar1[1] ) < Precision::PConfusion() || + Abs( uv1.Coord(2) - myPar2[1] ) < Precision::PConfusion() ); + } + } + if ( isSeam ) + { // store seam shape indices, negative if shape encounters twice int edgeID = meshDS->ShapeToIndex( edge ); mySeamShapeIds.insert( IsSeamShape( edgeID ) ? -edgeID : edgeID ); @@ -284,27 +312,12 @@ void SMESH_MesherHelper::SetSubShape(const TopoDS_Shape& aSh) mySeamShapeIds.insert( IsSeamShape( vertexID ) ? -vertexID : vertexID ); } } - - // look for a degenerated edge - if ( SMESH_Algo::isDegenerated( edge )) { - myDegenShapeIds.insert( meshDS->ShapeToIndex( edge )); - for ( TopExp_Explorer v( edge, TopAbs_VERTEX ); v.More(); v.Next() ) - myDegenShapeIds.insert( meshDS->ShapeToIndex( v.Current() )); - } } - if ( !myDegenShapeIds.empty() && !myParIndex ) - { - BRepAdaptor_Surface surf( face, false ); - if ( surf.IsUPeriodic() || surf.IsUClosed() ) { - myParIndex |= U_periodic; - myPar1[0] = surf.FirstUParameter(); - myPar2[0] = surf.LastUParameter(); - } - else if ( surf.IsVPeriodic() || surf.IsVClosed() ) { - myParIndex |= V_periodic; - myPar1[1] = surf.FirstVParameter(); - myPar2[1] = surf.LastVParameter(); - } + // look for a degenerated edge + if ( SMESH_Algo::isDegenerated( edge )) { + myDegenShapeIds.insert( meshDS->ShapeToIndex( edge )); + for ( TopExp_Explorer v( edge, TopAbs_VERTEX ); v.More(); v.Next() ) + myDegenShapeIds.insert( meshDS->ShapeToIndex( v.Current() )); } } } @@ -380,10 +393,13 @@ void SMESH_MesherHelper::AddTLinkNode(const SMDS_MeshNode* n1, */ //================================================================================ -void SMESH_MesherHelper::AddTLinks(const SMDS_MeshEdge* edge) +bool SMESH_MesherHelper::AddTLinks(const SMDS_MeshEdge* edge) { - if ( edge->IsQuadratic() ) + if ( edge && edge->IsQuadratic() ) AddTLinkNode(edge->GetNode(0), edge->GetNode(1), edge->GetNode(2)); + else + return false; + return true; } //================================================================================ @@ -392,8 +408,9 @@ void SMESH_MesherHelper::AddTLinks(const SMDS_MeshEdge* edge) */ //================================================================================ -void SMESH_MesherHelper::AddTLinks(const SMDS_MeshFace* f) +bool SMESH_MesherHelper::AddTLinks(const SMDS_MeshFace* f) { + bool isQuad = true; if ( !f->IsPoly() ) switch ( f->NbNodes() ) { case 7: @@ -417,7 +434,9 @@ void SMESH_MesherHelper::AddTLinks(const SMDS_MeshFace* f) AddTLinkNode(f->GetNode(2),f->GetNode(3),f->GetNode(6)); AddTLinkNode(f->GetNode(3),f->GetNode(0),f->GetNode(7)); break; default:; + isQuad = false; } + return isQuad; } //================================================================================ @@ -426,7 +445,7 @@ void SMESH_MesherHelper::AddTLinks(const SMDS_MeshFace* f) */ //================================================================================ -void SMESH_MesherHelper::AddTLinks(const SMDS_MeshVolume* volume) +bool SMESH_MesherHelper::AddTLinks(const SMDS_MeshVolume* volume) { if ( volume->IsQuadratic() ) { @@ -460,7 +479,9 @@ void SMESH_MesherHelper::AddTLinks(const SMDS_MeshVolume* volume) nFCenter )); } } + return true; } + return false; } //================================================================================ @@ -586,14 +607,24 @@ gp_XY SMESH_MesherHelper::GetNodeUV(const TopoDS_Face& F, Handle(Geom_Surface) S = BRep_Tool::Surface(F,loc); Standard_Boolean isUPeriodic = S->IsUPeriodic(); Standard_Boolean isVPeriodic = S->IsVPeriodic(); + gp_Pnt2d newUV = uv; if ( isUPeriodic || isVPeriodic ) { Standard_Real UF,UL,VF,VL; S->Bounds(UF,UL,VF,VL); - if(isUPeriodic) - uv.SetX( uv.X() + ShapeAnalysis::AdjustToPeriod(uv.X(),UF,UL)); - if(isVPeriodic) - uv.SetY( uv.Y() + ShapeAnalysis::AdjustToPeriod(uv.Y(),VF,VL)); + if ( isUPeriodic ) + newUV.SetX( uv.X() + ShapeAnalysis::AdjustToPeriod(uv.X(),UF,UL)); + if ( isVPeriodic ) + newUV.SetY( uv.Y() + ShapeAnalysis::AdjustToPeriod(uv.Y(),VF,VL)); } + if ( n2 ) + { + gp_Pnt2d uv2 = GetNodeUV( F, n2, 0, check ); + if ( isUPeriodic && Abs( uv.X()-uv2.X() ) < Abs( newUV.X()-uv2.X() )) + newUV.SetX( uv.X() ); + if ( isVPeriodic && Abs( uv.Y()-uv2.Y() ) < Abs( newUV.Y()-uv2.Y() )) + newUV.SetY( uv.Y() ); + } + uv = newUV; } } else if(Pos->GetTypeOfPosition()==SMDS_TOP_VERTEX) @@ -910,7 +941,7 @@ bool SMESH_MesherHelper::CheckNodeU(const TopoDS_Edge& E, int shapeID = n->getshapeId(); bool infinit = Precision::IsInfinite( u ); bool zero = ( u == 0. ); - if ( force || toCheckPosOnShape( shapeID ) || infinit || zero ) + if ( force || infinit || zero || toCheckPosOnShape( shapeID )) { TopLoc_Location loc; double f,l; Handle(Geom_Curve) curve = BRep_Tool::Curve( E,loc,f,l ); @@ -927,7 +958,7 @@ bool SMESH_MesherHelper::CheckNodeU(const TopoDS_Edge& E, gp_Pnt nodePnt = SMESH_TNodeXYZ( n ); if ( !loc.IsIdentity() ) nodePnt.Transform( loc.Transformation().Inverted() ); gp_Pnt curvPnt; - double dist = u; + double dist = 2*tol; if ( !infinit ) { curvPnt = curve->Value( u ); @@ -2433,7 +2464,7 @@ namespace //======================================================================= //function : IsStructured -//purpose : Return true if 2D mesh on FACE is structured +//purpose : Return true if 2D mesh on FACE is a structured rectangle //======================================================================= bool SMESH_MesherHelper::IsStructured( SMESH_subMesh* faceSM ) @@ -2523,6 +2554,79 @@ bool SMESH_MesherHelper::IsStructured( SMESH_subMesh* faceSM ) return true; } +//======================================================================= +//function : IsDistorted2D +//purpose : Return true if 2D mesh on FACE is ditorted +//======================================================================= + +bool SMESH_MesherHelper::IsDistorted2D( SMESH_subMesh* faceSM, + bool checkUV) +{ + if ( !faceSM || faceSM->GetSubShape().ShapeType() != TopAbs_FACE ) + return false; + + bool haveBadFaces = false; + + SMESH_MesherHelper helper( *faceSM->GetFather() ); + helper.SetSubShape( faceSM->GetSubShape() ); + + const TopoDS_Face& F = TopoDS::Face( faceSM->GetSubShape() ); + SMESHDS_SubMesh* smDS = helper.GetMeshDS()->MeshElements( F ); + if ( !smDS || smDS->NbElements() == 0 ) return false; + + SMDS_ElemIteratorPtr faceIt = smDS->GetElements(); + double prevArea = 0; + vector< const SMDS_MeshNode* > nodes; + vector< gp_XY > uv; + bool* toCheckUV = checkUV ? & checkUV : 0; + while ( faceIt->more() && !haveBadFaces ) + { + const SMDS_MeshElement* face = faceIt->next(); + + // get nodes + nodes.resize( face->NbCornerNodes() ); + SMDS_MeshElement::iterator n = face->begin_nodes(); + for ( size_t i = 0; i < nodes.size(); ++n, ++i ) + nodes[ i ] = *n; + + // avoid elems on degenarate shapes as UV on them can be wrong + if ( helper.HasDegeneratedEdges() ) + { + bool isOnDegen = false; + for ( size_t i = 0; ( i < nodes.size() && !isOnDegen ); ++i ) + isOnDegen = helper.IsDegenShape( nodes[ i ]->getshapeId() ); + if ( isOnDegen ) + continue; + } + // prepare to getting UVs + const SMDS_MeshNode* inFaceNode = 0; + if ( helper.HasSeam() ) { + for ( size_t i = 0; ( i < nodes.size() && !inFaceNode ); ++i ) + if ( !helper.IsSeamShape( nodes[ i ]->getshapeId() )) + inFaceNode = nodes[ i ]; + if ( !inFaceNode ) + continue; + } + // get UVs + uv.resize( nodes.size() ); + for ( size_t i = 0; i < nodes.size(); ++i ) + uv[ i ] = helper.GetNodeUV( F, nodes[ i ], inFaceNode, toCheckUV ); + + // compare orientation of triangles + double faceArea = 0; + for ( int iT = 0, nbT = nodes.size()-2; iT < nbT; ++iT ) + { + gp_XY v1 = uv[ iT+1 ] - uv[ 0 ]; + gp_XY v2 = uv[ iT+2 ] - uv[ 0 ]; + faceArea += v2 ^ v1; + } + haveBadFaces = ( faceArea * prevArea < 0 ); + prevArea = faceArea; + } + + return haveBadFaces; +} + //================================================================================ /*! * \brief Find out elements orientation on a geometrical face @@ -2702,6 +2806,28 @@ bool SMESH_MesherHelper::IsSubShape( const TopoDS_Shape& shape, SMESH_Mesh* aMes (shape.ShapeType() == TopAbs_COMPOUND && aMesh->GetMeshDS()->IsGroupOfSubShapes( shape )); } +//======================================================================= +//function : IsBlock +//purpose : +//======================================================================= + +bool SMESH_MesherHelper::IsBlock( const TopoDS_Shape& shape ) +{ + if ( shape.IsNull() ) + return false; + + TopoDS_Shell shell; + TopExp_Explorer exp( shape, TopAbs_SHELL ); + if ( !exp.More() ) return false; + shell = TopoDS::Shell( exp.Current() ); + if ( exp.Next(), exp.More() ) return false; + + TopoDS_Vertex v; + TopTools_IndexedMapOfOrientedShape map; + return SMESH_Block::FindBlockShapes( shell, v, v, map ); +} + + //================================================================================ /*! * \brief Return maximal tolerance of shape diff --git a/src/SMESH/SMESH_MesherHelper.hxx b/src/SMESH/SMESH_MesherHelper.hxx index 51ea719de..164861c32 100644 --- a/src/SMESH/SMESH_MesherHelper.hxx +++ b/src/SMESH/SMESH_MesherHelper.hxx @@ -117,6 +117,11 @@ class SMESH_EXPORT SMESH_MesherHelper */ static bool IsStructured( SMESH_subMesh* faceSM ); + /*! + * \brief Return true if 2D mesh on FACE is distored + */ + static bool IsDistorted2D( SMESH_subMesh* faceSM, bool checkUV=false ); + /*! * \brief Returns true if given node is medium * \param n - node to check @@ -167,15 +172,15 @@ class SMESH_EXPORT SMESH_MesherHelper * a0 p0 a1 */ inline static gp_XY calcTFI(double x, double y, - const gp_XY a0,const gp_XY a1,const gp_XY a2,const gp_XY a3, - const gp_XY p0,const gp_XY p1,const gp_XY p2,const gp_XY p3); + const gp_XY& a0,const gp_XY& a1,const gp_XY& a2,const gp_XY& a3, + const gp_XY& p0,const gp_XY& p1,const gp_XY& p2,const gp_XY& p3); /*! * \brief Same as "gp_XY calcTFI(...)" but in 3D */ inline static gp_XYZ calcTFI(double x, double y, - const gp_XYZ a0,const gp_XYZ a1,const gp_XYZ a2,const gp_XYZ a3, - const gp_XYZ p0,const gp_XYZ p1,const gp_XYZ p2,const gp_XYZ p3); + const gp_XYZ& a0,const gp_XYZ& a1,const gp_XYZ& a2,const gp_XYZ& a3, + const gp_XYZ& p0,const gp_XYZ& p1,const gp_XYZ& p2,const gp_XYZ& p3); /*! * \brief Count nb of sub-shapes * \param shape - the shape @@ -216,6 +221,8 @@ class SMESH_EXPORT SMESH_MesherHelper static bool IsSubShape( const TopoDS_Shape& shape, SMESH_Mesh* aMesh ); + static bool IsBlock( const TopoDS_Shape& shape ); + static double MaxTolerance( const TopoDS_Shape& shape ); static double GetAngle( const TopoDS_Edge & E1, const TopoDS_Edge & E2, @@ -637,9 +644,9 @@ public: void AddTLinkNodeMap(const TLinkNodeMap& aMap) { myTLinkNodeMap.insert(aMap.begin(), aMap.end()); } - void AddTLinks(const SMDS_MeshEdge* edge); - void AddTLinks(const SMDS_MeshFace* face); - void AddTLinks(const SMDS_MeshVolume* vol); + bool AddTLinks(const SMDS_MeshEdge* edge); + bool AddTLinks(const SMDS_MeshFace* face); + bool AddTLinks(const SMDS_MeshVolume* vol); /** * Returns myTLinkNodeMap @@ -725,8 +732,8 @@ public: //======================================================================= inline gp_XY SMESH_MesherHelper::calcTFI(double x, double y, - const gp_XY a0,const gp_XY a1,const gp_XY a2,const gp_XY a3, - const gp_XY p0,const gp_XY p1,const gp_XY p2,const gp_XY p3) + const gp_XY& a0,const gp_XY& a1,const gp_XY& a2,const gp_XY& a3, + const gp_XY& p0,const gp_XY& p1,const gp_XY& p2,const gp_XY& p3) { return ((1 - y) * p0 + x * p1 + y * p2 + (1 - x) * p3 ) - @@ -735,8 +742,8 @@ SMESH_MesherHelper::calcTFI(double x, double y, //======================================================================= inline gp_XYZ SMESH_MesherHelper::calcTFI(double x, double y, - const gp_XYZ a0,const gp_XYZ a1,const gp_XYZ a2,const gp_XYZ a3, - const gp_XYZ p0,const gp_XYZ p1,const gp_XYZ p2,const gp_XYZ p3) + const gp_XYZ& a0,const gp_XYZ& a1,const gp_XYZ& a2,const gp_XYZ& a3, + const gp_XYZ& p0,const gp_XYZ& p1,const gp_XYZ& p2,const gp_XYZ& p3) { return ((1 - y) * p0 + x * p1 + y * p2 + (1 - x) * p3 ) - diff --git a/src/SMESH/SMESH_Pattern.cxx b/src/SMESH/SMESH_Pattern.cxx index 75d26244d..2264ba3d1 100644 --- a/src/SMESH/SMESH_Pattern.cxx +++ b/src/SMESH/SMESH_Pattern.cxx @@ -501,13 +501,8 @@ static gp_XY project (const SMDS_MeshNode* theNode, } double u, v, minVal = DBL_MAX; for ( int i = theProjectorPS.NbExt(); i > 0; i-- ) -#if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1 if ( theProjectorPS.SquareDistance( i ) < minVal ) { minVal = theProjectorPS.SquareDistance( i ); -#else - if ( theProjectorPS.Value( i ) < minVal ) { - minVal = theProjectorPS.Value( i ); -#endif theProjectorPS.Point( i ).Parameter( u, v ); } return gp_XY( u, v ); diff --git a/src/SMESH/SMESH_subMesh.cxx b/src/SMESH/SMESH_subMesh.cxx index 59294a54c..0d4e2d120 100644 --- a/src/SMESH/SMESH_subMesh.cxx +++ b/src/SMESH/SMESH_subMesh.cxx @@ -2148,9 +2148,9 @@ TopoDS_Shape SMESH_subMesh::getCollection(SMESH_Gen * theGen, if ( mainShape.IsSame( _subShape )) return _subShape; - const bool ignoreAuxiliaryHyps = false; + const bool skipAuxHyps = false; list aUsedHyp = - theAlgo->GetUsedHypothesis( *_father, _subShape, ignoreAuxiliaryHyps ); // copy + theAlgo->GetUsedHypothesis( *_father, _subShape, skipAuxHyps ); // copy // put in a compound all shapes with the same hypothesis assigned // and a good ComputeState @@ -2161,11 +2161,13 @@ TopoDS_Shape SMESH_subMesh::getCollection(SMESH_Gen * theGen, theSubs.clear(); - TopExp_Explorer anExplorer( mainShape, _subShape.ShapeType() ); - for ( ; anExplorer.More(); anExplorer.Next() ) + SMESH_subMeshIteratorPtr smIt = _father->GetSubMesh( mainShape )->getDependsOnIterator(false); + while ( smIt->more() ) { - const TopoDS_Shape& S = anExplorer.Current(); - SMESH_subMesh* subMesh = _father->GetSubMesh( S ); + SMESH_subMesh* subMesh = smIt->next(); + const TopoDS_Shape& S = subMesh->_subShape; + if ( S.ShapeType() != this->_subShape.ShapeType() ) + continue; theSubs.push_back( subMesh ); if ( subMesh == this ) { @@ -2173,12 +2175,14 @@ TopoDS_Shape SMESH_subMesh::getCollection(SMESH_Gen * theGen, } else if ( subMesh->GetComputeState() == READY_TO_COMPUTE ) { - SMESH_Algo* anAlgo = theGen->GetAlgo( subMesh ); - if (strcmp( anAlgo->GetName(), theAlgo->GetName()) == 0 && // same algo - anAlgo->GetUsedHypothesis( *_father, S, ignoreAuxiliaryHyps ) == aUsedHyp) // same hyps + SMESH_Algo* anAlgo = subMesh->GetAlgo(); + if (( anAlgo->IsSameName( *theAlgo )) && // same algo + ( anAlgo->GetUsedHypothesis( *_father, S, skipAuxHyps ) == aUsedHyp )) // same hyps + { aBuilder.Add( aCompound, S ); - if ( !subMesh->SubMeshesComputed() ) - theSubComputed = false; + if ( !subMesh->SubMeshesComputed() ) + theSubComputed = false; + } } } diff --git a/src/SMESHGUI/CMakeLists.txt b/src/SMESHGUI/CMakeLists.txt index d92818942..59a99865b 100644 --- a/src/SMESHGUI/CMakeLists.txt +++ b/src/SMESHGUI/CMakeLists.txt @@ -142,6 +142,7 @@ SET(_moc_HEADERS SMESHGUI_PropertiesDlg.h SMESHGUI_Add0DElemsOnAllNodesDlg.h SMESHGUI_FieldSelectorWdg.h + SMESHGUI_DisplayEntitiesDlg.h ) # header files / no moc processing @@ -249,6 +250,7 @@ SET(_other_SOURCES SMESHGUI_MeshEditPreview.cxx SMESHGUI_FileValidator.cxx SMESHGUI_FieldSelectorWdg.cxx + SMESHGUI_DisplayEntitiesDlg.cxx ) # sources / to compile diff --git a/src/SMESHGUI/SMESHGUI.cxx b/src/SMESHGUI/SMESHGUI.cxx index 71ccf611d..7908b4f49 100644 --- a/src/SMESHGUI/SMESHGUI.cxx +++ b/src/SMESHGUI/SMESHGUI.cxx @@ -81,6 +81,7 @@ #include "SMESHGUI_SymmetryDlg.h" #include "SMESHGUI_TranslationDlg.h" #include "SMESHGUI_TransparencyDlg.h" +#include "SMESHGUI_DisplayEntitiesDlg.h" #include "SMESHGUI_FilterUtils.h" #include "SMESHGUI_GEOMGenUtils.h" @@ -91,14 +92,14 @@ #include "SMESHGUI_Utils.h" #include "SMESHGUI_VTKUtils.h" -#include +#include "SMESH_version.h" #include "SMESH_ControlsDef.hxx" -#include -#include -#include -#include -#include +#include "SMESH_Actor.h" +#include "SMESH_ActorUtils.h" +#include "SMESH_Client.hxx" +#include "SMESH_ScalarBarActor.h" +#include "SMESH_TypeFilter.hxx" // SALOME GUI includes #include @@ -132,7 +133,6 @@ #include #include -#include #ifndef DISABLE_PLOT2DVIEWER #include @@ -1566,111 +1566,124 @@ namespace void Control( int theCommandID ) { + SMESH_Actor::eControl aControl = SMESH_Actor::eNone; + switch ( theCommandID ){ + case SMESHOp::OpFreeNode: + aControl = SMESH_Actor::eFreeNodes; + break; + case SMESHOp::OpEqualNode: + aControl = SMESH_Actor::eCoincidentNodes; + break; + case SMESHOp::OpFreeEdge: + aControl = SMESH_Actor::eFreeEdges; + break; + case SMESHOp::OpFreeBorder: + aControl = SMESH_Actor::eFreeBorders; + break; + case SMESHOp::OpLength: + aControl = SMESH_Actor::eLength; + break; + case SMESHOp::OpConnection: + aControl = SMESH_Actor::eMultiConnection; + break; + case SMESHOp::OpEqualEdge: + aControl = SMESH_Actor::eCoincidentElems1D; + break; + case SMESHOp::OpFreeFace: + aControl = SMESH_Actor::eFreeFaces; + break; + case SMESHOp::OpBareBorderFace: + aControl = SMESH_Actor::eBareBorderFace; + break; + case SMESHOp::OpOverConstrainedFace: + aControl = SMESH_Actor::eOverConstrainedFace; + break; + case SMESHOp::OpLength2D: + aControl = SMESH_Actor::eLength2D; + break; + case SMESHOp::OpConnection2D: + aControl = SMESH_Actor::eMultiConnection2D; + break; + case SMESHOp::OpArea: + aControl = SMESH_Actor::eArea; + break; + case SMESHOp::OpTaper: + aControl = SMESH_Actor::eTaper; + break; + case SMESHOp::OpAspectRatio: + aControl = SMESH_Actor::eAspectRatio; + break; + case SMESHOp::OpMinimumAngle: + aControl = SMESH_Actor::eMinimumAngle; + break; + case SMESHOp::OpWarpingAngle: + aControl = SMESH_Actor::eWarping; + break; + case SMESHOp::OpSkew: + aControl = SMESH_Actor::eSkew; + break; + case SMESHOp::OpMaxElementLength2D: + aControl = SMESH_Actor::eMaxElementLength2D; + break; + case SMESHOp::OpEqualFace: + aControl = SMESH_Actor:: eCoincidentElems2D; + break; + case SMESHOp::OpAspectRatio3D: + aControl = SMESH_Actor::eAspectRatio3D; + break; + case SMESHOp::OpVolume: + aControl = SMESH_Actor::eVolume3D; + break; + case SMESHOp::OpMaxElementLength3D: + aControl = SMESH_Actor::eMaxElementLength3D; + break; + case SMESHOp::OpBareBorderVolume: + aControl = SMESH_Actor::eBareBorderVolume; + break; + case SMESHOp::OpOverConstrainedVolume: + aControl = SMESH_Actor::eOverConstrainedVolume; + break; + case SMESHOp::OpEqualVolume: + aControl = SMESH_Actor::eCoincidentElems3D; + break; + } + _PTR(Study) aStudy = SMESH::GetActiveStudyDocument(); LightApp_SelectionMgr *aSel = SMESHGUI::selectionMgr(); SALOME_ListIO selected; if( aSel ) aSel->selectedObjects( selected ); if( !selected.IsEmpty() ){ - Handle(SALOME_InteractiveObject) anIO = selected.First(); - if(!anIO.IsNull()){ - SMESH_Actor::eControl aControl = SMESH_Actor::eNone; - if(SMESH_Actor *anActor = SMESH::FindActorByEntry(anIO->getEntry())) { - switch ( theCommandID ){ - case SMESHOp::OpFreeNode: - aControl = SMESH_Actor::eFreeNodes; - break; - case SMESHOp::OpEqualNode: - aControl = SMESH_Actor::eCoincidentNodes; - break; - case SMESHOp::OpFreeEdge: - aControl = SMESH_Actor::eFreeEdges; - break; - case SMESHOp::OpFreeBorder: - aControl = SMESH_Actor::eFreeBorders; - break; - case SMESHOp::OpLength: - aControl = SMESH_Actor::eLength; - break; - case SMESHOp::OpConnection: - aControl = SMESH_Actor::eMultiConnection; - break; - case SMESHOp::OpEqualEdge: - aControl = SMESH_Actor::eCoincidentElems1D; - break; - case SMESHOp::OpFreeFace: - aControl = SMESH_Actor::eFreeFaces; - break; - case SMESHOp::OpBareBorderFace: - aControl = SMESH_Actor::eBareBorderFace; - break; - case SMESHOp::OpOverConstrainedFace: - aControl = SMESH_Actor::eOverConstrainedFace; - break; - case SMESHOp::OpLength2D: - aControl = SMESH_Actor::eLength2D; - break; - case SMESHOp::OpConnection2D: - aControl = SMESH_Actor::eMultiConnection2D; - break; - case SMESHOp::OpArea: - aControl = SMESH_Actor::eArea; - break; - case SMESHOp::OpTaper: - aControl = SMESH_Actor::eTaper; - break; - case SMESHOp::OpAspectRatio: - aControl = SMESH_Actor::eAspectRatio; - break; - case SMESHOp::OpMinimumAngle: - aControl = SMESH_Actor::eMinimumAngle; - break; - case SMESHOp::OpWarpingAngle: - aControl = SMESH_Actor::eWarping; - break; - case SMESHOp::OpSkew: - aControl = SMESH_Actor::eSkew; - break; - case SMESHOp::OpMaxElementLength2D: - aControl = SMESH_Actor::eMaxElementLength2D; - break; - case SMESHOp::OpEqualFace: - aControl = SMESH_Actor:: eCoincidentElems2D; - break; - case SMESHOp::OpAspectRatio3D: - aControl = SMESH_Actor::eAspectRatio3D; - break; - case SMESHOp::OpVolume: - aControl = SMESH_Actor::eVolume3D; - break; - case SMESHOp::OpMaxElementLength3D: - aControl = SMESH_Actor::eMaxElementLength3D; - break; - case SMESHOp::OpBareBorderVolume: - aControl = SMESH_Actor::eBareBorderVolume; - break; - case SMESHOp::OpOverConstrainedVolume: - aControl = SMESH_Actor::eOverConstrainedVolume; - break; - case SMESHOp::OpEqualVolume: - aControl = SMESH_Actor::eCoincidentElems3D; - break; - } - - anActor->SetControlMode(aControl); - anActor->GetScalarBarActor()->SetTitle( functorToString( anActor->GetFunctor() ).toLatin1().constData() ); - SMESH::RepaintCurrentView(); + SALOME_ListIteratorOfListIO It(selected); + for ( ; It.More(); It.Next()) + { + Handle(SALOME_InteractiveObject) anIO = It.Value(); + if(!anIO.IsNull()){ + _PTR(SObject) SO = aStudy->FindObjectID( It.Value()->getEntry() ); + if ( SO ) { + CORBA::Object_var aObject = SMESH::SObjectToObject( SO ); + SMESH::SMESH_Mesh_var aMesh = SMESH::SMESH_Mesh::_narrow( aObject ); + SMESH::SMESH_subMesh_var aSubMesh = SMESH::SMESH_subMesh::_narrow( aObject ); + SMESH::SMESH_GroupBase_var aGroup = SMESH::SMESH_GroupBase::_narrow( aObject ); + if ( !aMesh->_is_nil() || !aSubMesh->_is_nil() || !aGroup->_is_nil() ) { + if(SMESH_Actor *anActor = SMESH::FindActorByEntry(anIO->getEntry())) { + anActor->SetControlMode(aControl); + anActor->GetScalarBarActor()->SetTitle( functorToString( anActor->GetFunctor() ).toLatin1().constData() ); + SMESH::RepaintCurrentView(); #ifndef DISABLE_PLOT2DVIEWER - if(anActor->GetPlot2Histogram()) { - SPlot2d_Histogram* aHistogram = anActor->UpdatePlot2Histogram(); - QString functorName = functorToString( anActor->GetFunctor()); - QString aHistogramName("%1 : %2"); - aHistogramName = aHistogramName.arg(anIO->getName()).arg(functorName); - aHistogram->setName(aHistogramName); - aHistogram->setHorTitle(functorName); - SMESH::ProcessIn2DViewers(anActor); - } + if(anActor->GetPlot2Histogram()) { + SPlot2d_Histogram* aHistogram = anActor->UpdatePlot2Histogram(); + QString functorName = functorToString( anActor->GetFunctor()); + QString aHistogramName("%1 : %2"); + aHistogramName = aHistogramName.arg(anIO->getName()).arg(functorName); + aHistogram->setName(aHistogramName); + aHistogram->setHorTitle(functorName); + SMESH::ProcessIn2DViewers(anActor); + } #endif + } + } + } } } } @@ -1743,6 +1756,19 @@ namespace return RefType; } + uint randomize( uint size ) + { + static bool initialized = false; + if ( !initialized ) { + qsrand( QDateTime::currentDateTime().toTime_t() ); + initialized = true; + } + uint v = qrand(); + v = uint( (double)( v ) / RAND_MAX * size ); + v = qMax( uint(0), qMin ( v, size-1 ) ); + return v; + } + } //namespace void SMESHGUI::OnEditDelete() @@ -2503,6 +2529,13 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) ::SetDisplayEntity(theCommandID); break; + // Choose entities to be displayed + case SMESHOp::OpDEChoose: + { + ( new SMESHGUI_DisplayEntitiesDlg( SMESHGUI::desktop() ) )->exec(); + break; + } + case SMESHOp::OpOrientationOnFaces: { LightApp_SelectionMgr* mgr = selectionMgr(); @@ -3530,19 +3563,10 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) LightApp_SelectionMgr* mgr = selectionMgr(); SALOME_ListIO selected; mgr->selectedObjects( selected ); - if ( selected.Extent() == 1 && selected.First()->hasEntry() ) { - _PTR(SObject) SO = aStudy->FindObjectID( selected.First()->getEntry() ); - if ( SO ) { - CORBA::Object_var aObject = SMESH::SObjectToObject( SO ); - SMESH::SMESH_Mesh_var aMesh = SMESH::SMESH_Mesh::_narrow( aObject ); - SMESH::SMESH_subMesh_var aSubMesh = SMESH::SMESH_subMesh::_narrow( aObject ); - SMESH::SMESH_GroupBase_var aGroup = SMESH::SMESH_GroupBase::_narrow( aObject ); - if ( !aMesh->_is_nil() || !aSubMesh->_is_nil() || !aGroup->_is_nil() ) { - SUIT_OverrideCursor wc; - ::Control( theCommandID ); - break; - } - } + if( !selected.IsEmpty() ) { + SUIT_OverrideCursor wc; + ::Control( theCommandID ); + break; } SUIT_MessageBox::warning(desktop(), tr( "SMESH_WRN_WARNING" ), @@ -3855,8 +3879,8 @@ void SMESHGUI::initialize( CAM_Application* app ) createSMESHAction( SMESHOp::OpRemoveOrphanNodes, "REMOVE_ORPHAN_NODES", "ICON_DLG_REM_ORPHAN_NODES" ); createSMESHAction( SMESHOp::OpClearMesh, "CLEAR_MESH", "ICON_CLEAR_MESH" ); - createSMESHAction( SMESHOp::OpRenumberingNodes, "RENUM_NODES", "ICON_DLG_RENUMBERING_NODES" ); - createSMESHAction( SMESHOp::OpRenumberingElements, "RENUM_ELEMENTS", "ICON_DLG_RENUMBERING_ELEMENTS" ); + //createSMESHAction( SMESHOp::OpRenumberingNodes, "RENUM_NODES", "ICON_DLG_RENUMBERING_NODES" ); + //createSMESHAction( SMESHOp::OpRenumberingElements, "RENUM_ELEMENTS", "ICON_DLG_RENUMBERING_ELEMENTS" ); createSMESHAction( SMESHOp::OpTranslation, "TRANS", "ICON_SMESH_TRANSLATION_VECTOR" ); createSMESHAction( SMESHOp::OpRotation, "ROT", "ICON_DLG_MESH_ROTATION" ); @@ -3899,7 +3923,8 @@ void SMESHGUI::initialize( CAM_Application* app ) createSMESHAction( SMESHOp::OpDEFaces, "FACES", "ICON_DLG_TRIANGLE", 0, true ); createSMESHAction( SMESHOp::OpDEVolumes, "VOLUMES", "ICON_DLG_TETRAS", 0, true ); createSMESHAction( SMESHOp::OpDEBalls, "BALLS", "ICON_DLG_BALL", 0, true ); - createSMESHAction( SMESHOp::OpDEAllEntity, "ALL" ); + createSMESHAction( SMESHOp::OpDEChoose, "CHOOSE", "ICON_DLG_CHOOSE", 0, false ); + createSMESHAction( SMESHOp::OpDEAllEntity, "ALL", "ICON_DLG_CHOOSE_ALL", 0, false ); createSMESHAction( SMESHOp::OpOrientationOnFaces, "FACE_ORIENTATION", "", 0, true ); createSMESHAction( SMESHOp::OpRepresentationLines, "LINE_REPRESENTATION", "", 0, true ); @@ -3927,6 +3952,23 @@ void SMESHGUI::initialize( CAM_Application* app ) createSMESHAction( SMESHOp::OpSortChild, "SORT_CHILD_ITEMS" ); + QList aCtrlActions; + aCtrlActions << SMESHOp::OpFreeNode << SMESHOp::OpEqualNode // node controls + << SMESHOp::OpFreeEdge << SMESHOp::OpFreeBorder + << SMESHOp::OpLength << SMESHOp::OpConnection << SMESHOp::OpEqualEdge // edge controls + << SMESHOp::OpFreeFace << SMESHOp::OpLength2D << SMESHOp::OpConnection2D + << SMESHOp::OpArea << SMESHOp::OpTaper << SMESHOp::OpAspectRatio + << SMESHOp::OpMinimumAngle << SMESHOp::OpWarpingAngle << SMESHOp::OpSkew + << SMESHOp::OpMaxElementLength2D << SMESHOp::OpBareBorderFace + << SMESHOp::OpOverConstrainedFace << SMESHOp::OpEqualFace // face controls + << SMESHOp::OpAspectRatio3D << SMESHOp::OpVolume + << SMESHOp::OpMaxElementLength3D << SMESHOp::OpBareBorderVolume + << SMESHOp::OpOverConstrainedVolume << SMESHOp::OpEqualVolume; // volume controls + QActionGroup* aCtrlGroup = new QActionGroup( application()->desktop() ); + aCtrlGroup->setExclusive( true ); + for( int i = 0; i < aCtrlActions.size(); i++ ) + aCtrlGroup->addAction( action( aCtrlActions[i] ) ); + // ----- create menu -------------- int fileId = createMenu( tr( "MEN_FILE" ), -1, 1 ), editId = createMenu( tr( "MEN_EDIT" ), -1, 3 ), @@ -3947,7 +3989,7 @@ void SMESHGUI::initialize( CAM_Application* app ) volumeId = createMenu( tr( "MEN_VOLUME_CTRL" ), ctrlId, -1, 10 ), addId = createMenu( tr( "MEN_ADD" ), modifyId, 402 ), removeId = createMenu( tr( "MEN_REMOVE" ), modifyId, 403 ), - renumId = createMenu( tr( "MEN_RENUM" ), modifyId, 404 ), + //renumId = createMenu( tr( "MEN_RENUM" ), modifyId, 404 ), transfId = createMenu( tr( "MEN_TRANSF" ), modifyId, 405 ), basicPropId = createMenu( tr( "MEN_BASIC_PROPERTIES" ), measureId, -1, 10 ); @@ -4031,6 +4073,8 @@ void SMESHGUI::initialize( CAM_Application* app ) createMenu( SMESHOp::OpOverConstrainedVolume, volumeId, -1 ); createMenu( SMESHOp::OpEqualVolume, volumeId, -1 ); createMenu( separator(), ctrlId, -1 ); + createMenu( SMESHOp::OpReset, ctrlId, -1 ); + createMenu( separator(), ctrlId, -1 ); createMenu( SMESHOp::OpOverallMeshQuality, ctrlId, -1 ); createMenu( SMESHOp::OpNode, addId, -1 ); @@ -4067,8 +4111,8 @@ void SMESHGUI::initialize( CAM_Application* app ) createMenu( separator(), removeId, -1 ); createMenu( SMESHOp::OpClearMesh, removeId, -1 ); - createMenu( SMESHOp::OpRenumberingNodes, renumId, -1 ); - createMenu( SMESHOp::OpRenumberingElements, renumId, -1 ); + //createMenu( SMESHOp::OpRenumberingNodes, renumId, -1 ); + //createMenu( SMESHOp::OpRenumberingElements, renumId, -1 ); createMenu( SMESHOp::OpTranslation, transfId, -1 ); createMenu( SMESHOp::OpRotation, transfId, -1 ); @@ -4103,21 +4147,21 @@ void SMESHGUI::initialize( CAM_Application* app ) createMenu( SMESHOp::OpUpdate, viewId, -1 ); // ----- create toolbars -------------- - int meshTb = createTool( tr( "TB_MESH" ) ), - info = createTool( tr( "TB_INFO" ) ), - groupTb = createTool( tr( "TB_GROUP" ) ), - ctrl0dTb = createTool( tr( "TB_CTRL0D" ) ), - ctrl1dTb = createTool( tr( "TB_CTRL1D" ) ), - ctrl2dTb = createTool( tr( "TB_CTRL2D" ) ), - ctrl3dTb = createTool( tr( "TB_CTRL3D" ) ), - addElemTb = createTool( tr( "TB_ADD" ) ), - addNonElemTb = createTool( tr( "TB_ADDNON" ) ), - remTb = createTool( tr( "TB_REM" ) ), - renumbTb = createTool( tr( "TB_RENUMBER" ) ), - transformTb = createTool( tr( "TB_TRANSFORM" ) ), - modifyTb = createTool( tr( "TB_MODIFY" ) ), - measuremTb = createTool( tr( "TB_MEASUREM" ) ), - dispModeTb = createTool( tr( "TB_DISP_MODE" ) ); + int meshTb = createTool( tr( "TB_MESH" ), QString( "SMESHMeshToolbar" ) ), + info = createTool( tr( "TB_INFO" ), QString( "SMESHInformationToolbar" ) ), + groupTb = createTool( tr( "TB_GROUP" ), QString( "SMESHGroupToolbar" ) ), + ctrl0dTb = createTool( tr( "TB_CTRL0D" ), QString( "SMESHNodeControlsToolbar" ) ), + ctrl1dTb = createTool( tr( "TB_CTRL1D" ), QString( "SMESHEdgeControlsToolbar" ) ), + ctrl2dTb = createTool( tr( "TB_CTRL2D" ), QString( "SMESHFaceControlsToolbar" ) ), + ctrl3dTb = createTool( tr( "TB_CTRL3D" ), QString( "SMESHVolumeControlsToolbar" ) ), + addElemTb = createTool( tr( "TB_ADD" ), QString( "SMESHAddElementToolbar" ) ), + addNonElemTb = createTool( tr( "TB_ADDNON" ), QString( "SMESHAddElementToolbar" ) ), + remTb = createTool( tr( "TB_REM" ), QString( "SMESHRemoveToolbar" ) ), + //renumbTb = createTool( tr( "TB_RENUMBER" ), QString( "SMESHRenumberingToolbar" ) ), + transformTb = createTool( tr( "TB_TRANSFORM" ), QString( "SMESHTransformationToolbar" ) ), + modifyTb = createTool( tr( "TB_MODIFY" ), QString( "SMESHModificationToolbar" ) ), + measuremTb = createTool( tr( "TB_MEASUREM" ), QString( "SMESHMeasurementsToolbar" ) ), + dispModeTb = createTool( tr( "TB_DISP_MODE" ), QString( "SMESHDisplayModeToolbar" ) ); createTool( SMESHOp::OpCreateMesh, meshTb ); createTool( SMESHOp::OpCreateSubMesh, meshTb ); @@ -4201,8 +4245,8 @@ void SMESHGUI::initialize( CAM_Application* app ) createTool( SMESHOp::OpRemoveOrphanNodes, remTb ); createTool( SMESHOp::OpClearMesh, remTb ); - createTool( SMESHOp::OpRenumberingNodes, renumbTb ); - createTool( SMESHOp::OpRenumberingElements, renumbTb ); + //createTool( SMESHOp::OpRenumberingNodes, renumbTb ); + //createTool( SMESHOp::OpRenumberingElements, renumbTb ); createTool( SMESHOp::OpTranslation, transformTb ); createTool( SMESHOp::OpRotation, transformTb ); @@ -4413,6 +4457,11 @@ void SMESHGUI::initialize( CAM_Application* app ) popupMgr()->insert( separator(), anId, -1 ); + popupMgr()->insert( action( SMESHOp::OpDEChoose ), anId, -1 ); + popupMgr()->setRule( action( SMESHOp::OpDEChoose ), aClient + "&&" + aType + "&&" + isNotEmpty, QtxPopupMgr::VisibleRule ); + + popupMgr()->insert( separator(), anId, -1 ); + popupMgr()->insert( action( SMESHOp::OpDEAllEntity ), anId, -1 ); popupMgr()->setRule( action( SMESHOp::OpDEAllEntity ), aDiffElemsInVTK + "&& isVisible && not( elemTypes in entityMode )", QtxPopupMgr::VisibleRule ); @@ -4731,6 +4780,8 @@ bool SMESHGUI::deactivateModule( SUIT_Study* study ) void SMESHGUI::studyClosed( SUIT_Study* s ) { + if( !s ) + return; SMESH::RemoveVisuData( s->id() ); SalomeApp_Module::studyClosed( s ); } @@ -4879,7 +4930,7 @@ void SMESHGUI::createPreferences() addPreference( tr( "PREF_PRECISION_USE" ), qaGroup, LightApp_Preferences::Bool, "SMESH", "use_precision" ); int prec = addPreference( tr( "PREF_PRECISION_VALUE" ), qaGroup, LightApp_Preferences::IntSpin, "SMESH", "controls_precision" ); setPreferenceProperty( prec, "min", 0 ); - setPreferenceProperty( prec, "max", 16 ); + setPreferenceProperty( prec, "max", 100 ); int doubleNodesTol = addPreference( tr( "PREF_EQUAL_NODES_TOL" ), qaGroup, LightApp_Preferences::DblSpin, "SMESH", "equal_nodes_tolerance" ); setPreferenceProperty( doubleNodesTol, "precision", 10 ); setPreferenceProperty( doubleNodesTol, "min", 0.0000000001 ); @@ -6901,7 +6952,7 @@ SALOMEDS::Color SMESHGUI::getPredefinedUniqueColor() } } } - static int currentColor = 0; + static int currentColor = randomize( colors.size() ); SALOMEDS::Color color; color.R = (double)colors[currentColor].red() / 255.0; diff --git a/src/SMESHGUI/SMESHGUI_Add0DElemsOnAllNodesDlg.cxx b/src/SMESHGUI/SMESHGUI_Add0DElemsOnAllNodesDlg.cxx index 9cbad861c..b053c6099 100644 --- a/src/SMESHGUI/SMESHGUI_Add0DElemsOnAllNodesDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_Add0DElemsOnAllNodesDlg.cxx @@ -463,9 +463,7 @@ void SMESHGUI_Add0DElemsOnAllNodesOp::onSelTypeChange(int selType) //================================================================================ /*! - * \brief Install - * - * + * \brief Install filters */ //================================================================================ diff --git a/src/SMESHGUI/SMESHGUI_AddMeshElementDlg.cxx b/src/SMESHGUI/SMESHGUI_AddMeshElementDlg.cxx index 79588047c..cbc584da5 100644 --- a/src/SMESHGUI/SMESHGUI_AddMeshElementDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_AddMeshElementDlg.cxx @@ -586,6 +586,7 @@ void SMESHGUI_AddMeshElementDlg::ClickOnApply() SMESH::long_array_var anIdList = new SMESH::long_array; anIdList->length( 1 ); anIdList[0] = -1; + const bool onlyNodesInMesh = ( myMesh->NbElements() == 0 ); switch (myElementType) { case SMDSAbs_0DElement: @@ -645,8 +646,10 @@ void SMESHGUI_AddMeshElementDlg::ClickOnApply() mySelectionMgr->setSelectedObjects( aList, false ); mySimulation->SetVisibility(false); + if ( onlyNodesInMesh ) + myActor->SetRepresentation( SMESH_Actor::eEdge ); // wireframe SMESH::UpdateView(); - + buttonOk->setEnabled(false); buttonApply->setEnabled(false); diff --git a/src/SMESHGUI/SMESHGUI_CopyMeshDlg.cxx b/src/SMESHGUI/SMESHGUI_CopyMeshDlg.cxx index 39665f3a5..8a02ddd03 100644 --- a/src/SMESHGUI/SMESHGUI_CopyMeshDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_CopyMeshDlg.cxx @@ -166,9 +166,10 @@ SMESHGUI_CopyMeshDlg::SMESHGUI_CopyMeshDlg( SMESHGUI* theModule ) myCopyGroupsCheck = new QCheckBox(tr("SMESH_MAKE_GROUPS"), GroupArguments); myCopyGroupsCheck->setChecked(false); - // CheckBox for keeping ids + // CheckBox for keeping ids ( OBSOLETE ) myKeepIdsCheck = new QCheckBox(tr("SMESH_KEEP_IDS"), GroupArguments); myKeepIdsCheck->setChecked(true); + myKeepIdsCheck->hide(); // layout GroupArgumentsLayout->addWidget(myTextLabelElements, 0, 0); @@ -178,7 +179,7 @@ SMESHGUI_CopyMeshDlg::SMESHGUI_CopyMeshDlg( SMESHGUI* theModule ) GroupArgumentsLayout->addWidget(meshNameLabel, 2, 0); GroupArgumentsLayout->addWidget(myMeshNameEdit, 2, 1, 1, 5); GroupArgumentsLayout->addWidget(myCopyGroupsCheck, 3, 0, 1, 6); - GroupArgumentsLayout->addWidget(myKeepIdsCheck, 4, 0, 1, 6); + // GroupArgumentsLayout->addWidget(myKeepIdsCheck, 4, 0, 1, 6); /***************************************************************/ GroupButtons = new QGroupBox(this); diff --git a/src/SMESHGUI/SMESHGUI_DeleteGroupDlg.cxx b/src/SMESHGUI/SMESHGUI_DeleteGroupDlg.cxx index 5d0a1ee7d..f106c0b66 100644 --- a/src/SMESHGUI/SMESHGUI_DeleteGroupDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_DeleteGroupDlg.cxx @@ -43,7 +43,6 @@ #include #include -#include #include #include diff --git a/src/SMESHGUI/SMESHGUI_DisplayEntitiesDlg.cxx b/src/SMESHGUI/SMESHGUI_DisplayEntitiesDlg.cxx new file mode 100644 index 000000000..1e0a288d5 --- /dev/null +++ b/src/SMESHGUI/SMESHGUI_DisplayEntitiesDlg.cxx @@ -0,0 +1,247 @@ +// Copyright (C) 2014 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 +// +// File : SMESHGUI_DisplayEntitiesDlg.cxx +// Author : Alexander KOVALEV, Open CASCADE S.A.S. (alexander.kovalev@opencascade.com) + +#include "SMESHGUI_DisplayEntitiesDlg.h" + +#include "SMESHGUI.h" +#include "SMESHGUI_Utils.h" +#include "SMESHGUI_VTKUtils.h" +#include "SMESHGUI_MeshUtils.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +const int MARGIN = 9; +const int SPACING = 6; + +/*! + \class SMESHGUI_DisplayEntitiesDlg + \brief Dialog box to select entities to be displayed in viewer +*/ + +/* + \brief Constructor + \param parent parent widget +*/ +SMESHGUI_DisplayEntitiesDlg::SMESHGUI_DisplayEntitiesDlg( QWidget* parent ) + : SMESHGUI_Dialog( parent, true, false, Standard ) +{ + SUIT_ResourceMgr* aResMgr = SUIT_Session::session()->resourceMgr(); + + LightApp_SelectionMgr* mgr = SMESHGUI::selectionMgr(); + SALOME_ListIO selected; + mgr->selectedObjects( selected ); + SMESH::SMESH_Mesh_var aMesh = SMESH::SMESH_Mesh::_nil(); + myActor = 0; + myNbCheckedButtons = 0; + + SALOME_ListIteratorOfListIO it( selected ); + myIObject = selected.First(); + if ( myIObject->hasEntry() ) { + myActor = SMESH::FindActorByEntry( myIObject->getEntry() ); + } + myEntityMode = myActor ? myActor->GetEntityMode() : 0; + + aMesh = SMESH::GetMeshByIO( myIObject ); + + // set title + setWindowTitle( tr( "MEN_DISP_ENT" ) ); + + // create widgets + QGroupBox* anEntitiesGrp = new QGroupBox( tr( "SMESH_MESHINFO_ENTITIES" ), mainFrame() ); + QGridLayout* hl = new QGridLayout( anEntitiesGrp ); + hl->setMargin( MARGIN ); + hl->setSpacing( SPACING ); + int nbElements; + + // 0DElements + nbElements = myActor ? myActor->GetObject()->GetNbEntities( SMDSAbs_0DElement ) : aMesh->Nb0DElements(); + my0DElemsTB = new QCheckBox( tr("SMESH_ELEMS0D"), anEntitiesGrp ); + my0DElemsTB->setIcon( QIcon( aResMgr->loadPixmap( "SMESH", tr( "ICON_DLG_ELEM0D" ) ) ) ); + bool has0DElems = myEntityMode & SMESH_Actor::e0DElements; + my0DElemsTB->setChecked( has0DElems ); + if ( has0DElems ) + myNbCheckedButtons++; + connect( my0DElemsTB, SIGNAL(toggled(bool)), this, SLOT(onChangeEntityMode(bool)) ); + QLabel* nb0DElemsLab = new QLabel( QString("%1").arg(nbElements).toLatin1().data(), anEntitiesGrp ); + hl->addWidget( my0DElemsTB, 0, 0 ); + hl->addWidget( nb0DElemsLab, 0, 1 ); + my0DElemsTB->setEnabled( nbElements ); + nb0DElemsLab->setEnabled( nbElements ); + + // Edges + nbElements = myActor ? myActor->GetObject()->GetNbEntities( SMDSAbs_Edge ) : aMesh->NbEdges(); + myEdgesTB = new QCheckBox( tr("SMESH_EDGES"), anEntitiesGrp ); + myEdgesTB->setIcon( QIcon( aResMgr->loadPixmap( "SMESH", tr( "ICON_DLG_EDGE" ) ) ) ); + bool hasEdges = myEntityMode & SMESH_Actor::eEdges; + myEdgesTB->setChecked( hasEdges ); + if ( hasEdges ) + myNbCheckedButtons++; + connect( myEdgesTB, SIGNAL(toggled(bool)), this, SLOT(onChangeEntityMode(bool)) ); + QLabel* nbEdgesLab = new QLabel( QString("%1").arg(nbElements).toLatin1().data(), anEntitiesGrp ); + hl->addWidget( myEdgesTB, 1, 0 ); + hl->addWidget( nbEdgesLab, 1, 1 ); + myEdgesTB->setEnabled( nbElements ); + nbEdgesLab->setEnabled( nbElements ); + + // Faces + nbElements = myActor ? myActor->GetObject()->GetNbEntities( SMDSAbs_Face ) : aMesh->NbFaces(); + myFacesTB = new QCheckBox( tr("SMESH_FACES"), anEntitiesGrp ); + myFacesTB->setIcon( QIcon( aResMgr->loadPixmap( "SMESH", tr( "ICON_DLG_TRIANGLE" ) ) ) ); + bool hasFaces = myEntityMode & SMESH_Actor::eFaces; + myFacesTB->setChecked( hasFaces ); + if ( hasFaces ) + myNbCheckedButtons++; + connect( myFacesTB, SIGNAL(toggled(bool)), this, SLOT(onChangeEntityMode(bool)) ); + QLabel* nbFacesLab = new QLabel( QString("%1").arg(nbElements).toLatin1().data(), anEntitiesGrp ); + hl->addWidget( myFacesTB, 2, 0 ); + hl->addWidget( nbFacesLab, 2, 1 ); + myFacesTB->setEnabled( nbElements ); + nbFacesLab->setEnabled( nbElements ); + + // Volumes + nbElements = myActor ? myActor->GetObject()->GetNbEntities( SMDSAbs_Volume ) : aMesh->NbVolumes(); + myVolumesTB = new QCheckBox( tr("SMESH_VOLUMES"), anEntitiesGrp ); + myVolumesTB->setIcon( QIcon( aResMgr->loadPixmap( "SMESH", tr( "ICON_DLG_TETRAS" ) ) ) ); + bool hasVolumes = myEntityMode & SMESH_Actor::eVolumes; + myVolumesTB->setChecked( hasVolumes ); + if ( hasVolumes ) + myNbCheckedButtons++; + connect( myVolumesTB, SIGNAL(toggled(bool)), this, SLOT(onChangeEntityMode(bool) ) ); + QLabel* nbVolumesLab = new QLabel( QString("%1").arg(nbElements).toLatin1().data(), anEntitiesGrp ); + hl->addWidget( myVolumesTB, 3, 0 ); + hl->addWidget( nbVolumesLab, 3, 1 ); + myVolumesTB->setEnabled( nbElements ); + nbVolumesLab->setEnabled( nbElements ); + + // Balls + nbElements = myActor ? myActor->GetObject()->GetNbEntities( SMDSAbs_Ball ) : aMesh->NbBalls(); + myBallsTB = new QCheckBox( tr("SMESH_BALLS"), anEntitiesGrp ); + myBallsTB->setIcon( QIcon( aResMgr->loadPixmap( "SMESH", tr( "ICON_DLG_BALL" ) ) ) ); + bool hasBalls = myEntityMode & SMESH_Actor::eBallElem; + myBallsTB->setChecked( hasBalls ); + if ( hasBalls ) + myNbCheckedButtons++; + connect( myBallsTB, SIGNAL(toggled(bool)), this, SLOT(onChangeEntityMode(bool)) ); + QLabel* nbBallsLab = new QLabel( QString("%1").arg(nbElements).toLatin1().data(), anEntitiesGrp ); + hl->addWidget( myBallsTB, 4, 0 ); + hl->addWidget( nbBallsLab, 4, 1 ); + myBallsTB->setEnabled( nbElements ); + nbBallsLab->setEnabled( nbElements ); + + QVBoxLayout* aDlgLay = new QVBoxLayout( mainFrame() ); + aDlgLay->setMargin( 0 ); + aDlgLay->setSpacing( SPACING ); + aDlgLay->addWidget( anEntitiesGrp ); + + button( OK )->setText( tr( "SMESH_BUT_OK" ) ); + + connect( this, SIGNAL( dlgHelp() ), this, SLOT( onHelp() ) ); + connect( this, SIGNAL( dlgOk() ), this, SLOT( onOk() ) ); +} + +/* + \brief Destructor: clean-up resources if necessary +*/ +SMESHGUI_DisplayEntitiesDlg::~SMESHGUI_DisplayEntitiesDlg() +{ +} + +void SMESHGUI_DisplayEntitiesDlg::InverseEntityMode(unsigned int& theOutputMode, + unsigned int theMode) +{ + bool anIsNotPresent = ~theOutputMode & theMode; + if(anIsNotPresent) + theOutputMode |= theMode; + else + theOutputMode &= ~theMode; +} + +/*! + \brief Slot for changing entities state +*/ +void SMESHGUI_DisplayEntitiesDlg::onChangeEntityMode( bool isChecked ) +{ + QCheckBox* aSender = (QCheckBox*)sender(); + if ( myNbCheckedButtons == 1 && !isChecked ) { + SUIT_MessageBox::warning(this, tr("SMESH_WRN_WARNING"), + tr("WRN_AT_LEAST_ONE")); + disconnect( aSender, SIGNAL(toggled(bool)), this, SLOT(onChangeEntityMode(bool)) ); + aSender->setChecked( true ); + connect( aSender, SIGNAL(toggled(bool)), this, SLOT(onChangeEntityMode(bool)) ); + return; + } + if ( my0DElemsTB == aSender ) + InverseEntityMode( myEntityMode, SMESH_Actor::e0DElements ); + else if ( myEdgesTB == aSender ) + InverseEntityMode( myEntityMode, SMESH_Actor::eEdges ); + else if ( myFacesTB == aSender ) + InverseEntityMode( myEntityMode, SMESH_Actor::eFaces ); + else if ( myVolumesTB == aSender ) + InverseEntityMode( myEntityMode, SMESH_Actor::eVolumes ); + else if ( myBallsTB == aSender ) + InverseEntityMode( myEntityMode, SMESH_Actor::eBallElem ); + + isChecked ? myNbCheckedButtons++ : myNbCheckedButtons--; + +} + +/*! + \brief Show online help on dialog box +*/ +void SMESHGUI_DisplayEntitiesDlg::onHelp() +{ + LightApp_Application* app = (LightApp_Application*)(SUIT_Session::session()->activeApplication()); + app->onHelpContextModule( "SMESH", "display_entity_page.html" ); +} + +/*! + \brief Display or update the mesh in the 3D view with selected entity mode +*/ +void SMESHGUI_DisplayEntitiesDlg::onOk() +{ + const char* entry = myIObject->getEntry(); + + if ( !myActor ) { + myActor = SMESH::CreateActor(SMESH::GetActiveStudyDocument(), + entry, true); + } + + if( myEntityMode != myActor->GetEntityMode() ) { + myActor->SetEntityMode(myEntityMode); + SUIT_ViewWindow* wnd = SMESH::GetActiveWindow(); + SMESH::DisplayActor( wnd, myActor ); + SUIT_DataOwnerPtrList aList; + aList.append( new LightApp_DataOwner( entry ) ); + SMESHGUI::selectionMgr()->setSelected( aList, false ); + SMESH::UpdateView( wnd, SMESH::eDisplay, entry ); + } +} diff --git a/src/SMESHGUI/SMESHGUI_DisplayEntitiesDlg.h b/src/SMESHGUI/SMESHGUI_DisplayEntitiesDlg.h new file mode 100644 index 000000000..4b36a6b25 --- /dev/null +++ b/src/SMESHGUI/SMESHGUI_DisplayEntitiesDlg.h @@ -0,0 +1,61 @@ +// Copyright (C) 2014 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 +// +// File : SMESHGUI_DisplayEntitiesDlg.h +// Author : Alexander KOVALEV, Open CASCADE S.A.S. (alexander.kovalev@opencascade.com) + +#ifndef SMESHGUI_DISPLAYENTITIES_H +#define SMESHGUI_DISPLAYENTITIES_H + +#include "SMESHGUI_Dialog.h" +#include "SMESH_SMESHGUI.hxx" + +#include + +class QCheckBox; + +class SMESHGUI_EXPORT SMESHGUI_DisplayEntitiesDlg : public SMESHGUI_Dialog +{ + Q_OBJECT + +public: + SMESHGUI_DisplayEntitiesDlg( QWidget* parent ); + ~SMESHGUI_DisplayEntitiesDlg(); + +private: + void InverseEntityMode( unsigned int& theOutputMode, + unsigned int theMode ); + +private slots: + void onOk(); + void onHelp(); + void onChangeEntityMode( bool isChecked ); + +private: + Handle(SALOME_InteractiveObject) myIObject; + unsigned int myEntityMode; + SMESH_Actor *myActor; + int myNbCheckedButtons; + QCheckBox* my0DElemsTB; + QCheckBox* myEdgesTB; + QCheckBox* myFacesTB; + QCheckBox* myVolumesTB; + QCheckBox* myBallsTB; +}; + +#endif // SMESHGUI_DISPLAYENTITIES_H diff --git a/src/SMESHGUI/SMESHGUI_DuplicateNodesDlg.cxx b/src/SMESHGUI/SMESHGUI_DuplicateNodesDlg.cxx index ad4997644..57428add2 100644 --- a/src/SMESHGUI/SMESHGUI_DuplicateNodesDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_DuplicateNodesDlg.cxx @@ -48,7 +48,6 @@ #include #include -#include // Qt includes #include diff --git a/src/SMESHGUI/SMESHGUI_ExtrusionDlg.cxx b/src/SMESHGUI/SMESHGUI_ExtrusionDlg.cxx index 5dba32360..798b6b9eb 100644 --- a/src/SMESHGUI/SMESHGUI_ExtrusionDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_ExtrusionDlg.cxx @@ -860,7 +860,7 @@ void SMESHGUI_ExtrusionDlg::SelectionIntoArgument() else return; } else { - // get indices of selcted elements + // get indices of selected elements TColStd_IndexedMapOfInteger aMapIndex; mySelector->GetIndex(IO,aMapIndex); aNbElements = aMapIndex.Extent(); diff --git a/src/SMESHGUI/SMESHGUI_FilterDlg.cxx b/src/SMESHGUI/SMESHGUI_FilterDlg.cxx index 8409afa4a..8db0a7814 100755 --- a/src/SMESHGUI/SMESHGUI_FilterDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_FilterDlg.cxx @@ -62,8 +62,6 @@ #include #include -#include -#include #include @@ -1956,7 +1954,10 @@ void SMESHGUI_FilterTable::onCriterionChanged (const int row, const int col, con break; } case 3: { + int oldValue = aCompareItem->value(); aCompareItem->setItems(getCompare()); + if ( oldValue >= 0 ) + aCompareItem->setValue( oldValue ); break; } } diff --git a/src/SMESHGUI/SMESHGUI_GEOMGenUtils.cxx b/src/SMESHGUI/SMESHGUI_GEOMGenUtils.cxx index 88b181944..5453a6a1b 100644 --- a/src/SMESHGUI/SMESHGUI_GEOMGenUtils.cxx +++ b/src/SMESHGUI/SMESHGUI_GEOMGenUtils.cxx @@ -82,20 +82,25 @@ namespace SMESH return GEOM::GEOM_Object::_nil(); } - GEOM::GEOM_Object_ptr GetGeom (_PTR(SObject) theSO) + GEOM::GEOM_Object_var GetGeom (_PTR(SObject) theSO) { + GEOM::GEOM_Object_var aMeshShape; if (!theSO) - return GEOM::GEOM_Object::_nil(); + return aMeshShape; + + CORBA::Object_var obj = _CAST( SObject,theSO )->GetObject(); + aMeshShape = GEOM::GEOM_Object::_narrow( obj ); + if ( !aMeshShape->_is_nil() ) + return aMeshShape; _PTR(Study) aStudy = SMESH::GetActiveStudyDocument(); if (!aStudy) - return GEOM::GEOM_Object::_nil(); + return aMeshShape; _PTR(ChildIterator) anIter (aStudy->NewChildIterator(theSO)); for ( ; anIter->More(); anIter->Next()) { _PTR(SObject) aSObject = anIter->Value(); _PTR(SObject) aRefSOClient; - GEOM::GEOM_Object_var aMeshShape; if (aSObject->ReferencedObject(aRefSOClient)) { SALOMEDS_SObject* aRefSO = _CAST(SObject,aRefSOClient); @@ -104,11 +109,10 @@ namespace SMESH SALOMEDS_SObject* aSO = _CAST(SObject,aSObject); aMeshShape = GEOM::GEOM_Object::_narrow(aSO->GetObject()); } - - if (!aMeshShape->_is_nil()) - return aMeshShape._retn(); + if ( !aMeshShape->_is_nil() ) + return aMeshShape; } - return GEOM::GEOM_Object::_nil(); + return aMeshShape; } SMESHGUI_EXPORT char* GetGeomName( _PTR(SObject) smeshSO ) diff --git a/src/SMESHGUI/SMESHGUI_GEOMGenUtils.h b/src/SMESHGUI/SMESHGUI_GEOMGenUtils.h index f9cdeafd4..0aa10bd7a 100644 --- a/src/SMESHGUI/SMESHGUI_GEOMGenUtils.h +++ b/src/SMESHGUI/SMESHGUI_GEOMGenUtils.h @@ -47,7 +47,7 @@ namespace SMESH SMESHGUI_EXPORT GEOM::GEOM_Object_var GetShapeOnMeshOrSubMesh( _PTR(SObject), bool* isMesh=0 ); - SMESHGUI_EXPORT GEOM::GEOM_Object_ptr GetGeom( _PTR(SObject) ); + SMESHGUI_EXPORT GEOM::GEOM_Object_var GetGeom( _PTR(SObject) ); SMESHGUI_EXPORT char* GetGeomName( _PTR(SObject) smeshSO ); diff --git a/src/SMESHGUI/SMESHGUI_GroupDlg.cxx b/src/SMESHGUI/SMESHGUI_GroupDlg.cxx index 60095ebe2..7cad33071 100644 --- a/src/SMESHGUI/SMESHGUI_GroupDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_GroupDlg.cxx @@ -61,7 +61,6 @@ #include #include -#include #include diff --git a/src/SMESHGUI/SMESHGUI_GroupOpDlg.cxx b/src/SMESHGUI/SMESHGUI_GroupOpDlg.cxx index 33a4720ea..bbebee448 100644 --- a/src/SMESHGUI/SMESHGUI_GroupOpDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_GroupOpDlg.cxx @@ -59,7 +59,6 @@ #include #include #include -#include #include #include diff --git a/src/SMESHGUI/SMESHGUI_Hypotheses.cxx b/src/SMESHGUI/SMESHGUI_Hypotheses.cxx index af1377aba..630100e71 100644 --- a/src/SMESHGUI/SMESHGUI_Hypotheses.cxx +++ b/src/SMESHGUI/SMESHGUI_Hypotheses.cxx @@ -670,7 +670,7 @@ void SMESHGUI_HypothesisDlg::onHelp() if (app) { QString name = "SMESH"; if(myCreator) { - QVariant pluginName = myCreator->property( PLUGIN_NAME ); + QVariant pluginName = myCreator->property( SMESH::Plugin_Name() ); if( pluginName.isValid() ) { QString rootDir = pluginName.toString() + "PLUGIN_ROOT_DIR"; QString varValue = QString( getenv(rootDir.toLatin1().constData())); diff --git a/src/SMESHGUI/SMESHGUI_HypothesesUtils.cxx b/src/SMESHGUI/SMESHGUI_HypothesesUtils.cxx index 379ed1b2b..fa29da180 100644 --- a/src/SMESHGUI/SMESHGUI_HypothesesUtils.cxx +++ b/src/SMESHGUI/SMESHGUI_HypothesesUtils.cxx @@ -128,7 +128,7 @@ namespace SMESH } else { - QObject::tr(QString("SMESH_HYP_%1").arg(theHypStatus).toLatin1().data()); + aMsg += QObject::tr(QString("SMESH_HYP_%1").arg(theHypStatus).toLatin1().data()); if ( theHypStatus == SMESH::HYP_HIDDEN_ALGO ) { // PAL18501 CORBA::String_var hypType = theHyp->GetName(); @@ -469,7 +469,7 @@ namespace SMESH // It is used to obtain plugin root dir environment variable // in the SMESHGUI_HypothesisDlg class. Plugin root dir environment // variable is used to display documentation. - aCreator->setProperty(PLUGIN_NAME,aHypData->PluginName); + aCreator->setProperty(SMESH::Plugin_Name(),aHypData->PluginName); } } } @@ -511,10 +511,14 @@ namespace SMESH return SMESH::SMESH_Hypothesis::_nil(); } + bool IsApplicable(const QString& aHypType, GEOM::GEOM_Object_ptr theGeomObject, const bool toCheckAll) { + if ( getenv("NO_LIMIT_ALGO_BY_SHAPE")) // allow a workaround for a case if + return true; // IsApplicable() returns false due to a bug + HypothesisData* aHypData = GetHypothesisData(aHypType); QString aServLib = aHypData->ServerLibName; return SMESHGUI::GetSMESHGen()->IsApplicable( aHypType.toLatin1().data(), diff --git a/src/SMESHGUI/SMESHGUI_HypothesesUtils.h b/src/SMESHGUI/SMESHGUI_HypothesesUtils.h index 2841b7a7f..8768e0711 100644 --- a/src/SMESHGUI/SMESHGUI_HypothesesUtils.h +++ b/src/SMESHGUI/SMESHGUI_HypothesesUtils.h @@ -58,8 +58,6 @@ class SALOMEDSClient_SObject; class algo_error_array; -#define PLUGIN_NAME "PLUGIN_NAME" - namespace SMESH { SMESHGUI_EXPORT @@ -119,6 +117,10 @@ namespace SMESH SMESHGUI_EXPORT QString GetMessageOnAlgoStateErrors( const algo_error_array& ); + + SMESHGUI_EXPORT + // name of proprty saving plug-in of a hypothesis + inline const char* Plugin_Name() { return "PLUGIN_NAME"; } } #endif // SMESHGUI_HYPOTHESESUTILS_H diff --git a/src/SMESHGUI/SMESHGUI_MakeNodeAtPointDlg.cxx b/src/SMESHGUI/SMESHGUI_MakeNodeAtPointDlg.cxx index 970500e69..2754b34a9 100644 --- a/src/SMESHGUI/SMESHGUI_MakeNodeAtPointDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_MakeNodeAtPointDlg.cxx @@ -716,17 +716,17 @@ void SMESHGUI_MakeNodeAtPointOp::redisplayPreview() myDlg->myDestinationZ->SetValue(z); } if ( myDestCoordChanged ) { - dx = myDlg->myDestinationX->GetValue() - myDlg->myCurrentX->GetValue(); - dy = myDlg->myDestinationY->GetValue() - myDlg->myCurrentY->GetValue(); - dz = myDlg->myDestinationZ->GetValue() - myDlg->myCurrentZ->GetValue(); + dx = myDlg->myDestinationX->GetValue() - x; + dy = myDlg->myDestinationY->GetValue() - y; + dz = myDlg->myDestinationZ->GetValue() - z; myDlg->myDestDX->SetValue(dx); myDlg->myDestDY->SetValue(dy); myDlg->myDestDZ->SetValue(dz); } else { - dx = myDlg->myDestDX->GetValue() + myDlg->myCurrentX->GetValue();; - dy = myDlg->myDestDY->GetValue() + myDlg->myCurrentY->GetValue();; - dz = myDlg->myDestDZ->GetValue() + myDlg->myCurrentZ->GetValue();; + dx = myDlg->myDestDX->GetValue() + x; + dy = myDlg->myDestDY->GetValue() + y; + dz = myDlg->myDestDZ->GetValue() + z; myDlg->myDestinationX->SetValue(dx); myDlg->myDestinationY->SetValue(dy); myDlg->myDestinationZ->SetValue(dz); diff --git a/src/SMESHGUI/SMESHGUI_Measurements.cxx b/src/SMESHGUI/SMESHGUI_Measurements.cxx index e00937aff..9f7c9bb26 100644 --- a/src/SMESHGUI/SMESHGUI_Measurements.cxx +++ b/src/SMESHGUI/SMESHGUI_Measurements.cxx @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/SMESHGUI/SMESHGUI_MeshDlg.cxx b/src/SMESHGUI/SMESHGUI_MeshDlg.cxx index f3a2719d4..a381acde0 100644 --- a/src/SMESHGUI/SMESHGUI_MeshDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_MeshDlg.cxx @@ -171,6 +171,7 @@ void SMESHGUI_MeshTab::addItem( const QString& txt, const int type, const int in if ( type <= AddHyp ) { myHypCombo[ type ]->addItem( txt, QVariant( index )); + myHypCombo[ type ]->setMaxVisibleItems( qMax( 10, myHypCombo[ type ]->count() ) ); } else { diff --git a/src/SMESHGUI/SMESHGUI_MeshEditPreview.cxx b/src/SMESHGUI/SMESHGUI_MeshEditPreview.cxx index ef9ac22ad..7f8b060c8 100644 --- a/src/SMESHGUI/SMESHGUI_MeshEditPreview.cxx +++ b/src/SMESHGUI/SMESHGUI_MeshEditPreview.cxx @@ -126,8 +126,9 @@ vtkIdType getCellType( const SMDSAbs_ElementType theType, { switch( theType ) { + case SMDSAbs_Ball: return VTK_VERTEX; case SMDSAbs_Node: return VTK_VERTEX; - case SMDSAbs_Edge: + case SMDSAbs_Edge: if( theNbNodes == 2 ) return VTK_LINE; else if ( theNbNodes == 3 ) return VTK_QUADRATIC_EDGE; else return VTK_EMPTY_CELL; diff --git a/src/SMESHGUI/SMESHGUI_MeshInfo.cxx b/src/SMESHGUI/SMESHGUI_MeshInfo.cxx index 2dca23bba..e91afa388 100644 --- a/src/SMESHGUI/SMESHGUI_MeshInfo.cxx +++ b/src/SMESHGUI/SMESHGUI_MeshInfo.cxx @@ -506,8 +506,9 @@ void SMESHGUI_MeshInfo::showInfo( SMESH::SMESH_IDSource_ptr obj ) long nb2DLinear = info[SMDSEntity_Triangle] + info[SMDSEntity_Quadrangle] + info[SMDSEntity_Polygon]; long nb2DQuadratic = info[SMDSEntity_Quad_Triangle] + info[SMDSEntity_Quad_Quadrangle]; long nb2DBiQuadratic = info[SMDSEntity_BiQuad_Triangle] + info[SMDSEntity_BiQuad_Quadrangle]; + long nb2DTotal = nb2DLinear + nb2DQuadratic + nb2DBiQuadratic; - myWidgets[i2D][iTotal] ->setProperty( "text", QString::number( nb2DLinear + nb2DQuadratic )); + myWidgets[i2D][iTotal] ->setProperty( "text", QString::number( nb2DTotal )); myWidgets[i2D][iLinear] ->setProperty( "text", QString::number( nb2DLinear ) ); myWidgets[i2D][iQuadratic] ->setProperty( "text", QString::number( nb2DQuadratic ) ); myWidgets[i2D][iBiQuadratic] ->setProperty( "text", QString::number( nb2DBiQuadratic ) ); @@ -524,10 +525,11 @@ void SMESHGUI_MeshInfo::showInfo( SMESH::SMESH_IDSource_ptr obj ) long nbHexahedrons = info[SMDSEntity_Hexa] + info[SMDSEntity_Quad_Hexa] + info[SMDSEntity_TriQuad_Hexa]; long nbPyramids = info[SMDSEntity_Pyramid] + info[SMDSEntity_Quad_Pyramid]; long nbPrisms = info[SMDSEntity_Penta] + info[SMDSEntity_Quad_Penta]; - long nb3DLinear = info[SMDSEntity_Tetra] + info[SMDSEntity_Hexa] + info[SMDSEntity_Pyramid] + info[SMDSEntity_Penta] + info[SMDSEntity_Polyhedra] + info[SMDSEntity_Hexagonal_Prism]; + long nb3DLinear = info[SMDSEntity_Tetra] + info[SMDSEntity_Hexa] + info[SMDSEntity_Pyramid] + info[SMDSEntity_Penta] + info[SMDSEntity_Polyhedra] + info[SMDSEntity_Hexagonal_Prism]; long nb3DQuadratic = info[SMDSEntity_Quad_Tetra] + info[SMDSEntity_Quad_Hexa] + info[SMDSEntity_Quad_Pyramid] + info[SMDSEntity_Quad_Penta]; long nb3DBiQuadratic = info[SMDSEntity_TriQuad_Hexa]; - myWidgets[i3D][iTotal] ->setProperty( "text", QString::number( nb3DLinear + nb3DQuadratic ) ); + long nb3DTotal = nb3DLinear + nb3DQuadratic + nb3DBiQuadratic; + myWidgets[i3D][iTotal] ->setProperty( "text", QString::number( nb3DTotal ) ); myWidgets[i3D][iLinear] ->setProperty( "text", QString::number( nb3DLinear ) ); myWidgets[i3D][iQuadratic] ->setProperty( "text", QString::number( nb3DQuadratic ) ); myWidgets[i3D][iBiQuadratic] ->setProperty( "text", QString::number( nb3DBiQuadratic ) ); @@ -546,7 +548,7 @@ void SMESHGUI_MeshInfo::showInfo( SMESH::SMESH_IDSource_ptr obj ) myWidgets[i3DPrisms][iQuadratic] ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Penta] ) ); myWidgets[i3DHexaPrisms][iTotal] ->setProperty( "text", QString::number( info[SMDSEntity_Hexagonal_Prism] ) ); myWidgets[i3DPolyhedrons][iTotal] ->setProperty( "text", QString::number( info[SMDSEntity_Polyhedra] ) ); - long nbElemTotal = info[SMDSEntity_0D] + info[SMDSEntity_Ball] + nbEdges + nb2DLinear + nb2DQuadratic + nb2DBiQuadratic + nb3DLinear + nb3DQuadratic + nb3DBiQuadratic; + long nbElemTotal = info[SMDSEntity_0D] + info[SMDSEntity_Ball] + nbEdges + nb2DTotal + nb3DTotal; long nbElemLinerial = info[SMDSEntity_Edge] + nb2DLinear + nb3DLinear; long nbElemQuadratic = info[SMDSEntity_Quad_Edge] + nb2DQuadratic + nb3DQuadratic; long nbElemBiQuadratic = nb2DBiQuadratic + nb3DBiQuadratic; diff --git a/src/SMESHGUI/SMESHGUI_MeshOp.cxx b/src/SMESHGUI/SMESHGUI_MeshOp.cxx index ab8b437a6..cdb3bc919 100644 --- a/src/SMESHGUI/SMESHGUI_MeshOp.cxx +++ b/src/SMESHGUI/SMESHGUI_MeshOp.cxx @@ -26,15 +26,15 @@ #include "SMESHGUI_MeshOp.h" #include "SMESHGUI.h" -#include "SMESHGUI_MeshDlg.h" -#include "SMESHGUI_ShapeByMeshDlg.h" -#include "SMESHGUI_HypothesesUtils.h" -#include "SMESHGUI_Hypotheses.h" -#include "SMESHGUI_Utils.h" #include "SMESHGUI_GEOMGenUtils.h" - -#include -#include +#include "SMESHGUI_Hypotheses.h" +#include "SMESHGUI_HypothesesUtils.h" +#include "SMESHGUI_MeshDlg.h" +#include "SMESHGUI_Operations.h" +#include "SMESHGUI_ShapeByMeshDlg.h" +#include "SMESHGUI_Utils.h" +#include "SMESH_NumberFilter.hxx" +#include "SMESH_TypeFilter.hxx" // SALOME GEOM includes #include @@ -247,8 +247,9 @@ void SMESHGUI_MeshOp::startOperation() myDlg->activateObject( myIsMesh ? SMESHGUI_MeshDlg::Geom : SMESHGUI_MeshDlg::Mesh ); } else + { myDlg->activateObject( SMESHGUI_MeshDlg::Obj ); - + } myDlg->setCurrentTab( SMESH::DIM_3D ); QStringList TypeMeshList; @@ -363,15 +364,39 @@ bool SMESHGUI_MeshOp::isSubshapeOk() const // skl for NPAL14695 - implementation of searching of mainObj GEOM::GEOM_Object_var mainObj = op->GetMainShape(aSubGeomVar); /* _var not _wrap as mainObj already exists! */ - while(1) { - if (mainObj->_is_nil()) - return false; + while( !mainObj->_is_nil()) { CORBA::String_var entry1 = mainObj->GetEntry(); CORBA::String_var entry2 = mainGeom->GetEntry(); if (std::string( entry1.in() ) == entry2.in() ) return true; mainObj = op->GetMainShape(mainObj); } + if ( aSubGeomVar->GetShapeType() == GEOM::COMPOUND ) + { + // is aSubGeomVar a compound of sub-shapes? + GEOM::GEOM_IShapesOperations_wrap sop = geomGen->GetIShapesOperations(aStudy->StudyId()); + if (sop->_is_nil()) return false; + GEOM::ListOfLong_var ids = sop->GetAllSubShapesIDs( aSubGeomVar, + GEOM::SHAPE,/*sorted=*/false); + if ( ids->length() > 0 ) + { + ids->length( 1 ); + GEOM::GEOM_Object_var compSub = geomGen->AddSubShape( aSubGeomVar, ids ); + if ( !compSub->_is_nil() ) + { + GEOM::ListOfGO_var shared = sop->GetSharedShapes( mainGeom, + compSub, + compSub->GetShapeType() ); + geomGen->RemoveObject( compSub ); + compSub->UnRegister(); + if ( shared->length() > 0 ) { + geomGen->RemoveObject( shared[0] ); + shared[0]->UnRegister(); + } + return ( shared->length() > 0 ); + } + } + } } } @@ -380,8 +405,8 @@ bool SMESHGUI_MeshOp::isSubshapeOk() const //================================================================================ /*! - * \brief Return name of the algorithm that does not support submeshes and makes - * submesh creation useless + * \brief Return name of the algorithm that does not support sub-meshes and makes + * sub-mesh creation useless * \retval char* - string is to be deleted!!! */ //================================================================================ @@ -847,7 +872,7 @@ void SMESHGUI_MeshOp::availableHyps( const int theDim, theDataList.clear(); theHyps.clear(); bool isAlgo = ( theHypType == Algo ); - bool isAux = ( theHypType == AddHyp ); + bool isAux = ( theHypType >= AddHyp ); QStringList aHypTypeNameList = SMESH::GetAvailableHypotheses( isAlgo, theDim, isAux, myIsOnGeometry, !myIsMesh ); QStringList::const_iterator anIter; @@ -906,7 +931,7 @@ void SMESHGUI_MeshOp::existingHyps( const int theDim, else aPart = theHypType == Algo ? SMESH::Tag_AlgorithmsRoot : SMESH::Tag_HypothesisRoot; - const bool isAux = ( theHypType == AddHyp ); + const bool isAux = ( theHypType >= AddHyp ); const bool allHyps = ( !isMesh && theHypType != Algo && theDim > -1); if ( theFather->FindSubObject( aPart, aHypRoot ) ) @@ -1489,14 +1514,24 @@ void SMESHGUI_MeshOp::onAlgoSelected( const int theIndex, { if ( !isAccessibleDim( dim )) continue; - for ( int dlgType = MainHyp; dlgType < nbDlgHypTypes(dim); dlgType++ ) + + // get indices of selected hyps + const int nbTypes = nbDlgHypTypes(dim); + std::vector hypIndexByType( nbTypes, -1 ); + for ( int dlgType = MainHyp; dlgType < nbTypes; dlgType++ ) + { + hypIndexByType[ dlgType ] = currentHyp( dim, dlgType ); + } + + // update hyps + for ( int dlgType = MainHyp; dlgType < nbTypes; dlgType++ ) { const int type = Min( dlgType, AddHyp ); myAvailableHypData[ dim ][ type ].clear(); QStringList anAvailable, anExisting; HypothesisData* curAlgo = algoByDim[ dim ]; - int hypIndex = currentHyp( dim, dlgType ); + int hypIndex = hypIndexByType[ dlgType ]; SMESH::SMESH_Hypothesis_var curHyp; if ( hypIndex >= 0 && hypIndex < myExistingHyps[ dim ][ type ].count() ) @@ -1535,24 +1570,26 @@ void SMESHGUI_MeshOp::onAlgoSelected( const int theIndex, defaulHypAvlbl = (type == MainHyp && !curAlgo->IsAuxOrNeedHyp ); } // set list of hypotheses - myDlg->tab( dim )->setAvailableHyps( type, anAvailable ); - myDlg->tab( dim )->setExistingHyps( type, anExisting, defaulHypAvlbl ); - + if ( dlgType <= AddHyp ) + { + myDlg->tab( dim )->setAvailableHyps( type, anAvailable ); + myDlg->tab( dim )->setExistingHyps( type, anExisting, defaulHypAvlbl ); + } // set current existing hypothesis if ( !curHyp->_is_nil() && !anExisting.isEmpty() ) hypIndex = this->find( curHyp, myExistingHyps[ dim ][ type ]); else hypIndex = -1; - if ( !isSubmesh && hypIndex < 0 && anExisting.count() == 1 ) { + if ( !isSubmesh && myToCreate && hypIndex < 0 && anExisting.count() == 1 ) { // none is yet selected => select the sole existing if it is not optional CORBA::String_var hypTypeName = myExistingHyps[ dim ][ type ].first().first->GetName(); bool isOptional = true; if ( algoByDim[ dim ] && - SMESH::IsAvailableHypothesis( algoByDim[ dim ], hypTypeName.in(), isOptional ) && - !isOptional ) + SMESH::IsAvailableHypothesis( algoByDim[ dim ], hypTypeName.in(), isOptional ) && + !isOptional ) hypIndex = 0; } - setCurrentHyp( dim, type, hypIndex ); + setCurrentHyp( dim, dlgType, hypIndex ); } } } @@ -2371,7 +2408,7 @@ bool SMESHGUI_MeshOp::checkSubMeshConcurrency(SMESH::SMESH_Mesh_ptr mesh, myDlg->setEnabled( false ); // disactivate selection selectionMgr()->clearFilters(); selectObject( meshSO ); - SMESHGUI::GetSMESHGUI()->OnGUIEvent( 713 ); // MESH_ORDER + SMESHGUI::GetSMESHGUI()->OnGUIEvent( SMESHOp::OpMeshOrder ); // MESH_ORDER qApp->processEvents(); myDlg->setEnabled( true ); @@ -2578,11 +2615,11 @@ void SMESHGUI_MeshOp::setFilteredAlgoData( const int theTabIndex, const int theI bool toCheckIsApplicableToAll = !myIsMesh; GEOM::GEOM_Object_var aGeomVar; - QString anEntry = myDlg->selectedObject( SMESHGUI_MeshDlg::Geom ); + QString anEntry = + myDlg->selectedObject( myToCreate ? SMESHGUI_MeshDlg::Geom : SMESHGUI_MeshDlg::Obj ); if ( _PTR(SObject) so = studyDS()->FindObjectID( anEntry.toLatin1().data() )) { - CORBA::Object_var obj = _CAST( SObject,so )->GetObject(); - aGeomVar = GEOM::GEOM_Object::_narrow( obj ); + aGeomVar = SMESH::GetGeom( so ); if ( !aGeomVar->_is_nil() && toCheckIsApplicableToAll ) toCheckIsApplicableToAll = ( aGeomVar->GetType() == GEOM_GROUP ); } diff --git a/src/SMESHGUI/SMESHGUI_MultiEditDlg.cxx b/src/SMESHGUI/SMESHGUI_MultiEditDlg.cxx index b2fdc8bdd..e42a8389d 100755 --- a/src/SMESHGUI/SMESHGUI_MultiEditDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_MultiEditDlg.cxx @@ -53,7 +53,6 @@ #include #include #include -#include #include #include diff --git a/src/SMESHGUI/SMESHGUI_Operations.h b/src/SMESHGUI/SMESHGUI_Operations.h index 0d1cfe56a..18c28a441 100644 --- a/src/SMESHGUI/SMESHGUI_Operations.h +++ b/src/SMESHGUI/SMESHGUI_Operations.h @@ -200,7 +200,8 @@ namespace SMESHOp { OpDEFaces = 6042, // POPUP MENU - DISPLAY ENTITY - FACES OpDEVolumes = 6043, // POPUP MENU - DISPLAY ENTITY - VOLUMES OpDEBalls = 6044, // POPUP MENU - DISPLAY ENTITY - BALLS - OpDEAllEntity = 6045, // POPUP MENU - DISPLAY ENTITY - ALL ENTITY + OpDEAllEntity = 6045, // POPUP MENU - DISPLAY ENTITY - ALL ENTITIES + OpDEChoose = 6046, // POPUP MENU - DISPLAY ENTITY - CHOOSE ENTITIES // Representation -----------------//-------------------------------- OpRepresentationLines = 6050, // POPUP MENU - 2D QUADRATIC - LINES OpRepresentationArcs = 6051, // POPUP MENU - 2D QUADRATIC - ARCS diff --git a/src/SMESHGUI/SMESHGUI_ReorientFacesDlg.cxx b/src/SMESHGUI/SMESHGUI_ReorientFacesDlg.cxx index 41e341cca..064df3909 100644 --- a/src/SMESHGUI/SMESHGUI_ReorientFacesDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_ReorientFacesDlg.cxx @@ -46,7 +46,6 @@ // SALOME GUI includes #include #include -#include #include #include #include diff --git a/src/SMESHGUI/SMESHGUI_RotationDlg.cxx b/src/SMESHGUI/SMESHGUI_RotationDlg.cxx index 936a228c1..1a9724012 100644 --- a/src/SMESHGUI/SMESHGUI_RotationDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_RotationDlg.cxx @@ -52,7 +52,6 @@ #include #include #include -#include // SALOME KERNEL includes #include diff --git a/src/SMESHGUI/SMESHGUI_ScaleDlg.cxx b/src/SMESHGUI/SMESHGUI_ScaleDlg.cxx index 9da433c69..e07177bf1 100644 --- a/src/SMESHGUI/SMESHGUI_ScaleDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_ScaleDlg.cxx @@ -49,7 +49,6 @@ #include #include #include -#include // SALOME KERNEL includes #include diff --git a/src/SMESHGUI/SMESHGUI_Selection.cxx b/src/SMESHGUI/SMESHGUI_Selection.cxx index 80ca03466..94331c901 100644 --- a/src/SMESHGUI/SMESHGUI_Selection.cxx +++ b/src/SMESHGUI/SMESHGUI_Selection.cxx @@ -80,8 +80,10 @@ void SMESHGUI_Selection::init( const QString& client, LightApp_SelectionMgr* mgr return; _PTR(Study) aStudy = aSStudy->studyDS(); - for( int i=0, n=count(); i 0 ) { + QString mode = myControls[0]; + for( int ind = 1; ind < myControls.count(); ind++ ) { + if( mode != myControls[ind] ) + return "eNone"; + } + return mode; + } + return "eNone"; +} + bool SMESHGUI_Selection::isNumFunctor( int ind ) const { bool result = false; diff --git a/src/SMESHGUI/SMESHGUI_Selection.h b/src/SMESHGUI/SMESHGUI_Selection.h index 0a9d46ccc..3ba1bf4cb 100644 --- a/src/SMESHGUI/SMESHGUI_Selection.h +++ b/src/SMESHGUI/SMESHGUI_Selection.h @@ -49,6 +49,7 @@ public: virtual void init( const QString&, LightApp_SelectionMgr* ); virtual QVariant parameter( const int, const QString& ) const; + virtual QVariant parameter( const QString& ) const; virtual bool processOwner( const LightApp_DataOwner* ); // got from object, not from actor @@ -74,6 +75,7 @@ public: virtual QString shrinkMode( int ) const; virtual QList entityMode( int ) const; virtual QString controlMode( int ) const; + virtual QString controlMode() const; virtual bool isNumFunctor( int ) const; virtual QString facesOrientationMode( int ) const; virtual QString groupType( int ) const; @@ -87,6 +89,7 @@ public: private: QStringList myTypes; + QStringList myControls; QList myActors; }; diff --git a/src/SMESHGUI/SMESHGUI_SelectionOp.cxx b/src/SMESHGUI/SMESHGUI_SelectionOp.cxx index 0c8486ed2..daf2bf493 100644 --- a/src/SMESHGUI/SMESHGUI_SelectionOp.cxx +++ b/src/SMESHGUI/SMESHGUI_SelectionOp.cxx @@ -43,7 +43,6 @@ #include #include -#include // SALOME KERNEL includes #include @@ -428,7 +427,7 @@ void SMESHGUI_SelectionOp::selected( QStringList& names, { _PTR(SObject) obj = _study->studyDS()->FindObjectID( anIt.Value()->getEntry() ); if( obj ) - names.append( obj->GetName().c_str() ); + names.append( QString( obj->GetName().c_str() ).trimmed() ); } } } diff --git a/src/SMESHGUI/SMESHGUI_SmoothingDlg.cxx b/src/SMESHGUI/SMESHGUI_SmoothingDlg.cxx index 7e1d8d051..6fcc47a41 100644 --- a/src/SMESHGUI/SMESHGUI_SmoothingDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_SmoothingDlg.cxx @@ -596,20 +596,21 @@ void SMESHGUI_SmoothingDlg::SelectionIntoArgument() if (myNbOkElements < 1) return; - + QStringList elements; for ( int i = 0; i < myNbOkElements; ++i ) elements << QString::number( aMapIndex( i+1 ) ); aString = elements.join(" "); } - } else if (myEditCurrentArgument == LineEditNodes && !myMesh->_is_nil() && myIO == IO ) { + } else if (myEditCurrentArgument == LineEditNodes && !myMesh->_is_nil() && myIO->isSame(IO) ) + { myNbOkNodes = SMESH::GetNameOfSelectedNodes(mySelector, IO, aString); } myEditCurrentArgument->setText(aString); myEditCurrentArgument->repaint(); myEditCurrentArgument->setEnabled(false); // to update lineedit IPAL 19809 - myEditCurrentArgument->setEnabled(true); + myEditCurrentArgument->setEnabled(true); if (myNbOkElements && (myNbOkNodes || LineEditNodes->text().trimmed().isEmpty())) { buttonOk->setEnabled(true); diff --git a/src/SMESHGUI/SMESHGUI_SymmetryDlg.cxx b/src/SMESHGUI/SMESHGUI_SymmetryDlg.cxx index c887edf84..2a014f21e 100644 --- a/src/SMESHGUI/SMESHGUI_SymmetryDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_SymmetryDlg.cxx @@ -52,7 +52,6 @@ #include #include #include -#include // SALOME KERNEL includes #include diff --git a/src/SMESHGUI/SMESHGUI_TranslationDlg.cxx b/src/SMESHGUI/SMESHGUI_TranslationDlg.cxx index e4bf823f8..ae7adcfa0 100644 --- a/src/SMESHGUI/SMESHGUI_TranslationDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_TranslationDlg.cxx @@ -52,7 +52,6 @@ #include #include #include -#include // SALOME KERNEL includes #include diff --git a/src/SMESHGUI/SMESHGUI_TransparencyDlg.cxx b/src/SMESHGUI/SMESHGUI_TransparencyDlg.cxx index 58b52c670..6c1370943 100644 --- a/src/SMESHGUI/SMESHGUI_TransparencyDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_TransparencyDlg.cxx @@ -40,7 +40,6 @@ #include #include -#include #include #include diff --git a/src/SMESHGUI/SMESHGUI_Utils.h b/src/SMESHGUI/SMESHGUI_Utils.h index d5ec25ed4..5ac9ee97c 100644 --- a/src/SMESHGUI/SMESHGUI_Utils.h +++ b/src/SMESHGUI/SMESHGUI_Utils.h @@ -204,7 +204,7 @@ SMESHGUI_EXPORT struct toQStr : public toStrT< QString > { toQStr( char* s ): toStrT< QString >(s) {} }; - class toStdStr : public toStrT< std::string > { + struct toStdStr : public toStrT< std::string > { toStdStr( char* s ): toStrT< std::string >(s) {} }; diff --git a/src/SMESHGUI/SMESHGUI_VTKUtils.cxx b/src/SMESHGUI/SMESHGUI_VTKUtils.cxx index 6b67d5e9c..7ca3e9395 100644 --- a/src/SMESHGUI/SMESHGUI_VTKUtils.cxx +++ b/src/SMESHGUI/SMESHGUI_VTKUtils.cxx @@ -47,7 +47,6 @@ #include #include -#include #include #include diff --git a/src/SMESHGUI/SMESHGUI_XmlHandler.cxx b/src/SMESHGUI/SMESHGUI_XmlHandler.cxx index b5c53d4b5..cb27cf9b4 100644 --- a/src/SMESHGUI/SMESHGUI_XmlHandler.cxx +++ b/src/SMESHGUI/SMESHGUI_XmlHandler.cxx @@ -161,8 +161,9 @@ bool SMESHGUI_XmlHandler::startElement (const QString&, const QString&, for ( int i = 0; i < NB_ATTRIBUTES; ++i ) { QString aStr = atts.value( name[i] ); if ( !aStr.isEmpty() ) { - aStr.remove( ' ' ); - attr[ i ] = aStr.split( ',', QString::SkipEmptyParts ); + attr[i] = aStr.split( ',', QString::SkipEmptyParts ); + for ( int j = 0; j < attr[i].count(); ++j ) + attr[i][j] = attr[i][j].trimmed(); } } diff --git a/src/SMESHGUI/SMESH_images.ts b/src/SMESHGUI/SMESH_images.ts index 80c04e7d6..7da6cad1a 100644 --- a/src/SMESHGUI/SMESH_images.ts +++ b/src/SMESHGUI/SMESH_images.ts @@ -255,6 +255,14 @@ ICON_DLG_TRIANGLE mesh_triangle.png + + ICON_DLG_CHOOSE + mesh_choose.png + + + ICON_DLG_CHOOSE_ALL + mesh_choose_all.png + ICON_EDIT_GROUP mesh_edit_group.png diff --git a/src/SMESHGUI/SMESH_msg_en.ts b/src/SMESHGUI/SMESH_msg_en.ts index fcb37740a..3f8a01c03 100644 --- a/src/SMESHGUI/SMESH_msg_en.ts +++ b/src/SMESHGUI/SMESH_msg_en.ts @@ -396,6 +396,10 @@ MEN_EDGES Edges + + MEN_CHOOSE + Choose... + MEN_EDIT Edit @@ -7805,4 +7809,11 @@ as they are of improper type: Shrink coef: + + SMESHGUI_DisplayEntitiesDlg + + WRN_AT_LEAST_ONE + At least one entity type should be chosen! + + diff --git a/src/SMESHGUI/SMESH_msg_fr.ts b/src/SMESHGUI/SMESH_msg_fr.ts index f20d819eb..91596f776 100755 --- a/src/SMESHGUI/SMESH_msg_fr.ts +++ b/src/SMESHGUI/SMESH_msg_fr.ts @@ -396,6 +396,10 @@ MEN_EDGES Arêtes + + MEN_CHOOSE + Choose... + MEN_EDIT Edition @@ -7753,4 +7757,11 @@ en raison de leurs types incompatibles: Coef de réduction: + + SMESHGUI_DisplayEntitiesDlg + + WRN_AT_LEAST_ONE + At least one entity type should be chosen! + + diff --git a/src/SMESHGUI/SMESH_msg_ja.ts b/src/SMESHGUI/SMESH_msg_ja.ts index 5d6e78d20..0332875cf 100644 --- a/src/SMESHGUI/SMESH_msg_ja.ts +++ b/src/SMESHGUI/SMESH_msg_ja.ts @@ -395,6 +395,10 @@ MEN_EDGES エッジ + + MEN_CHOOSE + Choose... + MEN_EDIT 編集(&E) @@ -7687,4 +7691,11 @@ 減少係数: + + SMESHGUI_DisplayEntitiesDlg + + WRN_AT_LEAST_ONE + At least one entity type should be chosen! + + diff --git a/src/SMESHUtils/SMESH_TypeDefs.hxx b/src/SMESHUtils/SMESH_TypeDefs.hxx index 9fec2e5bd..f5dedaec0 100644 --- a/src/SMESHUtils/SMESH_TypeDefs.hxx +++ b/src/SMESHUtils/SMESH_TypeDefs.hxx @@ -43,7 +43,8 @@ typedef std::map, TIDCompare > TElemOfElemListMap; typedef std::map, TIDCompare > TElemOfNodeListMap; -typedef std::map TNodeNodeMap; +typedef std::map TNodeNodeMap; //!< Set of elements sorted by ID, to be used to assure predictability of edition typedef std::set< const SMDS_MeshElement*, TIDCompare > TIDSortedElemSet; diff --git a/src/SMESH_I/SMESH_2smeshpy.cxx b/src/SMESH_I/SMESH_2smeshpy.cxx index 564632744..911375f68 100644 --- a/src/SMESH_I/SMESH_2smeshpy.cxx +++ b/src/SMESH_I/SMESH_2smeshpy.cxx @@ -1793,10 +1793,29 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand ) list< Handle(_pyHypothesis) >::iterator hyp; if ( !myLastComputeCmd.IsNull() ) { - for ( hyp = myHypos.begin(); hyp != myHypos.end(); ++hyp ) - (*hyp)->ComputeDiscarded( myLastComputeCmd ); + // check if the previously computed mesh has been edited, + // if so then we do not clear the previous Compute() + bool toClear = true; + if ( myLastComputeCmd->GetMethod() == "Compute" ) + { + list< Handle(_pyMeshEditor)>::iterator e = myEditors.begin(); + for ( ; e != myEditors.end() && toClear; ++e ) + { + list< Handle(_pyCommand)>& cmds = (*e)->GetProcessedCmds(); + list< Handle(_pyCommand) >::reverse_iterator cmd = cmds.rbegin(); + if ( cmd != cmds.rend() && + (*cmd)->GetOrderNb() > myLastComputeCmd->GetOrderNb() ) + toClear = false; + } + } + if ( toClear ) + { + // clear hyp commands called before myLastComputeCmd + for ( hyp = myHypos.begin(); hyp != myHypos.end(); ++hyp ) + (*hyp)->ComputeDiscarded( myLastComputeCmd ); - myLastComputeCmd->Clear(); + myLastComputeCmd->Clear(); + } } myLastComputeCmd = theCommand; @@ -1961,7 +1980,7 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand ) // // remove "PartTo" from the method TCollection_AsciiString newMethod = method; - newMethod.Remove( 7, 6 ); + newMethod.Remove( /*where=*/7, /*howmany=*/6 ); theCommand->SetMethod( newMethod ); // make the 1st arg be the last one (or last but three for ExportMED()) _pyID partID = theCommand->GetArg( 1 ); diff --git a/src/SMESH_I/SMESH_2smeshpy.hxx b/src/SMESH_I/SMESH_2smeshpy.hxx index 4e6531dde..04352f24c 100644 --- a/src/SMESH_I/SMESH_2smeshpy.hxx +++ b/src/SMESH_I/SMESH_2smeshpy.hxx @@ -117,17 +117,17 @@ public: _pyCommand( const _AString& theString, int theNb=-1 ) : myString( theString ), myOrderNb( theNb ) {}; _AString & GetString() { return myString; } - int GetOrderNb() const { return myOrderNb; } + int GetOrderNb() const { return myOrderNb; } void SetOrderNb( int theNb ) { myOrderNb = theNb; } typedef void* TAddr; TAddr GetAddress() const { return (void*) this; } - int Length() const { return myString.Length(); } + int Length() const { return myString.Length(); } void Clear() { myString.Clear(); myBegPos.Clear(); myArgs.Clear(); } bool IsEmpty() const { return myString.IsEmpty(); } _AString GetIndentation(); const _AString & GetResultValue(); int GetNbResultValues(); - const _AString& GetResultValue(int res); + const _AString & GetResultValue(int res); const _AString & GetObject(); const _AString & GetMethod(); const _AString & GetArg( int index ); @@ -183,11 +183,11 @@ public: const _pyID& GetID() { return myID.IsEmpty() ? myCreationCmd->GetResultValue() : myID; } static _pyID FatherID(const _pyID & childID); const Handle(_pyCommand)& GetCreationCmd() { return myCreationCmd; } - int GetNbCalls() const { return myProcessedCmds.size(); } + int GetNbCalls() const { return myProcessedCmds.size(); } bool IsInStudy() const { return myIsPublished; } virtual void SetRemovedFromStudy(const bool isRemoved) { myIsPublished = !isRemoved; } void SetCreationCmd( Handle(_pyCommand) cmd ) { myCreationCmd = cmd; } - int GetCommandNb() { return myCreationCmd->GetOrderNb(); } + int GetCommandNb() { return myCreationCmd->GetOrderNb(); } void AddProcessedCmd( const Handle(_pyCommand) & cmd ) { if (myProcessedCmds.empty() || myProcessedCmds.back()!=cmd) myProcessedCmds.push_back( cmd );} std::list< Handle(_pyCommand) >& GetProcessedCmds() { return myProcessedCmds; } diff --git a/src/SMESH_I/SMESH_Filter_i.cxx b/src/SMESH_I/SMESH_Filter_i.cxx index 0293f51a3..3d7977cb6 100644 --- a/src/SMESH_I/SMESH_Filter_i.cxx +++ b/src/SMESH_I/SMESH_Filter_i.cxx @@ -1550,8 +1550,8 @@ void ConnectedElements_i::SetThreshold ( const char* if ( sobj->_is_nil() ) THROW_SALOME_CORBA_EXCEPTION ( "ConnectedElements_i::SetThreshold(): invalid vertex study entry", SALOME::BAD_PARAM ); - CORBA::Object_var obj = sobj->GetObject(); - GEOM::GEOM_Object_wrap vertex = GEOM::GEOM_Object::_narrow( obj ); + CORBA::Object_var obj = sobj->GetObject(); + GEOM::GEOM_Object_var vertex = GEOM::GEOM_Object::_narrow( obj ); if ( vertex->_is_nil() ) THROW_SALOME_CORBA_EXCEPTION ( "ConnectedElements_i::SetThreshold(): no GEOM_Object in SObject", SALOME::BAD_PARAM ); @@ -3020,7 +3020,8 @@ CORBA::Boolean Filter_i::SetCriteria( const SMESH::Filter::Criteria& theCriteria SMESH::Predicate_ptr aPrevPredicate = SMESH::Predicate::_nil(); int aPrevBinary = SMESH::FT_Undefined; - aBinaries.back() = SMESH::FT_Undefined; + if ( !aBinaries.empty() ) + aBinaries.back() = SMESH::FT_Undefined; for ( aPredIter = aPredicates.begin(), aBinaryIter = aBinaries.begin(); aPredIter != aPredicates.end() && aBinaryIter != aBinaries.end(); diff --git a/src/SMESH_I/SMESH_Gen_i.cxx b/src/SMESH_I/SMESH_Gen_i.cxx index b822651b7..cffb3d573 100644 --- a/src/SMESH_I/SMESH_Gen_i.cxx +++ b/src/SMESH_I/SMESH_Gen_i.cxx @@ -467,23 +467,22 @@ SMESH::SMESH_Hypothesis_ptr SMESH_Gen_i::createHypothesis(const char* theHypName SMESH_Hypothesis_i* myHypothesis_i = 0; SMESH::SMESH_Hypothesis_var hypothesis_i; std::string aPlatformLibName; - typedef GenericHypothesisCreator_i* (*GetHypothesisCreator)(const char* ); - GenericHypothesisCreator_i* aCreator = getHypothesisCreator(theHypName, theLibName, aPlatformLibName); + GenericHypothesisCreator_i* aCreator = + getHypothesisCreator(theHypName, theLibName, aPlatformLibName); + // create a new hypothesis object, store its ref. in studyContext - if(MYDEBUG) MESSAGE("Create Hypothesis " << theHypName); - myHypothesis_i = - myHypCreatorMap[string(theHypName)]->Create(myPoa, GetCurrentStudyID(), &myGen); - myHypothesis_i->SetLibName(aPlatformLibName.c_str()); // for persistency assurance - - if (!myHypothesis_i) - return hypothesis_i._retn(); - - // activate the CORBA servant of hypothesis - hypothesis_i = myHypothesis_i->_this(); - int nextId = RegisterObject( hypothesis_i ); - if(MYDEBUG) { MESSAGE( "Add hypo to map with id = "<< nextId ); } - else { nextId = 0; } // avoid "unused variable" warning in release mode + myHypothesis_i = aCreator->Create(myPoa, GetCurrentStudyID(), &myGen); + if (myHypothesis_i) + { + myHypothesis_i->SetLibName(aPlatformLibName.c_str()); // for persistency assurance + myHypCreatorMap[ myHypothesis_i->GetName() ] = aCreator; + // activate the CORBA servant of hypothesis + hypothesis_i = myHypothesis_i->_this(); + int nextId = RegisterObject( hypothesis_i ); + if(MYDEBUG) { MESSAGE( "Add hypo to map with id = "<< nextId ); } + else { nextId = 0; } // avoid "unused variable" warning in release mode + } return hypothesis_i._retn(); } diff --git a/src/SMESH_I/SMESH_Gen_i_1.cxx b/src/SMESH_I/SMESH_Gen_i_1.cxx index 6890bcf08..b59479fce 100644 --- a/src/SMESH_I/SMESH_Gen_i_1.cxx +++ b/src/SMESH_I/SMESH_Gen_i_1.cxx @@ -43,6 +43,8 @@ #include #include +#include + #ifdef _DEBUG_ static int MYDEBUG = 0; //static int VARIABLE_DEBUG = 0; @@ -341,9 +343,15 @@ void SMESH_Gen_i::SetName(SALOMEDS::SObject_ptr theSObject, SALOMEDS::GenericAttribute_wrap anAttr = aStudyBuilder->FindOrCreateAttribute( theSObject, "AttributeName" ); SALOMEDS::AttributeName_wrap aNameAttr = anAttr; - if ( theName && strlen( theName ) != 0 ) - aNameAttr->SetValue( theName ); - else { + if ( theName && theName[0] ) { + std::string name( theName ); // trim trailing white spaces + for ( size_t i = name.size()-1; i > 0; --i ) + if ( isspace( name[i] )) name[i] = '\0'; + else break; + aNameAttr->SetValue( name.c_str() ); + } + else + { CORBA::String_var curName = aNameAttr->Value(); if ( strlen( curName.in() ) == 0 ) { SMESH_Comment aName(theDefaultName); @@ -355,7 +363,7 @@ void SMESH_Gen_i::SetName(SALOMEDS::SObject_ptr theSObject, //======================================================================= //function : SetPixMap -//purpose : +//purpose : //======================================================================= void SMESH_Gen_i::SetPixMap(SALOMEDS::SObject_ptr theSObject, diff --git a/src/SMESH_I/SMESH_MeshEditor_i.cxx b/src/SMESH_I/SMESH_MeshEditor_i.cxx index c54b068cf..763f976e4 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.cxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.cxx @@ -64,6 +64,7 @@ #include #include #include +#include #include #include @@ -4746,9 +4747,16 @@ SMESH_MeshEditor_i::scale(SMESH::SMESH_IDSource_ptr theObject, }; double tol = std::numeric_limits::max(); gp_Trsf aTrsf; + +#if OCC_VERSION_LARGE > 0x06070100 + aTrsf.SetValues( S[0], 0, 0, thePoint.x * (1-S[0]), + 0, S[1], 0, thePoint.y * (1-S[1]), + 0, 0, S[2], thePoint.z * (1-S[2]) ); +#else aTrsf.SetValues( S[0], 0, 0, thePoint.x * (1-S[0]), 0, S[1], 0, thePoint.y * (1-S[1]), 0, 0, S[2], thePoint.z * (1-S[2]), tol, tol); +#endif TIDSortedElemSet copyElements; TIDSortedElemSet* workElements = &elements; diff --git a/src/SMESH_SWIG/StdMeshersBuilder.py b/src/SMESH_SWIG/StdMeshersBuilder.py index 1e9c73533..1496202ff 100644 --- a/src/SMESH_SWIG/StdMeshersBuilder.py +++ b/src/SMESH_SWIG/StdMeshersBuilder.py @@ -385,7 +385,7 @@ class StdMeshersBuilder_Segment(Mesh_Algorithm): algo = self.mesh.smeshpyD.CreateHypothesis("SegmentAroundVertex_0D", "libStdMeshersEngine.so") pass status = self.mesh.mesh.AddHypothesis(self.geom, algo) - TreatHypoStatus(status, "SegmentAroundVertex_0D", name, True) + TreatHypoStatus(status, "SegmentAroundVertex_0D", name, True, self.mesh) # from salome.smesh.smeshBuilder import IsEqual comFun = lambda hyp, args: IsEqual(hyp.GetLength(), args[0]) @@ -830,12 +830,13 @@ class StdMeshersBuilder_Projection2D(Mesh_Algorithm): from salome.smesh.smeshBuilder import AssureGeomPublished AssureGeomPublished( self.mesh, geom ) hyp = self.Hypothesis("ProjectionSource2D", [face,mesh,srcV1,tgtV1,srcV2,tgtV2], - UseExisting=0) + UseExisting=0, toAdd=False) # it does not seem to be useful to reuse the existing "SourceFace" hypothesis #UseExisting=UseExisting, CompareMethod=self.CompareSourceFace) hyp.SetSourceFace( face ) hyp.SetSourceMesh( mesh ) hyp.SetVertexAssociation( srcV1, srcV2, tgtV1, tgtV2 ) + self.mesh.AddHypothesis(hyp, self.geom) return hyp pass # end of StdMeshersBuilder_Projection2D class diff --git a/src/SMESH_SWIG/smeshBuilder.py b/src/SMESH_SWIG/smeshBuilder.py index dbbbe973b..fe63e726b 100644 --- a/src/SMESH_SWIG/smeshBuilder.py +++ b/src/SMESH_SWIG/smeshBuilder.py @@ -627,7 +627,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): # pass result of Mesh.GetIDSource( list_of_ids, type ) as meshPart # @param meshName a name of the new mesh # @param toCopyGroups to create in the new mesh groups the copied elements belongs to - # @param toKeepIDs to preserve IDs of the copied elements or not + # @param toKeepIDs to preserve order of the copied elements or not # @return an instance of Mesh class def CopyMesh( self, meshPart, meshName, toCopyGroups=False, toKeepIDs=False): if (isinstance( meshPart, Mesh )): @@ -1596,7 +1596,7 @@ class Mesh: AssureGeomPublished( self, geom, "shape for %s" % hyp.GetName()) status = self.mesh.AddHypothesis(geom, hyp) else: - status = HYP_BAD_GEOMETRY + status = HYP_BAD_GEOMETRY,"" hyp_name = GetName( hyp ) geom_name = "" if geom: @@ -1876,7 +1876,12 @@ class Mesh: # @ingroup l2_grps_create def MakeGroupByIds(self, groupName, elementType, elemIDs): group = self.mesh.CreateGroup(elementType, groupName) - group.Add(elemIDs) + if hasattr( elemIDs, "GetIDs" ): + if hasattr( elemIDs, "SetMesh" ): + elemIDs.SetMesh( self.GetMesh() ) + group.AddFrom( elemIDs ) + else: + group.Add(elemIDs) return group ## Creates a mesh group by the given conditions @@ -3451,7 +3456,7 @@ class Mesh: ## # @brief Creates missing boundary elements around either the whole mesh or - # groups of 2D elements + # groups of elements # @param dimension - defines type of boundary elements to create # @param groupName - a name of group to store all boundary elements in, # "" means not to create the group @@ -3459,7 +3464,7 @@ class Mesh: # mesh + created boundary elements; "" means not to create the new mesh # @param toCopyAll - if true, the whole initial mesh will be copied into # the new mesh else only boundary elements will be copied into the new mesh - # @param groups - groups of 2D elements to make boundary around + # @param groups - groups of elements to make boundary around # @retval tuple( long, mesh, groups ) # long - number of added boundary elements # mesh - the mesh where elements were added to @@ -3472,12 +3477,12 @@ class Mesh: if mesh: mesh = self.smeshpyD.Mesh(mesh) return nb, mesh, group - ## Renumber mesh nodes + ## Renumber mesh nodes (Obsolete, does nothing) # @ingroup l2_modif_renumber def RenumberNodes(self): self.editor.RenumberNodes() - ## Renumber mesh elements + ## Renumber mesh elements (Obsole, does nothing) # @ingroup l2_modif_renumber def RenumberElements(self): self.editor.RenumberElements() diff --git a/src/SMESH_SWIG/smesh_algorithm.py b/src/SMESH_SWIG/smesh_algorithm.py index 3623b5176..8ce382e17 100644 --- a/src/SMESH_SWIG/smesh_algorithm.py +++ b/src/SMESH_SWIG/smesh_algorithm.py @@ -40,7 +40,7 @@ import SMESH # @code # meshMethod = "MyAlgorithm" # @endcode -# then an instance of @c MyPlugin_Algorithm can be created by the direct invokation of the function +# then an instance of @c MyPlugin_Algorithm can be created by the direct invocation of the function # of smesh.Mesh class: # @code # my_algo = mesh.MyAlgorithm() @@ -257,7 +257,7 @@ class Mesh_Algorithm: ## Defines "ViscousLayers" hypothesis to give parameters of layers of prisms to build # near mesh boundary. This hypothesis can be used by several 3D algorithms: - # NETGEN 3D, GHS3D, Hexahedron(i,j,k) + # NETGEN 3D, MG-Tetra, Hexahedron(i,j,k) # @param thickness total thickness of layers of prisms # @param numberOfLayers number of layers of prisms # @param stretchFactor factor (>1.0) of growth of layer thickness towards inside of mesh @@ -274,7 +274,14 @@ class Mesh_Algorithm: if not "ViscousLayers" in self.GetCompatibleHypothesis(): raise TypeError, "ViscousLayers are not supported by %s"%self.algo.GetName() if faces and isinstance( faces[0], geomBuilder.GEOM._objref_GEOM_Object ): - faces = [ self.mesh.geompyD.GetSubShapeID(self.mesh.geom, f) for f in faces ] + import GEOM + faceIDs = [] + for f in faces: + if self.mesh.geompyD.ShapeIdToType( f.GetType() ) == "GROUP": + faceIDs += f.GetSubShapeIndices() + else: + faceIDs += [self.mesh.geompyD.GetSubShapeID(self.mesh.geom, f)] + faces = faceIDs hyp = self.Hypothesis("ViscousLayers", [thickness, numberOfLayers, stretchFactor, faces, isFacesToIgnore], toAdd=False) @@ -287,7 +294,7 @@ class Mesh_Algorithm: ## 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: - # NETGEN 2D, NETGEN 1D-2D, Quadrangle (mapping), MEFISTO, BLSURF + # NETGEN 2D, NETGEN 1D-2D, Quadrangle (mapping), MEFISTO, MG-CADSurf # @param thickness total thickness of layers of quadrilaterals # @param numberOfLayers number of layers # @param stretchFactor factor (>1.0) of growth of layer thickness towards inside of mesh diff --git a/src/StdMeshers/StdMeshers_Adaptive1D.cxx b/src/StdMeshers/StdMeshers_Adaptive1D.cxx index 62a2cf5a9..7bcfca77d 100644 --- a/src/StdMeshers/StdMeshers_Adaptive1D.cxx +++ b/src/StdMeshers/StdMeshers_Adaptive1D.cxx @@ -1179,6 +1179,7 @@ bool AdaptiveAlgo::Compute(SMESH_Mesh & theMesh, eData.AddPoint( eData.myPoints.end(), eData.myC3d.LastParameter() ); } } + if ( myEdges.empty() ) return true; if ( _computeCanceled ) return false; // Take into account size of already existing segments diff --git a/src/StdMeshers/StdMeshers_CartesianParameters3D.cxx b/src/StdMeshers/StdMeshers_CartesianParameters3D.cxx index 0b7ac0235..b2e15df8c 100644 --- a/src/StdMeshers/StdMeshers_CartesianParameters3D.cxx +++ b/src/StdMeshers/StdMeshers_CartesianParameters3D.cxx @@ -329,7 +329,7 @@ void StdMeshers_CartesianParameters3D::ComputeCoordinates(const double x0, coords.clear(); for ( size_t i = 0; i < spaceFuns.size(); ++i ) { - FunctionExpr fun( spaceFuns[i].c_str(), /*convMode=*/-1 ); + StdMeshers::FunctionExpr fun( spaceFuns[i].c_str(), /*convMode=*/-1 ); const double p0 = x0 * ( 1. - points[i]) + x1 * points[i]; const double p1 = x0 * ( 1. - points[i+1]) + x1 * points[i+1]; diff --git a/src/StdMeshers/StdMeshers_Cartesian_3D.cxx b/src/StdMeshers/StdMeshers_Cartesian_3D.cxx index 3cd23ff35..bec175bb3 100644 --- a/src/StdMeshers/StdMeshers_Cartesian_3D.cxx +++ b/src/StdMeshers/StdMeshers_Cartesian_3D.cxx @@ -100,17 +100,6 @@ using namespace std; //#define _MY_DEBUG_ #endif -#if OCC_VERSION_LARGE <= 0x06050300 -// workaround is required only for OCCT6.5.3 and older (see OCC22809) -#define ELLIPSOLID_WORKAROUND -#endif - -#ifdef ELLIPSOLID_WORKAROUND -#include -#include -#include -#endif - //============================================================================= /*! * Constructor @@ -317,41 +306,6 @@ namespace void ComputeUVW(const gp_XYZ& p, double uvw[3]); void ComputeNodes(SMESH_MesherHelper& helper); }; -#ifdef ELLIPSOLID_WORKAROUND - // -------------------------------------------------------------------------- - /*! - * \brief struct temporary replacing IntCurvesFace_Intersector until - * OCCT bug 0022809 is fixed - * http://tracker.dev.opencascade.org/view.php?id=22809 - */ - struct TMP_IntCurvesFace_Intersector - { - BRepAdaptor_Surface _surf; - double _tol; - BRepIntCurveSurface_Inter _intcs; - vector _points; - BRepTopAdaptor_TopolTool _clsf; - - TMP_IntCurvesFace_Intersector(const TopoDS_Face& face, const double tol) - :_surf( face ), _tol( tol ), _clsf( new BRepAdaptor_HSurface(_surf) ) {} - Bnd_Box Bounding() const { Bnd_Box b; BRepBndLib::Add (_surf.Face(), b); return b; } - void Perform( const gp_Lin& line, const double w0, const double w1 ) - { - _points.clear(); - for ( _intcs.Init( _surf.Face(), line, _tol ); _intcs.More(); _intcs.Next() ) - if ( w0 <= _intcs.W() && _intcs.W() <= w1 ) - _points.push_back( _intcs.Point() ); - } - bool IsDone() const { return true; } - int NbPnt() const { return _points.size(); } - IntCurveSurface_TransitionOnCurve Transition( const int i ) const { return _points[ i-1 ].Transition(); } - double WParameter( const int i ) const { return _points[ i-1 ].W(); } - TopAbs_State ClassifyUVPoint(const gp_Pnt2d& p) { return _clsf.Classify( p, _tol ); } - }; -#define __IntCurvesFace_Intersector TMP_IntCurvesFace_Intersector -#else -#define __IntCurvesFace_Intersector IntCurvesFace_Intersector -#endif // -------------------------------------------------------------------------- /*! * \brief Intersector of TopoDS_Face with all GridLine's @@ -362,7 +316,7 @@ namespace TGeomID _faceID; Grid* _grid; Bnd_Box _bndBox; - __IntCurvesFace_Intersector* _surfaceInt; + IntCurvesFace_Intersector* _surfaceInt; vector< std::pair< GridLine*, F_IntersectPoint > > _intersections; FaceGridIntersector(): _grid(0), _surfaceInt(0) {} @@ -383,11 +337,11 @@ namespace GetCurveFaceIntersector(); return _bndBox; } - __IntCurvesFace_Intersector* GetCurveFaceIntersector() + IntCurvesFace_Intersector* GetCurveFaceIntersector() { if ( !_surfaceInt ) { - _surfaceInt = new __IntCurvesFace_Intersector( _face, Precision::PConfusion() ); + _surfaceInt = new IntCurvesFace_Intersector( _face, Precision::PConfusion() ); _bndBox = _surfaceInt->Bounding(); if ( _bndBox.IsVoid() ) BRepBndLib::Add (_face, _bndBox); @@ -412,7 +366,7 @@ namespace gp_Cone _cone; gp_Sphere _sphere; gp_Torus _torus; - __IntCurvesFace_Intersector* _surfaceInt; + IntCurvesFace_Intersector* _surfaceInt; vector< F_IntersectPoint > _intPoints; diff --git a/src/StdMeshers/StdMeshers_Distribution.cxx b/src/StdMeshers/StdMeshers_Distribution.cxx index aa7ebf1f5..3a0a7334b 100644 --- a/src/StdMeshers/StdMeshers_Distribution.cxx +++ b/src/StdMeshers/StdMeshers_Distribution.cxx @@ -43,6 +43,8 @@ using namespace std; +namespace StdMeshers { + Function::Function( const int conv ) : myConv( conv ) { @@ -345,3 +347,4 @@ bool buildDistribution( const Function& func, const double start, const double e data[nbSeg] = end; return true; } +} diff --git a/src/StdMeshers/StdMeshers_Distribution.hxx b/src/StdMeshers/StdMeshers_Distribution.hxx index d5744d2da..e974e95f7 100644 --- a/src/StdMeshers/StdMeshers_Distribution.hxx +++ b/src/StdMeshers/StdMeshers_Distribution.hxx @@ -37,7 +37,8 @@ #include #include - +namespace StdMeshers +{ class STDMESHERS_EXPORT Function { public: @@ -114,5 +115,5 @@ bool buildDistribution( const TCollection_AsciiString& f, const int conv, const STDMESHERS_EXPORT bool buildDistribution( const std::vector& f, const int conv, const double start, const double end, const int nbSeg, std::vector& data, const double eps ); - +} #endif diff --git a/src/StdMeshers/StdMeshers_FaceSide.cxx b/src/StdMeshers/StdMeshers_FaceSide.cxx index c2596b4b6..84884800b 100644 --- a/src/StdMeshers/StdMeshers_FaceSide.cxx +++ b/src/StdMeshers/StdMeshers_FaceSide.cxx @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -151,21 +152,26 @@ StdMeshers_FaceSide::StdMeshers_FaceSide(const TopoDS_Face& theFace, myMissingVertexNodes = true; // check if the edge has a non-uniform parametrization (issue 0020705) - if ( !myC2d[i].IsNull() && myEdgeLength[i] > DBL_MIN) + if ( !myC2d[i].IsNull() ) { - Geom2dAdaptor_Curve A2dC( myC2d[i], - std::min( myFirst[i], myLast[i] ), - std::max( myFirst[i], myLast[i] )); - double p2 = myFirst[i]+(myLast[i]-myFirst[i])/2., p4 = myFirst[i]+(myLast[i]-myFirst[i])/4.; - double d2 = GCPnts_AbscissaPoint::Length( A2dC, myFirst[i], p2 ); - double d4 = GCPnts_AbscissaPoint::Length( A2dC, myFirst[i], p4 ); - //cout<<"len = "< meshedPrism; + list< TopoDS_Face > suspectSourceFaces; TopTools_ListIteratorOfListOfShape solidIt; while ( meshedSolids.Extent() < nbSolids ) @@ -704,7 +712,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh { prism.Clear(); prism.myBottom = face; - if ( !initPrism( prism, solid ) || + if ( !initPrism( prism, solid, selectBottom ) || !compute( prism )) return false; @@ -713,6 +721,10 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh { meshedFaces.push_front( prism.myTop ); } + else + { + suspectSourceFaces.push_back( prism.myTop ); + } meshedPrism.push_back( prism ); } } @@ -742,6 +754,10 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh solidList.Remove( solidIt ); continue; // already computed prism } + if ( myHelper->IsBlock( solid )) { + solidIt.Next(); + continue; // too trivial + } // find a source FACE of the SOLID: it's a FACE sharing a bottom EDGE with wFace const TopoDS_Edge& wEdge = (*wQuad)->side[ QUAD_TOP_SIDE ].grid->Edge(0); PShapeIteratorPtr faceIt = myHelper->GetAncestors( wEdge, *myHelper->GetMesh(), @@ -749,14 +765,24 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh while ( const TopoDS_Shape* f = faceIt->next() ) { const TopoDS_Face& candidateF = TopoDS::Face( *f ); + if ( candidateF.IsSame( wFace )) continue; + // select a source FACE: prismIt->myBottom or prismIt->myTop + TopoDS_Face sourceF = prismIt->myBottom; + for ( TopExp_Explorer v( prismIt->myTop, TopAbs_VERTEX ); v.More(); v.Next() ) + if ( myHelper->IsSubShape( v.Current(), candidateF )) { + sourceF = prismIt->myTop; + break; + } prism.Clear(); - prism.myBottom = candidateF; + prism.myBottom = candidateF; mySetErrorToSM = false; if ( !myHelper->IsSubShape( candidateF, prismIt->myShape3D ) && - myHelper->IsSubShape( candidateF, solid ) && + myHelper ->IsSubShape( candidateF, solid ) && !myHelper->GetMesh()->GetSubMesh( candidateF )->IsMeshComputed() && - initPrism( prism, solid ) && - project2dMesh( prismIt->myBottom, candidateF)) + initPrism( prism, solid, /*selectBottom=*/false ) && + !myHelper->GetMesh()->GetSubMesh( prism.myTop )->IsMeshComputed() && + !myHelper->GetMesh()->GetSubMesh( prism.myBottom )->IsMeshComputed() && + project2dMesh( sourceF, prism.myBottom )) { mySetErrorToSM = true; if ( !compute( prism )) @@ -766,6 +792,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh { meshedFaces.push_front( prism.myTop ); meshedFaces.push_front( prism.myBottom ); + selectBottom = false; } meshedPrism.push_back( prism ); meshedSolids.Add( solid ); @@ -785,31 +812,52 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh break; // to compute prisms with avident sources } + if ( meshedFaces.empty() ) + { + meshedFaces.splice( meshedFaces.end(), suspectSourceFaces ); + selectBottom = true; + } + // find FACEs with local 1D hyps, which has to be computed by now, // or at least any computed FACEs - for ( int iF = 1; ( meshedFaces.empty() && iF < faceToSolids.Extent() ); ++iF ) + if ( meshedFaces.empty() ) { - const TopoDS_Face& face = TopoDS::Face( faceToSolids.FindKey( iF )); - const TopTools_ListOfShape& solidList = faceToSolids.FindFromKey( face ); - if ( solidList.IsEmpty() ) continue; - SMESH_subMesh* faceSM = theMesh.GetSubMesh( face ); - if ( !faceSM->IsEmpty() ) + int prevNbFaces = 0; + for ( int iF = 1; iF <= faceToSolids.Extent(); ++iF ) { - meshedFaces.push_back( face ); // lower priority - } - else - { - bool allSubMeComputed = true; - SMESH_subMeshIteratorPtr smIt = faceSM->getDependsOnIterator(false,true); - while ( smIt->more() && allSubMeComputed ) - allSubMeComputed = smIt->next()->IsMeshComputed(); - if ( allSubMeComputed ) + const TopoDS_Face& face = TopoDS::Face( faceToSolids.FindKey( iF )); + const TopTools_ListOfShape& solidList = faceToSolids.FindFromKey( face ); + if ( solidList.IsEmpty() ) continue; + SMESH_subMesh* faceSM = theMesh.GetSubMesh( face ); + if ( !faceSM->IsEmpty() ) { - faceSM->ComputeStateEngine( SMESH_subMesh::COMPUTE ); - if ( !faceSM->IsEmpty() ) - meshedFaces.push_front( face ); // higher priority - else - faceSM->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + int nbFaces = faceSM->GetSubMeshDS()->NbElements(); + if ( prevNbFaces < nbFaces ) + { + if ( !meshedFaces.empty() ) meshedFaces.pop_back(); + meshedFaces.push_back( face ); // lower priority + selectBottom = true; + prevNbFaces = nbFaces; + } + } + else + { + bool allSubMeComputed = true; + SMESH_subMeshIteratorPtr smIt = faceSM->getDependsOnIterator(false,true); + while ( smIt->more() && allSubMeComputed ) + allSubMeComputed = smIt->next()->IsMeshComputed(); + if ( allSubMeComputed ) + { + faceSM->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + if ( !faceSM->IsEmpty() ) { + meshedFaces.push_front( face ); // higher priority + selectBottom = true; + break; + } + else { + faceSM->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + } + } } } } @@ -835,6 +883,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh meshedFaces.push_front( prism.myBottom ); meshedPrism.push_back( prism ); meshedSolids.Add( solid.Current() ); + selectBottom = true; } mySetErrorToSM = true; } @@ -983,6 +1032,7 @@ bool StdMeshers_Prism_3D::getWallFaces( Prism_3D::TPrismTopo & thePrism, // find wall FACEs adjacent to each of thePrism.myWallQuads by the top side EDGE if ( totalNbFaces - faceMap.Extent() > 2 ) { + const int nbFoundWalls = faceMap.Extent(); for ( size_t i = 0; i < thePrism.myWallQuads.size(); ++i ) { StdMeshers_FaceSidePtr topSide = thePrism.myWallQuads[i].back()->side[ QUAD_TOP_SIDE ]; @@ -1009,6 +1059,9 @@ bool StdMeshers_Prism_3D::getWallFaces( Prism_3D::TPrismTopo & thePrism, } } } + if ( nbFoundWalls == faceMap.Extent() ) + return toSM( error("Failed to find wall faces")); + } } // while ( totalNbFaces - faceMap.Extent() > 2 ) @@ -1035,7 +1088,7 @@ bool StdMeshers_Prism_3D::getWallFaces( Prism_3D::TPrismTopo & thePrism, StdMeshers_FaceSidePtr topSide = thePrism.myWallQuads[i].back()->side[ QUAD_TOP_SIDE ]; const TopoDS_Edge & topE = topSide->Edge( 0 ); if ( !myHelper->IsSubShape( topE, thePrism.myTop )) - return toSM( error( TCom("Wrong source face (#") << shapeID( thePrism.myBottom ))); + return toSM( error( TCom("Wrong source face: #") << shapeID( thePrism.myBottom ))); } return true; @@ -1052,11 +1105,23 @@ bool StdMeshers_Prism_3D::compute(const Prism_3D::TPrismTopo& thePrism) if ( _computeCanceled ) return toSM( error( SMESH_ComputeError::New(COMPERR_CANCELED))); + // Assure the bottom is meshed + SMESH_subMesh * botSM = myHelper->GetMesh()->GetSubMesh( thePrism.myBottom ); + if (( botSM->IsEmpty() ) && + ( ! botSM->GetAlgo() || + ! _gen->Compute( *botSM->GetFather(), botSM->GetSubShape(), /*shapeOnly=*/true ))) + return error( COMPERR_BAD_INPUT_MESH, + TCom( "No mesher defined to compute the face #") + << shapeID( thePrism.myBottom )); + // Make all side FACEs of thePrism meshed with quads if ( !computeWalls( thePrism )) return false; // Analyse mesh and geometry to find all block sub-shapes and submeshes + // (after fixing IPAL52499 myBlock is used as a holder of boundary nodes + // and for 2D projection in hard cases where StdMeshers_Projection_2D fails; + // location of internal nodes is usually computed by StdMeshers_Sweeper) if ( !myBlock.Init( myHelper, thePrism )) return toSM( error( myBlock.GetError())); @@ -1067,10 +1132,10 @@ bool StdMeshers_Prism_3D::compute(const Prism_3D::TPrismTopo& thePrism) // Try to get gp_Trsf to get all nodes from bottom ones vector trsf; gp_Trsf bottomToTopTrsf; - if ( !myBlock.GetLayersTransformation( trsf, thePrism )) - trsf.clear(); - else if ( !trsf.empty() ) - bottomToTopTrsf = trsf.back(); + // if ( !myBlock.GetLayersTransformation( trsf, thePrism )) + // trsf.clear(); + // else if ( !trsf.empty() ) + // bottomToTopTrsf = trsf.back(); // To compute coordinates of a node inside a block, it is necessary to know // 1. normalized parameters of the node by which @@ -1085,6 +1150,7 @@ bool StdMeshers_Prism_3D::compute(const Prism_3D::TPrismTopo& thePrism) // Projections on the top and bottom faces are taken from nodes existing // on these faces; find correspondence between bottom and top nodes + myUseBlock = false; myBotToColumnMap.clear(); if ( !assocOrProjBottom2Top( bottomToTopTrsf, thePrism ) ) // it also fills myBotToColumnMap return false; @@ -1092,31 +1158,36 @@ bool StdMeshers_Prism_3D::compute(const Prism_3D::TPrismTopo& thePrism) // Create nodes inside the block - // try to use transformation (issue 0020680) - if ( !trsf.empty() ) + // use transformation (issue 0020680, IPAL0052499) + StdMeshers_Sweeper sweeper; + double tol; + bool allowHighBndError; + + if ( !myUseBlock ) { - // loop on nodes inside the bottom face + // load boundary nodes into sweeper + bool dummy; + list< TopoDS_Edge >::const_iterator edge = thePrism.myBottomEdges.begin(); + for ( ; edge != thePrism.myBottomEdges.end(); ++edge ) + { + int edgeID = meshDS->ShapeToIndex( *edge ); + TParam2ColumnMap* u2col = const_cast + ( myBlock.GetParam2ColumnMap( edgeID, dummy )); + TParam2ColumnMap::iterator u2colIt = u2col->begin(); + for ( ; u2colIt != u2col->end(); ++u2colIt ) + sweeper.myBndColumns.push_back( & u2colIt->second ); + } + // load node columns inside the bottom face TNode2ColumnMap::iterator bot_column = myBotToColumnMap.begin(); for ( ; bot_column != myBotToColumnMap.end(); ++bot_column ) - { - const Prism_3D::TNode& tBotNode = bot_column->first; // bottom TNode - if ( tBotNode.GetPositionType() != SMDS_TOP_FACE ) - continue; // node is not inside face + sweeper.myIntColumns.push_back( & bot_column->second ); - // column nodes; middle part of the column are zero pointers - TNodeColumn& column = bot_column->second; - TNodeColumn::iterator columnNodes = column.begin(); - for ( int z = 0; columnNodes != column.end(); ++columnNodes, ++z) - { - const SMDS_MeshNode* & node = *columnNodes; - if ( node ) continue; // skip bottom or top node + tol = getSweepTolerance( thePrism ); + allowHighBndError = !isSimpleBottom( thePrism ); + } - gp_XYZ coords = tBotNode.GetCoords(); - trsf[z-1].Transforms( coords ); - node = meshDS->AddNode( coords.X(), coords.Y(), coords.Z() ); - meshDS->SetNodeInVolume( node, volumeID ); - } - } // loop on bottom nodes + if ( !myUseBlock && sweeper.ComputeNodes( *myHelper, tol, allowHighBndError )) + { } else // use block approach { @@ -1127,7 +1198,7 @@ bool StdMeshers_Prism_3D::compute(const Prism_3D::TPrismTopo& thePrism) { const Prism_3D::TNode& tBotNode = bot_column->first; // bottom TNode if ( tBotNode.GetPositionType() != SMDS_TOP_FACE ) - continue; // node is not inside the FACE + continue; // node is not inside the FACE // column nodes; middle part of the column are zero pointers TNodeColumn& column = bot_column->second; @@ -1249,7 +1320,17 @@ bool StdMeshers_Prism_3D::compute(const Prism_3D::TPrismTopo& thePrism) // clear data myBotToColumnMap.clear(); myBlock.Clear(); - + + // update state of sub-meshes (mostly in order to erase improper errors) + SMESH_subMesh* sm = myHelper->GetMesh()->GetSubMesh( thePrism.myShape3D ); + SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(/*includeSelf=*/false); + while ( smIt->more() ) + { + sm = smIt->next(); + sm->GetComputeError().reset(); + sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + } + return true; } @@ -1491,7 +1572,7 @@ bool StdMeshers_Prism_3D::computeWalls(const Prism_3D::TPrismTopo& thePrism) for ( ; quad != thePrism.myWallQuads[iW].end(); ++quad ) { const TopoDS_Face& face = (*quad)->face; - SMESH_subMesh* fSM = mesh->GetSubMesh( face ); + SMESH_subMesh* fSM = mesh->GetSubMesh( face ); if ( ! fSM->IsMeshComputed() ) { // Top EDGEs must be projections from the bottom ones @@ -1503,6 +1584,8 @@ bool StdMeshers_Prism_3D::computeWalls(const Prism_3D::TPrismTopo& thePrism) SMESH_subMesh* topSM = mesh->GetSubMesh( topE ); SMESH_subMesh* srcSM = botSM; SMESH_subMesh* tgtSM = topSM; + srcSM->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + tgtSM->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); if ( !srcSM->IsMeshComputed() && tgtSM->IsMeshComputed() ) std::swap( srcSM, tgtSM ); @@ -1512,7 +1595,6 @@ bool StdMeshers_Prism_3D::computeWalls(const Prism_3D::TPrismTopo& thePrism) srcSM->ComputeSubMeshStateEngine( SMESH_subMesh::COMPUTE ); // nodes on VERTEXes srcSM->ComputeStateEngine( SMESH_subMesh::COMPUTE ); // segments on the EDGE } - srcSM->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); if ( tgtSM->IsMeshComputed() && tgtSM->GetSubMeshDS()->NbNodes() != srcSM->GetSubMeshDS()->NbNodes() ) @@ -1853,8 +1935,8 @@ void StdMeshers_Prism_3D::AddPrisms( vector & columns, bool StdMeshers_Prism_3D::assocOrProjBottom2Top( const gp_Trsf & bottomToTopTrsf, const Prism_3D::TPrismTopo& thePrism) { - SMESH_subMesh * botSM = myBlock.SubMesh( ID_BOT_FACE ); - SMESH_subMesh * topSM = myBlock.SubMesh( ID_TOP_FACE ); + SMESH_subMesh * botSM = myHelper->GetMesh()->GetSubMesh( thePrism.myBottom ); + SMESH_subMesh * topSM = myHelper->GetMesh()->GetSubMesh( thePrism.myTop ); SMESHDS_SubMesh * botSMDS = botSM->GetSubMeshDS(); SMESHDS_SubMesh * topSMDS = topSM->GetSubMeshDS(); @@ -1885,86 +1967,90 @@ bool StdMeshers_Prism_3D::assocOrProjBottom2Top( const gp_Trsf & bottomToTopTrsf <<" and #"<< topSM->GetId() << " seems different" )); ///RETURN_BAD_RESULT("Need to project but not allowed"); + NSProjUtils::TNodeNodeMap n2nMap; + const NSProjUtils::TNodeNodeMap* n2nMapPtr = & n2nMap; if ( needProject ) { - return projectBottomToTop( bottomToTopTrsf ); + if ( !projectBottomToTop( bottomToTopTrsf, thePrism )) + return false; + n2nMapPtr = & TProjction2dAlgo::instance( this )->GetNodesMap(); } - TopoDS_Face botFace = TopoDS::Face( myBlock.Shape( ID_BOT_FACE )); - TopoDS_Face topFace = TopoDS::Face( myBlock.Shape( ID_TOP_FACE )); - // associate top and bottom faces - TAssocTool::TShapeShapeMap shape2ShapeMap; - const bool sameTopo = - TAssocTool::FindSubShapeAssociation( botFace, myBlock.Mesh(), - topFace, myBlock.Mesh(), - shape2ShapeMap); - if ( !sameTopo ) - for ( size_t iQ = 0; iQ < thePrism.myWallQuads.size(); ++iQ ) - { - const Prism_3D::TQuadList& quadList = thePrism.myWallQuads[iQ]; - StdMeshers_FaceSidePtr botSide = quadList.front()->side[ QUAD_BOTTOM_SIDE ]; - StdMeshers_FaceSidePtr topSide = quadList.back ()->side[ QUAD_TOP_SIDE ]; - if ( botSide->NbEdges() == topSide->NbEdges() ) - { - for ( int iE = 0; iE < botSide->NbEdges(); ++iE ) - { - TAssocTool::InsertAssociation( botSide->Edge( iE ), - topSide->Edge( iE ), shape2ShapeMap ); - TAssocTool::InsertAssociation( myHelper->IthVertex( 0, botSide->Edge( iE )), - myHelper->IthVertex( 0, topSide->Edge( iE )), - shape2ShapeMap ); - } - } - else - { - TopoDS_Vertex vb, vt; - StdMeshers_FaceSidePtr sideB, sideT; - vb = myHelper->IthVertex( 0, botSide->Edge( 0 )); - vt = myHelper->IthVertex( 0, topSide->Edge( 0 )); - sideB = quadList.front()->side[ QUAD_LEFT_SIDE ]; - sideT = quadList.back ()->side[ QUAD_LEFT_SIDE ]; - if ( vb.IsSame( sideB->FirstVertex() ) && - vt.IsSame( sideT->LastVertex() )) - { - TAssocTool::InsertAssociation( botSide->Edge( 0 ), - topSide->Edge( 0 ), shape2ShapeMap ); - TAssocTool::InsertAssociation( vb, vt, shape2ShapeMap ); - } - vb = myHelper->IthVertex( 1, botSide->Edge( botSide->NbEdges()-1 )); - vt = myHelper->IthVertex( 1, topSide->Edge( topSide->NbEdges()-1 )); - sideB = quadList.front()->side[ QUAD_RIGHT_SIDE ]; - sideT = quadList.back ()->side[ QUAD_RIGHT_SIDE ]; - if ( vb.IsSame( sideB->FirstVertex() ) && - vt.IsSame( sideT->LastVertex() )) - { - TAssocTool::InsertAssociation( botSide->Edge( botSide->NbEdges()-1 ), - topSide->Edge( topSide->NbEdges()-1 ), - shape2ShapeMap ); - TAssocTool::InsertAssociation( vb, vt, shape2ShapeMap ); - } - } - } - - // Find matching nodes of top and bottom faces - TNodeNodeMap n2nMap; - if ( ! TAssocTool::FindMatchingNodesOnFaces( botFace, myBlock.Mesh(), - topFace, myBlock.Mesh(), - shape2ShapeMap, n2nMap )) + if ( !n2nMapPtr || n2nMapPtr->size() < botSMDS->NbNodes() ) { - if ( sameTopo ) - return toSM( error(TCom("Mesh on faces #") << botSM->GetId() - <<" and #"<< topSM->GetId() << " seems different" )); - else - return toSM( error(TCom("Topology of faces #") << botSM->GetId() - <<" and #"<< topSM->GetId() << " seems different" )); + // associate top and bottom faces + NSProjUtils::TShapeShapeMap shape2ShapeMap; + const bool sameTopo = + NSProjUtils::FindSubShapeAssociation( thePrism.myBottom, myHelper->GetMesh(), + thePrism.myTop, myHelper->GetMesh(), + shape2ShapeMap); + if ( !sameTopo ) + for ( size_t iQ = 0; iQ < thePrism.myWallQuads.size(); ++iQ ) + { + const Prism_3D::TQuadList& quadList = thePrism.myWallQuads[iQ]; + StdMeshers_FaceSidePtr botSide = quadList.front()->side[ QUAD_BOTTOM_SIDE ]; + StdMeshers_FaceSidePtr topSide = quadList.back ()->side[ QUAD_TOP_SIDE ]; + if ( botSide->NbEdges() == topSide->NbEdges() ) + { + for ( int iE = 0; iE < botSide->NbEdges(); ++iE ) + { + NSProjUtils::InsertAssociation( botSide->Edge( iE ), + topSide->Edge( iE ), shape2ShapeMap ); + NSProjUtils::InsertAssociation( myHelper->IthVertex( 0, botSide->Edge( iE )), + myHelper->IthVertex( 0, topSide->Edge( iE )), + shape2ShapeMap ); + } + } + else + { + TopoDS_Vertex vb, vt; + StdMeshers_FaceSidePtr sideB, sideT; + vb = myHelper->IthVertex( 0, botSide->Edge( 0 )); + vt = myHelper->IthVertex( 0, topSide->Edge( 0 )); + sideB = quadList.front()->side[ QUAD_LEFT_SIDE ]; + sideT = quadList.back ()->side[ QUAD_LEFT_SIDE ]; + if ( vb.IsSame( sideB->FirstVertex() ) && + vt.IsSame( sideT->LastVertex() )) + { + NSProjUtils::InsertAssociation( botSide->Edge( 0 ), + topSide->Edge( 0 ), shape2ShapeMap ); + NSProjUtils::InsertAssociation( vb, vt, shape2ShapeMap ); + } + vb = myHelper->IthVertex( 1, botSide->Edge( botSide->NbEdges()-1 )); + vt = myHelper->IthVertex( 1, topSide->Edge( topSide->NbEdges()-1 )); + sideB = quadList.front()->side[ QUAD_RIGHT_SIDE ]; + sideT = quadList.back ()->side[ QUAD_RIGHT_SIDE ]; + if ( vb.IsSame( sideB->FirstVertex() ) && + vt.IsSame( sideT->LastVertex() )) + { + NSProjUtils::InsertAssociation( botSide->Edge( botSide->NbEdges()-1 ), + topSide->Edge( topSide->NbEdges()-1 ), + shape2ShapeMap ); + NSProjUtils::InsertAssociation( vb, vt, shape2ShapeMap ); + } + } + } + + // Find matching nodes of top and bottom faces + n2nMapPtr = & n2nMap; + if ( ! NSProjUtils::FindMatchingNodesOnFaces( thePrism.myBottom, myHelper->GetMesh(), + thePrism.myTop, myHelper->GetMesh(), + shape2ShapeMap, n2nMap )) + { + if ( sameTopo ) + return toSM( error(TCom("Mesh on faces #") << botSM->GetId() + <<" and #"<< topSM->GetId() << " seems different" )); + else + return toSM( error(TCom("Topology of faces #") << botSM->GetId() + <<" and #"<< topSM->GetId() << " seems different" )); + } } // Fill myBotToColumnMap int zSize = myBlock.VerticalSize(); - //TNode prevTNode; - TNodeNodeMap::iterator bN_tN = n2nMap.begin(); - for ( ; bN_tN != n2nMap.end(); ++bN_tN ) + TNodeNodeMap::const_iterator bN_tN = n2nMapPtr->begin(); + for ( ; bN_tN != n2nMapPtr->end(); ++bN_tN ) { const SMDS_MeshNode* botNode = bN_tN->first; const SMDS_MeshNode* topNode = bN_tN->second; @@ -1972,7 +2058,7 @@ bool StdMeshers_Prism_3D::assocOrProjBottom2Top( const gp_Trsf & bottomToTopTrsf continue; // wall columns are contained in myBlock // create node column Prism_3D::TNode bN( botNode ); - TNode2ColumnMap::iterator bN_col = + TNode2ColumnMap::iterator bN_col = myBotToColumnMap.insert( make_pair ( bN, TNodeColumn() )).first; TNodeColumn & column = bN_col->second; column.resize( zSize ); @@ -1984,27 +2070,43 @@ bool StdMeshers_Prism_3D::assocOrProjBottom2Top( const gp_Trsf & bottomToTopTrsf //================================================================================ /*! - * \brief Remove quadrangles from the top face and - * create triangles there by projection from the bottom + * \brief Remove faces from the top face and re-create them by projection from the bottom * \retval bool - a success or not */ //================================================================================ -bool StdMeshers_Prism_3D::projectBottomToTop( const gp_Trsf & bottomToTopTrsf ) +bool StdMeshers_Prism_3D::projectBottomToTop( const gp_Trsf & bottomToTopTrsf, + const Prism_3D::TPrismTopo& thePrism ) { - SMESHDS_Mesh* meshDS = myBlock.MeshDS(); - SMESH_subMesh * botSM = myBlock.SubMesh( ID_BOT_FACE ); - SMESH_subMesh * topSM = myBlock.SubMesh( ID_TOP_FACE ); + if ( project2dMesh( thePrism.myBottom, thePrism.myTop )) + { + return true; + } + NSProjUtils::TNodeNodeMap& n2nMap = + (NSProjUtils::TNodeNodeMap&) TProjction2dAlgo::instance( this )->GetNodesMap(); + n2nMap.clear(); + + myUseBlock = true; + + SMESHDS_Mesh* meshDS = myHelper->GetMeshDS(); + SMESH_subMesh * botSM = myHelper->GetMesh()->GetSubMesh( thePrism.myBottom ); + SMESH_subMesh * topSM = myHelper->GetMesh()->GetSubMesh( thePrism.myTop ); SMESHDS_SubMesh * botSMDS = botSM->GetSubMeshDS(); SMESHDS_SubMesh * topSMDS = topSM->GetSubMeshDS(); if ( topSMDS && topSMDS->NbElements() > 0 ) - topSM->ComputeStateEngine( SMESH_subMesh::CLEAN ); + { + //topSM->ComputeStateEngine( SMESH_subMesh::CLEAN ); -- avoid propagation of events + for ( SMDS_ElemIteratorPtr eIt = topSMDS->GetElements(); eIt->more(); ) + meshDS->RemoveFreeElement( eIt->next(), topSMDS, /*fromGroups=*/false ); + for ( SMDS_NodeIteratorPtr nIt = topSMDS->GetNodes(); nIt->more(); ) + meshDS->RemoveFreeNode( nIt->next(), topSMDS, /*fromGroups=*/false ); + } - const TopoDS_Face& botFace = TopoDS::Face( myBlock.Shape( ID_BOT_FACE )); // oriented within - const TopoDS_Face& topFace = TopoDS::Face( myBlock.Shape( ID_TOP_FACE )); // the 3D SHAPE - int topFaceID = meshDS->ShapeToIndex( topFace ); + const TopoDS_Face& botFace = thePrism.myBottom; // oriented within + const TopoDS_Face& topFace = thePrism.myTop; // the 3D SHAPE + int topFaceID = meshDS->ShapeToIndex( thePrism.myTop ); SMESH_MesherHelper botHelper( *myHelper->GetMesh() ); botHelper.SetSubShape( botFace ); @@ -2071,6 +2173,11 @@ bool StdMeshers_Prism_3D::projectBottomToTop( const gp_Trsf & bottomToTopTrsf ) column.resize( zSize ); column.front() = botNode; column.back() = topNode; + + n2nMap.insert( n2nMap.end(), make_pair( botNode, topNode )); + + if ( _computeCanceled ) + return toSM( error( SMESH_ComputeError::New(COMPERR_CANCELED))); } // Create top faces @@ -2118,11 +2225,11 @@ bool StdMeshers_Prism_3D::projectBottomToTop( const gp_Trsf & bottomToTopTrsf ) case 3: { newFace = myHelper->AddFace(nodes[0], nodes[1], nodes[2]); break; - } + } case 4: { newFace = myHelper->AddFace( nodes[0], nodes[1], nodes[2], nodes[3] ); break; - } + } default: newFace = meshDS->AddPolygonalFace( nodes ); } @@ -2130,8 +2237,152 @@ bool StdMeshers_Prism_3D::projectBottomToTop( const gp_Trsf & bottomToTopTrsf ) meshDS->SetMeshElementOnShape( newFace, topFaceID ); } - myHelper->SetElementsOnShape( oldSetElemsOnShape ); + myHelper->SetElementsOnShape( oldSetElemsOnShape ); + // Check the projected mesh + + if ( thePrism.myNbEdgesInWires.size() > 1 && // there are holes + topHelper.IsDistorted2D( topSM, /*checkUV=*/false )) + { + SMESH_MeshEditor editor( topHelper.GetMesh() ); + + // smooth in 2D or 3D? + TopLoc_Location loc; + Handle(Geom_Surface) surface = BRep_Tool::Surface( topFace, loc ); + bool isPlanar = GeomLib_IsPlanarSurface( surface ).IsPlanar(); + + bool isFixed = false; + set fixedNodes; + for ( int iAttemp = 0; !isFixed && iAttemp < 10; ++iAttemp ) + { + TIDSortedElemSet faces; + for ( faceIt = topSMDS->GetElements(); faceIt->more(); ) + faces.insert( faces.end(), faceIt->next() ); + + SMESH_MeshEditor::SmoothMethod algo = + iAttemp ? SMESH_MeshEditor::CENTROIDAL : SMESH_MeshEditor::LAPLACIAN; + + // smoothing + editor.Smooth( faces, fixedNodes, algo, /*nbIterations=*/ 10, + /*theTgtAspectRatio=*/1.0, /*the2D=*/!isPlanar); + + isFixed = !topHelper.IsDistorted2D( topSM, /*checkUV=*/true ); + } + if ( !isFixed ) + return toSM( error( TCom("Projection from face #") << botSM->GetId() + << " to face #" << topSM->GetId() + << " failed: inverted elements created")); + } + + return true; +} + +//======================================================================= +//function : getSweepTolerance +//purpose : Compute tolerance to pass to StdMeshers_Sweeper +//======================================================================= + +double StdMeshers_Prism_3D::getSweepTolerance( const Prism_3D::TPrismTopo& thePrism ) +{ + SMESHDS_Mesh* meshDS = myHelper->GetMeshDS(); + SMESHDS_SubMesh * sm[2] = { meshDS->MeshElements( thePrism.myBottom ), + meshDS->MeshElements( thePrism.myTop ) }; + double minDist = 1e100; + + vector< SMESH_TNodeXYZ > nodes; + for ( int iSM = 0; iSM < 2; ++iSM ) + { + if ( !sm[ iSM ]) continue; + + SMDS_ElemIteratorPtr fIt = sm[ iSM ]->GetElements(); + while ( fIt->more() ) + { + const SMDS_MeshElement* face = fIt->next(); + const int nbNodes = face->NbCornerNodes(); + SMDS_ElemIteratorPtr nIt = face->nodesIterator(); + + nodes.resize( nbNodes + 1 ); + for ( int iN = 0; iN < nbNodes; ++iN ) + nodes[ iN ] = nIt->next(); + nodes.back() = nodes[0]; + + // loop on links + double dist2; + for ( int iN = 0; iN < nbNodes; ++iN ) + { + if ( nodes[ iN ]._node->GetPosition()->GetDim() < 2 && + nodes[ iN+1 ]._node->GetPosition()->GetDim() < 2 ) + { + // it's a boundary link; measure distance of other + // nodes to this link + gp_XYZ linkDir = nodes[ iN ] - nodes[ iN+1 ]; + double linkLen = linkDir.Modulus(); + bool isDegen = ( linkLen < numeric_limits::min() ); + if ( !isDegen ) linkDir /= linkLen; + for ( int iN2 = 0; iN2 < nbNodes; ++iN2 ) // loop on other nodes + { + if ( nodes[ iN2 ] == nodes[ iN ] || + nodes[ iN2 ] == nodes[ iN+1 ]) continue; + if ( isDegen ) + { + dist2 = ( nodes[ iN ] - nodes[ iN2 ]).SquareModulus(); + } + else + { + dist2 = linkDir.CrossSquareMagnitude( nodes[ iN ] - nodes[ iN2 ]); + } + if ( dist2 > numeric_limits::min() ) + minDist = Min ( minDist, dist2 ); + } + } + // measure length link + else if ( nodes[ iN ]._node < nodes[ iN+1 ]._node ) // not to measure same link twice + { + dist2 = ( nodes[ iN ] - nodes[ iN+1 ]).SquareModulus(); + if ( dist2 > numeric_limits::min() ) + minDist = Min ( minDist, dist2 ); + } + } + } + } + return 0.1 * Sqrt ( minDist ); +} + +//======================================================================= +//function : isSimpleQuad +//purpose : check if the bottom FACE is meshable with nice qudrangles, +// if so the block aproach can work rather fast. +// This is a temporary mean caused by problems in StdMeshers_Sweeper +//======================================================================= + +bool StdMeshers_Prism_3D::isSimpleBottom( const Prism_3D::TPrismTopo& thePrism ) +{ + // analyse angles between edges + double nbConcaveAng = 0, nbConvexAng = 0; + TopoDS_Face reverseBottom = TopoDS::Face( thePrism.myBottom.Reversed() ); // see initPrism() + TopoDS_Vertex commonV; + const list< TopoDS_Edge >& botEdges = thePrism.myBottomEdges; + list< TopoDS_Edge >::const_iterator edge = botEdges.begin(); + while ( edge != botEdges.end() ) + { + if ( SMESH_Algo::isDegenerated( *edge )) + return false; + TopoDS_Edge e1 = *edge++; + TopoDS_Edge e2 = ( edge == botEdges.end() ? botEdges.front() : *edge ); + if ( ! TopExp::CommonVertex( e1, e2, commonV )) + { + e2 = botEdges.front(); + if ( ! TopExp::CommonVertex( e1, e2, commonV )) + break; + } + double angle = myHelper->GetAngle( e1, e2, reverseBottom, commonV ); + if ( angle < -5 * M_PI/180 ) + if ( ++nbConcaveAng > 1 ) + return false; + if ( angle > 85 * M_PI/180 ) + if ( ++nbConvexAng > 4 ) + return false; + } return true; } @@ -2149,6 +2400,15 @@ bool StdMeshers_Prism_3D::project2dMesh(const TopoDS_Face& theSrcFace, bool ok = projector2D->Compute( *myHelper->GetMesh(), theTgtFace ); SMESH_subMesh* tgtSM = myHelper->GetMesh()->GetSubMesh( theTgtFace ); + if ( !ok && tgtSM->GetSubMeshDS() ) { + //tgtSM->ComputeStateEngine( SMESH_subMesh::CLEAN ); -- avoid propagation of events + SMESHDS_Mesh* meshDS = myHelper->GetMeshDS(); + SMESHDS_SubMesh* tgtSMDS = tgtSM->GetSubMeshDS(); + for ( SMDS_ElemIteratorPtr eIt = tgtSMDS->GetElements(); eIt->more(); ) + meshDS->RemoveFreeElement( eIt->next(), tgtSMDS, /*fromGroups=*/false ); + for ( SMDS_NodeIteratorPtr nIt = tgtSMDS->GetNodes(); nIt->more(); ) + meshDS->RemoveFreeNode( nIt->next(), tgtSMDS, /*fromGroups=*/false ); + } tgtSM->ComputeStateEngine ( SMESH_subMesh::CHECK_COMPUTE_STATE ); tgtSM->ComputeSubMeshStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); @@ -2261,6 +2521,12 @@ namespace // utils used by StdMeshers_Prism_3D::IsApplicable() if ( E.IsSame( Edge( i ))) return i; return -1; } + bool IsSideFace( const TopoDS_Shape& face ) const + { + if ( _faces->Contains( face )) // avoid returning true for a prism top FACE + return ( !_face.IsNull() || !( face.IsSame( _faces->FindKey( _faces->Extent() )))); + return false; + } }; //-------------------------------------------------------------------------------- /*! @@ -2392,12 +2658,11 @@ bool StdMeshers_Prism_3D::IsApplicable(const TopoDS_Shape & shape, bool toCheckA TEdgeWithNeighborsVec& botEdges = faceEdgesVec[ iF ]; if ( botEdges.empty() ) - { if ( !getEdges( botF, botEdges, /*noHoles=*/false )) break; - if ( allFaces.Extent()-1 <= (int) botEdges.size() ) - continue; // all faces are adjacent to botF - no top FACE - } + if ( allFaces.Extent()-1 <= (int) botEdges.size() ) + continue; // all faces are adjacent to botF - no top FACE + // init data of side FACEs vector< PrismSide > sides( botEdges.size() ); for ( int iS = 0; iS < botEdges.size(); ++iS ) @@ -2411,8 +2676,8 @@ bool StdMeshers_Prism_3D::IsApplicable(const TopoDS_Shape & shape, bool toCheckA } bool isOK = true; // ok for a current botF - bool isAdvanced = true; - int nbFoundSideFaces = 0; + bool isAdvanced = true; // is new data found in a current loop + int nbFoundSideFaces = 0; for ( int iLoop = 0; isOK && isAdvanced; ++iLoop ) { isAdvanced = false; @@ -2420,7 +2685,8 @@ bool StdMeshers_Prism_3D::IsApplicable(const TopoDS_Shape & shape, bool toCheckA { PrismSide& side = sides[ iS ]; if ( side._face.IsNull() ) - continue; + continue; // probably the prism top face is the last of side._faces + if ( side._topEdge.IsNull() ) { // find vertical EDGEs --- EGDEs shared with neighbor side FACEs @@ -2434,7 +2700,7 @@ bool StdMeshers_Prism_3D::IsApplicable(const TopoDS_Shape & shape, bool toCheckA if ( side._isCheckedEdge[ iE ] ) continue; const TopoDS_Edge& vertE = side.Edge( iE ); const TopoDS_Shape& neighborF = getAnotherFace( side._face, vertE, facesOfEdge ); - bool isEdgeShared = adjSide->_faces->Contains( neighborF ); + bool isEdgeShared = adjSide->IsSideFace( neighborF ); if ( isEdgeShared ) { isAdvanced = true; @@ -2480,13 +2746,13 @@ bool StdMeshers_Prism_3D::IsApplicable(const TopoDS_Shape & shape, bool toCheckA { if ( side._leftSide->_faces->Contains( f )) { - stop = true; + stop = true; // probably f is the prism top face side._leftSide->_face.Nullify(); side._leftSide->_topEdge.Nullify(); } if ( side._rightSide->_faces->Contains( f )) { - stop = true; + stop = true; // probably f is the prism top face side._rightSide->_face.Nullify(); side._rightSide->_topEdge.Nullify(); } @@ -2497,8 +2763,8 @@ bool StdMeshers_Prism_3D::IsApplicable(const TopoDS_Shape & shape, bool toCheckA side._topEdge.Nullify(); continue; } - side._face = TopoDS::Face( f ); - int faceID = allFaces.FindIndex( side._face ); + side._face = TopoDS::Face( f ); + int faceID = allFaces.FindIndex( side._face ); side._edges = & faceEdgesVec[ faceID ]; if ( side._edges->empty() ) if ( !getEdges( side._face, * side._edges, /*noHoles=*/true )) @@ -2658,16 +2924,18 @@ void StdMeshers_PrismAsBlock::Clear() //======================================================================= bool StdMeshers_Prism_3D::initPrism(Prism_3D::TPrismTopo& thePrism, - const TopoDS_Shape& shape3D) + const TopoDS_Shape& theShape3D, + const bool selectBottom) { - myHelper->SetSubShape( shape3D ); + myHelper->SetSubShape( theShape3D ); - SMESH_subMesh* mainSubMesh = myHelper->GetMesh()->GetSubMeshContaining( shape3D ); + SMESH_subMesh* mainSubMesh = myHelper->GetMesh()->GetSubMeshContaining( theShape3D ); if ( !mainSubMesh ) return toSM( error(COMPERR_BAD_INPUT_MESH,"Null submesh of shape3D")); // detect not-quad FACE sub-meshes of the 3D SHAPE list< SMESH_subMesh* > notQuadGeomSubMesh; list< SMESH_subMesh* > notQuadElemSubMesh; + list< SMESH_subMesh* > meshedSubMesh; int nbFaces = 0; // SMESH_subMesh* anyFaceSM = 0; @@ -2689,10 +2957,14 @@ bool StdMeshers_Prism_3D::initPrism(Prism_3D::TPrismTopo& thePrism, if ( nbWires != 1 || nbEdgesInWires.front() != 4 ) notQuadGeomSubMesh.push_back( sm ); - // look for not quadrangle mesh elements - if ( SMESHDS_SubMesh* smDS = sm->GetSubMeshDS() ) - if ( !myHelper->IsSameElemGeometry( smDS, SMDSGeom_QUADRANGLE )) + // look for a not structured sub-mesh + if ( !sm->IsEmpty() ) + { + meshedSubMesh.push_back( sm ); + if ( !myHelper->IsSameElemGeometry( sm->GetSubMeshDS(), SMDSGeom_QUADRANGLE ) || + !myHelper->IsStructured ( sm )) notQuadElemSubMesh.push_back( sm ); + } } int nbNotQuadMeshed = notQuadElemSubMesh.size(); @@ -2757,33 +3029,50 @@ bool StdMeshers_Prism_3D::initPrism(Prism_3D::TPrismTopo& thePrism, // use thePrism.myBottom if ( !thePrism.myBottom.IsNull() ) { - if ( botSM ) { + if ( botSM ) { // <-- not quad geom or mesh on botSM if ( ! botSM->GetSubShape().IsSame( thePrism.myBottom )) { std::swap( botSM, topSM ); - if ( !botSM || ! botSM->GetSubShape().IsSame( thePrism.myBottom )) - return toSM( error( COMPERR_BAD_INPUT_MESH, - "Incompatible non-structured sub-meshes")); + if ( !botSM || ! botSM->GetSubShape().IsSame( thePrism.myBottom )) { + if ( !selectBottom ) + return toSM( error( COMPERR_BAD_INPUT_MESH, + "Incompatible non-structured sub-meshes")); + std::swap( botSM, topSM ); + thePrism.myBottom = TopoDS::Face( botSM->GetSubShape() ); + } } } - else { + else if ( !selectBottom ) { botSM = myHelper->GetMesh()->GetSubMesh( thePrism.myBottom ); } } - else if ( !botSM ) // find a proper bottom + if ( !botSM ) // find a proper bottom { - // composite walls or not prism shape - for ( TopExp_Explorer f( shape3D, TopAbs_FACE ); f.More(); f.Next() ) + bool savedSetErrorToSM = mySetErrorToSM; + mySetErrorToSM = false; // ingore errors in initPrism() + + // search among meshed FACEs + list< SMESH_subMesh* >::iterator sm = meshedSubMesh.begin(); + for ( ; !botSM && sm != meshedSubMesh.end(); ++sm ) + { + thePrism.Clear(); + botSM = *sm; + thePrism.myBottom = TopoDS::Face( botSM->GetSubShape() ); + if ( !initPrism( thePrism, theShape3D, /*selectBottom=*/false )) + botSM = NULL; + } + // search among all FACEs + for ( TopExp_Explorer f( theShape3D, TopAbs_FACE ); !botSM && f.More(); f.Next() ) { int minNbFaces = 2 + myHelper->Count( f.Current(), TopAbs_EDGE, false); - if ( nbFaces >= minNbFaces) - { - thePrism.Clear(); - thePrism.myBottom = TopoDS::Face( f.Current() ); - if ( initPrism( thePrism, shape3D )) - return true; - } - return toSM( error( COMPERR_BAD_SHAPE )); + if ( nbFaces < minNbFaces) continue; + thePrism.Clear(); + thePrism.myBottom = TopoDS::Face( f.Current() ); + botSM = myHelper->GetMesh()->GetSubMesh( thePrism.myBottom ); + if ( !initPrism( thePrism, theShape3D, /*selectBottom=*/false )) + botSM = NULL; } + mySetErrorToSM = savedSetErrorToSM; + return botSM ? true : toSM( error( COMPERR_BAD_SHAPE )); } // find vertex 000 - the one with smallest coordinates (for easy DEBUG :-) @@ -2802,11 +3091,12 @@ bool StdMeshers_Prism_3D::initPrism(Prism_3D::TPrismTopo& thePrism, } } - thePrism.myShape3D = shape3D; + thePrism.myShape3D = theShape3D; if ( thePrism.myBottom.IsNull() ) thePrism.myBottom = TopoDS::Face( botSM->GetSubShape() ); - thePrism.myBottom.Orientation( myHelper->GetSubShapeOri( shape3D, - thePrism.myBottom )); + thePrism.myBottom.Orientation( myHelper->GetSubShapeOri( theShape3D, thePrism.myBottom )); + thePrism.myTop. Orientation( myHelper->GetSubShapeOri( theShape3D, thePrism.myTop )); + // Get ordered bottom edges TopoDS_Face reverseBottom = // to have order of top EDGEs as in the top FACE TopoDS::Face( thePrism.myBottom.Reversed() ); @@ -2815,7 +3105,7 @@ bool StdMeshers_Prism_3D::initPrism(Prism_3D::TPrismTopo& thePrism, thePrism.myNbEdgesInWires, V000 ); // Get Wall faces corresponding to the ordered bottom edges and the top FACE - if ( !getWallFaces( thePrism, nbFaces )) + if ( !getWallFaces( thePrism, nbFaces )) // it also sets thePrism.myTop return false; //toSM( error(COMPERR_BAD_SHAPE, "Can't find side faces")); if ( topSM ) @@ -3759,7 +4049,7 @@ gp_Pnt StdMeshers_PrismAsBlock::TSideFace::Value(const Standard_Real U, TopoDS_Shape s = myHelper.GetSubShapeByNode( nn[0], myHelper.GetMeshDS() ); if ( s.ShapeType() != TopAbs_EDGE ) s = myHelper.GetSubShapeByNode( nn[2], myHelper.GetMeshDS() ); - if ( s.ShapeType() == TopAbs_EDGE ) + if ( !s.IsNull() && s.ShapeType() == TopAbs_EDGE ) edge = TopoDS::Edge( s ); } if ( !edge.IsNull() ) @@ -4221,3 +4511,359 @@ gp_Pnt2d StdMeshers_PrismAsBlock::TPCurveOnHorFaceAdaptor::Value(const Standard_ double r = ( U - i1->first ) / ( i2->first - i1->first ); return i1->second * ( 1 - r ) + i2->second * r; } + +//================================================================================ +/*! + * \brief Projects internal nodes using transformation found by boundary nodes + */ +//================================================================================ + +bool StdMeshers_Sweeper::projectIntPoints(const vector< gp_XYZ >& fromBndPoints, + const vector< gp_XYZ >& toBndPoints, + const vector< gp_XYZ >& fromIntPoints, + vector< gp_XYZ >& toIntPoints, + NSProjUtils::TrsfFinder3D& trsf, + vector< gp_XYZ > * bndError) +{ + // find transformation + if ( trsf.IsIdentity() && !trsf.Solve( fromBndPoints, toBndPoints )) + return false; + + // compute internal points using the found trsf + for ( size_t iP = 0; iP < fromIntPoints.size(); ++iP ) + { + toIntPoints[ iP ] = trsf.Transform( fromIntPoints[ iP ]); + } + + // compute boundary error + if ( bndError ) + { + bndError->resize( fromBndPoints.size() ); + gp_XYZ fromTrsf; + for ( size_t iP = 0; iP < fromBndPoints.size(); ++iP ) + { + fromTrsf = trsf.Transform( fromBndPoints[ iP ] ); + (*bndError)[ iP ] = toBndPoints[ iP ] - fromTrsf; + } + } + return true; +} + +//================================================================================ +/*! + * \brief Add boundary error to ineternal points + */ +//================================================================================ + +void StdMeshers_Sweeper::applyBoundaryError(const vector< gp_XYZ >& bndPoints, + const vector< gp_XYZ >& bndError1, + const vector< gp_XYZ >& bndError2, + const double r, + vector< gp_XYZ >& intPoints, + vector< double >& int2BndDist) +{ + // fix each internal point + const double eps = 1e-100; + for ( size_t iP = 0; iP < intPoints.size(); ++iP ) + { + gp_XYZ & intPnt = intPoints[ iP ]; + + // compute distance from intPnt to each boundary node + double int2BndDistSum = 0; + for ( size_t iBnd = 0; iBnd < bndPoints.size(); ++iBnd ) + { + int2BndDist[ iBnd ] = 1 / (( intPnt - bndPoints[ iBnd ]).SquareModulus() + eps ); + int2BndDistSum += int2BndDist[ iBnd ]; + } + + // apply bndError + for ( size_t iBnd = 0; iBnd < bndPoints.size(); ++iBnd ) + { + intPnt += bndError1[ iBnd ] * ( 1 - r ) * int2BndDist[ iBnd ] / int2BndDistSum; + intPnt += bndError2[ iBnd ] * r * int2BndDist[ iBnd ] / int2BndDistSum; + } + } +} + +//================================================================================ +/*! + * \brief Creates internal nodes of the prism + */ +//================================================================================ + +bool StdMeshers_Sweeper::ComputeNodes( SMESH_MesherHelper& helper, + const double tol, + const bool allowHighBndError) +{ + const size_t zSize = myBndColumns[0]->size(); + const size_t zSrc = 0, zTgt = zSize-1; + if ( zSize < 3 ) return true; + + vector< vector< gp_XYZ > > intPntsOfLayer( zSize ); // node coodinates to compute + // set coordinates of src and tgt nodes + for ( size_t z = 0; z < intPntsOfLayer.size(); ++z ) + intPntsOfLayer[ z ].resize( myIntColumns.size() ); + for ( size_t iP = 0; iP < myIntColumns.size(); ++iP ) + { + intPntsOfLayer[ zSrc ][ iP ] = intPoint( iP, zSrc ); + intPntsOfLayer[ zTgt ][ iP ] = intPoint( iP, zTgt ); + } + + // compute coordinates of internal nodes by projecting (transfroming) src and tgt + // nodes towards the central layer + + vector< NSProjUtils::TrsfFinder3D > trsfOfLayer( zSize ); + vector< vector< gp_XYZ > > bndError( zSize ); + + // boundary points used to compute an affine transformation from a layer to a next one + vector< gp_XYZ > fromSrcBndPnts( myBndColumns.size() ), fromTgtBndPnts( myBndColumns.size() ); + vector< gp_XYZ > toSrcBndPnts ( myBndColumns.size() ), toTgtBndPnts ( myBndColumns.size() ); + for ( size_t iP = 0; iP < myBndColumns.size(); ++iP ) + { + fromSrcBndPnts[ iP ] = bndPoint( iP, zSrc ); + fromTgtBndPnts[ iP ] = bndPoint( iP, zTgt ); + } + + size_t zS = zSrc + 1; + size_t zT = zTgt - 1; + for ( ; zS < zT; ++zS, --zT ) // vertical loop on layers + { + for ( size_t iP = 0; iP < myBndColumns.size(); ++iP ) + { + toSrcBndPnts[ iP ] = bndPoint( iP, zS ); + toTgtBndPnts[ iP ] = bndPoint( iP, zT ); + } + if (! projectIntPoints( fromSrcBndPnts, toSrcBndPnts, + intPntsOfLayer[ zS-1 ], intPntsOfLayer[ zS ], + trsfOfLayer [ zS-1 ], & bndError[ zS-1 ])) + return false; + if (! projectIntPoints( fromTgtBndPnts, toTgtBndPnts, + intPntsOfLayer[ zT+1 ], intPntsOfLayer[ zT ], + trsfOfLayer [ zT+1 ], & bndError[ zT+1 ])) + return false; + + // if ( zT == zTgt - 1 ) + // { + // for ( size_t iP = 0; iP < myBndColumns.size(); ++iP ) + // { + // gp_XYZ fromTrsf = trsfOfLayer [ zT+1].Transform( fromTgtBndPnts[ iP ] ); + // cout << "mesh.AddNode( " + // << fromTrsf.X() << ", " + // << fromTrsf.Y() << ", " + // << fromTrsf.Z() << ") " << endl; + // } + // for ( size_t iP = 0; iP < myIntColumns.size(); ++iP ) + // cout << "mesh.AddNode( " + // << intPntsOfLayer[ zT ][ iP ].X() << ", " + // << intPntsOfLayer[ zT ][ iP ].Y() << ", " + // << intPntsOfLayer[ zT ][ iP ].Z() << ") " << endl; + // } + + fromTgtBndPnts.swap( toTgtBndPnts ); + fromSrcBndPnts.swap( toSrcBndPnts ); + } + + // Compute two projections of internal points to the central layer + // in order to evaluate an error of internal points + + bool centerIntErrorIsSmall; + vector< gp_XYZ > centerSrcIntPnts( myIntColumns.size() ); + vector< gp_XYZ > centerTgtIntPnts( myIntColumns.size() ); + + for ( size_t iP = 0; iP < myBndColumns.size(); ++iP ) + { + toSrcBndPnts[ iP ] = bndPoint( iP, zS ); + toTgtBndPnts[ iP ] = bndPoint( iP, zT ); + } + if (! projectIntPoints( fromSrcBndPnts, toSrcBndPnts, + intPntsOfLayer[ zS-1 ], centerSrcIntPnts, + trsfOfLayer [ zS-1 ], & bndError[ zS-1 ])) + return false; + if (! projectIntPoints( fromTgtBndPnts, toTgtBndPnts, + intPntsOfLayer[ zT+1 ], centerTgtIntPnts, + trsfOfLayer [ zT+1 ], & bndError[ zT+1 ])) + return false; + + // evaluate an error of internal points on the central layer + centerIntErrorIsSmall = true; + if ( zS == zT ) // odd zSize + { + for ( size_t iP = 0; ( iP < myIntColumns.size() && centerIntErrorIsSmall ); ++iP ) + centerIntErrorIsSmall = + (centerSrcIntPnts[ iP ] - centerTgtIntPnts[ iP ]).SquareModulus() < tol*tol; + } + else // even zSize + { + for ( size_t iP = 0; ( iP < myIntColumns.size() && centerIntErrorIsSmall ); ++iP ) + centerIntErrorIsSmall = + (intPntsOfLayer[ zS-1 ][ iP ] - centerTgtIntPnts[ iP ]).SquareModulus() < tol*tol; + } + + // Evaluate an error of boundary points + + bool bndErrorIsSmall = true; + for ( size_t iP = 0; ( iP < myBndColumns.size() && bndErrorIsSmall ); ++iP ) + { + double sumError = 0; + for ( size_t z = 1; z < zS; ++z ) // loop on layers + sumError += ( bndError[ z-1 ][ iP ].Modulus() + + bndError[ zSize-z ][ iP ].Modulus() ); + + bndErrorIsSmall = ( sumError < tol ); + } + + if ( !bndErrorIsSmall && !allowHighBndError ) + return false; + + // compute final points on the central layer + std::vector< double > int2BndDist( myBndColumns.size() ); // work array of applyBoundaryError() + double r = zS / ( zSize - 1.); + if ( zS == zT ) + { + for ( size_t iP = 0; iP < myIntColumns.size(); ++iP ) + { + intPntsOfLayer[ zS ][ iP ] = + ( 1 - r ) * centerSrcIntPnts[ iP ] + r * centerTgtIntPnts[ iP ]; + } + if ( !bndErrorIsSmall ) + { + applyBoundaryError( toSrcBndPnts, bndError[ zS-1 ], bndError[ zS+1 ], r, + intPntsOfLayer[ zS ], int2BndDist ); + } + } + else + { + for ( size_t iP = 0; iP < myIntColumns.size(); ++iP ) + { + intPntsOfLayer[ zS ][ iP ] = + r * intPntsOfLayer[ zS ][ iP ] + ( 1 - r ) * centerSrcIntPnts[ iP ]; + intPntsOfLayer[ zT ][ iP ] = + r * intPntsOfLayer[ zT ][ iP ] + ( 1 - r ) * centerTgtIntPnts[ iP ]; + } + if ( !bndErrorIsSmall ) + { + applyBoundaryError( toSrcBndPnts, bndError[ zS-1 ], bndError[ zS+1 ], r, + intPntsOfLayer[ zS ], int2BndDist ); + applyBoundaryError( toTgtBndPnts, bndError[ zT+1 ], bndError[ zT-1 ], r, + intPntsOfLayer[ zT ], int2BndDist ); + } + } + + //centerIntErrorIsSmall = true; + //bndErrorIsSmall = true; + if ( !centerIntErrorIsSmall ) + { + // Compensate the central error; continue adding projection + // by going from central layer to the source and target ones + + vector< gp_XYZ >& fromSrcIntPnts = centerSrcIntPnts; + vector< gp_XYZ >& fromTgtIntPnts = centerTgtIntPnts; + vector< gp_XYZ > toSrcIntPnts( myIntColumns.size() ); + vector< gp_XYZ > toTgtIntPnts( myIntColumns.size() ); + vector< gp_XYZ > srcBndError( myBndColumns.size() ); + vector< gp_XYZ > tgtBndError( myBndColumns.size() ); + + fromTgtBndPnts.swap( toTgtBndPnts ); + fromSrcBndPnts.swap( toSrcBndPnts ); + + for ( ++zS, --zT; zS < zTgt; ++zS, --zT ) // vertical loop on layers + { + // invert transformation + if ( !trsfOfLayer[ zS+1 ].Invert() ) + trsfOfLayer[ zS+1 ] = NSProjUtils::TrsfFinder3D(); // to recompute + if ( !trsfOfLayer[ zT-1 ].Invert() ) + trsfOfLayer[ zT-1 ] = NSProjUtils::TrsfFinder3D(); + + // project internal nodes and compute bnd error + for ( size_t iP = 0; iP < myBndColumns.size(); ++iP ) + { + toSrcBndPnts[ iP ] = bndPoint( iP, zS ); + toTgtBndPnts[ iP ] = bndPoint( iP, zT ); + } + projectIntPoints( fromSrcBndPnts, toSrcBndPnts, + fromSrcIntPnts, toSrcIntPnts, + trsfOfLayer[ zS+1 ], & srcBndError ); + projectIntPoints( fromTgtBndPnts, toTgtBndPnts, + fromTgtIntPnts, toTgtIntPnts, + trsfOfLayer[ zT-1 ], & tgtBndError ); + + // if ( zS == zTgt - 1 ) + // { + // cout << "mesh2 = smesh.Mesh()" << endl; + // for ( size_t iP = 0; iP < myBndColumns.size(); ++iP ) + // { + // gp_XYZ fromTrsf = trsfOfLayer [ zS+1].Transform( fromSrcBndPnts[ iP ] ); + // cout << "mesh2.AddNode( " + // << fromTrsf.X() << ", " + // << fromTrsf.Y() << ", " + // << fromTrsf.Z() << ") " << endl; + // } + // for ( size_t iP = 0; iP < myIntColumns.size(); ++iP ) + // cout << "mesh2.AddNode( " + // << toSrcIntPnts[ iP ].X() << ", " + // << toSrcIntPnts[ iP ].Y() << ", " + // << toSrcIntPnts[ iP ].Z() << ") " << endl; + // } + + // sum up 2 projections + r = zS / ( zSize - 1.); + vector< gp_XYZ >& zSIntPnts = intPntsOfLayer[ zS ]; + vector< gp_XYZ >& zTIntPnts = intPntsOfLayer[ zT ]; + for ( size_t iP = 0; iP < myIntColumns.size(); ++iP ) + { + zSIntPnts[ iP ] = r * zSIntPnts[ iP ] + ( 1 - r ) * toSrcIntPnts[ iP ]; + zTIntPnts[ iP ] = r * zTIntPnts[ iP ] + ( 1 - r ) * toTgtIntPnts[ iP ]; + } + + // compensate bnd error + if ( !bndErrorIsSmall ) + { + applyBoundaryError( toSrcBndPnts, srcBndError, bndError[ zS+1 ], r, + intPntsOfLayer[ zS ], int2BndDist ); + applyBoundaryError( toTgtBndPnts, tgtBndError, bndError[ zT-1 ], r, + intPntsOfLayer[ zT ], int2BndDist ); + } + + fromSrcBndPnts.swap( toSrcBndPnts ); + fromSrcIntPnts.swap( toSrcIntPnts ); + fromTgtBndPnts.swap( toTgtBndPnts ); + fromTgtIntPnts.swap( toTgtIntPnts ); + } + } // if ( !centerIntErrorIsSmall ) + + else if ( !bndErrorIsSmall ) + { + zS = zSrc + 1; + zT = zTgt - 1; + for ( ; zS < zT; ++zS, --zT ) // vertical loop on layers + { + for ( size_t iP = 0; iP < myBndColumns.size(); ++iP ) + { + toSrcBndPnts[ iP ] = bndPoint( iP, zS ); + toTgtBndPnts[ iP ] = bndPoint( iP, zT ); + } + // compensate bnd error + applyBoundaryError( toSrcBndPnts, bndError[ zS-1 ], bndError[ zS-1 ], 0.5, + intPntsOfLayer[ zS ], int2BndDist ); + applyBoundaryError( toTgtBndPnts, bndError[ zT+1 ], bndError[ zT+1 ], 0.5, + intPntsOfLayer[ zT ], int2BndDist ); + } + } + + // cout << "centerIntErrorIsSmall = " << centerIntErrorIsSmall<< endl; + // cout << "bndErrorIsSmall = " << bndErrorIsSmall<< endl; + + // Create nodes + for ( size_t iP = 0; iP < myIntColumns.size(); ++iP ) + { + vector< const SMDS_MeshNode* > & nodeCol = *myIntColumns[ iP ]; + for ( size_t z = zSrc + 1; z < zTgt; ++z ) // vertical loop on layers + { + const gp_XYZ & xyz = intPntsOfLayer[ z ][ iP ]; + if ( !( nodeCol[ z ] = helper.AddNode( xyz.X(), xyz.Y(), xyz.Z() ))) + return false; + } + } + + return true; +} diff --git a/src/StdMeshers/StdMeshers_Prism_3D.hxx b/src/StdMeshers/StdMeshers_Prism_3D.hxx index f2929c31a..546bf4950 100644 --- a/src/StdMeshers/StdMeshers_Prism_3D.hxx +++ b/src/StdMeshers/StdMeshers_Prism_3D.hxx @@ -56,6 +56,10 @@ namespace Prism_3D struct TNode; struct TPrismTopo; } +namespace StdMeshers_ProjectionUtils +{ + class TrsfFinder3D; +} class SMESHDS_SubMesh; class TopoDS_Edge; @@ -398,7 +402,43 @@ private: }; // class StdMeshers_PrismAsBlock -// ============================================= +// =============================================== +/*! + * \brief Tool building internal nodes in a prism + */ +struct StdMeshers_Sweeper +{ + std::vector< TNodeColumn* > myBndColumns; // boundary nodes + std::vector< TNodeColumn* > myIntColumns; // internal nodes + + bool ComputeNodes( SMESH_MesherHelper& helper, + const double tol, + const bool allowHighBndError ); + +private: + + gp_XYZ bndPoint( int iP, int z ) const + { return SMESH_TNodeXYZ( (*myBndColumns[ iP ])[ z ]); } + + gp_XYZ intPoint( int iP, int z ) const + { return SMESH_TNodeXYZ( (*myIntColumns[ iP ])[ z ]); } + + static bool projectIntPoints(const std::vector< gp_XYZ >& fromBndPoints, + const std::vector< gp_XYZ >& toBndPoints, + const std::vector< gp_XYZ >& fromIntPoints, + std::vector< gp_XYZ >& toIntPoints, + StdMeshers_ProjectionUtils::TrsfFinder3D& trsf, + std::vector< gp_XYZ > * bndError); + + static void applyBoundaryError(const std::vector< gp_XYZ >& bndPoints, + const std::vector< gp_XYZ >& bndError1, + const std::vector< gp_XYZ >& bndError2, + const double r, + std::vector< gp_XYZ >& toIntPoints, + std::vector< double >& int2BndDist); +}; + +// =============================================== /*! * \brief Algo building prisms on a prism shape */ @@ -443,7 +483,9 @@ public: * \brief Analyse shape geometry and mesh. * If there are triangles on one of faces, it becomes 'bottom' */ - bool initPrism(Prism_3D::TPrismTopo& thePrism, const TopoDS_Shape& theSolid); + bool initPrism(Prism_3D::TPrismTopo& thePrism, + const TopoDS_Shape& theSolid, + const bool selectBottom = true); /*! * \brief Fill thePrism.myWallQuads and thePrism.myTopEdges @@ -480,7 +522,18 @@ public: * create triangles there by projection from the bottom * \retval bool - a success or not */ - bool projectBottomToTop( const gp_Trsf & bottomToTopTrsf ); + bool projectBottomToTop( const gp_Trsf & bottomToTopTrsf, + const Prism_3D::TPrismTopo& thePrism ); + + /*! + * \brief Compute tolerance to pass to StdMeshers_Sweeper + */ + double getSweepTolerance( const Prism_3D::TPrismTopo& thePrism ); + + /*! + * \brief Defines if it's safe to use the block approach + */ + bool isSimpleBottom( const Prism_3D::TPrismTopo& thePrism ); /*! * \brief Project mesh faces from a source FACE of one prism to @@ -511,6 +564,7 @@ private: bool myProjectTriangles; bool mySetErrorToSM; + bool myUseBlock; StdMeshers_PrismAsBlock myBlock; SMESH_MesherHelper* myHelper; diff --git a/src/StdMeshers/StdMeshers_ProjectionUtils.cxx b/src/StdMeshers/StdMeshers_ProjectionUtils.cxx index 92474f205..e5ab88a1e 100644 --- a/src/StdMeshers/StdMeshers_ProjectionUtils.cxx +++ b/src/StdMeshers/StdMeshers_ProjectionUtils.cxx @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -66,6 +67,7 @@ #include #include #include +#include #include #include @@ -98,7 +100,7 @@ namespace HERE = StdMeshers_ProjectionUtils; namespace { - static SMESHDS_Mesh* theMeshDS[2] = { 0, 0 }; // used to debug only + static SMESHDS_Mesh* theMeshDS[2] = { 0, 0 }; // used for debug only long shapeIndex(const TopoDS_Shape& S) { if ( theMeshDS[0] && theMeshDS[1] ) @@ -548,7 +550,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the // ---------------------------------------------------------------------- case TopAbs_EDGE: { // TopAbs_EDGE // ---------------------------------------------------------------------- - if ( theMap.Extent() != 2 ) + if ( theMap.Extent() != 1 ) RETURN_BAD_RESULT("Wrong map extent " << theMap.Extent() ); TopoDS_Edge edge1 = TopoDS::Edge( theShape1 ); TopoDS_Edge edge2 = TopoDS::Edge( theShape2 ); @@ -656,7 +658,6 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the TopoDS_Shape F1, F2; // get a face sharing edge1 (F1) - TopoDS_Shape FF2[2]; TopTools_ListIteratorOfListOfShape ancestIt1( edgeToFace1.FindFromKey( edge1 )); for ( ; F1.IsNull() && ancestIt1.More(); ancestIt1.Next() ) if ( ancestIt1.Value().ShapeType() == TopAbs_FACE ) @@ -666,6 +667,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the RETURN_BAD_RESULT(" Face1 not found"); // get 2 faces sharing edge2 (one of them is F2) + TopoDS_Shape FF2[2]; TopTools_ListIteratorOfListOfShape ancestIt2( edgeToFace2.FindFromKey( edge2 )); for ( int i = 0; FF2[1].IsNull() && ancestIt2.More(); ancestIt2.Next() ) if ( ancestIt2.Value().ShapeType() == TopAbs_FACE ) @@ -1244,8 +1246,9 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the double minDist = std::numeric_limits::max(); for ( int nbChecked=0; edge1 != allBndEdges1.end() && nbChecked++ < 10; ++edge1 ) { - TopExp::Vertices( TopoDS::Edge( edge1->Oriented(TopAbs_FORWARD)), VV1[0], VV1[1]); - if ( VV1[0].IsSame( VV1[1] )) + TopoDS_Vertex edge1VV[2]; + TopExp::Vertices( TopoDS::Edge( edge1->Oriented(TopAbs_FORWARD)), edge1VV[0], edge1VV[1]); + if ( edge1VV[0].IsSame( edge1VV[1] )) continue;//RETURN_BAD_RESULT("Only closed edges"); // find vertices closest to 2 linked vertices of shape 1 @@ -1253,7 +1256,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the TopoDS_Vertex edge2VV[2]; for ( int i1 = 0; i1 < 2; ++i1 ) { - gp_Pnt p1 = BRep_Tool::Pnt( VV1[ i1 ]); + gp_Pnt p1 = BRep_Tool::Pnt( edge1VV[ i1 ]); p1.Scale( gc[0], scale ); p1.Translate( vec01 ); if ( !i1 ) { @@ -1289,6 +1292,8 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the } } if ( dist2[0] + dist2[1] < minDist ) { + VV1[0] = edge1VV[0]; + VV1[1] = edge1VV[1]; VV2[0] = edge2VV[0]; VV2[1] = edge2VV[1]; minDist = dist2[0] + dist2[1]; @@ -1448,8 +1453,10 @@ int StdMeshers_ProjectionUtils::FindFaceAssociation(const TopoDS_Face& face1, edge1End = edge1Beg; std::advance( edge1End, *nbE1 ); // UV on face1 to find on face2 - v0f1UV = BRep_Tool::Parameters( TopExp::FirstVertex(*edge1Beg,true), face1 ); - v1f1UV = BRep_Tool::Parameters( TopExp::LastVertex (*edge1Beg,true), face1 ); + TopoDS_Vertex v01 = SMESH_MesherHelper::IthVertex(0,*edge1Beg); + TopoDS_Vertex v11 = SMESH_MesherHelper::IthVertex(1,*edge1Beg); + v0f1UV = BRep_Tool::Parameters( v01, face1 ); + v1f1UV = BRep_Tool::Parameters( v11, face1 ); v0f1UV.ChangeCoord() += dUV; v1f1UV.ChangeCoord() += dUV; // @@ -1474,9 +1481,30 @@ int StdMeshers_ProjectionUtils::FindFaceAssociation(const TopoDS_Face& face1, sameVertexUV( *edge2Beg, face2, 0, v0f1UV, vTolUV )) { if ( iW1 == 0 ) OK = true; // OK is for the first wire + // reverse edges2 if needed - if ( !sameVertexUV( *edge2Beg, face2, 1, v1f1UV, vTolUV )) - reverseEdges( edges2 , *nbE2, std::distance( edges2.begin(),edge2Beg )); + if ( SMESH_MesherHelper::IsClosedEdge( *edge1Beg )) + { + double f,l; + Handle(Geom2d_Curve) c1 = BRep_Tool::CurveOnSurface( *edge1Beg, face1,f,l ); + if ( edge1Beg->Orientation() == TopAbs_REVERSED ) + std::swap( f,l ); + gp_Pnt2d uv1 = dUV + c1->Value( f * 0.8 + l * 0.2 ).XY(); + + Handle(Geom2d_Curve) c2 = BRep_Tool::CurveOnSurface( *edge2Beg, face2,f,l ); + if ( edge2Beg->Orientation() == TopAbs_REVERSED ) + std::swap( f,l ); + gp_Pnt2d uv2 = c2->Value( f * 0.8 + l * 0.2 ); + + if ( uv1.Distance( uv2 ) > vTolUV ) + edge2Beg->Reverse(); + } + else + { + if ( !sameVertexUV( *edge2Beg, face2, 1, v1f1UV, vTolUV )) + reverseEdges( edges2 , *nbE2, std::distance( edges2.begin(),edge2Beg )); + } + // put wire2 at a right place within edges2 if ( iW1 != iW2 ) { list< TopoDS_Edge >::iterator place2 = edges2.begin(); @@ -1914,97 +1942,109 @@ FindMatchingNodesOnFaces( const TopoDS_Face& face1, // 2. face sets - set Elems1, Elems2; - for ( int is2 = 0; is2 < 2; ++is2 ) + int assocRes; + for ( int iAttempt = 0; iAttempt < 2; ++iAttempt ) { - set & elems = is2 ? Elems2 : Elems1; - SMESHDS_SubMesh* sm = is2 ? SM2 : SM1; - SMESH_MesherHelper* helper = is2 ? &helper2 : &helper1; - const TopoDS_Face & face = is2 ? face2 : face1; - SMDS_ElemIteratorPtr eIt = sm->GetElements(); - - if ( !helper->IsRealSeam( is2 ? edge2 : edge1 )) + set Elems1, Elems2; + for ( int is2 = 0; is2 < 2; ++is2 ) { - while ( eIt->more() ) elems.insert( eIt->next() ); - } - else - { - // the only suitable edge is seam, i.e. it is a sphere. - // FindMatchingNodes() will not know which way to go from any edge. - // So we ignore all faces having nodes on edges or vertices except - // one of faces sharing current start nodes + set & elems = is2 ? Elems2 : Elems1; + SMESHDS_SubMesh* sm = is2 ? SM2 : SM1; + SMESH_MesherHelper* helper = is2 ? &helper2 : &helper1; + const TopoDS_Face & face = is2 ? face2 : face1; + SMDS_ElemIteratorPtr eIt = sm->GetElements(); - // find a face to keep - const SMDS_MeshElement* faceToKeep = 0; - const SMDS_MeshNode* vNode = is2 ? vNode2 : vNode1; - const SMDS_MeshNode* eNode = is2 ? eNode2[0] : eNode1[0]; - TIDSortedElemSet inSet, notInSet; - - const SMDS_MeshElement* f1 = - SMESH_MeshAlgos::FindFaceInSet( vNode, eNode, inSet, notInSet ); - if ( !f1 ) RETURN_BAD_RESULT("The first face on seam not found"); - notInSet.insert( f1 ); - - const SMDS_MeshElement* f2 = - SMESH_MeshAlgos::FindFaceInSet( vNode, eNode, inSet, notInSet ); - if ( !f2 ) RETURN_BAD_RESULT("The second face on seam not found"); - - // select a face with less UV of vNode - const SMDS_MeshNode* notSeamNode[2] = {0, 0}; - for ( int iF = 0; iF < 2; ++iF ) { - const SMDS_MeshElement* f = ( iF ? f2 : f1 ); - for ( int i = 0; !notSeamNode[ iF ] && i < f->NbNodes(); ++i ) { - const SMDS_MeshNode* node = f->GetNode( i ); - if ( !helper->IsSeamShape( node->getshapeId() )) - notSeamNode[ iF ] = node; - } + if ( !helper->IsRealSeam( is2 ? edge2 : edge1 )) + { + while ( eIt->more() ) elems.insert( elems.end(), eIt->next() ); } - gp_Pnt2d uv1 = helper->GetNodeUV( face, vNode, notSeamNode[0] ); - gp_Pnt2d uv2 = helper->GetNodeUV( face, vNode, notSeamNode[1] ); - if ( uv1.X() + uv1.Y() > uv2.X() + uv2.Y() ) - faceToKeep = f2; else - faceToKeep = f1; + { + // the only suitable edge is seam, i.e. it is a sphere. + // FindMatchingNodes() will not know which way to go from any edge. + // So we ignore all faces having nodes on edges or vertices except + // one of faces sharing current start nodes - // fill elem set - elems.insert( faceToKeep ); - while ( eIt->more() ) { - const SMDS_MeshElement* f = eIt->next(); - int nbNodes = f->NbNodes(); - if ( f->IsQuadratic() ) - nbNodes /= 2; - bool onBnd = false; - for ( int i = 0; !onBnd && i < nbNodes; ++i ) { - const SMDS_MeshNode* node = f->GetNode( i ); - onBnd = ( node->GetPosition()->GetTypeOfPosition() != SMDS_TOP_FACE); + // find a face to keep + const SMDS_MeshElement* faceToKeep = 0; + const SMDS_MeshNode* vNode = is2 ? vNode2 : vNode1; + const SMDS_MeshNode* eNode = is2 ? eNode2[0] : eNode1[0]; + TIDSortedElemSet inSet, notInSet; + + const SMDS_MeshElement* f1 = + SMESH_MeshAlgos::FindFaceInSet( vNode, eNode, inSet, notInSet ); + if ( !f1 ) RETURN_BAD_RESULT("The first face on seam not found"); + notInSet.insert( f1 ); + + const SMDS_MeshElement* f2 = + SMESH_MeshAlgos::FindFaceInSet( vNode, eNode, inSet, notInSet ); + if ( !f2 ) RETURN_BAD_RESULT("The second face on seam not found"); + + // select a face with less UV of vNode + const SMDS_MeshNode* notSeamNode[2] = {0, 0}; + for ( int iF = 0; iF < 2; ++iF ) { + const SMDS_MeshElement* f = ( iF ? f2 : f1 ); + for ( int i = 0; !notSeamNode[ iF ] && i < f->NbNodes(); ++i ) { + const SMDS_MeshNode* node = f->GetNode( i ); + if ( !helper->IsSeamShape( node->getshapeId() )) + notSeamNode[ iF ] = node; + } } - if ( !onBnd ) - elems.insert( f ); - } - // add also faces adjacent to faceToKeep - int nbNodes = faceToKeep->NbNodes(); - if ( faceToKeep->IsQuadratic() ) nbNodes /= 2; - notInSet.insert( f1 ); - notInSet.insert( f2 ); - for ( int i = 0; i < nbNodes; ++i ) { - const SMDS_MeshNode* n1 = faceToKeep->GetNode( i ); - const SMDS_MeshNode* n2 = faceToKeep->GetNode(( i+1 ) % nbNodes ); - f1 = SMESH_MeshAlgos::FindFaceInSet( n1, n2, inSet, notInSet ); - if ( f1 ) - elems.insert( f1 ); - } - } // case on a sphere - } // loop on 2 faces + gp_Pnt2d uv1 = helper->GetNodeUV( face, vNode, notSeamNode[0] ); + gp_Pnt2d uv2 = helper->GetNodeUV( face, vNode, notSeamNode[1] ); + if ( uv1.X() + uv1.Y() > uv2.X() + uv2.Y() ) + faceToKeep = f2; + else + faceToKeep = f1; - // int quadFactor = (*Elems1.begin())->IsQuadratic() ? 2 : 1; + // fill elem set + elems.insert( faceToKeep ); + while ( eIt->more() ) { + const SMDS_MeshElement* f = eIt->next(); + int nbNodes = f->NbNodes(); + if ( f->IsQuadratic() ) + nbNodes /= 2; + bool onBnd = false; + for ( int i = 0; !onBnd && i < nbNodes; ++i ) { + const SMDS_MeshNode* node = f->GetNode( i ); + onBnd = ( node->GetPosition()->GetTypeOfPosition() != SMDS_TOP_FACE); + } + if ( !onBnd ) + elems.insert( f ); + } + // add also faces adjacent to faceToKeep + int nbNodes = faceToKeep->NbNodes(); + if ( faceToKeep->IsQuadratic() ) nbNodes /= 2; + notInSet.insert( f1 ); + notInSet.insert( f2 ); + for ( int i = 0; i < nbNodes; ++i ) { + const SMDS_MeshNode* n1 = faceToKeep->GetNode( i ); + const SMDS_MeshNode* n2 = faceToKeep->GetNode(( i+1 ) % nbNodes ); + f1 = SMESH_MeshAlgos::FindFaceInSet( n1, n2, inSet, notInSet ); + if ( f1 ) + elems.insert( f1 ); + } + } // case on a sphere + } // loop on 2 faces - node1To2Map.clear(); - int res = SMESH_MeshEditor::FindMatchingNodes( Elems1, Elems2, - vNode1, vNode2, - eNode1[0], eNode2[0], - node1To2Map); - if ( res != SMESH_MeshEditor::SEW_OK ) - RETURN_BAD_RESULT("FindMatchingNodes() result " << res ); + node1To2Map.clear(); + assocRes = SMESH_MeshEditor::FindMatchingNodes( Elems1, Elems2, + vNode1, vNode2, + eNode1[0], eNode2[0], + node1To2Map); + if (( assocRes != SMESH_MeshEditor::SEW_OK ) && + ( eNode1[1] || eNode2[1] )) // there is another node to try (on a closed EDGE) + { + node1To2Map.clear(); + if ( eNode1[1] ) std::swap( eNode1[0], eNode1[1] ); + else std::swap( eNode2[0], eNode2[1] ); + continue; // one more attempt + } + + break; + } + if ( assocRes != SMESH_MeshEditor::SEW_OK ) + RETURN_BAD_RESULT("FindMatchingNodes() result " << assocRes ); // On a sphere, add matching nodes on the edge @@ -2402,3 +2442,229 @@ void StdMeshers_ProjectionUtils::SetEventListener(SMESH_subMesh* subMesh, } } } + +namespace StdMeshers_ProjectionUtils +{ + + //================================================================================ + /*! + * \brief Computes transformation beween two sets of 2D points using + * a least square approximation + * + * See "Surface Mesh Projection For Hexahedral Mesh Generation By Sweeping" + * by X.Roca, J.Sarrate, A.Huerta. (2.2) + */ + //================================================================================ + + bool TrsfFinder2D::Solve( const vector< gp_XY >& srcPnts, + const vector< gp_XY >& tgtPnts ) + { + // find gravity centers + gp_XY srcGC( 0,0 ), tgtGC( 0,0 ); + for ( size_t i = 0; i < srcPnts.size(); ++i ) + { + srcGC += srcPnts[i]; + tgtGC += tgtPnts[i]; + } + srcGC /= srcPnts.size(); + tgtGC /= tgtPnts.size(); + + // find trsf + + math_Matrix mat (1,4,1,4, 0.); + math_Vector vec (1,4, 0.); + + // cout << "m1 = smesh.Mesh('src')" << endl + // << "m2 = smesh.Mesh('tgt')" << endl; + double xx = 0, xy = 0, yy = 0; + for ( size_t i = 0; i < srcPnts.size(); ++i ) + { + gp_XY srcUV = srcPnts[i] - srcGC; + gp_XY tgtUV = tgtPnts[i] - tgtGC; + xx += srcUV.X() * srcUV.X(); + yy += srcUV.Y() * srcUV.Y(); + xy += srcUV.X() * srcUV.Y(); + vec( 1 ) += srcUV.X() * tgtUV.X(); + vec( 2 ) += srcUV.Y() * tgtUV.X(); + vec( 3 ) += srcUV.X() * tgtUV.Y(); + vec( 4 ) += srcUV.Y() * tgtUV.Y(); + // cout << "m1.AddNode( " << srcUV.X() << ", " << srcUV.Y() << ", 0 )" << endl + // << "m2.AddNode( " << tgtUV.X() << ", " << tgtUV.Y() << ", 0 )" << endl; + } + mat( 1,1 ) = mat( 3,3 ) = xx; + mat( 2,2 ) = mat( 4,4 ) = yy; + mat( 1,2 ) = mat( 2,1 ) = mat( 3,4 ) = mat( 4,3 ) = xy; + + math_Gauss solver( mat ); + if ( !solver.IsDone() ) + return false; + solver.Solve( vec ); + if ( vec.Norm2() < gp::Resolution() ) + return false; + // cout << vec( 1 ) << "\t " << vec( 2 ) << endl + // << vec( 3 ) << "\t " << vec( 4 ) << endl; + + _trsf.SetTranslation( tgtGC ); + _srcOrig = srcGC; + + gp_Mat2d& M = const_cast< gp_Mat2d& >( _trsf.HVectorialPart()); + M( 1,1 ) = vec( 1 ); + M( 2,1 ) = vec( 2 ); + M( 1,2 ) = vec( 3 ); + M( 2,2 ) = vec( 4 ); + + return true; + } + + //================================================================================ + /*! + * \brief Transforms a 2D points using a found transformation + */ + //================================================================================ + + gp_XY TrsfFinder2D::Transform( const gp_Pnt2d& srcUV ) const + { + gp_XY uv = srcUV.XY() - _srcOrig ; + _trsf.Transforms( uv ); + return uv; + } + + //================================================================================ + /*! + * \brief Computes transformation beween two sets of 3D points using + * a least square approximation + * + * See "Surface Mesh Projection For Hexahedral Mesh Generation By Sweeping" + * by X.Roca, J.Sarrate, A.Huerta. (2.4) + */ + //================================================================================ + + bool TrsfFinder3D::Solve( const vector< gp_XYZ > & srcPnts, + const vector< gp_XYZ > & tgtPnts ) + { + // find gravity center + gp_XYZ srcGC( 0,0,0 ), tgtGC( 0,0,0 ); + for ( size_t i = 0; i < srcPnts.size(); ++i ) + { + srcGC += srcPnts[i]; + tgtGC += tgtPnts[i]; + } + srcGC /= srcPnts.size(); + tgtGC /= tgtPnts.size(); + + gp_XYZ srcOrig = 2 * srcGC - tgtGC; + gp_XYZ tgtOrig = srcGC; + + // find trsf + + math_Matrix mat (1,9,1,9, 0.); + math_Vector vec (1,9, 0.); + + double xx = 0, yy = 0, zz = 0; + double xy = 0, xz = 0, yz = 0; + for ( size_t i = 0; i < srcPnts.size(); ++i ) + { + gp_XYZ src = srcPnts[i] - srcOrig; + gp_XYZ tgt = tgtPnts[i] - tgtOrig; + xx += src.X() * src.X(); + yy += src.Y() * src.Y(); + zz += src.Z() * src.Z(); + xy += src.X() * src.Y(); + xz += src.X() * src.Z(); + yz += src.Y() * src.Z(); + vec( 1 ) += src.X() * tgt.X(); + vec( 2 ) += src.Y() * tgt.X(); + vec( 3 ) += src.Z() * tgt.X(); + vec( 4 ) += src.X() * tgt.Y(); + vec( 5 ) += src.Y() * tgt.Y(); + vec( 6 ) += src.Z() * tgt.Y(); + vec( 7 ) += src.X() * tgt.Z(); + vec( 8 ) += src.Y() * tgt.Z(); + vec( 9 ) += src.Z() * tgt.Z(); + } + mat( 1,1 ) = mat( 4,4 ) = mat( 7,7 ) = xx; + mat( 2,2 ) = mat( 5,5 ) = mat( 8,8 ) = yy; + mat( 3,3 ) = mat( 6,6 ) = mat( 9,9 ) = zz; + mat( 1,2 ) = mat( 2,1 ) = mat( 4,5 ) = mat( 5,4 ) = mat( 7,8 ) = mat( 8,7 ) = xy; + mat( 1,3 ) = mat( 3,1 ) = mat( 4,6 ) = mat( 6,4 ) = mat( 7,9 ) = mat( 9,7 ) = xz; + mat( 2,3 ) = mat( 3,2 ) = mat( 5,6 ) = mat( 6,5 ) = mat( 8,9 ) = mat( 9,8 ) = yz; + + math_Gauss solver( mat ); + if ( !solver.IsDone() ) + return false; + solver.Solve( vec ); + if ( vec.Norm2() < gp::Resolution() ) + return false; + // cout << endl + // << vec( 1 ) << "\t " << vec( 2 ) << "\t " << vec( 3 ) << endl + // << vec( 4 ) << "\t " << vec( 5 ) << "\t " << vec( 6 ) << endl + // << vec( 7 ) << "\t " << vec( 8 ) << "\t " << vec( 9 ) << endl; + + _srcOrig = srcOrig; + _trsf.SetTranslation( tgtOrig ); + + gp_Mat& M = const_cast< gp_Mat& >( _trsf.HVectorialPart() ); + M.SetRows( gp_XYZ( vec( 1 ), vec( 2 ), vec( 3 )), + gp_XYZ( vec( 4 ), vec( 5 ), vec( 6 )), + gp_XYZ( vec( 7 ), vec( 8 ), vec( 9 ))); + return true; + } + + //================================================================================ + /*! + * \brief Transforms a 3D point using a found transformation + */ + //================================================================================ + + gp_XYZ TrsfFinder3D::Transform( const gp_Pnt& srcP ) const + { + gp_XYZ p = srcP.XYZ() - _srcOrig; + _trsf.Transforms( p ); + return p; + } + + //================================================================================ + /*! + * \brief Transforms a 3D vector using a found transformation + */ + //================================================================================ + + gp_XYZ TrsfFinder3D::TransformVec( const gp_Vec& v ) const + { + return v.XYZ().Multiplied( _trsf.HVectorialPart() ); + } + //================================================================================ + /*! + * \brief Inversion + */ + //================================================================================ + + bool TrsfFinder3D::Invert() + { + if (( _trsf.Form() == gp_Translation ) && + ( _srcOrig.X() != 0 || _srcOrig.Y() != 0 || _srcOrig.Z() != 0 )) + { + // seems to be defined via Solve() + gp_XYZ newSrcOrig = _trsf.TranslationPart(); + gp_Mat& M = const_cast< gp_Mat& >( _trsf.HVectorialPart() ); + const double D = M.Determinant(); + if ( D < 1e-3 * ( newSrcOrig - _srcOrig ).Modulus() ) + { +#ifdef _DEBUG_ + cerr << "TrsfFinder3D::Invert()" + << "D " << M.Determinant() << " IsSingular " << M.IsSingular() << endl; +#endif + return false; + } + gp_Mat Minv = M.Inverted(); + _trsf.SetTranslation( _srcOrig ); + _srcOrig = newSrcOrig; + M = Minv; + } + else + { + _trsf.Invert(); + } + return true; + } +} diff --git a/src/StdMeshers/StdMeshers_ProjectionUtils.hxx b/src/StdMeshers/StdMeshers_ProjectionUtils.hxx index 31afb072f..e7ea4423d 100644 --- a/src/StdMeshers/StdMeshers_ProjectionUtils.hxx +++ b/src/StdMeshers/StdMeshers_ProjectionUtils.hxx @@ -30,10 +30,14 @@ #include "SMESH_StdMeshers.hxx" +#include "SMDS_MeshElement.hxx" + #include #include -#include #include +#include +#include +#include #include #include @@ -77,7 +81,54 @@ namespace StdMeshers_ProjectionUtils { typedef StdMeshers_ShapeShapeBiDirectionMap TShapeShapeMap; typedef TopTools_IndexedDataMapOfShapeListOfShape TAncestorMap; - typedef std::map TNodeNodeMap; + typedef std::map TNodeNodeMap; + + + /*! + * \brief Finds transformation beween two sets of 2D points using + * a least square approximation + */ + class TrsfFinder2D + { + gp_Trsf2d _trsf; + gp_XY _srcOrig; + public: + TrsfFinder2D(): _srcOrig(0,0) {} + + void Set( const gp_Trsf2d& t ) { _trsf = t; } // it's an alternative to Solve() + + bool Solve( const std::vector< gp_XY >& srcPnts, + const std::vector< gp_XY >& tgtPnts ); + + gp_XY Transform( const gp_Pnt2d& srcUV ) const; + + bool IsIdentity() const { return ( _trsf.Form() == gp_Identity ); } + }; + /*! + * \brief Finds transformation beween two sets of 3D points using + * a least square approximation + */ + class TrsfFinder3D + { + gp_Trsf _trsf; + gp_XYZ _srcOrig; + public: + TrsfFinder3D(): _srcOrig(0,0,0) {} + + void Set( const gp_Trsf& t ) { _trsf = t; } // it's an alternative to Solve() + + bool Solve( const std::vector< gp_XYZ > & srcPnts, + const std::vector< gp_XYZ > & tgtPnts ); + + gp_XYZ Transform( const gp_Pnt& srcP ) const; + + gp_XYZ TransformVec( const gp_Vec& v ) const; + + bool IsIdentity() const { return ( _trsf.Form() == gp_Identity ); } + + bool Invert(); + }; /*! * \brief Looks for association of all sub-shapes of two shapes diff --git a/src/StdMeshers/StdMeshers_Projection_2D.cxx b/src/StdMeshers/StdMeshers_Projection_2D.cxx index a0eb3248f..7b3d1e1e1 100644 --- a/src/StdMeshers/StdMeshers_Projection_2D.cxx +++ b/src/StdMeshers/StdMeshers_Projection_2D.cxx @@ -47,8 +47,11 @@ #include "utilities.h" +#include #include #include +#include +#include #include #include #include @@ -139,6 +142,7 @@ bool StdMeshers_Projection_2D::CheckHypothesis(SMESH_Mesh& !SMESH_MesherHelper::IsSubShape( edge, _sourceHypo->GetSourceFace() )) { theStatus = HYP_BAD_PARAMETER; + error("Invalid source vertices"); SCRUTE((edge.IsNull())); SCRUTE((SMESH_MesherHelper::IsSubShape( edge, srcMesh ))); SCRUTE((SMESH_MesherHelper::IsSubShape( edge, _sourceHypo->GetSourceFace() ))); @@ -151,6 +155,7 @@ bool StdMeshers_Projection_2D::CheckHypothesis(SMESH_Mesh& if ( edge.IsNull() || !SMESH_MesherHelper::IsSubShape( edge, tgtMesh )) { theStatus = HYP_BAD_PARAMETER; + error("Invalid target vertices"); SCRUTE((edge.IsNull())); SCRUTE((SMESH_MesherHelper::IsSubShape( edge, tgtMesh ))); } @@ -159,6 +164,7 @@ bool StdMeshers_Projection_2D::CheckHypothesis(SMESH_Mesh& !SMESH_MesherHelper::IsSubShape( edge, theShape )) { theStatus = HYP_BAD_PARAMETER; + error("Invalid target vertices"); SCRUTE((SMESH_MesherHelper::IsSubShape( edge, theShape ))); } } @@ -168,6 +174,7 @@ bool StdMeshers_Projection_2D::CheckHypothesis(SMESH_Mesh& ( srcMesh == tgtMesh && theShape == _sourceHypo->GetSourceFace() )) { theStatus = HYP_BAD_PARAMETER; + error("Invalid source face"); SCRUTE((SMESH_MesherHelper::IsSubShape( _sourceHypo->GetSourceFace(), srcMesh ))); SCRUTE((srcMesh == tgtMesh)); SCRUTE(( theShape == _sourceHypo->GetSourceFace() )); @@ -190,7 +197,7 @@ namespace { */ //================================================================================ - bool isOldNode( const SMDS_MeshNode* node/*, const bool is1DComputed*/ ) + bool isOldNode( const SMDS_MeshNode* node ) { // old nodes are shared by edges and new ones are shared // only by faces created by mapper @@ -370,227 +377,274 @@ namespace { //================================================================================ /*! - * \brief Preform projection in case if tgtFace.IsPartner( srcFace ) and in case - * if projection by transformation is possible + * \brief Check if two consecutive EDGEs are connected in 2D + * \param [in] E1 - a well oriented non-seam EDGE + * \param [in] E2 - a possibly well oriented seam EDGE + * \param [in] F - a FACE + * \return bool - result */ //================================================================================ - bool projectPartner(const TopoDS_Face& tgtFace, - const TopoDS_Face& srcFace, - SMESH_Mesh * tgtMesh, - SMESH_Mesh * srcMesh, - const TAssocTool::TShapeShapeMap& shape2ShapeMap) + bool are2dConnected( const TopoDS_Edge & E1, + const TopoDS_Edge & E2, + const TopoDS_Face & F ) + { + double f,l; + Handle(Geom2d_Curve) c1 = BRep_Tool::CurveOnSurface( E1, F, f, l ); + gp_Pnt2d uvLast1 = c1->Value( E1.Orientation() == TopAbs_REVERSED ? f : l ); + + Handle(Geom2d_Curve) c2 = BRep_Tool::CurveOnSurface( E2, F, f, l ); + gp_Pnt2d uvFirst2 = c2->Value( f ); + gp_Pnt2d uvLast2 = c2->Value( l ); + double tol2 = 1e-5 * uvLast2.SquareDistance( uvFirst2 ); + + return (( uvLast1.SquareDistance( uvFirst2 ) < tol2 ) || + ( uvLast1.SquareDistance( uvLast2 ) < tol2 )); + } + + //================================================================================ + /*! + * \brief Compose TSideVector for both FACEs keeping matching order of EDGEs + * and fill src2tgtNodes map + */ + //================================================================================ + + TError getWires(const TopoDS_Face& tgtFace, + const TopoDS_Face& srcFace, + SMESH_Mesh * tgtMesh, + SMESH_Mesh * srcMesh, + const TAssocTool::TShapeShapeMap& shape2ShapeMap, + TSideVector& srcWires, + TSideVector& tgtWires, + TAssocTool::TNodeNodeMap& src2tgtNodes, + bool& is1DComputed) { SMESHDS_Mesh* tgtMeshDS = tgtMesh->GetMeshDS(); SMESHDS_Mesh* srcMeshDS = srcMesh->GetMeshDS(); + src2tgtNodes.clear(); + + // get ordered src EDGEs + TError err; + srcWires = StdMeshers_FaceSide::GetFaceWires( srcFace, *srcMesh,/*skipMediumNodes=*/0, err); + if ( err && !err->IsOK() ) + return err; + + // make corresponding sequence of tgt EDGEs + tgtWires.resize( srcWires.size() ); + for ( size_t iW = 0; iW < srcWires.size(); ++iW ) + { + list< TopoDS_Edge > tgtEdges; + StdMeshers_FaceSidePtr srcWire = srcWires[iW]; + TopTools_IndexedMapOfShape edgeMap; // to detect seam edges + for ( int iE = 0; iE < srcWire->NbEdges(); ++iE ) + { + TopoDS_Edge srcE = srcWire->Edge( iE ); + TopoDS_Edge tgtE = TopoDS::Edge( shape2ShapeMap( srcE, /*isSrc=*/true)); + TopoDS_Shape srcEbis = shape2ShapeMap( tgtE, /*isSrc=*/false ); + if ( srcE.Orientation() != srcEbis.Orientation() ) + tgtE.Reverse(); + // reverse a seam edge encountered for the second time + const int index = edgeMap.Add( tgtE ); + if ( index < edgeMap.Extent() ) // E is a seam + { + // check which of edges to reverse, E or one already being in tgtEdges + if ( are2dConnected( tgtEdges.back(), tgtE, tgtFace )) + { + list< TopoDS_Edge >::iterator eIt = tgtEdges.begin(); + std::advance( eIt, index-1 ); + eIt->Reverse(); + } + else + { + tgtE.Reverse(); + } + } + if ( srcWire->NbEdges() == 1 && tgtMesh == srcMesh ) // circle + { + // try to verify ori by propagation + pair nE = + StdMeshers_ProjectionUtils::GetPropagationEdge( srcMesh, tgtE, srcE ); + if ( !nE.second.IsNull() ) + tgtE = nE.second; + } + tgtEdges.push_back( tgtE ); + + + // Fill map of src to tgt nodes with nodes on edges + + if ( srcMesh->GetSubMesh( srcE )->IsEmpty() || + tgtMesh->GetSubMesh( tgtE )->IsEmpty() ) + { + // add nodes on VERTEXes for a case of not meshes EDGEs + const TopoDS_Shape& srcV = SMESH_MesherHelper::IthVertex( 0, srcE ); + const TopoDS_Shape& tgtV = shape2ShapeMap( srcV, /*isSrc=*/true ); + const SMDS_MeshNode* srcN = SMESH_Algo::VertexNode( TopoDS::Vertex( srcV ), srcMeshDS ); + const SMDS_MeshNode* tgtN = SMESH_Algo::VertexNode( TopoDS::Vertex( tgtV ), tgtMeshDS ); + if ( srcN && tgtN ) + src2tgtNodes.insert( make_pair( srcN, tgtN )); + } + else + { + const bool skipMediumNodes = true; + map< double, const SMDS_MeshNode* > srcNodes, tgtNodes; + if ( !SMESH_Algo::GetSortedNodesOnEdge( srcMeshDS, srcE, skipMediumNodes, srcNodes) || + !SMESH_Algo::GetSortedNodesOnEdge( tgtMeshDS, tgtE, skipMediumNodes, tgtNodes )) + return SMESH_ComputeError::New( COMPERR_BAD_INPUT_MESH, + "Invalid node parameters on edges"); + + if (( srcNodes.size() != tgtNodes.size() ) && tgtNodes.size() > 0 ) + return SMESH_ComputeError::New( COMPERR_BAD_INPUT_MESH, + "Different number of nodes on edges"); + if ( !tgtNodes.empty() ) + { + map< double, const SMDS_MeshNode* >::iterator u_tn = tgtNodes.begin(); + if ( srcE.Orientation() == tgtE.Orientation() ) + { + map< double, const SMDS_MeshNode* >::iterator u_sn = srcNodes.begin(); + for ( ; u_tn != tgtNodes.end(); ++u_tn, ++u_sn) + src2tgtNodes.insert( make_pair( u_sn->second, u_tn->second )); + } + else + { + map< double, const SMDS_MeshNode* >::reverse_iterator u_sn = srcNodes.rbegin(); + for ( ; u_tn != tgtNodes.end(); ++u_tn, ++u_sn) + src2tgtNodes.insert( make_pair( u_sn->second, u_tn->second )); + } + is1DComputed = true; + } + } + } // loop on EDGEs of a WIRE + + tgtWires[ iW ].reset( new StdMeshers_FaceSide( tgtFace, tgtEdges, tgtMesh, + /*theIsForward = */ true, + /*theIgnoreMediumNodes = */false)); + } // loop on WIREs + + return TError(); + } + + //================================================================================ + /*! + * \brief Preform projection in case if tgtFace.IsPartner( srcFace ) and in case + * if projection by 3D transformation is possible + */ + //================================================================================ + + bool projectPartner(const TopoDS_Face& tgtFace, + const TopoDS_Face& srcFace, + const TSideVector& tgtWires, + const TSideVector& srcWires, + const TAssocTool::TShapeShapeMap& shape2ShapeMap, + TAssocTool::TNodeNodeMap& src2tgtNodes, + const bool is1DComputed) + { + SMESH_Mesh * tgtMesh = tgtWires[0]->GetMesh(); + SMESH_Mesh * srcMesh = srcWires[0]->GetMesh(); + SMESHDS_Mesh* tgtMeshDS = tgtMesh->GetMeshDS(); + SMESHDS_Mesh* srcMeshDS = srcMesh->GetMeshDS(); + SMESH_MesherHelper helper( *tgtMesh ); + const double tol = 1.e-7 * srcMeshDS->getMaxDim(); - gp_Trsf trsf; // transformation to get location of target nodes from source ones + // transformation to get location of target nodes from source ones + StdMeshers_ProjectionUtils::TrsfFinder3D trsf; if ( tgtFace.IsPartner( srcFace )) { gp_Trsf srcTrsf = srcFace.Location(); gp_Trsf tgtTrsf = tgtFace.Location(); - trsf = srcTrsf.Inverted() * tgtTrsf; + trsf.Set( srcTrsf.Inverted() * tgtTrsf ); + // check + gp_Pnt srcP = BRep_Tool::Pnt( srcWires[0]->FirstVertex() ); + gp_Pnt tgtP = BRep_Tool::Pnt( tgtWires[0]->FirstVertex() ); + if ( tgtP.Distance( trsf.Transform( srcP )) > tol ) + trsf.Set( tgtTrsf.Inverted() * srcTrsf ); } else { - // Try to find the transformation + // Try to find the 3D transformation - // make any local coord systems of src and tgt faces - vector srcPP, tgtPP; // 3 points on face boundaries to make axes of CS - int tgtNbVert = SMESH_MesherHelper::Count( tgtFace, TopAbs_VERTEX, /*ignoreSame=*/true ); - int srcNbVert = SMESH_MesherHelper::Count( srcFace, TopAbs_VERTEX, /*ignoreSame=*/true ); - SMESH_subMesh * srcSM = srcMesh->GetSubMesh( srcFace ); - SMESH_subMeshIteratorPtr smIt = srcSM->getDependsOnIterator(/*includeSelf=*/false,false); - srcSM = smIt->next(); // sm of a vertex - while ( smIt->more() && srcPP.size() < 3 ) + const int totNbSeg = 50; + vector< gp_XYZ > srcPnts, tgtPnts; + srcPnts.reserve( totNbSeg ); + tgtPnts.reserve( totNbSeg ); + gp_XYZ srcBC( 0,0,0 ), tgtBC( 0,0,0 ); + for ( size_t iW = 0; iW < srcWires.size(); ++iW ) { - srcSM = smIt->next(); - SMESHDS_SubMesh* srcSmds = srcSM->GetSubMeshDS(); - if ( !srcSmds ) continue; - SMDS_NodeIteratorPtr nIt = srcSmds->GetNodes(); - while ( nIt->more() ) + const double minSegLen = srcWires[iW]->Length() / totNbSeg; + for ( int iE = 0; iE < srcWires[iW]->NbEdges(); ++iE ) { - SMESH_TNodeXYZ p ( nIt->next()); - bool pOK = false; - switch ( srcPP.size() ) + int nbSeg = Max( 1, int( srcWires[iW]->EdgeLength( iE ) / minSegLen )); + double srcU = srcWires[iW]->FirstParameter( iE ); + double tgtU = tgtWires[iW]->FirstParameter( iE ); + double srcDu = ( srcWires[iW]->LastParameter( iE )- srcU ) / nbSeg; + double tgtDu = ( tgtWires[iW]->LastParameter( iE )- tgtU ) / nbSeg; + for ( size_t i = 0; i < nbSeg; ++i ) { - case 0: pOK = true; break; - - case 1: pOK = ( srcPP[0].SquareDistance( p ) > 10*tol ); break; - - case 2: - { - gp_Vec p0p1( srcPP[0], srcPP[1] ), p0p( srcPP[0], p ); - // pOK = !p0p1.IsParallel( p0p, tol ); - pOK = !p0p1.IsParallel( p0p, 3.14/20 ); // angle min 18 degrees - break; - } + srcPnts.push_back( srcWires[iW]->Value3d( srcU ).XYZ() ); + tgtPnts.push_back( tgtWires[iW]->Value3d( tgtU ).XYZ() ); + srcU += srcDu; + tgtU += tgtDu; + srcBC += srcPnts.back(); + tgtBC += tgtPnts.back(); } - if ( !pOK ) - continue; - - // find corresponding point on target shape - pOK = false; - gp_Pnt tgtP; - const TopoDS_Shape& tgtShape = shape2ShapeMap( srcSM->GetSubShape(), /*isSrc=*/true ); - if ( tgtShape.ShapeType() == TopAbs_VERTEX ) - { - tgtP = BRep_Tool::Pnt( TopoDS::Vertex( tgtShape )); - if ( srcNbVert == tgtNbVert || tgtPP.empty() ) - pOK = true; - else - pOK = (( tgtP.Distance( tgtPP[0] ) > tol*tol ) && - ( tgtPP.size() == 1 || tgtP.Distance( tgtPP[1] ) > tol*tol )); - //cout << "V - nS " << p._node->GetID() << " - nT " << SMESH_Algo::VertexNode(TopoDS::Vertex( tgtShape),tgtMeshDS)->GetID() << endl; - } - else if ( tgtPP.size() > 0 ) - { - if ( SMESHDS_SubMesh* tgtSmds = tgtMeshDS->MeshElements( tgtShape )) - { - double srcDist = srcPP[0].Distance( p ); - double eTol = BRep_Tool::Tolerance( TopoDS::Edge( tgtShape )); - if (eTol < tol) eTol = tol; - SMDS_NodeIteratorPtr nItT = tgtSmds->GetNodes(); - while ( nItT->more() && !pOK ) - { - const SMDS_MeshNode* n = nItT->next(); - tgtP = SMESH_TNodeXYZ( n ); - pOK = ( fabs( srcDist - tgtPP[0].Distance( tgtP )) < 2*eTol ); - //cout << "E - nS " << p._node->GetID() << " - nT " << n->GetID()<< " OK - " << pOK<< " " << fabs( srcDist - tgtPP[0].Distance( tgtP ))<< " tol " << eTol<< endl; - } - } - } - if ( !pOK ) - continue; - - srcPP.push_back( p ); - tgtPP.push_back( tgtP ); } } - if ( srcPP.size() != 3 ) + if ( !trsf.Solve( srcPnts, tgtPnts )) return false; - // make transformation - gp_Trsf fromTgtCS, toSrcCS; // from/to global CS - gp_Ax2 srcCS( srcPP[0], gp_Vec( srcPP[0], srcPP[1] ), gp_Vec( srcPP[0], srcPP[2])); - gp_Ax2 tgtCS( tgtPP[0], gp_Vec( tgtPP[0], tgtPP[1] ), gp_Vec( tgtPP[0], tgtPP[2])); - toSrcCS .SetTransformation( gp_Ax3( srcCS )); - fromTgtCS.SetTransformation( gp_Ax3( tgtCS )); - fromTgtCS.Invert(); + // check trsf - trsf = fromTgtCS * toSrcCS; - } - - // Fill map of src to tgt nodes with nodes on edges - - map src2tgtNodes; - map::iterator srcN_tgtN; - - bool tgtEdgesMeshed = false; - for ( TopExp_Explorer srcExp( srcFace, TopAbs_EDGE); srcExp.More(); srcExp.Next() ) - { - const TopoDS_Shape& srcEdge = srcExp.Current(); - const TopoDS_Shape& tgtEdge = shape2ShapeMap( srcEdge, /*isSrc=*/true ); - tgtEdgesMeshed != tgtMesh->GetSubMesh( tgtEdge )->IsEmpty(); - - if ( srcMesh->GetSubMesh( srcEdge )->IsEmpty() || - tgtMesh->GetSubMesh( tgtEdge )->IsEmpty() ) - continue; - - map< double, const SMDS_MeshNode* > srcNodes, tgtNodes; - if (( ! SMESH_Algo::GetSortedNodesOnEdge( srcMeshDS, - TopoDS::Edge( srcEdge ), - /*ignoreMediumNodes = */true, - srcNodes )) - || - ( ! SMESH_Algo::GetSortedNodesOnEdge( tgtMeshDS, - TopoDS::Edge( tgtEdge ), - /*ignoreMediumNodes = */true, - tgtNodes )) - || - (( srcNodes.size() != tgtNodes.size() ) && tgtNodes.size() > 0 ) - ) + bool trsfIsOK = true; + const int nbTestPnt = 20; + const size_t iStep = Max( 1, int( srcPnts.size() / nbTestPnt )); + // check boundary + gp_Pnt trsfTgt = trsf.Transform( srcBC / srcPnts.size() ); + trsfIsOK = ( trsfTgt.SquareDistance( tgtBC / tgtPnts.size() ) < tol*tol ); + for ( size_t i = 0; ( i < srcPnts.size() && trsfIsOK ); i += iStep ) + { + gp_Pnt trsfTgt = trsf.Transform( srcPnts[i] ); + trsfIsOK = ( trsfTgt.SquareDistance( tgtPnts[i] ) < tol*tol ); + } + // check an in-FACE point + if ( trsfIsOK ) + { + BRepAdaptor_Surface srcSurf( srcFace ); + gp_Pnt srcP = + srcSurf.Value( 0.321 * ( srcSurf.FirstUParameter() + srcSurf.LastUParameter() ), + 0.123 * ( srcSurf.FirstVParameter() + srcSurf.LastVParameter() )); + gp_Pnt tgtTrsfP = trsf.Transform( srcP ); + TopLoc_Location loc; + GeomAPI_ProjectPointOnSurf& proj = helper.GetProjector( tgtFace, loc, 0.1*tol ); + if ( !loc.IsIdentity() ) + tgtTrsfP.Transform( loc.Transformation().Inverted() ); + proj.Perform( tgtTrsfP ); + trsfIsOK = ( proj.IsDone() && + proj.NbPoints() > 0 && + proj.LowerDistance() < tol ); + } + if ( !trsfIsOK ) return false; - - if ( !tgtEdge.IsPartner( srcEdge )) - { - if ( tgtNodes.empty() ) - return false; - // check that transformation is OK by three nodes - gp_Pnt p0S = SMESH_TNodeXYZ( (srcNodes.begin()) ->second); - gp_Pnt p1S = SMESH_TNodeXYZ( (srcNodes.rbegin()) ->second); - gp_Pnt p2S = SMESH_TNodeXYZ( (++srcNodes.begin())->second); - - gp_Pnt p0T = SMESH_TNodeXYZ( (tgtNodes.begin()) ->second); - gp_Pnt p1T = SMESH_TNodeXYZ( (tgtNodes.rbegin()) ->second); - gp_Pnt p2T = SMESH_TNodeXYZ( (++tgtNodes.begin())->second); - - // transform source points, they must coincide with target ones - if ( p0T.SquareDistance( p0S.Transformed( trsf )) > tol || - p1T.SquareDistance( p1S.Transformed( trsf )) > tol || - p2T.SquareDistance( p2S.Transformed( trsf )) > tol ) - { - //cout << "KO trsf, 3 dist: " - //<< p0T.SquareDistance( p0S.Transformed( trsf ))<< ", " - //<< p1T.SquareDistance( p1S.Transformed( trsf ))<< ", " - //<< p2T.SquareDistance( p2S.Transformed( trsf ))<< ", "<::iterator u_tn = tgtNodes.begin(); - map< double, const SMDS_MeshNode* >::iterator u_sn = srcNodes.begin(); - for ( ; u_tn != tgtNodes.end(); ++u_tn, ++u_sn) - src2tgtNodes.insert( make_pair( u_sn->second, u_tn->second )); - } } - // check nodes on VERTEXes for a case of not meshes EDGEs - for ( TopExp_Explorer srcExp( srcFace, TopAbs_VERTEX); srcExp.More(); srcExp.Next() ) - { - const TopoDS_Shape& srcV = srcExp.Current(); - const TopoDS_Shape& tgtV = shape2ShapeMap( srcV, /*isSrc=*/true ); - const SMDS_MeshNode* srcN = SMESH_Algo::VertexNode( TopoDS::Vertex( srcV ), srcMeshDS ); - const SMDS_MeshNode* tgtN = SMESH_Algo::VertexNode( TopoDS::Vertex( tgtV ), srcMeshDS ); - if ( !srcN ) - continue; - if ( !tgtN || tgtV.ShapeType() != TopAbs_VERTEX ) - return false; - - if ( !tgtV.IsPartner( srcV )) - { - // check that transformation is OK by three nodes - gp_Pnt p0S = SMESH_TNodeXYZ( srcN ); - gp_Pnt p0T = SMESH_TNodeXYZ( tgtN ); - if ( p0T.SquareDistance( p0S.Transformed( trsf )) > tol ) - { - return false; - } - } - src2tgtNodes.insert( make_pair( srcN, tgtN )); - } - // Make new faces // prepare the helper to adding quadratic elements if necessary - SMESH_MesherHelper helper( *tgtMesh ); helper.SetSubShape( tgtFace ); helper.IsQuadraticSubMesh( tgtFace ); SMESHDS_SubMesh* srcSubDS = srcMeshDS->MeshElements( srcFace ); - if ( !tgtEdgesMeshed && srcSubDS->NbElements() ) + if ( !is1DComputed && srcSubDS->NbElements() ) helper.SetIsQuadratic( srcSubDS->GetElements()->next()->IsQuadratic() ); SMESH_MesherHelper srcHelper( *srcMesh ); srcHelper.SetSubShape( srcFace ); const SMDS_MeshNode* nullNode = 0; + TAssocTool::TNodeNodeMap::iterator srcN_tgtN; // indices of nodes to create properly oriented faces - bool isReverse = ( trsf.Form() != gp_Identity ); + bool isReverse = ( !trsf.IsIdentity() ); int tri1 = 1, tri2 = 2, quad1 = 1, quad3 = 3; if ( isReverse ) std::swap( tri1, tri2 ), std::swap( quad1, quad3 ); @@ -610,7 +664,7 @@ namespace { if ( srcN_tgtN->second == nullNode ) { // create a new node - gp_Pnt tgtP = gp_Pnt( SMESH_TNodeXYZ( srcNode )).Transformed( trsf ); + gp_Pnt tgtP = trsf.Transform( SMESH_TNodeXYZ( srcNode )); SMDS_MeshNode* n = helper.AddNode( tgtP.X(), tgtP.Y(), tgtP.Z() ); srcN_tgtN->second = n; switch ( srcNode->GetPosition()->GetTypeOfPosition() ) @@ -657,7 +711,12 @@ namespace { if ( !tgtFace.IsPartner( srcFace ) ) { + SMESH_MesherHelper edgeHelper( *tgtMesh ); + edgeHelper.ToFixNodeParameters( true ); + helper.ToFixNodeParameters( true ); + int nbOkPos = 0; + bool toCheck = true; const double tol2d = 1e-12; srcN_tgtN = src2tgtNodes.begin(); for ( ; srcN_tgtN != src2tgtNodes.end(); ++srcN_tgtN ) @@ -667,22 +726,20 @@ namespace { { case SMDS_TOP_FACE: { + if ( nbOkPos > 10 ) break; gp_XY uv = helper.GetNodeUV( tgtFace, n ), uvBis = uv; if (( helper.CheckNodeUV( tgtFace, n, uv, tol )) && - (( uv - uvBis ).SquareModulus() < tol2d ) && - ( ++nbOkPos > 10 )) - return true; + (( uv - uvBis ).SquareModulus() < tol2d )) + ++nbOkPos; else - nbOkPos = 0; + nbOkPos = -((int) src2tgtNodes.size() ); break; } case SMDS_TOP_EDGE: { const TopoDS_Edge & tgtE = TopoDS::Edge( tgtMeshDS->IndexToShape( n->getshapeId() )); - double u = helper.GetNodeU( tgtE, n ), uBis = u; - if (( !helper.CheckNodeU( tgtE, n, u, tol )) || - (( u - uBis ) < tol2d )) - nbOkPos = 0; + edgeHelper.SetSubShape( tgtE ); + edgeHelper.GetNodeU( tgtE, n, 0, &toCheck ); break; } default:; @@ -694,95 +751,29 @@ namespace { } // bool projectPartner() - //================================================================================ - /*! - * \brief Check if two consecutive EDGEs are connected in 2D - * \param [in] E1 - a well oriented non-seam EDGE - * \param [in] E2 - a possibly well oriented seam EDGE - * \param [in] F - a FACE - * \return bool - result - */ - //================================================================================ - - bool are2dConnected( const TopoDS_Edge & E1, - const TopoDS_Edge & E2, - const TopoDS_Face & F ) - { - double f,l; - Handle(Geom2d_Curve) c1 = BRep_Tool::CurveOnSurface( E1, F, f, l ); - gp_Pnt2d uvLast1 = c1->Value( E1.Orientation() == TopAbs_REVERSED ? f : l ); - - Handle(Geom2d_Curve) c2 = BRep_Tool::CurveOnSurface( E2, F, f, l ); - gp_Pnt2d uvFirst2 = c2->Value( f ); - gp_Pnt2d uvLast2 = c2->Value( l ); - double tol2 = 1e-5 * uvLast2.SquareDistance( uvFirst2 ); - - return (( uvLast1.SquareDistance( uvFirst2 ) < tol2 ) || - ( uvLast1.SquareDistance( uvLast2 ) < tol2 )); - } - //================================================================================ /*! * \brief Preform projection in case if the faces are similar in 2D space */ //================================================================================ - bool projectBy2DSimilarity(const TopoDS_Face& tgtFace, - const TopoDS_Face& srcFace, - SMESH_Mesh * tgtMesh, - SMESH_Mesh * srcMesh, - const TAssocTool::TShapeShapeMap& shape2ShapeMap, - const bool is1DComputed) + bool projectBy2DSimilarity(const TopoDS_Face& tgtFace, + const TopoDS_Face& srcFace, + const TSideVector& tgtWires, + const TSideVector& srcWires, + const TAssocTool::TShapeShapeMap& shape2ShapeMap, + TAssocTool::TNodeNodeMap& src2tgtNodes, + const bool is1DComputed) { - // 1) Preparation + SMESH_Mesh * tgtMesh = tgtWires[0]->GetMesh(); + SMESH_Mesh * srcMesh = srcWires[0]->GetMesh(); - // get ordered src EDGEs - TError err; - TSideVector srcWires = - StdMeshers_FaceSide::GetFaceWires( srcFace, *srcMesh,/*ignoreMediumNodes = */false, err); - if ( err && !err->IsOK() ) - return false; + // WARNING: we can have problems if the FACE is symmetrical in 2D, + // then the projection can be mirrored relating to what is expected - // make corresponding sequence of tgt EDGEs - TSideVector tgtWires( srcWires.size() ); - for ( size_t iW = 0; iW < srcWires.size(); ++iW ) - { - list< TopoDS_Edge > tgtEdges; - StdMeshers_FaceSidePtr srcWire = srcWires[iW]; - TopTools_IndexedMapOfShape edgeMap; // to detect seam edges - for ( int iE = 0; iE < srcWire->NbEdges(); ++iE ) - { - TopoDS_Edge E = TopoDS::Edge( shape2ShapeMap( srcWire->Edge( iE ), /*isSrc=*/true)); - // reverse a seam edge encountered for the second time - const int index = edgeMap.Add( E ); - if ( index < edgeMap.Extent() ) // E is a seam - { - // check which of edges to reverse, E or one already being in tgtEdges - if ( are2dConnected( tgtEdges.back(), E, tgtFace )) - { - list< TopoDS_Edge >::iterator eIt = tgtEdges.begin(); - std::advance( eIt, index-1 ); - eIt->Reverse(); - } - else - { - E.Reverse(); - } - } - tgtEdges.push_back( E ); - } - tgtWires[ iW ].reset( new StdMeshers_FaceSide( tgtFace, tgtEdges, tgtMesh, - /*theIsForward = */ true, - /*theIgnoreMediumNodes = */false)); - if ( is1DComputed && - srcWires[iW]->GetUVPtStruct().size() != - tgtWires[iW]->GetUVPtStruct().size()) - return false; - } + // 1) Find 2D transformation - // 2) Find transformation - - gp_Trsf2d trsf; + StdMeshers_ProjectionUtils::TrsfFinder2D trsf; { // get 2 pairs of corresponding UVs gp_Pnt2d srcP0 = srcWires[0]->Value2d(0.0); @@ -797,50 +788,63 @@ namespace { toSrcCS .SetTransformation( srcCS ); fromTgtCS.SetTransformation( tgtCS ); fromTgtCS.Invert(); - - trsf = fromTgtCS * toSrcCS; + trsf.Set( fromTgtCS * toSrcCS ); // check transformation + bool trsfIsOK = true; const double tol = 1e-5 * gp_Vec2d( srcP0, srcP1 ).Magnitude(); - for ( double u = 0.12; u < 1.; u += 0.1 ) + for ( double u = 0.12; ( u < 1. && trsfIsOK ); u += 0.1 ) { - gp_Pnt2d srcUV = srcWires[0]->Value2d( u ); - gp_Pnt2d tgtUV = tgtWires[0]->Value2d( u ); - gp_Pnt2d tgtUV2 = srcUV.Transformed( trsf ); - if ( tgtUV.Distance( tgtUV2 ) > tol ) + gp_Pnt2d srcUV = srcWires[0]->Value2d( u ); + gp_Pnt2d tgtUV = tgtWires[0]->Value2d( u ); + gp_Pnt2d tgtUV2 = trsf.Transform( srcUV ); + trsfIsOK = ( tgtUV.Distance( tgtUV2 ) < tol ); + } + + // Find trsf using a least-square approximation + if ( !trsfIsOK ) + { + // find trsf + const int totNbSeg = 50; + vector< gp_XY > srcPnts, tgtPnts; + srcPnts.resize( totNbSeg ); + tgtPnts.resize( totNbSeg ); + for ( size_t iW = 0; iW < srcWires.size(); ++iW ) + { + const double minSegLen = srcWires[iW]->Length() / totNbSeg; + for ( int iE = 0; iE < srcWires[iW]->NbEdges(); ++iE ) + { + int nbSeg = Max( 1, int( srcWires[iW]->EdgeLength( iE ) / minSegLen )); + double srcU = srcWires[iW]->FirstParameter( iE ); + double tgtU = tgtWires[iW]->FirstParameter( iE ); + double srcDu = ( srcWires[iW]->LastParameter( iE )- srcU ) / nbSeg; + double tgtDu = ( tgtWires[iW]->LastParameter( iE )- tgtU ) / nbSeg; + for ( size_t i = 0; i < nbSeg; ++i, srcU += srcDu, tgtU += tgtDu ) + { + srcPnts.push_back( srcWires[iW]->Value2d( srcU ).XY() ); + tgtPnts.push_back( tgtWires[iW]->Value2d( tgtU ).XY() ); + } + } + } + if ( !trsf.Solve( srcPnts, tgtPnts )) + return false; + + // check trsf + + trsfIsOK = true; + const int nbTestPnt = 10; + const size_t iStep = Max( 1, int( srcPnts.size() / nbTestPnt )); + for ( size_t i = 0; ( i < srcPnts.size() && trsfIsOK ); i += iStep ) + { + gp_Pnt2d trsfTgt = trsf.Transform( srcPnts[i] ); + trsfIsOK = ( trsfTgt.Distance( tgtPnts[i] ) < tol ); + } + if ( !trsfIsOK ) return false; } - } + } // "Find transformation" block - // 3) Projection - - typedef map TN2NMap; - TN2NMap src2tgtNodes; - TN2NMap::iterator srcN_tgtN; - - // fill src2tgtNodes in with nodes on EDGEs - for ( unsigned iW = 0; iW < srcWires.size(); ++iW ) - if ( is1DComputed ) - { - const vector& srcUVs = srcWires[iW]->GetUVPtStruct(); - const vector& tgtUVs = tgtWires[iW]->GetUVPtStruct(); - for ( unsigned i = 0; i < srcUVs.size(); ++i ) - src2tgtNodes.insert( make_pair( srcUVs[i].node, tgtUVs[i].node )); - } - else - { - for ( int iE = 0; iE < srcWires[iW]->NbEdges(); ++iE ) - { - TopoDS_Vertex srcV = srcWires[iW]->FirstVertex(iE); - TopoDS_Vertex tgtV = tgtWires[iW]->FirstVertex(iE); - const SMDS_MeshNode* srcNode = SMESH_Algo::VertexNode( srcV, srcMesh->GetMeshDS() ); - const SMDS_MeshNode* tgtNode = SMESH_Algo::VertexNode( tgtV, tgtMesh->GetMeshDS() ); - if ( tgtNode && srcNode ) - src2tgtNodes.insert( make_pair( srcNode, tgtNode )); - } - } - - // make elements + // 2) Projection SMESHDS_SubMesh* srcSubDS = srcMesh->GetMeshDS()->MeshElements( srcFace ); @@ -858,6 +862,7 @@ namespace { srcHelper.SetSubShape( srcFace ); const SMDS_MeshNode* nullNode = 0; + TAssocTool::TNodeNodeMap::iterator srcN_tgtN; SMDS_ElemIteratorPtr elemIt = srcSubDS->GetElements(); vector< const SMDS_MeshNode* > tgtNodes; @@ -876,8 +881,8 @@ namespace { // create a new node gp_Pnt2d srcUV = srcHelper.GetNodeUV( srcFace, srcNode, elem->GetNode( helper.WrapIndex(i+1,nbN)), &uvOK); - gp_Pnt2d tgtUV = srcUV.Transformed( trsf ); - gp_Pnt tgtP = tgtSurface->Value( tgtUV.X(), tgtUV.Y() ); + gp_Pnt2d tgtUV = trsf.Transform( srcUV ); + gp_Pnt tgtP = tgtSurface->Value( tgtUV.X(), tgtUV.Y() ); SMDS_MeshNode* n = tgtMeshDS->AddNode( tgtP.X(), tgtP.Y(), tgtP.Z() ); switch ( srcNode->GetPosition()->GetTypeOfPosition() ) { @@ -888,10 +893,9 @@ namespace { case SMDS_TOP_EDGE: { TopoDS_Shape srcEdge = srcHelper.GetSubShapeByNode( srcNode, srcHelper.GetMeshDS() ); TopoDS_Edge tgtEdge = TopoDS::Edge( shape2ShapeMap( srcEdge, /*isSrc=*/true )); - tgtMeshDS->SetNodeOnEdge( n, TopoDS::Edge( tgtEdge )); - double U = srcHelper.GetNodeU( TopoDS::Edge( srcEdge ), srcNode ); + double U = Precision::Infinite(); helper.CheckNodeU( tgtEdge, n, U, Precision::PConfusion()); - n->SetPosition(SMDS_PositionPtr(new SMDS_EdgePosition( U ))); + tgtMeshDS->SetNodeOnEdge( n, TopoDS::Edge( tgtEdge ), U ); break; } case SMDS_TOP_VERTEX: { @@ -916,16 +920,75 @@ namespace { } // bool projectBy2DSimilarity(...) + //================================================================================ + /*! + * \brief Fix bad faces by smoothing + */ + //================================================================================ + + bool fixDistortedFaces( SMESH_MesherHelper& helper, + TSideVector& tgtWires ) + { + SMESH_subMesh* faceSM = helper.GetMesh()->GetSubMesh( helper.GetSubShape() ); + + if ( helper.IsDistorted2D( faceSM, /*checkUV=*/false )) + { + SMESH_MeshEditor editor( helper.GetMesh() ); + SMESHDS_SubMesh* smDS = faceSM->GetSubMeshDS(); + const TopoDS_Face& F = TopoDS::Face( faceSM->GetSubShape() ); + + TIDSortedElemSet faces; + SMDS_ElemIteratorPtr faceIt = smDS->GetElements(); + for ( faceIt = smDS->GetElements(); faceIt->more(); ) + faces.insert( faces.end(), faceIt->next() ); + + // choose smoothing algo + //SMESH_MeshEditor:: SmoothMethod algo = SMESH_MeshEditor::CENTROIDAL; + bool isConcaveBoundary = false; + for ( size_t iW = 0; iW < tgtWires.size() && !isConcaveBoundary; ++iW ) + { + TopoDS_Edge prevEdge = tgtWires[iW]->Edge( tgtWires[iW]->NbEdges() - 1 ); + for ( int iE = 0; iE < tgtWires[iW]->NbEdges() && !isConcaveBoundary; ++iE ) + { + double angle = helper.GetAngle( prevEdge, tgtWires[iW]->Edge( iE ), + F, tgtWires[iW]->FirstVertex( iE )); + isConcaveBoundary = ( angle < -5. * M_PI / 180. ); + + prevEdge = tgtWires[iW]->Edge( iE ); + } + } + SMESH_MeshEditor:: SmoothMethod algo = + isConcaveBoundary ? SMESH_MeshEditor::CENTROIDAL : SMESH_MeshEditor::LAPLACIAN; + + // smooth in 2D or 3D? + TopLoc_Location loc; + Handle(Geom_Surface) surface = BRep_Tool::Surface( F, loc ); + bool isPlanar = GeomLib_IsPlanarSurface( surface ).IsPlanar(); + + // smoothing + set fixedNodes; + editor.Smooth( faces, fixedNodes, algo, /*nbIterations=*/ 10, + /*theTgtAspectRatio=*/1.0, /*the2D=*/!isPlanar); + + helper.ToFixNodeParameters( true ); + + return !helper.IsDistorted2D( faceSM, /*checkUV=*/true ); + } + return true; + } + } // namespace //======================================================================= //function : Compute -//purpose : +//purpose : //======================================================================= bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theShape) { + _src2tgtNodes.clear(); + MESSAGE("Projection_2D Compute"); if ( !_sourceHypo ) return false; @@ -986,35 +1049,38 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& // Projection // =========== - // find out if EDGEs are meshed or not - bool is1DComputed = false; - SMESH_subMeshIteratorPtr smIt = tgtSubMesh->getDependsOnIterator(/*includeSelf=*/false, - /*complexShapeFirst=*/true); - while ( smIt->more() && !is1DComputed ) - { - SMESH_subMesh* sm = smIt->next(); - if ( sm->GetSubShape().ShapeType() == TopAbs_EDGE ) - is1DComputed = sm->IsMeshComputed(); - } + // get ordered src and tgt EDGEs + TSideVector srcWires, tgtWires; + bool is1DComputed = false; // if any tgt EDGE is meshed + TError err = getWires( tgtFace, srcFace, tgtMesh, srcMesh, + shape2ShapeMap, srcWires, tgtWires, _src2tgtNodes, is1DComputed ); + if ( err && !err->IsOK() ) + return error( err ); - bool done = false; + bool projDone = false; - if ( !done ) + if ( !projDone ) { // try to project from the same face with different location - done = projectPartner( tgtFace, srcFace, tgtMesh, srcMesh, shape2ShapeMap ); + projDone = projectPartner( tgtFace, srcFace, tgtWires, srcWires, + shape2ShapeMap, _src2tgtNodes, is1DComputed ); } - if ( !done ) + if ( !projDone ) { // projection in case if the faces are similar in 2D space - done = projectBy2DSimilarity( tgtFace, srcFace, tgtMesh, srcMesh, shape2ShapeMap, is1DComputed); + projDone = projectBy2DSimilarity( tgtFace, srcFace, tgtWires, srcWires, + shape2ShapeMap, _src2tgtNodes, is1DComputed); } SMESH_MesherHelper helper( theMesh ); helper.SetSubShape( tgtFace ); - if ( !done ) + // it will remove mesh built on edges and vertices in failure case + MeshCleaner cleaner( tgtSubMesh ); + + if ( !projDone ) { + _src2tgtNodes.clear(); // -------------------- // Prepare to mapping // -------------------- @@ -1096,7 +1162,7 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& return error(COMPERR_BAD_INPUT_MESH,"Can't load mesh pattern from the source face"); // -------------------- - // Perform 2D mapping + // Perform 2D mapping // -------------------- // Compute mesh on a target face @@ -1112,13 +1178,9 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK ) return error("Can't make mesh by source mesh pattern"); - // it will remove mesh built by pattern mapper on edges and vertices - // in failure case - MeshCleaner cleaner( tgtSubMesh ); - // ------------------------------------------------------------------------- // mapper doesn't take care of nodes already existing on edges and vertices, - // so we must merge nodes created by it with existing ones + // so we must merge nodes created by it with existing ones // ------------------------------------------------------------------------- SMESH_MeshEditor::TListOfListOfNodes groupsOfNodes; @@ -1126,7 +1188,8 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& // Make groups of nodes to merge // loop on EDGE and VERTEX sub-meshes of a target FACE - smIt = tgtSubMesh->getDependsOnIterator(/*includeSelf=*/false,/*complexShapeFirst=*/false); + SMESH_subMeshIteratorPtr smIt = tgtSubMesh->getDependsOnIterator(/*includeSelf=*/false, + /*complexShapeFirst=*/false); while ( smIt->more() ) { SMESH_subMesh* sm = smIt->next(); @@ -1134,7 +1197,7 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& if ( !smDS || smDS->NbNodes() == 0 ) continue; //if ( !is1DComputed && sm->GetSubShape().ShapeType() == TopAbs_EDGE ) - //break; + // break; if ( helper.IsDegenShape( sm->GetId() ) ) // to merge all nodes on degenerated { @@ -1292,11 +1355,18 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& editor.ConvertToQuadratic(/*theForce3d=*/false, tgtFaces, false); } - cleaner.Release(); // not to remove mesh - } // end of projection using Pattern mapping + if ( !projDone || is1DComputed ) + // ---------------------------------------------------------------- + // The mapper can create distorted faces by placing nodes out of the FACE + // boundary, also bad face can be created if EDGEs already discretized + // --> fix bad faces by smoothing + // ---------------------------------------------------------------- + if ( !fixDistortedFaces( helper, tgtWires )) + return error("Invalid mesh generated"); + // --------------------------- // Check elements orientation // --------------------------- @@ -1342,6 +1412,8 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& } } + cleaner.Release(); // not to remove mesh + return true; } diff --git a/src/StdMeshers/StdMeshers_Projection_2D.hxx b/src/StdMeshers/StdMeshers_Projection_2D.hxx index 57e34dbc4..878d21849 100644 --- a/src/StdMeshers/StdMeshers_Projection_2D.hxx +++ b/src/StdMeshers/StdMeshers_Projection_2D.hxx @@ -30,6 +30,7 @@ #include "SMESH_StdMeshers.hxx" #include "SMESH_Algo.hxx" +#include "StdMeshers_ProjectionUtils.hxx" class StdMeshers_ProjectionSource2D; @@ -59,9 +60,12 @@ public: */ virtual void SetEventListener(SMESH_subMesh* whenSetToSubMesh); -protected: - const StdMeshers_ProjectionSource2D* _sourceHypo; + protected: + + const StdMeshers_ProjectionSource2D* _sourceHypo; + + StdMeshers_ProjectionUtils::TNodeNodeMap _src2tgtNodes; }; diff --git a/src/StdMeshers/StdMeshers_Projection_3D.cxx b/src/StdMeshers/StdMeshers_Projection_3D.cxx index 3079c7bd8..93969dfeb 100644 --- a/src/StdMeshers/StdMeshers_Projection_3D.cxx +++ b/src/StdMeshers/StdMeshers_Projection_3D.cxx @@ -307,7 +307,7 @@ bool StdMeshers_Projection_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aS } } // Find matching nodes of tgt and src faces - TNodeNodeMap faceMatchingNodes; + TAssocTool::TNodeNodeMap faceMatchingNodes; if ( ! TAssocTool::FindMatchingNodesOnFaces( srcFace, srcMesh, tgtFace, tgtMesh, shape2ShapeMap, faceMatchingNodes )) return error(COMPERR_BAD_INPUT_MESH,SMESH_Comment("Mesh on faces #") diff --git a/src/StdMeshers/StdMeshers_Quadrangle_2D.cxx b/src/StdMeshers/StdMeshers_Quadrangle_2D.cxx index a9990e5e7..4d1321497 100644 --- a/src/StdMeshers/StdMeshers_Quadrangle_2D.cxx +++ b/src/StdMeshers/StdMeshers_Quadrangle_2D.cxx @@ -4280,16 +4280,17 @@ int StdMeshers_Quadrangle_2D::getCorners(const TopoDS_Face& theFace, vMap.Add( (*a2v).second ); // check if there are possible variations in choosing corners - bool isThereVariants = false; + bool haveVariants = false; if ( vertexByAngle.size() > nbCorners ) { double lostAngle = a2v->first; double lastAngle = ( --a2v, a2v->first ); - isThereVariants = ( lostAngle * 1.1 >= lastAngle ); + haveVariants = ( lostAngle * 1.1 >= lastAngle ); } + const double angleTol = 5.* M_PI/180; myCheckOri = ( vertexByAngle.size() > nbCorners || - vertexByAngle.begin()->first < 5.* M_PI/180 ); + vertexByAngle.begin()->first < angleTol ); // make theWire begin from a corner vertex or triaVertex if ( nbCorners == 3 ) @@ -4306,9 +4307,10 @@ int StdMeshers_Quadrangle_2D::getCorners(const TopoDS_Face& theFace, vector< double > angles; vector< TopoDS_Edge > edgeVec; vector< int > cornerInd, nbSeg; - angles.reserve( vertexByAngle.size() ); + int nbSegTot = 0; + angles .reserve( vertexByAngle.size() ); edgeVec.reserve( vertexByAngle.size() ); - nbSeg.reserve( vertexByAngle.size() ); + nbSeg .reserve( vertexByAngle.size() ); cornerInd.reserve( nbCorners ); for ( edge = theWire.begin(); edge != theWire.end(); ++edge ) { @@ -4321,105 +4323,219 @@ int StdMeshers_Quadrangle_2D::getCorners(const TopoDS_Face& theFace, theVertices.push_back( v ); cornerInd.push_back( angles.size() ); } - angles.push_back( angleByVertex.IsBound( v ) ? angleByVertex( v ) : -M_PI ); + angles .push_back( angleByVertex.IsBound( v ) ? angleByVertex( v ) : -M_PI ); edgeVec.push_back( *edge ); - if ( theConsiderMesh && isThereVariants ) + if ( theConsiderMesh && haveVariants ) { if ( SMESHDS_SubMesh* sm = helper.GetMeshDS()->MeshElements( *edge )) nbSeg.push_back( sm->NbNodes() + 1 ); else nbSeg.push_back( 0 ); + nbSegTot += nbSeg.back(); } } - // refine the result vector - make sides elual by length if + // refine the result vector - make sides equal by length if // there are several equal angles - if ( isThereVariants ) + if ( haveVariants ) { if ( nbCorners == 3 ) angles[0] = 2 * M_PI; // not to move the base triangle VERTEX - set< int > refinedCorners; + // here we refer to VERTEX'es and EDGEs by indices in angles and edgeVec vectors + typedef int TGeoIndex; + + // for each vertex find a vertex till which there are nbSegHalf segments + const int nbSegHalf = ( nbSegTot % 2 || nbCorners == 3 ) ? 0 : nbSegTot / 2; + vector< TGeoIndex > halfDivider( angles.size(), -1 ); + int nbHalfDividers = 0; + if ( nbSegHalf ) + { + // get min angle of corners + double minAngle = 10.; + for ( size_t iC = 0; iC < cornerInd.size(); ++iC ) + minAngle = Min( minAngle, angles[ cornerInd[ iC ]]); + + // find halfDivider's + for ( TGeoIndex iV1 = 0; iV1 < TGeoIndex( angles.size() ); ++iV1 ) + { + int nbSegs = 0; + TGeoIndex iV2 = iV1; + do { + nbSegs += nbSeg[ iV2 ]; + iV2 = helper.WrapIndex( iV2 + 1, nbSeg.size() ); + } while ( nbSegs < nbSegHalf ); + + if ( nbSegs == nbSegHalf && + angles[ iV1 ] + angleTol >= minAngle && + angles[ iV2 ] + angleTol >= minAngle ) + { + halfDivider[ iV1 ] = iV2; + ++nbHalfDividers; + } + } + } + + set< TGeoIndex > refinedCorners, treatedCorners; for ( size_t iC = 0; iC < cornerInd.size(); ++iC ) { - int iV = cornerInd[iC]; - if ( !refinedCorners.insert( iV ).second ) + TGeoIndex iV = cornerInd[iC]; + if ( !treatedCorners.insert( iV ).second ) continue; - list< int > equalVertices; - equalVertices.push_back( iV ); + list< TGeoIndex > equVerts; // inds of vertices that can become corners + equVerts.push_back( iV ); int nbC[2] = { 0, 0 }; // find equal angles backward and forward from the iV-th corner vertex for ( int isFwd = 0; isFwd < 2; ++isFwd ) { - int dV = isFwd ? +1 : -1; - int iCNext = helper.WrapIndex( iC + dV, cornerInd.size() ); - int iVNext = helper.WrapIndex( iV + dV, angles.size() ); + int dV = isFwd ? +1 : -1; + int iCNext = helper.WrapIndex( iC + dV, cornerInd.size() ); + TGeoIndex iVNext = helper.WrapIndex( iV + dV, angles.size() ); while ( iVNext != iV ) { - bool equal = Abs( angles[iV] - angles[iVNext] ) < 0.1 * angles[iV]; + bool equal = Abs( angles[iV] - angles[iVNext] ) < angleTol; if ( equal ) - equalVertices.insert( isFwd ? equalVertices.end() : equalVertices.begin(), iVNext ); + equVerts.insert( isFwd ? equVerts.end() : equVerts.begin(), iVNext ); if ( iVNext == cornerInd[ iCNext ]) { if ( !equal ) + { + if ( angles[iV] < angles[iVNext] ) + refinedCorners.insert( iVNext ); break; + } nbC[ isFwd ]++; - refinedCorners.insert( cornerInd[ iCNext ] ); + treatedCorners.insert( cornerInd[ iCNext ] ); iCNext = helper.WrapIndex( iCNext + dV, cornerInd.size() ); } iVNext = helper.WrapIndex( iVNext + dV, angles.size() ); } + if ( iVNext == iV ) + break; // all angles equal } - // move corners to make sides equal by length - int nbEqualV = equalVertices.size(); - int nbExcessV = nbEqualV - ( 1 + nbC[0] + nbC[1] ); - if ( nbExcessV > 0 ) + + const bool allCornersSame = ( nbC[0] == 3 ); + if ( allCornersSame && nbHalfDividers > 0 ) { - // calculate normalized length of each side enclosed between neighbor equalVertices - vector< double > curLengths; - double totalLen = 0; - vector< int > evVec( equalVertices.begin(), equalVertices.end() ); - int iEV = 0; - int iE = cornerInd[ helper.WrapIndex( iC - nbC[0] - 1, cornerInd.size() )]; - int iEEnd = cornerInd[ helper.WrapIndex( iC + nbC[1] + 1, cornerInd.size() )]; - while ( curLengths.size() < nbEqualV + 1 ) + // select two halfDivider's as corners + TGeoIndex hd1, hd2 = -1; + int iC2; + for ( iC2 = 0; iC2 < cornerInd.size() && hd2 < 0; ++iC2 ) { - curLengths.push_back( totalLen ); + hd1 = cornerInd[ iC2 ]; + hd2 = halfDivider[ hd1 ]; + if ( std::find( equVerts.begin(), equVerts.end(), hd2 ) == equVerts.end() ) + hd2 = -1; // hd2-th vertex can't become a corner + else + break; + } + if ( hd2 >= 0 ) + { + angles[ hd1 ] = 2 * M_PI; // make hd1-th vertex no more "equal" + angles[ hd2 ] = 2 * M_PI; + refinedCorners.insert( hd1 ); + refinedCorners.insert( hd2 ); + treatedCorners = refinedCorners; + // update cornerInd + equVerts.push_front( equVerts.back() ); + equVerts.push_back( equVerts.front() ); + list< TGeoIndex >::iterator hdPos = + std::find( equVerts.begin(), equVerts.end(), hd2 ); + if ( hdPos == equVerts.end() ) break; + cornerInd[ helper.WrapIndex( iC2 + 0, cornerInd.size()) ] = hd1; + cornerInd[ helper.WrapIndex( iC2 + 1, cornerInd.size()) ] = *( --hdPos ); + cornerInd[ helper.WrapIndex( iC2 + 2, cornerInd.size()) ] = hd2; + cornerInd[ helper.WrapIndex( iC2 + 3, cornerInd.size()) ] = *( ++hdPos, ++hdPos ); + + theVertices[ 0 ] = helper.IthVertex( 0, edgeVec[ cornerInd[0] ]); + theVertices[ 1 ] = helper.IthVertex( 0, edgeVec[ cornerInd[1] ]); + theVertices[ 2 ] = helper.IthVertex( 0, edgeVec[ cornerInd[2] ]); + theVertices[ 3 ] = helper.IthVertex( 0, edgeVec[ cornerInd[3] ]); + iC = -1; + continue; + } + } + + // move corners to make sides equal by length + int nbEqualV = equVerts.size(); + int nbExcessV = nbEqualV - ( 1 + nbC[0] + nbC[1] ); + if ( nbExcessV > 0 ) // there is nbExcessV vertices that can become corners + { + // calculate normalized length of each "side" enclosed between neighbor equVerts + vector< double > accuLength; + double totalLen = 0; + vector< TGeoIndex > evVec( equVerts.begin(), equVerts.end() ); + int iEV = 0; + TGeoIndex iE = cornerInd[ helper.WrapIndex( iC - nbC[0] - 1, cornerInd.size() )]; + TGeoIndex iEEnd = cornerInd[ helper.WrapIndex( iC + nbC[1] + 1, cornerInd.size() )]; + while ( accuLength.size() < nbEqualV + int( !allCornersSame ) ) + { + // accumulate length of edges before iEV-th equal vertex + accuLength.push_back( totalLen ); do { - curLengths.back() += SMESH_Algo::EdgeLength( edgeVec[ iE ]); + accuLength.back() += SMESH_Algo::EdgeLength( edgeVec[ iE ]); iE = helper.WrapIndex( iE + 1, edgeVec.size()); - if ( iEV < evVec.size() && iE == evVec[ iEV++ ] ) - break; + if ( iEV < evVec.size() && iE == evVec[ iEV ] ) { + iEV++; + break; // equal vertex reached + } } while( iE != iEEnd ); - totalLen = curLengths.back(); + totalLen = accuLength.back(); } - curLengths.resize( equalVertices.size() ); - for ( size_t iS = 0; iS < curLengths.size(); ++iS ) - curLengths[ iS ] /= totalLen; + accuLength.resize( equVerts.size() ); + for ( size_t iS = 0; iS < accuLength.size(); ++iS ) + accuLength[ iS ] /= totalLen; - // find equalVertices most close to the ideal sub-division of all sides + // find equVerts most close to the ideal sub-division of all sides int iBestEV = 0; int iCorner = helper.WrapIndex( iC - nbC[0], cornerInd.size() ); - int nbSides = 2 + nbC[0] + nbC[1]; + int nbSides = Min( nbCorners, 2 + nbC[0] + nbC[1] ); for ( int iS = 1; iS < nbSides; ++iS, ++iBestEV ) { double idealLen = iS / double( nbSides ); - double d, bestDist = 1.; - for ( iEV = iBestEV; iEV < curLengths.size(); ++iEV ) - if (( d = Abs( idealLen - curLengths[ iEV ])) < bestDist ) + double d, bestDist = 2.; + for ( iEV = iBestEV; iEV < accuLength.size(); ++iEV ) + { + d = Abs( idealLen - accuLength[ iEV ]); + + // take into account presence of a coresponding halfDivider + const double cornerWgt = 0.5 / nbSides; + const double vertexWgt = 0.25 / nbSides; + TGeoIndex hd = halfDivider[ evVec[ iEV ]]; + if ( hd < 0 ) + d += vertexWgt; + else if( refinedCorners.count( hd )) + d -= cornerWgt; + else + d -= vertexWgt; + + // choose vertex with the best d + if ( d < bestDist ) { bestDist = d; iBestEV = iEV; } + } if ( iBestEV > iS-1 + nbExcessV ) iBestEV = iS-1 + nbExcessV; theVertices[ iCorner ] = helper.IthVertex( 0, edgeVec[ evVec[ iBestEV ]]); + refinedCorners.insert( evVec[ iBestEV ]); iCorner = helper.WrapIndex( iCorner + 1, cornerInd.size() ); } + + } // if ( nbExcessV > 0 ) + else + { + refinedCorners.insert( cornerInd[ iC ]); } - } - } + } // loop on cornerInd + + // make theWire begin from the cornerInd[0]-th EDGE + while ( !theWire.front().IsSame( edgeVec[ cornerInd[0] ])) + theWire.splice( theWire.begin(), theWire, --theWire.end() ); + + } // if ( haveVariants ) return nbCorners; } diff --git a/src/StdMeshers/StdMeshers_RadialPrism_3D.cxx b/src/StdMeshers/StdMeshers_RadialPrism_3D.cxx index 17411417e..5ef61aab9 100644 --- a/src/StdMeshers/StdMeshers_RadialPrism_3D.cxx +++ b/src/StdMeshers/StdMeshers_RadialPrism_3D.cxx @@ -57,11 +57,7 @@ #include #include #include -#if OCC_VERSION_LARGE > 0x06050400 #include -#else -#include -#endif using namespace std; @@ -169,11 +165,7 @@ bool StdMeshers_RadialPrism_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& a // get 2 shells TopoDS_Solid solid = TopoDS::Solid( aShape ); -#if OCC_VERSION_LARGE > 0x06050400 TopoDS_Shell outerShell = BRepClass3d::OuterShell( solid ); -#else - TopoDS_Shell outerShell = BRepTools::OuterShell( solid ); -#endif TopoDS_Shape innerShell; int nbShells = 0; for ( TopoDS_Iterator It (solid); It.More(); It.Next(), ++nbShells ) @@ -187,13 +179,13 @@ bool StdMeshers_RadialPrism_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& a // ---------------------------------- ProjectionUtils::TShapeShapeMap shape2ShapeMaps[2]; - if ( !ProjectionUtils::FindSubShapeAssociation( innerShell, &aMesh, - outerShell, &aMesh, - shape2ShapeMaps[0]) - && - !ProjectionUtils::FindSubShapeAssociation( innerShell.Reversed(), &aMesh, - outerShell, &aMesh, - shape2ShapeMaps[1])) + bool mapOk1 = ProjectionUtils::FindSubShapeAssociation( innerShell, &aMesh, + outerShell, &aMesh, + shape2ShapeMaps[0]); + bool mapOk2 = ProjectionUtils::FindSubShapeAssociation( innerShell.Reversed(), &aMesh, + outerShell, &aMesh, + shape2ShapeMaps[1]); + if ( !mapOk1 && !mapOk2 ) return error(COMPERR_BAD_SHAPE,"Topology of inner and outer shells seems different" ); int iMap; @@ -239,7 +231,7 @@ bool StdMeshers_RadialPrism_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& a } // Find matching nodes of in and out faces - TNodeNodeMap nodeIn2OutMap; + ProjectionUtils::TNodeNodeMap nodeIn2OutMap; if ( ! ProjectionUtils::FindMatchingNodesOnFaces( inFace, &aMesh, outFace, &aMesh, shape2ShapeMap, nodeIn2OutMap )) return error(COMPERR_BAD_INPUT_MESH,SMESH_Comment("Mesh on faces #") @@ -439,11 +431,7 @@ bool StdMeshers_RadialPrism_3D::Evaluate(SMESH_Mesh& aMesh, { // get 2 shells TopoDS_Solid solid = TopoDS::Solid( aShape ); -#if OCC_VERSION_LARGE > 0x06050400 TopoDS_Shell outerShell = BRepClass3d::OuterShell( solid ); -#else - TopoDS_Shell outerShell = BRepTools::OuterShell( solid ); -#endif TopoDS_Shape innerShell; int nbShells = 0; for ( TopoDS_Iterator It (solid); It.More(); It.Next(), ++nbShells ) diff --git a/src/StdMeshers/StdMeshers_Regular_1D.cxx b/src/StdMeshers/StdMeshers_Regular_1D.cxx index cc964cfac..a7e67cfeb 100644 --- a/src/StdMeshers/StdMeshers_Regular_1D.cxx +++ b/src/StdMeshers/StdMeshers_Regular_1D.cxx @@ -68,6 +68,7 @@ #include using namespace std; +using namespace StdMeshers; //============================================================================= /*! diff --git a/src/StdMeshers/StdMeshers_ViscousLayers.cxx b/src/StdMeshers/StdMeshers_ViscousLayers.cxx index db5469ea2..704144d7a 100644 --- a/src/StdMeshers/StdMeshers_ViscousLayers.cxx +++ b/src/StdMeshers/StdMeshers_ViscousLayers.cxx @@ -44,6 +44,7 @@ #include "SMESH_subMeshEventListener.hxx" #include "StdMeshers_FaceSide.hxx" +#include #include #include #include @@ -75,6 +76,8 @@ #include #include #include +#include +#include #include #include @@ -83,7 +86,10 @@ #include #include -#define __myDEBUG +#ifdef _DEBUG_ +//#define __myDEBUG +//#define __NOT_INVALIDATE_BAD_SMOOTH +#endif using namespace std; @@ -97,6 +103,10 @@ namespace VISCOUS_3D const double theMinSmoothCosin = 0.1; const double theSmoothThickToElemSizeRatio = 0.3; + // what part of thickness is allowed till intersection + // (defined by SALOME_TESTS/Grids/smesh/viscous_layers_00/A5) + const double theThickToIntersection = 1.5; + bool needSmoothing( double cosin, double tgtThick, double elemSize ) { return cosin * tgtThick > theSmoothThickToElemSizeRatio * elemSize; @@ -109,7 +119,8 @@ namespace VISCOUS_3D struct _MeshOfSolid : public SMESH_ProxyMesh, public SMESH_subMeshEventListenerData { - bool _n2nMapComputed; + bool _n2nMapComputed; + SMESH_ComputeErrorPtr _warning; _MeshOfSolid( SMESH_Mesh* mesh) :SMESH_subMeshEventListenerData( /*isDeletable=*/true),_n2nMapComputed(false) @@ -173,7 +184,8 @@ namespace VISCOUS_3D SMESH_subMeshEventListenerData* data, const SMESH_Hypothesis* hyp) { - if ( SMESH_subMesh::COMPUTE_EVENT == eventType ) + if ( SMESH_subMesh::COMPUTE_EVENT == eventType && + SMESH_subMesh::CHECK_COMPUTE_STATE != event) { // delete SMESH_ProxyMesh containing temporary faces subMesh->DeleteEventListener( this ); @@ -228,6 +240,7 @@ namespace VISCOUS_3D sub->SetEventListener( _ShrinkShapeListener::Get(), data, /*whereToListenTo=*/mainSM ); } } + struct _SolidData; //-------------------------------------------------------------------------------- /*! * \brief Simplex (triangle or tetrahedron) based on 1 (tria) or 2 (tet) nodes of @@ -243,19 +256,19 @@ namespace VISCOUS_3D const SMDS_MeshNode* nNext=0, const SMDS_MeshNode* nOpp=0) : _nPrev(nPrev), _nNext(nNext), _nOpp(nOpp) {} - bool IsForward(const SMDS_MeshNode* nSrc, const gp_XYZ* pntTgt) const + bool IsForward(const SMDS_MeshNode* nSrc, const gp_XYZ* pntTgt, double& vol) const { const double M[3][3] = {{ _nNext->X() - nSrc->X(), _nNext->Y() - nSrc->Y(), _nNext->Z() - nSrc->Z() }, { pntTgt->X() - nSrc->X(), pntTgt->Y() - nSrc->Y(), pntTgt->Z() - nSrc->Z() }, { _nPrev->X() - nSrc->X(), _nPrev->Y() - nSrc->Y(), _nPrev->Z() - nSrc->Z() }}; - double determinant = ( + M[0][0]*M[1][1]*M[2][2] - + M[0][1]*M[1][2]*M[2][0] - + M[0][2]*M[1][0]*M[2][1] - - M[0][0]*M[1][2]*M[2][1] - - M[0][1]*M[1][0]*M[2][2] - - M[0][2]*M[1][1]*M[2][0]); - return determinant > 1e-100; + vol = ( + M[0][0]*M[1][1]*M[2][2] + + M[0][1]*M[1][2]*M[2][0] + + M[0][2]*M[1][0]*M[2][1] + - M[0][0]*M[1][2]*M[2][1] + - M[0][1]*M[1][0]*M[2][2] + - M[0][2]*M[1][1]*M[2][0]); + return vol > 1e-100; } bool IsForward(const gp_XY& tgtUV, const SMDS_MeshNode* smoothedNode, @@ -273,6 +286,12 @@ namespace VISCOUS_3D { return _nPrev == other._nNext || _nNext == other._nPrev; } + static void GetSimplices( const SMDS_MeshNode* node, + vector<_Simplex>& simplices, + const set& ingnoreShapes, + const _SolidData* dataToCheckOri = 0, + const bool toSort = false); + static void SortSimplices(vector<_Simplex>& simplices); }; //-------------------------------------------------------------------------------- /*! @@ -301,7 +320,12 @@ namespace VISCOUS_3D double lenDelta(double len) const { return _k * ( _r + len ); } double lenDeltaByDist(double dist) const { return dist * _h2lenRatio; } }; + //-------------------------------------------------------------------------------- + struct _2NearEdges; + struct _LayerEdge; + typedef map< const SMDS_MeshNode*, _LayerEdge*, TIDCompare > TNode2Edge; + //-------------------------------------------------------------------------------- /*! * \brief Edge normal to surface, connecting a node on solid surface (_nodes[0]) @@ -309,6 +333,8 @@ namespace VISCOUS_3D */ struct _LayerEdge { + typedef gp_XYZ (_LayerEdge::*PSmooFun)(); + vector< const SMDS_MeshNode*> _nodes; gp_XYZ _normal; // to solid surface @@ -322,6 +348,7 @@ namespace VISCOUS_3D // simplices connected to the source node (_nodes[0]); // used for smoothing and quality check of _LayerEdge's based on the FACE vector<_Simplex> _simplices; + PSmooFun _smooFunction; // smoothing function // data for smoothing of _LayerEdge's based on the EDGE _2NearEdges* _2neibors; @@ -336,7 +363,9 @@ namespace VISCOUS_3D const SMDS_MeshNode* n2, SMESH_MesherHelper& helper); void InvalidateStep( int curStep, bool restoreLength=false ); - bool Smooth(int& badNb); + void ChooseSmooFunction(const set< TGeomID >& concaveVertices, + const TNode2Edge& n2eMap); + int Smooth(const int step, const bool isConcaveFace, const bool findBest); bool SmoothOnEdge(Handle(Geom_Surface)& surface, const TopoDS_Face& F, SMESH_MesherHelper& helper); @@ -356,7 +385,30 @@ namespace VISCOUS_3D gp_XYZ Copy( _LayerEdge& other, SMESH_MesherHelper& helper ); void SetCosin( double cosin ); int NbSteps() const { return _pos.size() - 1; } // nb inlation steps + + gp_XYZ smoothLaplacian(); + gp_XYZ smoothAngular(); + gp_XYZ smoothLengthWeighted(); + gp_XYZ smoothCentroidal(); + gp_XYZ smoothNefPolygon(); + + enum { FUN_LAPLACIAN, FUN_LENWEIGHTED, FUN_CENTROIDAL, FUN_NEFPOLY, FUN_ANGULAR, FUN_NB }; + static const int theNbSmooFuns = FUN_NB; + static PSmooFun _funs[theNbSmooFuns]; + static const char* _funNames[theNbSmooFuns+1]; + int smooFunID( PSmooFun fun=0) const; }; + _LayerEdge::PSmooFun _LayerEdge::_funs[theNbSmooFuns] = { &_LayerEdge::smoothLaplacian, + &_LayerEdge::smoothLengthWeighted, + &_LayerEdge::smoothCentroidal, + &_LayerEdge::smoothNefPolygon, + &_LayerEdge::smoothAngular }; + const char* _LayerEdge::_funNames[theNbSmooFuns+1] = { "Laplacian", + "LengthWeighted", + "Centroidal", + "NefPolygon", + "Angular", + "None"}; struct _LayerEdgeCmp { bool operator () (const _LayerEdge* e1, const _LayerEdge* e2) const @@ -365,7 +417,29 @@ namespace VISCOUS_3D return cmpNodes ? ( e1->_nodes[0]->GetID() < e2->_nodes[0]->GetID()) : ( e1 < e2 ); } }; - struct _LayerEdge; + //-------------------------------------------------------------------------------- + /*! + * A 2D half plane used by _LayerEdge::smoothNefPolygon() + */ + struct _halfPlane + { + gp_XY _pos, _dir, _inNorm; + bool IsOut( const gp_XY p, const double tol ) const + { + return _inNorm * ( p - _pos ) < -tol; + } + bool FindInterestion( const _halfPlane& hp, gp_XY & intPnt ) + { + const double eps = 1e-10; + double D = _dir.Crossed( hp._dir ); + if ( fabs(D) < std::numeric_limits::min()) + return false; + gp_XY vec21 = _pos - hp._pos; + double u = hp._dir.Crossed( vec21 ) / D; + intPnt = _pos + _dir * u; + return true; + } + }; //-------------------------------------------------------------------------------- /*! * Structure used to smooth a _LayerEdge based on an EDGE. @@ -433,7 +507,7 @@ namespace VISCOUS_3D _nbHyps++; _nbLayers = hyp->GetNumberLayers(); //_thickness += hyp->GetTotalThickness(); - _thickness = Max( _thickness, hyp->GetTotalThickness() ); + _thickness = Max( _thickness, hyp->GetTotalThickness() ); _stretchFactor += hyp->GetStretchFactor(); } } @@ -445,10 +519,6 @@ namespace VISCOUS_3D double _thickness, _stretchFactor; }; - //-------------------------------------------------------------------------------- - - typedef map< const SMDS_MeshNode*, _LayerEdge*, TIDCompare > TNode2Edge; - //-------------------------------------------------------------------------------- /*! * \brief Data of a SOLID @@ -485,7 +555,7 @@ namespace VISCOUS_3D // Convex FACEs whose radius of curvature is less than the thickness of layers map< TGeomID, _ConvexFace > _convexFaces; - // shapes (EDGEs and VERTEXes) srink from which is forbiden due to collisions with + // shapes (EDGEs and VERTEXes) srink from which is forbidden due to collisions with // the adjacent SOLID set< TGeomID > _noShrinkShapes; @@ -495,6 +565,7 @@ namespace VISCOUS_3D // end indices in _edges of _LayerEdge on each shape, first go shapes to smooth vector< int > _endEdgeOnShape; int _nbShapesToSmooth; + set< TGeomID > _concaveFaces; // data of averaged StdMeshers_ViscousLayers parameters for each shape with _LayerEdge's vector< AverageHyp > _hypOnShape; @@ -511,15 +582,17 @@ namespace VISCOUS_3D Handle(Geom_Curve) CurveForSmooth( const TopoDS_Edge& E, const int iFrom, const int iTo, - Handle(Geom_Surface)& surface, const TopoDS_Face& F, - SMESH_MesherHelper& helper); + SMESH_MesherHelper& helper, + vector<_LayerEdge* >* edges=0); void SortOnEdge( const TopoDS_Edge& E, const int iFrom, const int iTo, SMESH_MesherHelper& helper); + void Sort2NeiborsOnEdge( const int iFrom, const int iTo); + _ConvexFace* GetConvexFace( const TGeomID faceID ) { map< TGeomID, _ConvexFace >::iterator id2face = _convexFaces.find( faceID ); @@ -534,6 +607,11 @@ namespace VISCOUS_3D bool GetShapeEdges(const TGeomID shapeID, size_t& iEdgeEnd, int* iBeg=0, int* iEnd=0 ) const; void AddShapesToSmooth( const set< TGeomID >& shapeIDs ); + + void PrepareEdgesToSmoothOnFace( _LayerEdge** edgeBeg, + _LayerEdge** edgeEnd, + const TopoDS_Face& face, + bool substituteSrcNodes ); }; //-------------------------------------------------------------------------------- /*! @@ -624,17 +702,17 @@ namespace VISCOUS_3D SMESH_MesherHelper& helper, bool& isOK, bool shiftInside=false); - gp_XYZ getWeigthedNormal( const SMDS_MeshNode* n, - std::pair< TGeomID, gp_XYZ > fId2Normal[], - const int nbFaces ); + bool getFaceNormalAtSingularity(const gp_XY& uv, + const TopoDS_Face& face, + SMESH_MesherHelper& helper, + gp_Dir& normal ); + gp_XYZ getWeigthedNormal( const SMDS_MeshNode* n, + std::pair< TopoDS_Face, gp_XYZ > fId2Normal[], + int nbFaces ); bool findNeiborsOnEdge(const _LayerEdge* edge, const SMDS_MeshNode*& n1, const SMDS_MeshNode*& n2, _SolidData& data); - void getSimplices( const SMDS_MeshNode* node, vector<_Simplex>& simplices, - const set& ingnoreShapes, - const _SolidData* dataToCheckOri = 0, - const bool toSort = false); void findSimplexTestEdges( _SolidData& data, vector< vector<_LayerEdge*> >& edgesByGeom); void computeGeomSize( _SolidData& data ); @@ -833,6 +911,14 @@ StdMeshers_ViscousLayers::Compute(SMESH_Mesh& theMesh, return SMESH_ProxyMesh::Ptr(); components.push_back( SMESH_ProxyMesh::Ptr( pm )); pm->myIsDeletable = false; // it will de deleted by boost::shared_ptr + + if ( pm->_warning && !pm->_warning->IsOK() ) + { + SMESH_subMesh* sm = theMesh.GetSubMesh( exp.Current() ); + SMESH_ComputeErrorPtr& smError = sm->GetComputeError(); + if ( !smError || smError->IsOK() ) + smError = pm->_warning; + } } _ViscousListener::RemoveSolidMesh ( &theMesh, exp.Current() ); } @@ -899,7 +985,7 @@ bool StdMeshers_ViscousLayers::IsShapeWithLayers(int shapeIndex) const // END StdMeshers_ViscousLayers hypothesis //================================================================================ -namespace +namespace VISCOUS_3D { gp_XYZ getEdgeDir( const TopoDS_Edge& E, const TopoDS_Vertex& fromV ) { @@ -1038,14 +1124,56 @@ namespace return dir; } + + //================================================================================ + /*! + * \brief Finds concave VERTEXes of a FACE + */ + //================================================================================ + + bool getConcaveVertices( const TopoDS_Face& F, + SMESH_MesherHelper& helper, + set< TGeomID >* vertices = 0) + { + // check angles at VERTEXes + TError error; + TSideVector wires = StdMeshers_FaceSide::GetFaceWires( F, *helper.GetMesh(), 0, error ); + for ( size_t iW = 0; iW < wires.size(); ++iW ) + { + const int nbEdges = wires[iW]->NbEdges(); + if ( nbEdges < 2 && SMESH_Algo::isDegenerated( wires[iW]->Edge(0))) + continue; + for ( int iE1 = 0; iE1 < nbEdges; ++iE1 ) + { + if ( SMESH_Algo::isDegenerated( wires[iW]->Edge( iE1 ))) continue; + int iE2 = ( iE1 + 1 ) % nbEdges; + while ( SMESH_Algo::isDegenerated( wires[iW]->Edge( iE2 ))) + iE2 = ( iE2 + 1 ) % nbEdges; + TopoDS_Vertex V = wires[iW]->FirstVertex( iE2 ); + double angle = helper.GetAngle( wires[iW]->Edge( iE1 ), + wires[iW]->Edge( iE2 ), F, V ); + if ( angle < -5. * M_PI / 180. ) + { + if ( !vertices ) + return true; + vertices->insert( helper.GetMeshDS()->ShapeToIndex( V )); + } + } + } + return vertices ? !vertices->empty() : false; + } + //================================================================================ /*! * \brief Returns true if a FACE is bound by a concave EDGE */ //================================================================================ - bool isConcave( const TopoDS_Face& F, SMESH_MesherHelper& helper ) + bool isConcave( const TopoDS_Face& F, + SMESH_MesherHelper& helper, + set< TGeomID >* vertices = 0 ) { + bool isConcv = false; // if ( helper.Count( F, TopAbs_WIRE, /*useMap=*/false) > 1 ) // return true; gp_Vec2d drv1, drv2; @@ -1074,32 +1202,21 @@ namespace if ( !isConvex ) { //cout << "Concave FACE " << helper.GetMeshDS()->ShapeToIndex( F ) << endl; - return true; - } - } - // check angles at VERTEXes - TError error; - TSideVector wires = StdMeshers_FaceSide::GetFaceWires( F, *helper.GetMesh(), 0, error ); - for ( size_t iW = 0; iW < wires.size(); ++iW ) - { - const int nbEdges = wires[iW]->NbEdges(); - if ( nbEdges < 2 && SMESH_Algo::isDegenerated( wires[iW]->Edge(0))) - continue; - for ( int iE1 = 0; iE1 < nbEdges; ++iE1 ) - { - if ( SMESH_Algo::isDegenerated( wires[iW]->Edge( iE1 ))) continue; - int iE2 = ( iE1 + 1 ) % nbEdges; - while ( SMESH_Algo::isDegenerated( wires[iW]->Edge( iE2 ))) - iE2 = ( iE2 + 1 ) % nbEdges; - double angle = helper.GetAngle( wires[iW]->Edge( iE1 ), - wires[iW]->Edge( iE2 ), F, - wires[iW]->FirstVertex( iE2 )); - if ( angle < -5. * M_PI / 180. ) + isConcv = true; + if ( vertices ) + break; + else return true; } } - return false; + + // check angles at VERTEXes + if ( getConcaveVertices( F, helper, vertices )) + isConcv = true; + + return isConcv; } + //================================================================================ /*! * \brief Computes mimimal distance of face in-FACE nodes from an EDGE @@ -1152,6 +1269,43 @@ namespace } return done; } + //================================================================================ + /*! + * \brief Return direction of axis or revolution of a surface + */ + //================================================================================ + + bool getRovolutionAxis( const Adaptor3d_Surface& surface, + gp_Dir & axis ) + { + switch ( surface.GetType() ) { + case GeomAbs_Cone: + { + gp_Cone cone = surface.Cone(); + axis = cone.Axis().Direction(); + break; + } + case GeomAbs_Sphere: + { + gp_Sphere sphere = surface.Sphere(); + axis = sphere.Position().Direction(); + break; + } + case GeomAbs_SurfaceOfRevolution: + { + axis = surface.AxeOfRevolution().Direction(); + break; + } + //case GeomAbs_SurfaceOfExtrusion: + case GeomAbs_OffsetSurface: + { + Handle(Adaptor3d_HSurface) base = surface.BasisSurface(); + return getRovolutionAxis( base->Surface(), axis ); + } + default: return false; + } + return true; + } //-------------------------------------------------------------------------------- // DEBUG. Dump intermediate node positions into a python script @@ -1159,18 +1313,19 @@ namespace // construction steps of viscous layers #ifdef __myDEBUG ofstream* py; - int theNbFunc; + int theNbPyFunc; struct PyDump { - PyDump() { + PyDump(SMESH_Mesh& m) { + int tag = 3 + m.GetId(); const char* fname = "/tmp/viscous.py"; cout << "execfile('"<GetID()<< ", "<< n->X() - << ", "<Y()<<", "<< n->Z()<< ")\t\t # "<< ln <Y()<<", "<< n->Z()<< ")\t\t # "<< ln <<" "<< txt << endl; } void _dumpCmd(const string& txt, int ln) { if (py) *py<< " "<GetNode( f->NbNodes()-1 )->GetID() << " ])"<< endl; }} #define debugMsg( txt ) { cout << txt << " (line: " << __LINE__ << ")" << endl; } #else - struct PyDump { void Finish() {} }; + struct PyDump { PyDump(SMESH_Mesh&) {} void Finish() {} }; #define dumpFunction(f) f #define dumpMove(n) +#define dumpMoveComm(n,txt) #define dumpCmd(txt) #define dumpFunctionEnd() #define dumpChangeNodes(f) @@ -1342,7 +1499,7 @@ SMESH_ComputeErrorPtr _ViscousBuilder::Compute(SMESH_Mesh& theMesh, if ( _ViscousListener::GetSolidMesh( _mesh, exp.Current(), /*toCreate=*/false)) return SMESH_ComputeErrorPtr(); // everything already computed - PyDump debugDump; + PyDump debugDump( theMesh ); // TODO: ignore already computed SOLIDs if ( !findSolidsWithLayers()) @@ -1547,27 +1704,28 @@ bool _ViscousBuilder::findFacesWithLayers(const bool onlyWith) { _sdVec[i]._ignoreFaceIds.swap( ignoreFacesOfHyps.back().first ); } - - // fill _SolidData::_reversedFaceIds - { - exp.Init( _sdVec[i]._solid.Oriented( TopAbs_FORWARD ), TopAbs_FACE ); - for ( ; exp.More(); exp.Next() ) - { - const TopoDS_Face& face = TopoDS::Face( exp.Current() ); - const TGeomID faceID = getMeshDS()->ShapeToIndex( face ); - if ( //!sdVec[i]._ignoreFaceIds.count( faceID ) && ??????? - helper.NbAncestors( face, *_mesh, TopAbs_SOLID ) > 1 && - helper.IsReversedSubMesh( face )) - { - _sdVec[i]._reversedFaceIds.insert( faceID ); - } - } - } } // loop on _sdVec if ( onlyWith ) // is called to check hypotheses compatibility only return true; + // fill _SolidData::_reversedFaceIds + for ( size_t i = 0; i < _sdVec.size(); ++i ) + { + exp.Init( _sdVec[i]._solid.Oriented( TopAbs_FORWARD ), TopAbs_FACE ); + for ( ; exp.More(); exp.Next() ) + { + const TopoDS_Face& face = TopoDS::Face( exp.Current() ); + const TGeomID faceID = getMeshDS()->ShapeToIndex( face ); + if ( //!sdVec[i]._ignoreFaceIds.count( faceID ) && + helper.NbAncestors( face, *_mesh, TopAbs_SOLID ) > 1 && + helper.IsReversedSubMesh( face )) + { + _sdVec[i]._reversedFaceIds.insert( faceID ); + } + } + } + // Find faces to shrink mesh on (solution 2 in issue 0020832); TopTools_IndexedMapOfShape shapes; for ( size_t i = 0; i < _sdVec.size(); ++i ) @@ -1849,14 +2007,16 @@ bool _ViscousBuilder::makeLayer(_SolidData& data) 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() )) { - SMESH_subMesh* fSubM = _mesh->GetSubMesh( exp.Current() ); - if ( ! data._ignoreFaceIds.count( fSubM->GetId() )) - faceIds.insert( fSubM->GetId() ); + faceIds.insert( fSubM->GetId() ); SMESH_subMeshIteratorPtr subIt = fSubM->getDependsOnIterator(/*includeSelf=*/true); while ( subIt->more() ) subIds.insert( subIt->next()->GetId() ); } + } // make a map to find new nodes on sub-shapes shared with other SOLID map< TGeomID, TNode2Edge* >::iterator s2ne; @@ -1879,7 +2039,7 @@ bool _ViscousBuilder::makeLayer(_SolidData& data) // Create temporary faces and _LayerEdge's - dumpFunction(SMESH_Comment("makeLayers_")<::iterator e2c = data._edge2curve.begin(); + for ( ; e2c != data._edge2curve.end(); ++e2c ) + if ( !e2c->second.IsNull() ) + { + size_t iEdgeEnd; int iBeg, iEnd; + if ( data.GetShapeEdges( e2c->first, iEdgeEnd, &iBeg, &iEnd )) + data.Sort2NeiborsOnEdge( iBeg, iEnd ); + } + dumpFunctionEnd(); return true; } @@ -2168,7 +2338,8 @@ void _ViscousBuilder::limitStepSizeByCurvature( _SolidData& data ) else continue; // check concavity and curvature and limit data._stepSize - const double minCurvature = 0.9 / data._hypOnShape[ edgesEnd ].GetTotalThickness(); + const double minCurvature = + 1. / ( data._hypOnShape[ edgesEnd ].GetTotalThickness() * ( 1+theThickToIntersection )); int nbLEdges = iEnd - iBeg; int iStep = Max( 1, nbLEdges / nbTestPnt ); for ( ; iBeg < iEnd; iBeg += iStep ) @@ -2239,7 +2410,7 @@ void _ViscousBuilder::limitStepSizeByCurvature( _SolidData& data ) const SMDS_MeshNode* srcNode = ledge->_nodes[0]; if ( !usedNodes.insert( srcNode ).second ) continue; - getSimplices( srcNode, ledge->_simplices, data._ignoreFaceIds, &data ); + _Simplex::GetSimplices( srcNode, ledge->_simplices, data._ignoreFaceIds, &data ); for ( size_t i = 0; i < ledge->_simplices.size(); ++i ) { usedNodes.insert( ledge->_simplices[i]._nPrev ); @@ -2278,104 +2449,133 @@ bool _ViscousBuilder::sortEdges( _SolidData& data, // boundry inclined to the shape at a sharp angle list< TGeomID > shapesToSmooth; - + TopTools_MapOfShape edgesOfSmooFaces; + SMESH_MesherHelper helper( *_mesh ); bool ok = true; - for ( size_t iS = 0; iS < edgesByGeom.size(); ++iS ) + for ( int isEdge = 0; isEdge < 2; ++isEdge ) // loop on [ FACEs, EDGEs ] { - vector<_LayerEdge*>& eS = edgesByGeom[iS]; - if ( eS.empty() ) continue; - const TopoDS_Shape& S = getMeshDS()->IndexToShape( iS ); - bool needSmooth = false; - switch ( S.ShapeType() ) - { - case TopAbs_EDGE: { + const int dim = isEdge ? 1 : 2; - if ( SMESH_Algo::isDegenerated( TopoDS::Edge( S ))) - break; - //bool isShrinkEdge = !eS[0]->_sWOL.IsNull(); - for ( TopoDS_Iterator vIt( S ); vIt.More() && !needSmooth; vIt.Next() ) + for ( size_t iS = 0; iS < edgesByGeom.size(); ++iS ) + { + vector<_LayerEdge*>& eS = edgesByGeom[iS]; + if ( eS.empty() ) continue; + if ( eS[0]->_nodes[0]->GetPosition()->GetDim() != dim ) continue; + + const TopoDS_Shape& S = getMeshDS()->IndexToShape( iS ); + bool needSmooth = false; + switch ( S.ShapeType() ) { - TGeomID iV = getMeshDS()->ShapeToIndex( vIt.Value() ); - vector<_LayerEdge*>& eV = edgesByGeom[ iV ]; - if ( eV.empty() ) continue; - gp_Vec eDir = getEdgeDir( TopoDS::Edge( S ), TopoDS::Vertex( vIt.Value() )); - double angle = eDir.Angle( eV[0]->_normal ); - double cosin = Cos( angle ); - if ( cosin > theMinSmoothCosin ) + case TopAbs_EDGE: { + + const TopoDS_Edge& E = TopoDS::Edge( S ); + if ( SMESH_Algo::isDegenerated( E ) || !edgesOfSmooFaces.Contains( E )) + break; + + TopoDS_Face F; + if ( !eS[0]->_sWOL.IsNull() && eS[0]->_sWOL.ShapeType() == TopAbs_FACE ) + F = TopoDS::Face( eS[0]->_sWOL ); + + for ( TopoDS_Iterator vIt( S ); vIt.More() && !needSmooth; vIt.Next() ) { - // compare tgtThick with the length of an end segment - SMDS_ElemIteratorPtr eIt = eV[0]->_nodes[0]->GetInverseElementIterator(SMDSAbs_Edge); - while ( eIt->more() ) + TGeomID iV = getMeshDS()->ShapeToIndex( vIt.Value() ); + vector<_LayerEdge*>& eV = edgesByGeom[ iV ]; + if ( eV.empty() ) continue; + gp_Vec eDir = getEdgeDir( TopoDS::Edge( S ), TopoDS::Vertex( vIt.Value() )); + double angle = eDir.Angle( eV[0]->_normal ); + double cosin = Cos( angle ); + double cosinAbs = Abs( cosin ); + if ( cosinAbs > theMinSmoothCosin ) { - const SMDS_MeshElement* endSeg = eIt->next(); - if ( endSeg->getshapeId() == iS ) + // always smooth analytic EDGEs + needSmooth = ! data.CurveForSmooth( E, 0, eS.size(), F, helper, &eS ).IsNull(); + + // compare tgtThick with the length of an end segment + SMDS_ElemIteratorPtr eIt = eV[0]->_nodes[0]->GetInverseElementIterator(SMDSAbs_Edge); + while ( eIt->more() && !needSmooth ) { - double segLen = - SMESH_TNodeXYZ( endSeg->GetNode(0) ).Distance( endSeg->GetNode(1 )); - needSmooth = needSmoothing( cosin, tgtThick, segLen ); - break; + const SMDS_MeshElement* endSeg = eIt->next(); + if ( endSeg->getshapeId() == iS ) + { + double segLen = + SMESH_TNodeXYZ( endSeg->GetNode(0) ).Distance( endSeg->GetNode(1 )); + needSmooth = needSmoothing( cosinAbs, tgtThick, segLen ); + } } } } + break; } - break; - } - case TopAbs_FACE: { + case TopAbs_FACE: { - for ( TopExp_Explorer eExp( S, TopAbs_EDGE ); eExp.More() && !needSmooth; eExp.Next() ) - { - TGeomID iE = getMeshDS()->ShapeToIndex( eExp.Current() ); - vector<_LayerEdge*>& eE = edgesByGeom[ iE ]; - if ( eE.empty() ) continue; - // TopLoc_Location loc; - // Handle(Geom_Surface) surface = BRep_Tool::Surface( TopoDS::Face( S ), loc ); - // bool isPlane = GeomLib_IsPlanarSurface( surface ).IsPlanar(); - //if ( eE[0]->_sWOL.IsNull() ) + for ( TopExp_Explorer eExp( S, TopAbs_EDGE ); eExp.More() && !needSmooth; eExp.Next() ) { - double faceSize; - for ( size_t i = 0; i < eE.size() && !needSmooth; ++i ) - if ( eE[i]->_cosin > theMinSmoothCosin ) - { - SMDS_ElemIteratorPtr fIt = eE[i]->_nodes[0]->GetInverseElementIterator(SMDSAbs_Face); - while ( fIt->more() && !needSmooth ) + TGeomID iE = getMeshDS()->ShapeToIndex( eExp.Current() ); + vector<_LayerEdge*>& eE = edgesByGeom[ iE ]; + if ( eE.empty() ) continue; + // TopLoc_Location loc; + // Handle(Geom_Surface) surface = BRep_Tool::Surface( TopoDS::Face( S ), loc ); + // bool isPlane = GeomLib_IsPlanarSurface( surface ).IsPlanar(); + //if ( eE[0]->_sWOL.IsNull() ) + { + double faceSize; + for ( size_t i = 0; i < eE.size() && !needSmooth; ++i ) + if ( eE[i]->_cosin > theMinSmoothCosin ) { - const SMDS_MeshElement* face = fIt->next(); - if ( getDistFromEdge( face, eE[i]->_nodes[0], faceSize )) - needSmooth = needSmoothing( eE[i]->_cosin, tgtThick, faceSize ); + SMDS_ElemIteratorPtr fIt = eE[i]->_nodes[0]->GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() && !needSmooth ) + { + const SMDS_MeshElement* face = fIt->next(); + if ( getDistFromEdge( face, eE[i]->_nodes[0], faceSize )) + needSmooth = needSmoothing( eE[i]->_cosin, tgtThick, faceSize ); + } } - } + } + // else + // { + // const TopoDS_Face& F1 = TopoDS::Face( S ); + // const TopoDS_Face& F2 = TopoDS::Face( eE[0]->_sWOL ); + // const TopoDS_Edge& E = TopoDS::Edge( eExp.Current() ); + // for ( size_t i = 0; i < eE.size() && !needSmooth; ++i ) + // { + // gp_Vec dir1 = getFaceDir( F1, E, eE[i]->_nodes[0], helper, ok ); + // gp_Vec dir2 = getFaceDir( F2, E, eE[i]->_nodes[0], helper, ok ); + // double angle = dir1.Angle( ); + // double cosin = cos( angle ); + // needSmooth = ( cosin > theMinSmoothCosin ); + // } + // } } - // else - // { - // const TopoDS_Face& F1 = TopoDS::Face( S ); - // const TopoDS_Face& F2 = TopoDS::Face( eE[0]->_sWOL ); - // const TopoDS_Edge& E = TopoDS::Edge( eExp.Current() ); - // for ( size_t i = 0; i < eE.size() && !needSmooth; ++i ) - // { - // gp_Vec dir1 = getFaceDir( F1, E, eE[i]->_nodes[0], helper, ok ); - // gp_Vec dir2 = getFaceDir( F2, E, eE[i]->_nodes[0], helper, ok ); - // double angle = dir1.Angle( ); - // double cosin = cos( angle ); - // needSmooth = ( cosin > theMinSmoothCosin ); - // } - // } + if ( needSmooth ) + for ( TopExp_Explorer eExp( S, TopAbs_EDGE ); eExp.More(); eExp.Next() ) + edgesOfSmooFaces.Add( eExp.Current() ); + + break; + } + case TopAbs_VERTEX: + continue; + default:; } - break; - } - case TopAbs_VERTEX: - continue; - default:; - } - if ( needSmooth ) - { - if ( S.ShapeType() == TopAbs_EDGE ) shapesToSmooth.push_front( iS ); - else shapesToSmooth.push_back ( iS ); - } + if ( needSmooth ) + { + if ( S.ShapeType() == TopAbs_EDGE ) shapesToSmooth.push_front( iS ); + else shapesToSmooth.push_back ( iS ); - } // loop on edgesByGeom + // preparation for smoothing + if ( S.ShapeType() == TopAbs_FACE ) + { + data.PrepareEdgesToSmoothOnFace( & eS[0], + & eS[0] + eS.size(), + TopoDS::Face( S ), + /*substituteSrcNodes=*/false); + } + } + + } // loop on edgesByGeom + } // // loop on [ FACEs, EDGEs ] data._edges.reserve( data._n2eMap.size() ); data._endEdgeOnShape.clear(); @@ -2460,7 +2660,7 @@ bool _ViscousBuilder::setEdgeData(_LayerEdge& edge, SMESH_MeshEditor editor(_mesh); const SMDS_MeshNode* node = edge._nodes[0]; // source node - SMDS_TypeOfPosition posType = node->GetPosition()->GetTypeOfPosition(); + const SMDS_TypeOfPosition posType = node->GetPosition()->GetTypeOfPosition(); edge._len = 0; edge._2neibors = 0; @@ -2474,13 +2674,41 @@ bool _ViscousBuilder::setEdgeData(_LayerEdge& edge, edge._normal.SetCoord(0,0,0); int totalNbFaces = 0; + TopoDS_Face F; + std::pair< TopoDS_Face, gp_XYZ > face2Norm[20]; gp_Vec geomNorm; bool normOK = true; + // get geom FACEs the node lies on + { + set faceIds; + if ( posType == SMDS_TOP_FACE ) + { + faceIds.insert( node->getshapeId() ); + } + else + { + SMDS_ElemIteratorPtr fIt = node->GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() ) + faceIds.insert( editor.FindShape(fIt->next())); + } + set::iterator id = faceIds.begin(); + for ( ; id != faceIds.end(); ++id ) + { + const TopoDS_Shape& s = getMeshDS()->IndexToShape( *id ); + if ( s.IsNull() || s.ShapeType() != TopAbs_FACE || !subIds.count( *id )) + continue; + F = TopoDS::Face( s ); + face2Norm[ totalNbFaces ].first = F; + totalNbFaces++; + } + } + const TGeomID shapeInd = node->getshapeId(); map< TGeomID, TopoDS_Shape >::const_iterator s2s = data._shrinkShape2Shape.find( shapeInd ); const bool onShrinkShape ( s2s != data._shrinkShape2Shape.end() ); + // find _normal if ( onShrinkShape ) // one of faces the node is on has no layers { TopoDS_Shape vertEdge = getMeshDS()->IndexToShape( s2s->first ); // vertex or edge @@ -2504,54 +2732,35 @@ bool _ViscousBuilder::setEdgeData(_LayerEdge& edge, } else // layers are on all faces of SOLID the node is on { - // find indices of geom faces the node lies on - set faceIds; - if ( posType == SMDS_TOP_FACE ) + int nbOkNorms = 0; + for ( int iF = 0; iF < totalNbFaces; ++iF ) { - faceIds.insert( node->getshapeId() ); - } - else - { - SMDS_ElemIteratorPtr fIt = node->GetInverseElementIterator(SMDSAbs_Face); - while ( fIt->more() ) - faceIds.insert( editor.FindShape(fIt->next())); - } - - set::iterator id = faceIds.begin(); - TopoDS_Face F; - std::pair< TGeomID, gp_XYZ > id2Norm[20]; - for ( ; id != faceIds.end(); ++id ) - { - const TopoDS_Shape& s = getMeshDS()->IndexToShape( *id ); - if ( s.IsNull() || s.ShapeType() != TopAbs_FACE || !subIds.count( *id )) - continue; - F = TopoDS::Face( s ); + F = TopoDS::Face( face2Norm[ iF ].first ); geomNorm = getFaceNormal( node, F, helper, normOK ); if ( !normOK ) continue; + nbOkNorms++; if ( helper.GetSubShapeOri( data._solid, F ) != TopAbs_REVERSED ) geomNorm.Reverse(); - id2Norm[ totalNbFaces ].first = *id; - id2Norm[ totalNbFaces ].second = geomNorm.XYZ(); - totalNbFaces++; + face2Norm[ iF ].second = geomNorm.XYZ(); edge._normal += geomNorm.XYZ(); } - if ( totalNbFaces == 0 ) + if ( nbOkNorms == 0 ) return error(SMESH_Comment("Can't get normal to node ") << node->GetID(), data._index); - if ( normOK && edge._normal.Modulus() < 1e-3 && totalNbFaces > 1 ) + if ( edge._normal.Modulus() < 1e-3 && nbOkNorms > 1 ) { // opposite normals, re-get normals at shifted positions (IPAL 52426) edge._normal.SetCoord( 0,0,0 ); - for ( int i = 0; i < totalNbFaces; ++i ) + for ( int iF = 0; iF < totalNbFaces; ++iF ) { - const TopoDS_Face& F = TopoDS::Face( getMeshDS()->IndexToShape( id2Norm[i].first )); + const TopoDS_Face& F = face2Norm[iF].first; geomNorm = getFaceNormal( node, F, helper, normOK, /*shiftInside=*/true ); if ( helper.GetSubShapeOri( data._solid, F ) != TopAbs_REVERSED ) geomNorm.Reverse(); if ( normOK ) - id2Norm[ i ].second = geomNorm.XYZ(); - edge._normal += id2Norm[ i ].second; + face2Norm[ iF ].second = geomNorm.XYZ(); + edge._normal += face2Norm[ iF ].second; } } @@ -2561,34 +2770,46 @@ bool _ViscousBuilder::setEdgeData(_LayerEdge& edge, } else { - edge._normal = getWeigthedNormal( node, id2Norm, totalNbFaces ); + edge._normal = getWeigthedNormal( node, face2Norm, totalNbFaces ); } + } - switch ( posType ) - { - case SMDS_TOP_FACE: - edge._cosin = 0; break; - - case SMDS_TOP_EDGE: { - TopoDS_Edge E = TopoDS::Edge( helper.GetSubShapeByNode( node, getMeshDS())); - gp_Vec inFaceDir = getFaceDir( F, E, node, helper, normOK ); - double angle = inFaceDir.Angle( edge._normal ); // [0,PI] - edge._cosin = cos( angle ); - //cout << "Cosin on EDGE " << edge._cosin << " node " << node->GetID() << endl; - break; - } - case SMDS_TOP_VERTEX: { - TopoDS_Vertex V = TopoDS::Vertex( helper.GetSubShapeByNode( node, getMeshDS())); - gp_Vec inFaceDir = getFaceDir( F, V, node, helper, normOK ); - double angle = inFaceDir.Angle( edge._normal ); // [0,PI] - edge._cosin = cos( angle ); - //cout << "Cosin on VERTEX " << edge._cosin << " node " << node->GetID() << endl; - break; - } - default: - return error(SMESH_Comment("Invalid shape position of node ")<GetID() << endl; + break; + } + case SMDS_TOP_VERTEX: { + TopoDS_Vertex V = TopoDS::Vertex( helper.GetSubShapeByNode( node, getMeshDS())); + gp_Vec inFaceDir = getFaceDir( F, V, node, helper, normOK ); + double angle = inFaceDir.Angle( edge._normal ); // [0,PI] + edge._cosin = Cos( angle ); + if ( totalNbFaces > 2 || helper.IsSeamShape( node->getshapeId() )) + for ( int iF = totalNbFaces-2; iF >=0; --iF ) + { + F = face2Norm[ iF ].first; + inFaceDir = getFaceDir( F, V, node, helper, normOK ); + if ( normOK ) { + double angle = inFaceDir.Angle( edge._normal ); + edge._cosin = Max( edge._cosin, Cos( angle )); + } + } + //cout << "Cosin on VERTEX " << edge._cosin << " node " << node->GetID() << endl; + break; + } + default: + return error(SMESH_Comment("Invalid shape position of node ")<::min() ) @@ -2630,17 +2851,7 @@ bool _ViscousBuilder::setEdgeData(_LayerEdge& edge, if ( posType == SMDS_TOP_FACE ) { - getSimplices( node, edge._simplices, data._ignoreFaceIds, &data ); - double avgNormProj = 0, avgLen = 0; - for ( size_t i = 0; i < edge._simplices.size(); ++i ) - { - gp_XYZ vec = edge._pos.back() - SMESH_TNodeXYZ( edge._simplices[i]._nPrev ); - avgNormProj += edge._normal * vec; - avgLen += vec.Modulus(); - } - avgNormProj /= edge._simplices.size(); - avgLen /= edge._simplices.size(); - edge._curvature = _Curvature::New( avgNormProj, avgLen ); + _Simplex::GetSimplices( node, edge._simplices, data._ignoreFaceIds, &data ); } } @@ -2733,6 +2944,15 @@ gp_XYZ _ViscousBuilder::getFaceNormal(const SMDS_MeshNode* node, isOK = false; Handle(Geom_Surface) surface = BRep_Tool::Surface( face ); + + if ( !shiftInside && + helper.IsDegenShape( node->getshapeId() ) && + getFaceNormalAtSingularity( uv, face, helper, normal )) + { + isOK = true; + return normal.XYZ(); + } + int pointKind = GeomLib::NormEstim( surface, uv, 1e-5, normal ); enum { REGULAR = 0, QUASYSINGULAR, CONICAL, IMPOSSIBLE }; @@ -2781,6 +3001,55 @@ gp_XYZ _ViscousBuilder::getFaceNormal(const SMDS_MeshNode* node, return normal.XYZ(); } +//================================================================================ +/*! + * \brief Try to get normal at a singularity of a surface basing on it's nature + */ +//================================================================================ + +bool _ViscousBuilder::getFaceNormalAtSingularity( const gp_XY& uv, + const TopoDS_Face& face, + SMESH_MesherHelper& helper, + gp_Dir& normal ) +{ + BRepAdaptor_Surface surface( face ); + gp_Dir axis; + if ( !getRovolutionAxis( surface, axis )) + return false; + + double f,l, d, du, dv; + f = surface.FirstUParameter(); + l = surface.LastUParameter(); + d = ( uv.X() - f ) / ( l - f ); + du = ( d < 0.5 ? +1. : -1 ) * 1e-5 * ( l - f ); + f = surface.FirstVParameter(); + l = surface.LastVParameter(); + d = ( uv.Y() - f ) / ( l - f ); + dv = ( d < 0.5 ? +1. : -1 ) * 1e-5 * ( l - f ); + + gp_Dir refDir; + gp_Pnt2d testUV = uv; + enum { REGULAR = 0, QUASYSINGULAR, CONICAL, IMPOSSIBLE }; + double tol = 1e-5; + Handle(Geom_Surface) geomsurf = surface.Surface().Surface(); + for ( int iLoop = 0; true ; ++iLoop ) + { + testUV.SetCoord( testUV.X() + du, testUV.Y() + dv ); + if ( GeomLib::NormEstim( geomsurf, testUV, tol, refDir ) == REGULAR ) + break; + if ( iLoop > 20 ) + return false; + tol /= 10.; + } + + if ( axis * refDir < 0. ) + axis.Reverse(); + + normal = axis; + + return true; +} + //================================================================================ /*! * \brief Return a normal at a node weighted with angles taken by FACEs @@ -2791,23 +3060,40 @@ gp_XYZ _ViscousBuilder::getFaceNormal(const SMDS_MeshNode* node, */ //================================================================================ -gp_XYZ _ViscousBuilder::getWeigthedNormal( const SMDS_MeshNode* n, - std::pair< TGeomID, gp_XYZ > fId2Normal[], - const int nbFaces ) +gp_XYZ _ViscousBuilder::getWeigthedNormal( const SMDS_MeshNode* n, + std::pair< TopoDS_Face, gp_XYZ > fId2Normal[], + int nbFaces ) { gp_XYZ resNorm(0,0,0); TopoDS_Shape V = SMESH_MesherHelper::GetSubShapeByNode( n, getMeshDS() ); if ( V.ShapeType() != TopAbs_VERTEX ) { for ( int i = 0; i < nbFaces; ++i ) - resNorm += fId2Normal[i].second / nbFaces ; + resNorm += fId2Normal[i].second; + return resNorm; + } + + // exclude equal normals + //int nbUniqNorms = nbFaces; + for ( int i = 0; i < nbFaces; ++i ) + for ( int j = i+1; j < nbFaces; ++j ) + if ( fId2Normal[i].second.IsEqual( fId2Normal[j].second, 0.1 )) + { + fId2Normal[i].second.SetCoord( 0,0,0 ); + //--nbUniqNorms; + break; + } + //if ( nbUniqNorms < 3 ) + { + for ( int i = 0; i < nbFaces; ++i ) + resNorm += fId2Normal[i].second; return resNorm; } double angles[30]; for ( int i = 0; i < nbFaces; ++i ) { - const TopoDS_Face& F = TopoDS::Face( getMeshDS()->IndexToShape( fId2Normal[i].first )); + const TopoDS_Face& F = fId2Normal[i].first; // look for two EDGEs shared by F and other FACEs within fId2Normal TopoDS_Edge ee[2]; @@ -2821,7 +3107,7 @@ gp_XYZ _ViscousBuilder::getWeigthedNormal( const SMDS_MeshNode* n, for ( int j = 0; j < nbFaces && !isSharedEdge; ++j ) { if ( i == j ) continue; - const TopoDS_Shape& otherF = getMeshDS()->IndexToShape( fId2Normal[j].first ); + const TopoDS_Shape& otherF = fId2Normal[j].first; isSharedEdge = SMESH_MesherHelper::IsSubShape( *E, otherF ); } if ( !isSharedEdge ) @@ -3015,11 +3301,11 @@ void _LayerEdge::SetCosin( double cosin ) */ //================================================================================ -void _ViscousBuilder::getSimplices( const SMDS_MeshNode* node, - vector<_Simplex>& simplices, - const set& ingnoreShapes, - const _SolidData* dataToCheckOri, - const bool toSort) +void _Simplex::GetSimplices( const SMDS_MeshNode* node, + vector<_Simplex>& simplices, + const set& ingnoreShapes, + const _SolidData* dataToCheckOri, + const bool toSort) { simplices.clear(); SMDS_ElemIteratorPtr fIt = node->GetInverseElementIterator(SMDSAbs_Face); @@ -3039,23 +3325,32 @@ void _ViscousBuilder::getSimplices( const SMDS_MeshNode* node, } if ( toSort ) + SortSimplices( simplices ); +} + +//================================================================================ +/*! + * \brief Set neighbor simplices side by side + */ +//================================================================================ + +void _Simplex::SortSimplices(vector<_Simplex>& simplices) +{ + vector<_Simplex> sortedSimplices( simplices.size() ); + sortedSimplices[0] = simplices[0]; + int nbFound = 0; + for ( size_t i = 1; i < simplices.size(); ++i ) { - vector<_Simplex> sortedSimplices( simplices.size() ); - sortedSimplices[0] = simplices[0]; - int nbFound = 0; - for ( size_t i = 1; i < simplices.size(); ++i ) - { - for ( size_t j = 1; j < simplices.size(); ++j ) - if ( sortedSimplices[i-1]._nNext == simplices[j]._nPrev ) - { - sortedSimplices[i] = simplices[j]; - nbFound++; - break; - } - } - if ( nbFound == simplices.size() - 1 ) - simplices.swap( sortedSimplices ); + for ( size_t j = 1; j < simplices.size(); ++j ) + if ( sortedSimplices[i-1]._nNext == simplices[j]._nPrev ) + { + sortedSimplices[i] = simplices[j]; + nbFound++; + break; + } } + if ( nbFound == simplices.size() - 1 ) + simplices.swap( sortedSimplices ); } //================================================================================ @@ -3093,11 +3388,13 @@ void _ViscousBuilder::makeGroupOfLE() dumpFunctionEnd(); dumpFunction( SMESH_Comment("makeTmpFaces_") << i ); + dumpCmd( "faceId1 = mesh.NbElements()" ); TopExp_Explorer fExp( _sdVec[i]._solid, TopAbs_FACE ); for ( ; fExp.More(); fExp.Next() ) { if (const SMESHDS_SubMesh* sm = _sdVec[i]._proxyMesh->GetProxySubMesh( fExp.Current())) { + if ( sm->NbElements() == 0 ) continue; SMDS_ElemIteratorPtr fIt = sm->GetElements(); while ( fIt->more()) { @@ -3109,6 +3406,10 @@ void _ViscousBuilder::makeGroupOfLE() } } } + dumpCmd( "faceId2 = mesh.NbElements()" ); + dumpCmd( SMESH_Comment( "mesh.MakeGroup( 'tmpFaces_" ) << i << "'," + << "SMESH.FACE, SMESH.FT_RangeOfIds,'='," + << "'%s-%s' % (faceId1+1, faceId2))"); dumpFunctionEnd(); } #endif @@ -3163,6 +3464,8 @@ bool _ViscousBuilder::inflate(_SolidData& data) debugMsg( "-- geomSize = " << data._geomSize << ", stepSize = " << data._stepSize ); + const double safeFactor = ( 2*data._maxThickness < data._geomSize ) ? 1 : theThickToIntersection; + double avgThick = 0, curThick = 0, distToIntersection = Precision::Infinite(); int nbSteps = 0, nbRepeats = 0; int iBeg, iEnd, iS; @@ -3196,6 +3499,10 @@ bool _ViscousBuilder::inflate(_SolidData& data) { if ( nbSteps > 0 ) { +#ifdef __NOT_INVALIDATE_BAD_SMOOTH + debugMsg("NOT INVALIDATED STEP!"); + return error("Smoothing failed", data._index); +#endif dumpFunction(SMESH_Comment("invalidate")<GetSubMeshContaining( data._index )) + { + if ( !data._proxyMesh->_warning || data._proxyMesh->_warning->IsOK() ) { - SMESH_ComputeErrorPtr& smError = sm->GetComputeError(); - if ( !smError || smError->IsOK() ) - smError.reset - ( new SMESH_ComputeError (COMPERR_WARNING, - SMESH_Comment("Thickness ") << tgtThick << - " of viscous layers not reached," - " average reached thickness is " << avgThick*tgtThick)); + data._proxyMesh->_warning.reset + ( new SMESH_ComputeError (COMPERR_WARNING, + SMESH_Comment("Thickness ") << tgtThick << + " of viscous layers not reached," + " average reached thickness is " << avgThick*tgtThick)); } - + } // Restore position of src nodes moved by infaltion on _noShrinkShapes dumpFunction(SMESH_Comment("restoNoShrink_So")< badSmooEdges; SMESH_MesherHelper helper(*_mesh); Handle(Geom_Surface) surface; @@ -3293,16 +3600,18 @@ bool _ViscousBuilder::smoothAndCheck(_SolidData& data, iBeg = iEnd; iEnd = data._endEdgeOnShape[ iS ]; - // bool toSmooth = false; - // for ( int i = iBeg; i < iEnd; ++i ) - // toSmooth = data._edges[ iBeg ]->NbSteps() >= nbSteps+1; - // if ( !toSmooth ) - // { - // if ( iS+1 == data._nbShapesToSmooth ) - // data._nbShapesToSmooth--; - // continue; // target length reached some steps before - // } + // need to smooth this shape? + bool toSmooth = ( data._hyps.front() == data._hyps.back() ); + for ( int i = iBeg; i < iEnd && !toSmooth; ++i ) + toSmooth = ( data._edges[ iBeg ]->NbSteps() >= nbSteps+1 ); + if ( !toSmooth ) + { + if ( iS+1 == data._nbShapesToSmooth ) + data._nbShapesToSmooth--; + continue; // target length reached some steps before + } + // prepare data if ( !data._edges[ iBeg ]->_sWOL.IsNull() && data._edges[ iBeg ]->_sWOL.ShapeType() == TopAbs_FACE ) { @@ -3316,7 +3625,9 @@ bool _ViscousBuilder::smoothAndCheck(_SolidData& data, { F.Nullify(); surface.Nullify(); } - TGeomID sInd = data._edges[ iBeg ]->_nodes[0]->getshapeId(); + const TGeomID sInd = data._edges[ iBeg ]->_nodes[0]->getshapeId(); + + // perform smoothing if ( data._edges[ iBeg ]->IsOnEdge() ) { @@ -3342,37 +3653,65 @@ bool _ViscousBuilder::smoothAndCheck(_SolidData& data, else { // smooth on FACE's - int step = 0, stepLimit = 5, badNb = 0; moved = true; - while (( ++step <= stepLimit && moved ) || improved ) + + const bool isConcaveFace = data._concaveFaces.count( sInd ); + + int step = 0, stepLimit = 5, badNb = 0; + while (( ++step <= stepLimit ) || improved ) { dumpFunction(SMESH_Comment("smooth")<Smooth(badNb); - else + if ( data._edges[i]->Smooth( step, isConcaveFace, false )) + badSmooEdges.push_back( data._edges[i] ); + } + else { for ( int i = iEnd-1; i >= iBeg; --i ) // iterate backward - moved |= data._edges[i]->Smooth(badNb); + if ( data._edges[i]->Smooth( step, isConcaveFace, false )) + badSmooEdges.push_back( data._edges[i] ); + } + badNb = badSmooEdges.size(); improved = ( badNb < oldBadNb ); + if ( !badSmooEdges.empty() && step >= stepLimit / 2 ) + { + // look for the best smooth of _LayerEdge's neighboring badSmooEdges + vector<_Simplex> simplices; + for ( size_t i = 0; i < badSmooEdges.size(); ++i ) + { + _LayerEdge* ledge = badSmooEdges[i]; + _Simplex::GetSimplices( ledge->_nodes[0], simplices, data._ignoreFaceIds ); + for ( size_t iS = 0; iS < simplices.size(); ++iS ) + { + TNode2Edge::iterator n2e = data._n2eMap.find( simplices[iS]._nNext ); + if ( n2e != data._n2eMap.end()) { + _LayerEdge* ledge2 = n2e->second; + if ( ledge2->_nodes[0]->getshapeId() == sInd ) + ledge2->Smooth( step, isConcaveFace, /*findBest=*/true ); + } + } + } + } // issue 22576 -- no bad faces but still there are intersections to fix - if ( improved && badNb == 0 ) - stepLimit = step + 3; + // if ( improved && badNb == 0 ) + // stepLimit = step + 3; dumpFunctionEnd(); } if ( badNb > 0 ) { #ifdef __myDEBUG + double vol = 0; for ( int i = iBeg; i < iEnd; ++i ) { _LayerEdge* edge = data._edges[i]; SMESH_TNodeXYZ tgtXYZ( edge->_nodes.back() ); for ( size_t j = 0; j < edge->_simplices.size(); ++j ) - if ( !edge->_simplices[j].IsForward( edge->_nodes[0], &tgtXYZ )) + if ( !edge->_simplices[j].IsForward( edge->_nodes[0], &tgtXYZ, vol )) { cout << "Bad simplex ( " << edge->_nodes[0]->GetID()<< " "<< tgtXYZ._node->GetID() << " "<< edge->_simplices[j]._nPrev->GetID() @@ -3425,6 +3764,11 @@ bool _ViscousBuilder::smoothAndCheck(_SolidData& data, if ( convFace->_subIdToEdgeEnd.count ( data._edges[i]->_nodes[0]->getshapeId() )) continue; + // ignore intersection of a _LayerEdge based on a FACE with an element on this FACE + // ( avoid limiting the thickness on the case of issue 22576) + if ( intFace->getshapeId() == data._edges[i]->_nodes[0]->getshapeId() ) + continue; + distToIntersection = dist; iLE = i; closestFace = intFace; @@ -3454,9 +3798,9 @@ bool _ViscousBuilder::smoothAndCheck(_SolidData& data, Handle(Geom_Curve) _SolidData::CurveForSmooth( const TopoDS_Edge& E, const int iFrom, const int iTo, - Handle(Geom_Surface)& surface, const TopoDS_Face& F, - SMESH_MesherHelper& helper) + SMESH_MesherHelper& helper, + vector<_LayerEdge* >* edges) { TGeomID eIndex = helper.GetMeshDS()->ShapeToIndex( E ); @@ -3464,6 +3808,9 @@ Handle(Geom_Curve) _SolidData::CurveForSmooth( const TopoDS_Edge& E, if ( i2curve == _edge2curve.end() ) { + if ( edges ) + _edges.swap( *edges ); + // sort _LayerEdge's by position on the EDGE SortOnEdge( E, iFrom, iTo, helper ); @@ -3494,11 +3841,21 @@ Handle(Geom_Curve) _SolidData::CurveForSmooth( const TopoDS_Edge& E, bndBox.Add( SMESH_TNodeXYZ( nIt->next() )); gp_XYZ size = bndBox.CornerMax() - bndBox.CornerMin(); - SMESH_TNodeXYZ p0( _edges[iFrom]->_2neibors->tgtNode(0) ); - SMESH_TNodeXYZ p1( _edges[iFrom]->_2neibors->tgtNode(1) ); - const double lineTol = 1e-2 * ( p0 - p1 ).Modulus(); + gp_Pnt p0, p1; + if ( iTo-iFrom > 1 ) { + p0 = SMESH_TNodeXYZ( _edges[iFrom]->_nodes[0] ); + p1 = SMESH_TNodeXYZ( _edges[iFrom+1]->_nodes[0] ); + } + else { + p0 = curve->Value( f ); + p1 = curve->Value( l ); + } + const double lineTol = 1e-2 * p0.Distance( p1 ); for ( int i = 0; i < 3 && !isLine; ++i ) isLine = ( size.Coord( i+1 ) <= lineTol ); + + if ( isLine ) + line = new Geom_Line( gp::OX() ); // only type does matter } if ( !isLine && !isCirc && iTo-iFrom > 2) // Check if the EDGE is close to a circle { @@ -3545,6 +3902,9 @@ Handle(Geom_Curve) _SolidData::CurveForSmooth( const TopoDS_Edge& E, } } + if ( edges ) + _edges.swap( *edges ); + Handle(Geom_Curve)& res = _edge2curve[ eIndex ]; if ( isLine ) res = line; @@ -3576,11 +3936,21 @@ void _SolidData::SortOnEdge( const TopoDS_Edge& E, for ( int i = iFrom; i < iTo; ++i, ++u2e ) _edges[i] = u2e->second; - // set _2neibors according to the new order + Sort2NeiborsOnEdge( iFrom, iTo ); +} + +//================================================================================ +/*! + * \brief Set _2neibors according to the order of _LayerEdge on EDGE + */ +//================================================================================ + +void _SolidData::Sort2NeiborsOnEdge( const int iFrom, const int iTo) +{ for ( int i = iFrom; i < iTo-1; ++i ) if ( _edges[i]->_2neibors->tgtNode(1) != _edges[i+1]->_nodes.back() ) _edges[i]->_2neibors->reverse(); - if ( u2edge.size() > 1 && + if ( iTo - iFrom > 1 && _edges[iTo-1]->_2neibors->tgtNode(0) != _edges[iTo-2]->_nodes.back() ) _edges[iTo-1]->_2neibors->reverse(); } @@ -3612,6 +3982,53 @@ bool _SolidData::GetShapeEdges(const TGeomID shapeID, return false; } +//================================================================================ +/*! + * \brief Prepare data of the _LayerEdge for smoothing on FACE + */ +//================================================================================ + +void _SolidData::PrepareEdgesToSmoothOnFace( _LayerEdge** edgeBeg, + _LayerEdge** edgeEnd, + const TopoDS_Face& face, + bool substituteSrcNodes ) +{ + set< TGeomID > vertices; + SMESH_MesherHelper helper( *_proxyMesh->GetMesh() ); + if ( isConcave( face, helper, &vertices )) + _concaveFaces.insert( (*edgeBeg)->_nodes[0]->getshapeId() ); + + for ( _LayerEdge** edge = edgeBeg; edge != edgeEnd; ++edge ) + (*edge)->_smooFunction = 0; + + for ( ; edgeBeg != edgeEnd; ++edgeBeg ) + { + _LayerEdge* edge = *edgeBeg; + _Simplex::GetSimplices + ( edge->_nodes[0], edge->_simplices, _ignoreFaceIds, this, /*sort=*/true ); + + edge->ChooseSmooFunction( vertices, _n2eMap ); + + double avgNormProj = 0, avgLen = 0; + for ( size_t i = 0; i < edge->_simplices.size(); ++i ) + { + _Simplex& s = edge->_simplices[i]; + + gp_XYZ vec = edge->_pos.back() - SMESH_TNodeXYZ( s._nPrev ); + avgNormProj += edge->_normal * vec; + avgLen += vec.Modulus(); + if ( substituteSrcNodes ) + { + s._nNext = _n2eMap[ s._nNext ]->_nodes.back(); + s._nPrev = _n2eMap[ s._nPrev ]->_nodes.back(); + } + } + avgNormProj /= edge->_simplices.size(); + avgLen /= edge->_simplices.size(); + edge->_curvature = _Curvature::New( avgNormProj, avgLen ); + } +} + //================================================================================ /*! * \brief Add faces for smoothing @@ -3648,10 +4065,25 @@ void _SolidData::AddShapesToSmooth( const set< TGeomID >& faceIDs ) int iBeg, iEnd; for ( size_t i = _nbShapesToSmooth; i <= lastSmooth; ++i ) { - vector< _LayerEdge* > & edgesVec = iEnds.count(i) ? smoothLE : nonSmoothLE; + bool toSmooth = iEnds.count(i); + vector< _LayerEdge* > & edgesVec = toSmooth ? smoothLE : nonSmoothLE; iBeg = i ? _endEdgeOnShape[ i-1 ] : 0; iEnd = _endEdgeOnShape[ i ]; - edgesVec.insert( edgesVec.end(), _edges.begin() + iBeg, _edges.begin() + iEnd ); + edgesVec.insert( edgesVec.end(), _edges.begin() + iBeg, _edges.begin() + iEnd ); + + // preparation for smoothing on FACE + if ( toSmooth && _edges[iBeg]->_nodes[0]->GetPosition()->GetDim() == 2 ) + { + TopoDS_Shape S = SMESH_MesherHelper::GetSubShapeByNode( _edges[iBeg]->_nodes[0], + _proxyMesh->GetMeshDS() ); + if ( !S.IsNull() && S.ShapeType() == TopAbs_FACE ) + { + PrepareEdgesToSmoothOnFace( &_edges[ iBeg ], + &_edges[ iEnd ], + TopoDS::Face( S ), + /*substituteSrcNodes=*/true ); + } + } } iBeg = _nbShapesToSmooth ? _endEdgeOnShape[ _nbShapesToSmooth-1 ] : 0; @@ -3688,7 +4120,7 @@ bool _ViscousBuilder::smoothAnalyticEdge( _SolidData& data, helper.GetMeshDS()); TopoDS_Edge E = TopoDS::Edge( S ); - Handle(Geom_Curve) curve = data.CurveForSmooth( E, iFrom, iTo, surface, F, helper ); + Handle(Geom_Curve) curve = data.CurveForSmooth( E, iFrom, iTo, F, helper ); if ( curve.IsNull() ) return false; // compute a relative length of segments @@ -4509,12 +4941,13 @@ bool _ConvexFace::GetCenterOfCurvature( _LayerEdge* ledge, bool _ConvexFace::CheckPrisms() const { + double vol = 0; for ( size_t i = 0; i < _simplexTestEdges.size(); ++i ) { const _LayerEdge* edge = _simplexTestEdges[i]; SMESH_TNodeXYZ tgtXYZ( edge->_nodes.back() ); for ( size_t j = 0; j < edge->_simplices.size(); ++j ) - if ( !edge->_simplices[j].IsForward( edge->_nodes[0], &tgtXYZ )) + if ( !edge->_simplices[j].IsForward( edge->_nodes[0], &tgtXYZ, vol )) { debugMsg( "Bad simplex of _simplexTestEdges (" << " "<< edge->_nodes[0]->GetID()<< " "<< tgtXYZ._node->GetID() @@ -4686,10 +5119,11 @@ gp_Ax1 _LayerEdge::LastSegment(double& segLen) const gp_XYZ orig = _pos.back(); gp_XYZ dir; int iPrev = _pos.size() - 2; + const double tol = ( _len > 0 ) ? 0.3*_len : 1e-100; // adjusted for IPAL52478 + PAL22576 while ( iPrev >= 0 ) { dir = orig - _pos[iPrev]; - if ( dir.SquareModulus() > 1e-100 ) + if ( dir.SquareModulus() > tol*tol ) break; else iPrev--; @@ -4772,15 +5206,15 @@ bool _LayerEdge::SegTriaInter( const gp_Ax1& lastSegment, { //const double EPSILON = 1e-6; - gp_XYZ orig = lastSegment.Location().XYZ(); - gp_XYZ dir = lastSegment.Direction().XYZ(); + const gp_Pnt& orig = lastSegment.Location(); + const gp_Dir& dir = lastSegment.Direction(); SMESH_TNodeXYZ vert0( n0 ); SMESH_TNodeXYZ vert1( n1 ); SMESH_TNodeXYZ vert2( n2 ); /* calculate distance from vert0 to ray origin */ - gp_XYZ tvec = orig - vert0; + gp_XYZ tvec = orig.XYZ() - vert0; //if ( tvec * dir > EPSILON ) // intersected face is at back side of the temporary face this _LayerEdge belongs to @@ -4790,17 +5224,16 @@ bool _LayerEdge::SegTriaInter( const gp_Ax1& lastSegment, gp_XYZ edge2 = vert2 - vert0; /* begin calculating determinant - also used to calculate U parameter */ - gp_XYZ pvec = dir ^ edge2; + gp_XYZ pvec = dir.XYZ() ^ edge2; /* if determinant is near zero, ray lies in plane of triangle */ double det = edge1 * pvec; if (det > -EPSILON && det < EPSILON) return false; - double inv_det = 1.0 / det; /* calculate U parameter and test bounds */ - double u = ( tvec * pvec ) * inv_det; + double u = ( tvec * pvec ) / det; //if (u < 0.0 || u > 1.0) if (u < -EPSILON || u > 1.0 + EPSILON) return false; @@ -4809,13 +5242,13 @@ bool _LayerEdge::SegTriaInter( const gp_Ax1& lastSegment, gp_XYZ qvec = tvec ^ edge1; /* calculate V parameter and test bounds */ - double v = (dir * qvec) * inv_det; + double v = (dir.XYZ() * qvec) / det; //if ( v < 0.0 || u + v > 1.0 ) if ( v < -EPSILON || u + v > 1.0 + EPSILON) return false; /* calculate t, ray intersects triangle */ - t = (edge2 * qvec) * inv_det; + t = (edge2 * qvec) / det; //return true; return t > 0.; @@ -4876,12 +5309,13 @@ bool _LayerEdge::SmoothOnEdge(Handle(Geom_Surface)& surface, tgtNode->setXYZ( newPos.X(), newPos.Y(), newPos.Z() ); } - if ( _curvature && lenDelta < 0 ) - { - gp_Pnt prevPos( _pos[ _pos.size()-2 ]); - _len -= prevPos.Distance( oldPos ); - _len += prevPos.Distance( newPos ); - } + // commented for IPAL0052478 + // if ( _curvature && lenDelta < 0 ) + // { + // gp_Pnt prevPos( _pos[ _pos.size()-2 ]); + // _len -= prevPos.Distance( oldPos ); + // _len += prevPos.Distance( newPos ); + // } bool moved = distNewOld > dist01/50; //if ( moved ) dumpMove( tgtNode ); // debug @@ -4896,59 +5330,552 @@ bool _LayerEdge::SmoothOnEdge(Handle(Geom_Surface)& surface, */ //================================================================================ -bool _LayerEdge::Smooth(int& badNb) +int _LayerEdge::Smooth(const int step, const bool isConcaveFace, const bool findBest ) { if ( _simplices.size() < 2 ) - return false; // _LayerEdge inflated along EDGE or FACE + return 0; // _LayerEdge inflated along EDGE or FACE - // compute new position for the last _pos + const gp_XYZ& curPos ( _pos.back() ); + const gp_XYZ& prevPos( _pos[ _pos.size()-2 ]); + + // quality metrics (orientation) of tetras around _tgtNode + int nbOkBefore = 0; + double vol, minVolBefore = 1e100; + for ( size_t i = 0; i < _simplices.size(); ++i ) + { + nbOkBefore += _simplices[i].IsForward( _nodes[0], &curPos, vol ); + minVolBefore = Min( minVolBefore, vol ); + } + int nbBad = _simplices.size() - nbOkBefore; + + // compute new position for the last _pos using different _funs + gp_XYZ newPos; + for ( int iFun = -1; iFun < theNbSmooFuns; ++iFun ) + { + if ( iFun < 0 ) + newPos = (this->*_smooFunction)(); // fun chosen by ChooseSmooFunction() + else if ( _funs[ iFun ] == _smooFunction ) + continue; // _smooFunction again + else if ( step > 0 ) + newPos = (this->*_funs[ iFun ])(); // try other smoothing fun + else + break; // let "easy" functions improve elements around distorted ones + + if ( _curvature ) + { + double delta = _curvature->lenDelta( _len ); + if ( delta > 0 ) + newPos += _normal * delta; + else + { + double segLen = _normal * ( newPos - prevPos ); + if ( segLen + delta > 0 ) + newPos += _normal * delta; + } + // double segLenChange = _normal * ( curPos - newPos ); + // newPos += 0.5 * _normal * segLenChange; + } + + int nbOkAfter = 0; + double minVolAfter = 1e100; + for ( size_t i = 0; i < _simplices.size(); ++i ) + { + nbOkAfter += _simplices[i].IsForward( _nodes[0], &newPos, vol ); + minVolAfter = Min( minVolAfter, vol ); + } + // get worse? + if ( nbOkAfter < nbOkBefore ) + continue; + if (( isConcaveFace || findBest ) && + ( nbOkAfter == nbOkBefore ) && + //( iFun > -1 || nbOkAfter < _simplices.size() ) && + ( minVolAfter <= minVolBefore )) + continue; + + SMDS_MeshNode* n = const_cast< SMDS_MeshNode* >( _nodes.back() ); + + // commented for IPAL0052478 + // _len -= prevPos.Distance(SMESH_TNodeXYZ( n )); + // _len += prevPos.Distance(newPos); + + n->setXYZ( newPos.X(), newPos.Y(), newPos.Z()); + _pos.back() = newPos; + dumpMoveComm( n, _funNames[ iFun < 0 ? smooFunID() : iFun ]); + + nbBad = _simplices.size() - nbOkAfter; + + if ( iFun > -1 ) + { + //_smooFunction = _funs[ iFun ]; + // cout << "# " << _funNames[ iFun ] << "\t N:" << _nodes.back()->GetID() + // << "\t nbBad: " << _simplices.size() - nbOkAfter + // << " minVol: " << minVolAfter + // << " " << newPos.X() << " " << newPos.Y() << " " << newPos.Z() + // << endl; + minVolBefore = minVolAfter; + nbOkBefore = nbOkAfter; + continue; // look for a better function + } + + if ( !findBest ) + break; + + } // loop on smoothing functions + + return nbBad; +} + +//================================================================================ +/*! + * \brief Chooses a smoothing technic giving a position most close to an initial one. + * For a correct result, _simplices must contain nodes lying on geometry. + */ +//================================================================================ + +void _LayerEdge::ChooseSmooFunction( const set< TGeomID >& concaveVertices, + const TNode2Edge& n2eMap) +{ + if ( _smooFunction ) return; + + // use smoothNefPolygon() near concaveVertices + if ( !concaveVertices.empty() ) + { + for ( size_t i = 0; i < _simplices.size(); ++i ) + { + if ( concaveVertices.count( _simplices[i]._nPrev->getshapeId() )) + { + _smooFunction = _funs[ FUN_NEFPOLY ]; + + // set FUN_CENTROIDAL to neighbor edges + TNode2Edge::const_iterator n2e; + for ( i = 0; i < _simplices.size(); ++i ) + { + if (( _simplices[i]._nPrev->GetPosition()->GetDim() == 2 ) && + (( n2e = n2eMap.find( _simplices[i]._nPrev )) != n2eMap.end() )) + { + n2e->second->_smooFunction = _funs[ FUN_CENTROIDAL ]; + } + } + return; + } + } + //} + + // this coice is done only if ( !concaveVertices.empty() ) for Grids/smesh/bugs_19/X1 + // where the nodes are smoothed too far along a sphere thus creating + // inverted _simplices + double dist[theNbSmooFuns]; + //double coef[theNbSmooFuns] = { 1., 1.2, 1.4, 1.4 }; + double coef[theNbSmooFuns] = { 1., 1., 1., 1. }; + + double minDist = Precision::Infinite(); + gp_Pnt p = SMESH_TNodeXYZ( _nodes[0] ); + for ( int i = 0; i < FUN_NEFPOLY; ++i ) + { + gp_Pnt newP = (this->*_funs[i])(); + dist[i] = p.SquareDistance( newP ); + if ( dist[i]*coef[i] < minDist ) + { + _smooFunction = _funs[i]; + minDist = dist[i]*coef[i]; + } + } + } + else + { + _smooFunction = _funs[ FUN_LAPLACIAN ]; + } + // int minDim = 3; + // for ( size_t i = 0; i < _simplices.size(); ++i ) + // minDim = Min( minDim, _simplices[i]._nPrev->GetPosition()->GetDim() ); + // if ( minDim == 0 ) + // _smooFunction = _funs[ FUN_CENTROIDAL ]; + // else if ( minDim == 1 ) + // _smooFunction = _funs[ FUN_CENTROIDAL ]; + + + // int iMin; + // for ( int i = 0; i < FUN_NB; ++i ) + // { + // //cout << dist[i] << " "; + // if ( _smooFunction == _funs[i] ) { + // iMin = i; + // //debugMsg( fNames[i] ); + // break; + // } + // } + // cout << _funNames[ iMin ] << "\t N:" << _nodes.back()->GetID() << endl; +} + +//================================================================================ +/*! + * \brief Returns a name of _SmooFunction + */ +//================================================================================ + +int _LayerEdge::smooFunID( _LayerEdge::PSmooFun fun) const +{ + if ( !fun ) + fun = _smooFunction; + for ( int i = 0; i < theNbSmooFuns; ++i ) + if ( fun == _funs[i] ) + return i; + + return theNbSmooFuns; +} + +//================================================================================ +/*! + * \brief Computes a new node position using Laplacian smoothing + */ +//================================================================================ + +gp_XYZ _LayerEdge::smoothLaplacian() +{ gp_XYZ newPos (0,0,0); for ( size_t i = 0; i < _simplices.size(); ++i ) newPos += SMESH_TNodeXYZ( _simplices[i]._nPrev ); newPos /= _simplices.size(); - const gp_XYZ& curPos ( _pos.back() ); - const gp_Pnt prevPos( _pos[ _pos.size()-2 ]); - if ( _curvature ) + return newPos; +} + +//================================================================================ +/*! + * \brief Computes a new node position using angular-based smoothing + */ +//================================================================================ + +gp_XYZ _LayerEdge::smoothAngular() +{ + vector< gp_Vec > edgeDir; edgeDir. reserve( _simplices.size() + 1); + vector< double > edgeSize; edgeSize.reserve( _simplices.size() ); + vector< gp_XYZ > points; points. reserve( _simplices.size() ); + + gp_XYZ pPrev = SMESH_TNodeXYZ( _simplices.back()._nPrev ); + gp_XYZ pN( 0,0,0 ); + for ( size_t i = 0; i < _simplices.size(); ++i ) { - double delta = _curvature->lenDelta( _len ); - if ( delta > 0 ) - newPos += _normal * delta; + gp_XYZ p = SMESH_TNodeXYZ( _simplices[i]._nPrev ); + edgeDir.push_back( p - pPrev ); + edgeSize.push_back( edgeDir.back().Magnitude() ); + //double edgeSize = edgeDir.back().Magnitude(); + if ( edgeSize.back() < numeric_limits::min() ) + { + edgeDir.pop_back(); + edgeSize.pop_back(); + } else { - double segLen = _normal * ( newPos - prevPos.XYZ() ); - if ( segLen + delta > 0 ) - newPos += _normal * delta; + edgeDir.back() /= edgeSize.back(); + points.push_back( p ); + pN += p; } - // double segLenChange = _normal * ( curPos - newPos ); - // newPos += 0.5 * _normal * segLenChange; + pPrev = p; + } + edgeDir.push_back ( edgeDir[0] ); + edgeSize.push_back( edgeSize[0] ); + pN /= points.size(); + + gp_XYZ newPos(0,0,0); + //gp_XYZ pN = SMESH_TNodeXYZ( _nodes.back() ); + double sumSize = 0; + for ( size_t i = 0; i < points.size(); ++i ) + { + gp_Vec toN( pN - points[i]); + double toNLen = toN.Magnitude(); + if ( toNLen < numeric_limits::min() ) + { + newPos += pN; + continue; + } + gp_Vec bisec = edgeDir[i] + edgeDir[i+1]; + double bisecLen = bisec.SquareMagnitude(); + if ( bisecLen < numeric_limits::min() ) + { + gp_Vec norm = edgeDir[i] ^ toN; + bisec = norm ^ edgeDir[i]; + bisecLen = bisec.SquareMagnitude(); + } + bisecLen = Sqrt( bisecLen ); + bisec /= bisecLen; + +#if 1 + //bisecLen = 1.; + gp_XYZ pNew = ( points[i] + bisec.XYZ() * toNLen ) * bisecLen; + sumSize += bisecLen; +#else + gp_XYZ pNew = ( points[i] + bisec.XYZ() * toNLen ) * ( edgeSize[i] + edgeSize[i+1] ); + sumSize += ( edgeSize[i] + edgeSize[i+1] ); +#endif + newPos += pNew; + } + newPos /= sumSize; + + return newPos; +} + +//================================================================================ +/*! + * \brief Computes a new node position using weigthed node positions + */ +//================================================================================ + +gp_XYZ _LayerEdge::smoothLengthWeighted() +{ + vector< double > edgeSize; edgeSize.reserve( _simplices.size() + 1); + vector< gp_XYZ > points; points. reserve( _simplices.size() ); + + gp_XYZ pPrev = SMESH_TNodeXYZ( _simplices.back()._nPrev ); + for ( size_t i = 0; i < _simplices.size(); ++i ) + { + gp_XYZ p = SMESH_TNodeXYZ( _simplices[i]._nPrev ); + edgeSize.push_back( ( p - pPrev ).Modulus() ); + if ( edgeSize.back() < numeric_limits::min() ) + { + edgeSize.pop_back(); + } + else + { + points.push_back( p ); + } + pPrev = p; + } + edgeSize.push_back( edgeSize[0] ); + + gp_XYZ newPos(0,0,0); + double sumSize = 0; + for ( size_t i = 0; i < points.size(); ++i ) + { + newPos += points[i] * ( edgeSize[i] + edgeSize[i+1] ); + sumSize += edgeSize[i] + edgeSize[i+1]; + } + newPos /= sumSize; + return newPos; +} + +//================================================================================ +/*! + * \brief Computes a new node position using angular-based smoothing + */ +//================================================================================ + +gp_XYZ _LayerEdge::smoothCentroidal() +{ + gp_XYZ newPos(0,0,0); + gp_XYZ pN = SMESH_TNodeXYZ( _nodes.back() ); + double sumSize = 0; + for ( size_t i = 0; i < _simplices.size(); ++i ) + { + gp_XYZ p1 = SMESH_TNodeXYZ( _simplices[i]._nPrev ); + gp_XYZ p2 = SMESH_TNodeXYZ( _simplices[i]._nNext ); + gp_XYZ gc = ( pN + p1 + p2 ) / 3.; + double size = (( p1 - pN ) ^ ( p2 - pN )).Modulus(); + + sumSize += size; + newPos += gc * size; + } + newPos /= sumSize; + + return newPos; +} + +//================================================================================ +/*! + * \brief Computes a new node position located inside a Nef polygon + */ +//================================================================================ + +gp_XYZ _LayerEdge::smoothNefPolygon() +{ + gp_XYZ newPos(0,0,0); + + // get a plane to seach a solution on + + vector< gp_XYZ > vecs( _simplices.size() + 1 ); + size_t i; + const double tol = numeric_limits::min(); + gp_XYZ center(0,0,0); + for ( i = 0; i < _simplices.size(); ++i ) + { + vecs[i] = ( SMESH_TNodeXYZ( _simplices[i]._nNext ) - + SMESH_TNodeXYZ( _simplices[i]._nPrev )); + center += SMESH_TNodeXYZ( _simplices[i]._nPrev ); + } + vecs.back() = vecs[0]; + center /= _simplices.size(); + + gp_XYZ zAxis(0,0,0); + for ( i = 0; i < _simplices.size(); ++i ) + zAxis += vecs[i] ^ vecs[i+1]; + + gp_XYZ yAxis; + for ( i = 0; i < _simplices.size(); ++i ) + { + yAxis = vecs[i]; + if ( yAxis.SquareModulus() > tol ) + break; + } + gp_XYZ xAxis = yAxis ^ zAxis; + // SMESH_TNodeXYZ p0( _simplices[0]._nPrev ); + // const double tol = 1e-6 * ( p0.Distance( _simplices[1]._nPrev ) + + // p0.Distance( _simplices[2]._nPrev )); + // gp_XYZ center = smoothLaplacian(); + // gp_XYZ xAxis, yAxis, zAxis; + // for ( i = 0; i < _simplices.size(); ++i ) + // { + // xAxis = SMESH_TNodeXYZ( _simplices[i]._nPrev ) - center; + // if ( xAxis.SquareModulus() > tol*tol ) + // break; + // } + // for ( i = 1; i < _simplices.size(); ++i ) + // { + // yAxis = SMESH_TNodeXYZ( _simplices[i]._nPrev ) - center; + // zAxis = xAxis ^ yAxis; + // if ( zAxis.SquareModulus() > tol*tol ) + // break; + // } + // if ( i == _simplices.size() ) return newPos; + + yAxis = zAxis ^ xAxis; + xAxis /= xAxis.Modulus(); + yAxis /= yAxis.Modulus(); + + // get half-planes of _simplices + + vector< _halfPlane > halfPlns( _simplices.size() ); + int nbHP = 0; + for ( size_t i = 0; i < _simplices.size(); ++i ) + { + gp_XYZ OP1 = SMESH_TNodeXYZ( _simplices[i]._nPrev ) - center; + gp_XYZ OP2 = SMESH_TNodeXYZ( _simplices[i]._nNext ) - center; + gp_XY p1( OP1 * xAxis, OP1 * yAxis ); + gp_XY p2( OP2 * xAxis, OP2 * yAxis ); + gp_XY vec12 = p2 - p1; + double dist12 = vec12.Modulus(); + if ( dist12 < tol ) + continue; + vec12 /= dist12; + halfPlns[ nbHP ]._pos = p1; + halfPlns[ nbHP ]._dir = vec12; + halfPlns[ nbHP ]._inNorm.SetCoord( -vec12.Y(), vec12.X() ); + ++nbHP; } - // count quality metrics (orientation) of tetras around _tgtNode - int nbOkBefore = 0; - for ( size_t i = 0; i < _simplices.size(); ++i ) - nbOkBefore += _simplices[i].IsForward( _nodes[0], &curPos ); + // intersect boundaries of half-planes, define state of intersection points + // in relation to all half-planes and calculate internal point of a 2D polygon - int nbOkAfter = 0; - for ( size_t i = 0; i < _simplices.size(); ++i ) - nbOkAfter += _simplices[i].IsForward( _nodes[0], &newPos ); + double sumLen = 0; + gp_XY newPos2D (0,0); - if ( nbOkAfter < nbOkBefore ) - return false; + enum { UNDEF = -1, NOT_OUT, IS_OUT, NO_INT }; + typedef std::pair< gp_XY, int > TIntPntState; // coord and isOut state + TIntPntState undefIPS( gp_XY(1e100,1e100), UNDEF ); - SMDS_MeshNode* n = const_cast< SMDS_MeshNode* >( _nodes.back() ); + vector< vector< TIntPntState > > allIntPnts( nbHP ); + for ( int iHP1 = 0; iHP1 < nbHP; ++iHP1 ) + { + vector< TIntPntState > & intPnts1 = allIntPnts[ iHP1 ]; + if ( intPnts1.empty() ) intPnts1.resize( nbHP, undefIPS ); - _len -= prevPos.Distance(SMESH_TNodeXYZ( n )); - _len += prevPos.Distance(newPos); + int iPrev = SMESH_MesherHelper::WrapIndex( iHP1 - 1, nbHP ); + int iNext = SMESH_MesherHelper::WrapIndex( iHP1 + 1, nbHP ); - n->setXYZ( newPos.X(), newPos.Y(), newPos.Z()); - _pos.back() = newPos; + int nbNotOut = 0; + const gp_XY* segEnds[2] = { 0, 0 }; // NOT_OUT points - badNb += _simplices.size() - nbOkAfter; + for ( int iHP2 = 0; iHP2 < nbHP; ++iHP2 ) + { + if ( iHP1 == iHP2 ) continue; - dumpMove( n ); + TIntPntState & ips1 = intPnts1[ iHP2 ]; + if ( ips1.second == UNDEF ) + { + // find an intersection point of boundaries of iHP1 and iHP2 - return true; + if ( iHP2 == iPrev ) // intersection with neighbors is known + ips1.first = halfPlns[ iHP1 ]._pos; + else if ( iHP2 == iNext ) + ips1.first = halfPlns[ iHP2 ]._pos; + else if ( !halfPlns[ iHP1 ].FindInterestion( halfPlns[ iHP2 ], ips1.first )) + ips1.second = NO_INT; + + // classify the found intersection point + if ( ips1.second != NO_INT ) + { + ips1.second = NOT_OUT; + for ( int i = 0; i < nbHP && ips1.second == NOT_OUT; ++i ) + if ( i != iHP1 && i != iHP2 && + halfPlns[ i ].IsOut( ips1.first, tol )) + ips1.second = IS_OUT; + } + vector< TIntPntState > & intPnts2 = allIntPnts[ iHP2 ]; + if ( intPnts2.empty() ) intPnts2.resize( nbHP, undefIPS ); + TIntPntState & ips2 = intPnts2[ iHP1 ]; + ips2 = ips1; + } + if ( ips1.second == NOT_OUT ) + { + ++nbNotOut; + segEnds[ bool(segEnds[0]) ] = & ips1.first; + } + } + + // find a NOT_OUT segment of boundary which is located between + // two NOT_OUT int points + + if ( nbNotOut < 2 ) + continue; // no such a segment + + if ( nbNotOut > 2 ) + { + // sort points along the boundary + map< double, TIntPntState* > ipsByParam; + for ( int iHP2 = 0; iHP2 < nbHP; ++iHP2 ) + { + TIntPntState & ips1 = intPnts1[ iHP2 ]; + if ( ips1.second != NO_INT ) + { + gp_XY op = ips1.first - halfPlns[ iHP1 ]._pos; + double param = op * halfPlns[ iHP1 ]._dir; + ipsByParam.insert( make_pair( param, & ips1 )); + } + } + // look for two neighboring NOT_OUT points + nbNotOut = 0; + map< double, TIntPntState* >::iterator u2ips = ipsByParam.begin(); + for ( ; u2ips != ipsByParam.end(); ++u2ips ) + { + TIntPntState & ips1 = *(u2ips->second); + if ( ips1.second == NOT_OUT ) + segEnds[ bool( nbNotOut++ ) ] = & ips1.first; + else if ( nbNotOut >= 2 ) + break; + else + nbNotOut = 0; + } + } + + if ( nbNotOut >= 2 ) + { + double len = ( *segEnds[0] - *segEnds[1] ).Modulus(); + sumLen += len; + + newPos2D += 0.5 * len * ( *segEnds[0] + *segEnds[1] ); + } + } + + if ( sumLen > 0 ) + { + newPos2D /= sumLen; + newPos = center + xAxis * newPos2D.X() + yAxis * newPos2D.Y(); + } + else + { + newPos = center; + } + + return newPos; } //================================================================================ @@ -5483,7 +6410,7 @@ bool _ViscousBuilder::shrink() if ( !smoothNodes.empty() ) { vector<_Simplex> simplices; - getSimplices( smoothNodes[0], simplices, ignoreShapes ); + _Simplex::GetSimplices( smoothNodes[0], simplices, ignoreShapes ); helper.GetNodeUV( F, simplices[0]._nPrev, 0, &isOkUV ); // fix UV of silpmex nodes helper.GetNodeUV( F, simplices[0]._nNext, 0, &isOkUV ); gp_XY uv = helper.GetNodeUV( F, smoothNodes[0], 0, &isOkUV ); @@ -5524,6 +6451,7 @@ bool _ViscousBuilder::shrink() while ( fIt->more() ) if ( const SMDS_MeshElement* f = fIt->next() ) dumpChangeNodes( f ); + dumpFunctionEnd(); // Replace source nodes by target nodes in mesh faces to shrink dumpFunction(SMESH_Comment("replNodesOnFace")<first); // debug @@ -5549,6 +6477,7 @@ bool _ViscousBuilder::shrink() dumpChangeNodes( f ); } } + dumpFunctionEnd(); // find out if a FACE is concave const bool isConcaveFace = isConcave( F, helper ); @@ -5563,11 +6492,12 @@ bool _ViscousBuilder::shrink() const SMDS_MeshNode* n = smoothNodes[i]; nodesToSmooth[ i ]._node = n; // src nodes must be replaced by tgt nodes to have tgt nodes in _simplices - getSimplices( n, nodesToSmooth[ i ]._simplices, ignoreShapes, NULL, sortSimplices ); + _Simplex::GetSimplices( n, nodesToSmooth[ i ]._simplices, ignoreShapes, 0, sortSimplices); // fix up incorrect uv of nodes on the FACE helper.GetNodeUV( F, n, 0, &isOkUV); dumpMove( n ); } + dumpFunctionEnd(); } //if ( nodesToSmooth.empty() ) continue; @@ -5588,7 +6518,7 @@ bool _ViscousBuilder::shrink() // srinked while srinking another FACE srinker.RestoreParams(); } - getSimplices( /*tgtNode=*/edge->_nodes.back(), edge->_simplices, ignoreShapes ); + _Simplex::GetSimplices( /*tgtNode=*/edge->_nodes.back(), edge->_simplices, ignoreShapes ); } } @@ -5678,10 +6608,10 @@ bool _ViscousBuilder::shrink() n = usedNodes.find( nodesToSmooth[ i ]._node ); if ( n != usedNodes.end()) { - getSimplices( nodesToSmooth[ i ]._node, - nodesToSmooth[ i ]._simplices, - ignoreShapes, NULL, - /*sortSimplices=*/ smoothType == _SmoothNode::ANGULAR ); + _Simplex::GetSimplices( nodesToSmooth[ i ]._node, + nodesToSmooth[ i ]._simplices, + ignoreShapes, NULL, + /*sortSimplices=*/ smoothType == _SmoothNode::ANGULAR ); usedNodes.erase( n ); } } @@ -5690,9 +6620,9 @@ bool _ViscousBuilder::shrink() n = usedNodes.find( /*tgtNode=*/ lEdges[i]->_nodes.back() ); if ( n != usedNodes.end()) { - getSimplices( lEdges[i]->_nodes.back(), - lEdges[i]->_simplices, - ignoreShapes ); + _Simplex::GetSimplices( lEdges[i]->_nodes.back(), + lEdges[i]->_simplices, + ignoreShapes ); usedNodes.erase( n ); } } @@ -6259,7 +7189,7 @@ gp_XY _SmoothNode::computeAngularPos(vector& uv, edgeSize.back() = edgeSize.front(); gp_XY newPos(0,0); - int nbEdges = 0; + //int nbEdges = 0; double sumSize = 0; for ( size_t i = 1; i < edgeDir.size(); ++i ) { @@ -6285,7 +7215,7 @@ gp_XY _SmoothNode::computeAngularPos(vector& uv, distToN = -distToN; newPos += ( p + bisec * distToN ) * ( edgeSize[i1] + edgeSize[i] ); - ++nbEdges; + //++nbEdges; sumSize += edgeSize[i1] + edgeSize[i]; } newPos /= /*nbEdges * */sumSize; diff --git a/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.cxx b/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.cxx index 4cdd2b92e..0c5ad56fb 100644 --- a/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.cxx +++ b/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.cxx @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include diff --git a/src/StdMeshersGUI/StdMeshersGUI_ObjectReferenceParamWdg.cxx b/src/StdMeshersGUI/StdMeshersGUI_ObjectReferenceParamWdg.cxx index 9e5768402..7960a9686 100644 --- a/src/StdMeshersGUI/StdMeshersGUI_ObjectReferenceParamWdg.cxx +++ b/src/StdMeshersGUI/StdMeshersGUI_ObjectReferenceParamWdg.cxx @@ -35,7 +35,6 @@ #include #include #include -#include // SALOME KERNEL incldues #include diff --git a/src/StdMeshersGUI/StdMeshersGUI_QuadrangleParamWdg.cxx b/src/StdMeshersGUI/StdMeshersGUI_QuadrangleParamWdg.cxx index a99177bce..9db22c2a9 100644 --- a/src/StdMeshersGUI/StdMeshersGUI_QuadrangleParamWdg.cxx +++ b/src/StdMeshersGUI/StdMeshersGUI_QuadrangleParamWdg.cxx @@ -29,7 +29,6 @@ #include #include #include -#include #include // Qt includes diff --git a/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx b/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx index c481eea7e..e912e113d 100644 --- a/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx +++ b/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx @@ -408,7 +408,7 @@ bool StdMeshersGUI_StdHypothesisCreator::checkParams( QString& msg ) const srcV = w1->GetValue(); tgtV = w2->GetValue(); ok = (( srcV.isEmpty() && tgtV.isEmpty() ) || - ( !srcV.isEmpty() && !tgtV.isEmpty() && srcV != tgtV )); + ( !srcV.isEmpty() && !tgtV.isEmpty() /*&& srcV != tgtV*/ )); if ( !ok ) { w1->SetObject( CORBA::Object::_nil() ); w2->SetObject( CORBA::Object::_nil() ); diff --git a/src/StdMeshersGUI/StdMeshersGUI_SubShapeSelectorWdg.cxx b/src/StdMeshersGUI/StdMeshersGUI_SubShapeSelectorWdg.cxx index 9cd4ff727..798635493 100644 --- a/src/StdMeshersGUI/StdMeshersGUI_SubShapeSelectorWdg.cxx +++ b/src/StdMeshersGUI/StdMeshersGUI_SubShapeSelectorWdg.cxx @@ -43,7 +43,6 @@ // SALOME GUI includes #include #include -#include // SUIT Includes #include diff --git a/src/Tools/YamsPlug/monYamsPlugDialog.py b/src/Tools/YamsPlug/monYamsPlugDialog.py index 7f43838c4..3fa65e557 100644 --- a/src/Tools/YamsPlug/monYamsPlugDialog.py +++ b/src/Tools/YamsPlug/monYamsPlugDialog.py @@ -485,7 +485,7 @@ class MonYamsPlugDialog(Ui_YamsPlugDialog,QWidget): if self.SP_Ridge.value() != 45.0 : self.commande+=" --ridge_angle %f"%self.SP_Ridge.value() if self.SP_MaxSize.value() != 100 : self.commande+=" --max_size %f" %self.SP_MaxSize.value() if self.SP_MinSize.value() != 5 : self.commande+=" --min_size %f" %self.SP_MinSize.value() - if self.SP_Gradation.value() != 1.3 : self.commande+=" --gradation %f" %self.SP_MaxSize.value() + if self.SP_Gradation.value() != 1.3 : self.commande+=" --gradation %f" %self.SP_Gradation.value() if self.SP_Memory.value() != 0 : self.commande+=" --max_memory %d" %self.SP_Memory.value() if self.SP_Verbosity.value() != 3 : self.commande+=" --verbose %d" %self.SP_Verbosity.value()