Salome HOME
Merge branch 'master' into pra/blocFissure
authorPaul RASCLE <paul.rascle@edf.fr>
Tue, 2 Dec 2014 10:01:36 +0000 (11:01 +0100)
committerPaul RASCLE <paul.rascle@edf.fr>
Tue, 2 Dec 2014 10:01:36 +0000 (11:01 +0100)
117 files changed:
CMakeLists.txt
doc/salome/examples/CMakeLists.txt
doc/salome/examples/a3DmeshOnModified2Dmesh.py [new file with mode: 0644]
doc/salome/examples/creating_meshes_ex08.py
doc/salome/examples/prism_3d_algo.py
doc/salome/gui/SMESH/images/copy_mesh_dlg.png
doc/salome/gui/SMESH/images/display_entity_choose_item.png [new file with mode: 0644]
doc/salome/gui/SMESH/images/display_entity_dlg.png [new file with mode: 0644]
doc/salome/gui/SMESH/images/extrusionalongaline1.png [changed mode: 0755->0644]
doc/salome/gui/SMESH/images/extrusionalongaline2.png [changed mode: 0755->0644]
doc/salome/gui/SMESH/input/1d_meshing_hypo.doc
doc/salome/gui/SMESH/input/2d_meshing_hypo.doc
doc/salome/gui/SMESH/input/about_meshes.doc
doc/salome/gui/SMESH/input/basic_meshing_algos.doc
doc/salome/gui/SMESH/input/constructing_meshes.doc
doc/salome/gui/SMESH/input/constructing_submeshes.doc
doc/salome/gui/SMESH/input/copy_mesh.doc
doc/salome/gui/SMESH/input/display_entity.doc
doc/salome/gui/SMESH/input/extrusion.doc
doc/salome/gui/SMESH/input/modifying_meshes.doc
doc/salome/gui/SMESH/input/pattern_mapping.doc
doc/salome/gui/SMESH/input/selection_filter_library.doc
doc/salome/gui/SMESH/input/tui_creating_meshes.doc
doc/salome/gui/SMESH/input/viewing_meshes_overview.doc
resources/CMakeLists.txt
resources/SalomeApp.xml.in
resources/mesh_choose.png [new file with mode: 0644]
resources/mesh_choose_all.png [new file with mode: 0644]
src/Controls/SMESH_Controls.cxx
src/PluginUtils/GeomSelectionTools.cxx
src/SMESH/CMakeLists.txt
src/SMESH/SMESH_Algo.cxx
src/SMESH/SMESH_HypoFilter.cxx
src/SMESH/SMESH_Mesh.cxx
src/SMESH/SMESH_Mesh.hxx
src/SMESH/SMESH_MeshEditor.cxx
src/SMESH/SMESH_MesherHelper.cxx
src/SMESH/SMESH_MesherHelper.hxx
src/SMESH/SMESH_Pattern.cxx
src/SMESH/SMESH_subMesh.cxx
src/SMESHGUI/CMakeLists.txt
src/SMESHGUI/SMESHGUI.cxx
src/SMESHGUI/SMESHGUI_Add0DElemsOnAllNodesDlg.cxx
src/SMESHGUI/SMESHGUI_AddMeshElementDlg.cxx
src/SMESHGUI/SMESHGUI_CopyMeshDlg.cxx
src/SMESHGUI/SMESHGUI_DeleteGroupDlg.cxx
src/SMESHGUI/SMESHGUI_DisplayEntitiesDlg.cxx [new file with mode: 0644]
src/SMESHGUI/SMESHGUI_DisplayEntitiesDlg.h [new file with mode: 0644]
src/SMESHGUI/SMESHGUI_DuplicateNodesDlg.cxx
src/SMESHGUI/SMESHGUI_ExtrusionDlg.cxx
src/SMESHGUI/SMESHGUI_FilterDlg.cxx
src/SMESHGUI/SMESHGUI_GEOMGenUtils.cxx
src/SMESHGUI/SMESHGUI_GEOMGenUtils.h
src/SMESHGUI/SMESHGUI_GroupDlg.cxx
src/SMESHGUI/SMESHGUI_GroupOpDlg.cxx
src/SMESHGUI/SMESHGUI_Hypotheses.cxx
src/SMESHGUI/SMESHGUI_HypothesesUtils.cxx
src/SMESHGUI/SMESHGUI_HypothesesUtils.h
src/SMESHGUI/SMESHGUI_MakeNodeAtPointDlg.cxx
src/SMESHGUI/SMESHGUI_Measurements.cxx
src/SMESHGUI/SMESHGUI_MeshDlg.cxx
src/SMESHGUI/SMESHGUI_MeshEditPreview.cxx
src/SMESHGUI/SMESHGUI_MeshInfo.cxx
src/SMESHGUI/SMESHGUI_MeshOp.cxx
src/SMESHGUI/SMESHGUI_MultiEditDlg.cxx
src/SMESHGUI/SMESHGUI_Operations.h
src/SMESHGUI/SMESHGUI_ReorientFacesDlg.cxx
src/SMESHGUI/SMESHGUI_RotationDlg.cxx
src/SMESHGUI/SMESHGUI_ScaleDlg.cxx
src/SMESHGUI/SMESHGUI_Selection.cxx
src/SMESHGUI/SMESHGUI_Selection.h
src/SMESHGUI/SMESHGUI_SelectionOp.cxx
src/SMESHGUI/SMESHGUI_SmoothingDlg.cxx
src/SMESHGUI/SMESHGUI_SymmetryDlg.cxx
src/SMESHGUI/SMESHGUI_TranslationDlg.cxx
src/SMESHGUI/SMESHGUI_TransparencyDlg.cxx
src/SMESHGUI/SMESHGUI_Utils.h
src/SMESHGUI/SMESHGUI_VTKUtils.cxx
src/SMESHGUI/SMESHGUI_XmlHandler.cxx
src/SMESHGUI/SMESH_images.ts
src/SMESHGUI/SMESH_msg_en.ts
src/SMESHGUI/SMESH_msg_fr.ts
src/SMESHGUI/SMESH_msg_ja.ts
src/SMESHUtils/SMESH_TypeDefs.hxx
src/SMESH_I/SMESH_2smeshpy.cxx
src/SMESH_I/SMESH_2smeshpy.hxx
src/SMESH_I/SMESH_Filter_i.cxx
src/SMESH_I/SMESH_Gen_i.cxx
src/SMESH_I/SMESH_Gen_i_1.cxx
src/SMESH_I/SMESH_MeshEditor_i.cxx
src/SMESH_SWIG/StdMeshersBuilder.py
src/SMESH_SWIG/smeshBuilder.py
src/SMESH_SWIG/smesh_algorithm.py
src/StdMeshers/StdMeshers_Adaptive1D.cxx
src/StdMeshers/StdMeshers_CartesianParameters3D.cxx
src/StdMeshers/StdMeshers_Cartesian_3D.cxx
src/StdMeshers/StdMeshers_Distribution.cxx
src/StdMeshers/StdMeshers_Distribution.hxx
src/StdMeshers/StdMeshers_FaceSide.cxx
src/StdMeshers/StdMeshers_NumberOfSegments.cxx
src/StdMeshers/StdMeshers_Prism_3D.cxx
src/StdMeshers/StdMeshers_Prism_3D.hxx
src/StdMeshers/StdMeshers_ProjectionUtils.cxx
src/StdMeshers/StdMeshers_ProjectionUtils.hxx
src/StdMeshers/StdMeshers_Projection_2D.cxx
src/StdMeshers/StdMeshers_Projection_2D.hxx
src/StdMeshers/StdMeshers_Projection_3D.cxx
src/StdMeshers/StdMeshers_Quadrangle_2D.cxx
src/StdMeshers/StdMeshers_RadialPrism_3D.cxx
src/StdMeshers/StdMeshers_Regular_1D.cxx
src/StdMeshers/StdMeshers_ViscousLayers.cxx
src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.cxx
src/StdMeshersGUI/StdMeshersGUI_ObjectReferenceParamWdg.cxx
src/StdMeshersGUI/StdMeshersGUI_QuadrangleParamWdg.cxx
src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx
src/StdMeshersGUI/StdMeshersGUI_SubShapeSelectorWdg.cxx
src/Tools/YamsPlug/monYamsPlugDialog.py

index 249c3c09dcfc18a3965cde005f4b3c8c2ee71cb3..a88f8c23a473c4e13cefb8f8d2bbec713a5608b0 100755 (executable)
@@ -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) 
 
index 227764998bb0c1281ab364df15d4bbc745604b8b..7aa0636896d74818d7515d8e56d0f36ad144f9e8 100644 (file)
 # 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 (file)
index 0000000..7fcdcac
--- /dev/null
@@ -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)
index 18f9dad011c02108c0b9a222bf36a0d1d327b5cc..e8f43eee6b7d23060241d922377ac175d303b730 100644 (file)
@@ -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:]
index df18d0fcb511a98627d2294bfc85ae2af6ae8a65..7be0a29d3ddabad9cebf570f5da15e9166d06087 100644 (file)
@@ -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)
index db9c929b5fca0f1a52838fa5dbc57a474cbbb14b..c959e680f6f20123999988deef191927db99fd4c 100644 (file)
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 (file)
index 0000000..d099618
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 (file)
index 0000000..d0f4fa0
Binary files /dev/null and b/doc/salome/gui/SMESH/images/display_entity_dlg.png differ
old mode 100755 (executable)
new mode 100644 (file)
index 95a26ca..0cc13d5
Binary files a/doc/salome/gui/SMESH/images/extrusionalongaline1.png and b/doc/salome/gui/SMESH/images/extrusionalongaline1.png differ
old mode 100755 (executable)
new mode 100644 (file)
index 8c16623..987a66c
Binary files a/doc/salome/gui/SMESH/images/extrusionalongaline2.png and b/doc/salome/gui/SMESH/images/extrusionalongaline2.png differ
index 7a9228b68497eb5bfd97e9677b94ce5d68387799..8c38c8ddfa1e645374989affaa7a24a80e9e1e85 100644 (file)
@@ -257,15 +257,14 @@ hypothesis operation.
 \anchor automatic_length_anchor
 <h2>Automatic Length</h2>
 
-This hypothesis is automatically applied when you select <b>Assign a
-set of hypotheses</b> 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."
index 0ccb902e0025d7266fde1d8fc95b8901a9ad9458..05b8d5a39eaff5d547459f907681d5b0b398834f 100644 (file)
@@ -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.</li>
 </ul>
+\note <b>Enforced nodes</b> can't be created at \b Reduced transition type.
 
 Let us see how the algorithm works:
-
-
 <ul>
   <li> Initially positions of nodes are computed without taking into
   account the enforced vertex (yellow point).</li> 
index 870e5c1825cdffb4185235ec4db026777ccf522a..65201ac6422e54c9a72469a622bcd5f3f6d8dc6a 100644 (file)
@@ -7,10 +7,12 @@ a set of entities with a simple topology.
 
 It is possible to \subpage constructing_meshes_page "construct meshes" 
 on the basis of geometrical shapes produced in the GEOM module.
-It is also possible to 
-\subpage constructing_submeshes_page "construct mesh on a part of the geometrical object", 
-for example, a face, with different meshing parameters or using
-another meshing algorithm.
+Construction of \subpage constructing_submeshes_page "sub-meshes"
+allows to mesh parts of the geometrical object, for example a face,
+with different meshing parameters or using another meshing algorithm
+than other parts.
+
+3D mesh can be generated basing on a 2D closed mesh.
 
 Several created meshes can be \subpage building_compounds_page "combined into another mesh".
 
@@ -62,44 +64,4 @@ described in the following way:
   coordinates of the corresponding vertex.</li>
 </ul>
 
-<br><h2>Connections</h2>
-
-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:
-
-<ul>
-<li>A node bounds edges, faces and volumes</li>
-<li>An edge bounds faces, and volumes</li>
-<li>A face bounds volumes</li>
-<li>A volume is bounded by faces, edges and nodes</li>
-<li>A face is bounded by edges, and nodes</li>
-<li>An edge is bounded by nodes</li>
-</ul>
-
-You can notice that there are two types of connections: \b inverse and
-\b direct connections.
-
-<br><h2>Inverse connections</h2>
-
-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.
-
-<br><h2>Direct connections</h2>
-
-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.
-
 */
index ee632b282113eb56970641ada4fda99b01a9a1ec..977b505dbad674d72220d8e33e9aaf5a4363c7bb 100644 (file)
@@ -52,15 +52,15 @@ geometrical objects.
 
 There is also a number of more specific algorithms:
 <ul>
+<li>\subpage prism_3d_algo_page "for meshing prismatic shapes"</li>
 <li>\subpage projection_algos_page "for meshing by projection of another mesh"</li>
 <li>\subpage import_algos_page "for meshing by importing elements from another mesh"</li>
 <li>\subpage radial_prism_algo_page "for meshing geometrical objects with cavities"</li>
-<li>\subpage segments_around_vertex_algo_page "for defining the local size of elements around a certain node"</li>
-<li>\subpage prism_3d_algo_page "for meshing prismatic shapes"</li>
 <li>\subpage radial_quadrangle_1D2D_algo_page "for meshing special 2d faces (circles and part of circles)"</li>
 <li>\subpage use_existing_page "Use Edges to be Created Manually" and 
 \ref use_existing_page "Use Faces to be Created Manually" algorithms can be
 used to create a 1D or a 2D mesh in a python script.</li>
+<li>\subpage segments_around_vertex_algo_page "for defining the local size of elements around a certain node"</li>
 </ul>
 
 \ref constructing_meshes_page "Constructing meshes" page describes in
index 232d4f524b006770d80f347e7900bf98699d3e74..5d26cae6c0f05ce1aa1e6dcd4e2f9dc631137c0a 100644 (file)
@@ -9,6 +9,7 @@
   <li> \ref preview_anchor "Previewing the mesh" (optional)</li>
   <li> \ref submesh_order_anchor "Changing sub-mesh priority" (optional)</li>
   <li> \ref compute_anchor "Computing the mesh"</li>
+  <li> \ref edit_anchor "Editing the mesh" (optional)</li>
 </ul>
 
 \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.
 
-<br><br>
-
-
+<p><p>
+\anchor edit_anchor
+<h2>Editing the mesh</h2>
+
+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.
+
+<b>See Also</b> a sample TUI Script demonstrates the possibility of 
+\ref tui_editing_while_meshing "Intermediate edition while meshing"
 
 */
index 230903449a5119b44b678cb47e447181b7ac8e37..782b5662ee539d38821e49c8c690df822326a585 100644 (file)
@@ -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: <ul>
+<li> In Geometry module, via <em>New Entity > Explode</em> menu.</li>
+<li> In Geometry module, by creation of a group (<em>New Entity >
+    Group > Create Group</em> menu).</li> 
+<li> In Mesh module, by
+  \ref subshape_by_mesh_elem "selecting a mesh element" generated on a
+  sub-shape of interest. This way is accessible if the mesh is
+  already computed.</li> 
+</ul>
 
 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, <b> Element Type </b> defines kind of element to pick in the
-Viewer. 
+In this dialog, <b> Element Type </b> defines kind of element to pick in the
+Viewer.
 Instead of picking an element in the Viewer, you can type its
 ID in <b> Element ID</b> field. 
-<b> Geometry name </b> field allows defining a name of the sub-shape.
-
+<b> Geometry name </b> 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
index 2c65ab8d0c5002207766f16445b335c2a1039657..15bf2d129e26169a60b29b3b58360e261f3f56da 100644 (file)
@@ -42,9 +42,6 @@ selection_filter_library_page "Selection filter library" page.</li>
 <ul>
 <li>activate <b>Generate groups</b> checkbox to copy the groups of
 elements of the source mesh to the newly created mesh.</li>
-<li>activate <b>Preserve IDs of elements</b> checkbox to keep
-the IDs of new nodes and elements the same as the IDs of source nodes
-and elements.</li>
 </ul>
 </li>
 
index 570674017264d06cbbeb7d20bec9ad74abd16066..ccd0043efbfd24267119c90e04552337b64f8239 100644 (file)
@@ -9,4 +9,13 @@ edges or combine them.
 
 \image html image58.gif Only Edges
 
+If the mesh contains a lot of elements, select <b>Choose...</b> item, 
+
+\image html display_entity_choose_item.png Item to call 'Display Entity' dialog box
+
+and <b>Display Entity</b> 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
index 4813eee5cae4badc998966fc2ca7b2c7f0dc6d55..a28af48d4673c0db26d087a53363270c2fdc13b1 100644 (file)
@@ -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:
 <table>
-<tr><td><b>Extruded element</b></td><td><b> Result elements </b></td></tr>
-<tr><td>Node              </td><td> Segments </td></tr>
-<tr><td>Segment           </td><td> Quadrilaterals </td></tr>
-<tr><td>Triangle          </td><td> Pentahedrons </td></tr>
-<tr><td>Quadrilateral     </td><td> Hexahedrons </td></tr>
-<tr><td>Polygon           </td><td> Polyhedrons </td></tr>
+<tr><td><b>Extruded element</b></td><td><b> Result element </b></td></tr>
+<tr><td>Node              </td><td> Segment </td></tr>
+<tr><td>Segment           </td><td> Quadrilateral </td></tr>
+<tr><td>Triangle          </td><td> Pentahedron </td></tr>
+<tr><td>Quadrilateral     </td><td> Hexahedron </td></tr>
+<tr><td>Polygon           </td><td> Polyhedron </td></tr>
 <tr><td>Hexagonal polygon </td><td> Hexagonal prism </td></tr>
 </table>
 
@@ -35,7 +35,8 @@ The following dialog common for line and planar elements will appear:
 
 <li>In this dialog:
 <ul>
-  <li>Select the type of elements which will be extruded (0D, 1D or 2D).</li>
+  <li>Select the type of elements which will be extruded (nodes, 1D or
+  2D elements).</li>
   <li>Specify the IDs of the elements which will be extruded by one
     following means:
     <ul>
@@ -62,9 +63,15 @@ The following dialog common for line and planar elements will appear:
     <li>specify the distance of extrusion along the vector.</li>
   </ul>
   <li>Specify the number of steps.</li>
-  <li>If you activate <b>Generate Groups</b> check-box, the created
-    elements contained in groups will be included into new groups named
-    by pattern "<old group name>_extruded" and "<old group name>_top".</li>
+  <li>If you activate <b>Generate Groups</b> check-box, the <em>result elements</em>
+    created from <em>extruded elements</em> contained in groups will be
+    included into new groups named by pattern "<old group
+    name>_extruded" and "<old group name>_top". For example if an
+    extruded quadrangle is included in \a Group_1 group then result
+    hexahedra will be included in \a Group_1_extruded group and a
+    quadrangle created at the "top" of extruded mesh will
+    be included in \a Group_1_top group. <br>This check-box is active
+    only if there are some groups in the mesh.</li>
 </ul>
 
 <li>Click \b Apply or <b> Apply and Close</b>  button to confirm the operation.</li>
index 9006ddcd0415495135211859ce5f41bc773472eb..f09ab21d47d03e7477f85efc37c810c38226a16b 100755 (executable)
@@ -12,8 +12,6 @@ nodes to polyhedrons at an arbitrary place in the mesh.</li>
 elements (used in quadratic meshes) from quadratic nodes to quadratic polyhedrons at an arbitrary place in the mesh.</li>
 <li>\subpage removing_nodes_and_elements_page "Remove" any existing
 mesh elements.</li>
-<li>\subpage renumbering_nodes_and_elements_page "Renumber" nodes and
-elements of the mesh.</li>
 <li>\subpage translation_page "Translate" in the indicated direction the mesh or some of
 its elements.</li>
 <li>\subpage rotation_page "Rotate" by the indicated axis and angle
@@ -53,6 +51,11 @@ or vice versa.</li>
 <li>\subpage cut_mesh_by_plane_page "Cut a tetrahedron mesh by a plane".</li>
 </ul>
 
+It is possible to \ref edit_anchor "modify the mesh" of lower
+dimension before generation of mesh of higher dimension.
+
+<p><br></p>
+
 \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.
 
index ef7f8ba66a704be2910dfba199764ad1a3e4665f..969b9fc5e066a39b75acea62020432974a51864c 100644 (file)
@@ -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:
 
 <br><h2>Application of pattern mapping</h2>
 
-<em>To apply pattern mapping to a geometrical object:</em>
+<em>To apply pattern mapping to a geometrical object or mesh elements:</em>
 
 From the \b Modification menu choose the <b>Pattern Mapping</b> item or click 
 <em>"Pattern mapping"</em> button in the toolbar.
@@ -113,16 +113,17 @@ created manually or generated automatically from an existing mesh or submesh.</l
      boundaries of the pattern must also be equal to the number of vertices
      on internal boundaries of the face;</li>
 <li> \b Vertex to which the first key-point should be mapped;</li>
+</ul>
 Alternatively, it is possible to select <b>Refine selected mesh elements</b> 
-checkbox and apply the pattern to
+check-box and apply the pattern to <ul>
 <li> <b>Mesh Face</b> instead of a geometric Face</li>
 <li> and select \b Node instead of vertex.</li>
-
-Additionally it is possible to:
-<li> <b>Reverse the order of key-points</b> By default, the vertices of
-     a face are ordered counterclockwise.<li>
+</ul>
+Additionally it is possible to: <ul>
+<li> <b>Reverse the order of key-points</b>. By default, the vertices of
+     a face are ordered counterclockwise.</li>
 <li> Enable to <b> Create polygons near boundary</b> </li>
-<li> and <b>Create polyhedrons near boundary</b><li>  
+<li> and <b>Create polyhedrons near boundary</b></li>
 </ul>
 
 \n For a <b>3D pattern</b>
@@ -133,21 +134,27 @@ In this dialog you should specify:
 <ul>
 <li> \b Pattern, which can be loaded from .smp pattern file previously
 created manually or generated automatically from an existing mesh or submesh.</li>
-   <li> A 3D block (Solid) object;</li>
-   <li> Two vertices that specify the order of nodes in the resulting mesh.</li>
+<li> A 3D block (Solid) object.</li>
+<li> Two vertices that specify the order of nodes in the resulting
+  mesh.</li>
+</ul>
 Alternatively, it is possible to select <b>Refine selected mesh elements</b> 
 checkbox and apply the pattern to
+<ul>
 <li> One or several <b>Mesh volumes</b> instead of a geometric 3D
 object</li>
 <li> and select two /b Nodes instead of vertices.</li> 
+</ul>
 Additionally it is possible to:
+<ul>
 <li> Enable to <b> Create polygons near boundary</b> </li>
-<li> and <b>Create polyhedrons near boundary</b><li>
+<li> and <b>Create polyhedrons near boundary</b></li>
 </ul>
 
-\n Automatic Generation 
+<br>
+<h3> Automatic Generation </h3>
 
-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:
index c06fb6ec5d09a7cf07581b11849f231231b93820..02d39a54150e9478484b6603d28bf0d41478a621 100644 (file)
@@ -237,7 +237,7 @@ See also \ref filter_double_elements "Double Elements quality control".
 <b>Bad oriented volume</b> selects mesh volumes, which are incorrectly oriented from
 the point of view of MED convention.
 </li><li>
-<b>Over-constrained volumes</b> selects mesh volumes having only one border shared 
+<b>Over-constrained volumes</b> selects mesh volumes having only one facet shared 
 with other volumes.
 See also \ref over_constrained_volumes_page "Over-constrained volumes quality control".
 </li><li>
index f1b12e4c41882ede90fe4b6e91c70341ba05fd58..984616457c7ff2b93f5bde86d206e9f2f0962671 100644 (file)
 <h2>Change priority of submeshes in Mesh</h2>
 \tui_script{creating_meshes_ex03.py}
 
+<br>
+\anchor tui_editing_while_meshing
+<h2>Intermediate edition while meshing</h2>
+\tui_script{a3DmeshOnModified2Dmesh.py}
+
 <br>
 \anchor tui_editing_mesh
 <h2>Editing a mesh</h2>
index 376da99b0e5ad10f745582d6a7f667171db2808f..248685579d9520764670d9577cd559f271de8e09 100644 (file)
@@ -33,7 +33,7 @@ viewer.</li>
 <li>\subpage display_mode_page "Display Mode" - allows to select between
 Wireframe, Shading and Nodes presentation.</li>
 <li>\subpage display_entity_page "Display Entity" - allows to display
-Faces, Edges or both.</li>
+entities by types (Faces, Edges, Volumes etc.).</li>
 <li><b>2D Quadratic</b> - allows to select between the representation
 of quadratic edges as broken <b>lines</b> or as <b>arcs</b></li>
 <li><b>Orientation of faces</b> - shows vectors of orientation of
index 4ffa049b7ea6c3b5b6c9e3c95fb710ac0535a3ef..46ca05a363db0190b76118b7b0aa9a8ce634ae4c 100755 (executable)
@@ -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
index 618692c762638f4dfecef4e14dea1adcd5639975..c49059d3a984ab6728550c093a4d3406a033cc03 100644 (file)
   </section>
 
  <section name="windows_geometry">
-  <parameter name="SMESH" value="#00 #00 #00 #FF #00 #00 #00 #00 #FD #00 #00 #00 #02 #00 #00 #00 #00 #00 #00 #01 #00 #00 #00 #02 #49 #FC #02 #00 #00 #00 #02 #FC #00 #00 #00 #7B #00 #00 #02 #44 #00 #00 #00 #00 #00 #FF #FF #FF #FA #00 #00 #00 #00 #01 #00 #00 #00 #02 #FB #00 #00 #00 #10 #00 #77 #00 #69 #00 #6E #00 #64 #00 #6F #00 #77 #00 #5F #00 #30 #01 #00 #00 #00 #00 #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #FB #00 #00 #00 #10 #00 #77 #00 #69 #00 #6E #00 #64 #00 #6F #00 #77 #00 #5F #00 #33 #01 #00 #00 #00 #00 #00 #00 #01 #00 #00 #00 #00 #00 #00 #00 #00 #00 #FC #00 #00 #00 #7B #00 #00 #02 #49 #00 #00 #00 #97 #01 #00 #00 #14 #FA #00 #00 #00 #00 #01 #00 #00 #00 #02 #FB #00 #00 #00 #22 #00 #6F #00 #62 #00 #6A #00 #65 #00 #63 #00 #74 #00 #42 #00 #72 #00 #6F #00 #77 #00 #73 #00 #65 #00 #72 #00 #44 #00 #6F #00 #63 #00 #6B #01 #00 #00 #00 #00 #FF #FF #FF #FF #00 #00 #00 #46 #00 #FF #FF #FF #FB #00 #00 #00 #18 #00 #6E #00 #6F #00 #74 #00 #65 #00 #42 #00 #6F #00 #6F #00 #6B #00 #44 #00 #6F #00 #63 #00 #6B #01 #00 #00 #00 #00 #00 #00 #01 #00 #00 #00 #00 #C0 #00 #FF #FF #FF #00 #00 #00 #03 #00 #00 #05 #40 #00 #00 #00 #53 #FC #01 #00 #00 #00 #02 #FB #00 #00 #00 #10 #00 #77 #00 #69 #00 #6E #00 #64 #00 #6F #00 #77 #00 #5F #00 #31 #01 #00 #00 #00 #00 #00 #00 #05 #40 #00 #00 #00 #00 #00 #00 #00 #00 #FB #00 #00 #00 #22 #00 #70 #00 #79 #00 #74 #00 #68 #00 #6F #00 #6E #00 #43 #00 #6F #00 #6E #00 #73 #00 #6F #00 #6C #00 #65 #00 #44 #00 #6F #00 #63 #00 #6B #01 #00 #00 #00 #00 #00 #00 #05 #40 #00 #00 #00 #46 #00 #FF #FF #FF #00 #00 #04 #38 #00 #00 #02 #49 #00 #00 #00 #04 #00 #00 #00 #04 #00 #00 #00 #08 #00 #00 #00 #08 #FC #00 #00 #00 #05 #00 #00 #00 #02 #00 #00 #00 #02 #00 #00 #00 #10 #00 #53 #00 #74 #00 #61 #00 #6E #00 #64 #00 #61 #00 #72 #00 #64 #01 #00 #00 #00 #00 #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #0E #00 #4D #00 #6F #00 #64 #00 #75 #00 #6C #00 #65 #00 #73 #01 #00 #00 #00 #CE #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #02 #00 #00 #00 #07 #00 #00 #00 #2A #00 #4E #00 #6F #00 #64 #00 #65 #00 #20 #00 #43 #00 #6F #00 #6E #00 #74 #00 #72 #00 #6F #00 #6C #00 #73 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #00 #00 #00 #02 #01 #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #2A #00 #45 #00 #64 #00 #67 #00 #65 #00 #20 #00 #43 #00 #6F #00 #6E #00 #74 #00 #72 #00 #6F #00 #6C #00 #73 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #00 #00 #00 #02 #4D #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #2A #00 #46 #00 #61 #00 #63 #00 #65 #00 #20 #00 #43 #00 #6F #00 #6E #00 #74 #00 #72 #00 #6F #00 #6C #00 #73 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #00 #00 #00 #02 #F6 #00 #00 #02 #4A #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #18 #00 #4D #00 #65 #00 #73 #00 #68 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #00 #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #26 #00 #41 #00 #64 #00 #64 #00 #20 #00 #45 #00 #6C #00 #65 #00 #6D #00 #65 #00 #6E #00 #74 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #01 #2B #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #3C #00 #41 #00 #64 #00 #64 #00 #20 #00 #4E #00 #6F #00 #6E #00 #20 #00 #4C #00 #69 #00 #6E #00 #65 #00 #61 #00 #72 #00 #20 #00 #45 #00 #6C #00 #65 #00 #6D #00 #65 #00 #6E #00 #74 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #02 #EB #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #1A #00 #47 #00 #72 #00 #6F #00 #75 #00 #70 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #04 #2F #00 #00 #01 #3E #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #02 #00 #00 #00 #01 #00 #00 #00 #2E #00 #56 #00 #6F #00 #6C #00 #75 #00 #6D #00 #65 #00 #20 #00 #43 #00 #6F #00 #6E #00 #74 #00 #72 #00 #6F #00 #6C #00 #73 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #00 #00 #00 #00 #00 #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #02 #00 #00 #00 #00 #00 #00 #00 #02 #00 #00 #00 #07 #00 #00 #00 #1C #00 #52 #00 #65 #00 #6D #00 #6F #00 #76 #00 #65 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #00 #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #2C #00 #54 #00 #72 #00 #61 #00 #6E #00 #73 #00 #66 #00 #6F #00 #72 #00 #6D #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #8A #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #28 #00 #4D #00 #6F #00 #64 #00 #69 #00 #66 #00 #69 #00 #63 #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #01 #90 #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #26 #00 #49 #00 #6E #00 #66 #00 #6F #00 #72 #00 #6D #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #03 #6F #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #26 #00 #52 #00 #65 #00 #6E #00 #75 #00 #6D #00 #62 #00 #65 #00 #72 #00 #69 #00 #6E #00 #67 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #03 #BB #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #28 #00 #4D #00 #65 #00 #61 #00 #73 #00 #75 #00 #72 #00 #65 #00 #6D #00 #65 #00 #6E #00 #74 #00 #73 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #04 #07 #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #28 #00 #44 #00 #69 #00 #73 #00 #70 #00 #6C #00 #61 #00 #79 #00 #20 #00 #4D #00 #6F #00 #64 #00 #65 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #04 #34 #00 #00 #01 #0C #00 #00 #00 #00 #00 #00 #00 #00"/>
+  <parameter name="SMESH" value="#00 #00 #00 #FF #00 #00 #00 #00 #FD #00 #00 #00 #02 #00 #00 #00 #00 #00 #00 #01 #00 #00 #00 #02 #49 #FC #02 #00 #00 #00 #02 #FC #00 #00 #00 #7B #00 #00 #02 #49 #00 #00 #00 #97 #01 #00 #00 #14 #FA #00 #00 #00 #00 #01 #00 #00 #00 #02 #FB #00 #00 #00 #22 #00 #6F #00 #62 #00 #6A #00 #65 #00 #63 #00 #74 #00 #42 #00 #72 #00 #6F #00 #77 #00 #73 #00 #65 #00 #72 #00 #44 #00 #6F #00 #63 #00 #6B #01 #00 #00 #00 #00 #FF #FF #FF #FF #00 #00 #00 #46 #00 #FF #FF #FF #FB #00 #00 #00 #18 #00 #6E #00 #6F #00 #74 #00 #65 #00 #42 #00 #6F #00 #6F #00 #6B #00 #44 #00 #6F #00 #63 #00 #6B #01 #00 #00 #00 #00 #00 #00 #01 #00 #00 #00 #00 #C0 #00 #FF #FF #FF #FB #00 #00 #00 #36 #00 #67 #00 #65 #00 #6F #00 #6D #00 #43 #00 #72 #00 #65 #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #49 #00 #6E #00 #66 #00 #6F #00 #72 #00 #6D #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #44 #00 #6F #00 #63 #00 #6B #00 #00 #00 #02 #1F #00 #00 #00 #A5 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #03 #00 #00 #05 #40 #00 #00 #00 #53 #FC #01 #00 #00 #00 #01 #FB #00 #00 #00 #22 #00 #70 #00 #79 #00 #74 #00 #68 #00 #6F #00 #6E #00 #43 #00 #6F #00 #6E #00 #73 #00 #6F #00 #6C #00 #65 #00 #44 #00 #6F #00 #63 #00 #6B #01 #00 #00 #00 #00 #00 #00 #05 #40 #00 #00 #00 #46 #00 #FF #FF #FF #00 #00 #04 #38 #00 #00 #02 #49 #00 #00 #00 #04 #00 #00 #00 #04 #00 #00 #00 #08 #00 #00 #00 #08 #FC #00 #00 #00 #06 #00 #00 #00 #02 #00 #00 #00 #02 #00 #00 #00 #1C #00 #53 #00 #61 #00 #6C #00 #6F #00 #6D #00 #65 #00 #53 #00 #74 #00 #61 #00 #6E #00 #64 #00 #61 #00 #72 #00 #64 #01 #00 #00 #00 #00 #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #1A #00 #53 #00 #61 #00 #6C #00 #6F #00 #6D #00 #65 #00 #4D #00 #6F #00 #64 #00 #75 #00 #6C #00 #65 #00 #73 #01 #00 #00 #00 #CE #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #02 #00 #00 #00 #07 #00 #00 #00 #12 #00 #47 #00 #45 #00 #4F #00 #4D #00 #42 #00 #61 #00 #73 #00 #69 #00 #63 #00 #00 #00 #00 #00 #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #1C #00 #47 #00 #45 #00 #4F #00 #4D #00 #50 #00 #72 #00 #69 #00 #6D #00 #69 #00 #74 #00 #69 #00 #76 #00 #65 #00 #73 #00 #00 #00 #00 #0E #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #2A #00 #47 #00 #45 #00 #4F #00 #4D #00 #42 #00 #6F #00 #6F #00 #6C #00 #65 #00 #61 #00 #6E #00 #4F #00 #70 #00 #65 #00 #72 #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #73 #00 #00 #00 #00 #1C #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #16 #00 #54 #00 #4F #00 #4F #00 #4C #00 #5F #00 #42 #00 #4C #00 #4F #00 #43 #00 #4B #00 #53 #00 #00 #00 #00 #2A #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #18 #00 #47 #00 #45 #00 #4F #00 #4D #00 #50 #00 #69 #00 #63 #00 #74 #00 #75 #00 #72 #00 #65 #00 #73 #00 #00 #00 #00 #38 #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #1A #00 #54 #00 #4F #00 #4F #00 #4C #00 #5F #00 #41 #00 #44 #00 #56 #00 #41 #00 #4E #00 #43 #00 #45 #00 #44 #00 #00 #00 #00 #46 #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #26 #00 #47 #00 #45 #00 #4F #00 #4D #00 #49 #00 #6D #00 #70 #00 #6F #00 #72 #00 #74 #00 #45 #00 #78 #00 #70 #00 #6F #00 #72 #00 #74 #00 #58 #00 #41 #00 #4F #00 #00 #00 #00 #54 #00 #00 #01 #69 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #02 #00 #00 #00 #05 #00 #00 #00 #24 #00 #47 #00 #45 #00 #4F #00 #4D #00 #54 #00 #72 #00 #61 #00 #6E #00 #73 #00 #66 #00 #6F #00 #72 #00 #6D #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #00 #00 #00 #00 #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #1C #00 #47 #00 #45 #00 #4F #00 #4D #00 #4F #00 #70 #00 #65 #00 #72 #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #73 #00 #00 #00 #00 #0E #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #1C #00 #47 #00 #45 #00 #4F #00 #4D #00 #47 #00 #65 #00 #6E #00 #65 #00 #72 #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #00 #00 #00 #1C #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #12 #00 #47 #00 #45 #00 #4F #00 #4D #00 #42 #00 #75 #00 #69 #00 #6C #00 #64 #00 #00 #00 #00 #2A #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #20 #00 #47 #00 #45 #00 #4F #00 #4D #00 #4D #00 #6F #00 #64 #00 #69 #00 #66 #00 #69 #00 #63 #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #00 #00 #00 #38 #00 #00 #01 #FB #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #02 #00 #00 #00 #05 #00 #00 #00 #18 #00 #47 #00 #45 #00 #4F #00 #4D #00 #4D #00 #65 #00 #61 #00 #73 #00 #75 #00 #72 #00 #65 #00 #73 #00 #00 #00 #00 #00 #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #20 #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #4D #00 #65 #00 #73 #00 #68 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #00 #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #2C #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #41 #00 #64 #00 #64 #00 #45 #00 #6C #00 #65 #00 #6D #00 #65 #00 #6E #00 #74 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #01 #2B #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #2C #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #41 #00 #64 #00 #64 #00 #45 #00 #6C #00 #65 #00 #6D #00 #65 #00 #6E #00 #74 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #02 #EB #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #24 #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #52 #00 #65 #00 #6D #00 #6F #00 #76 #00 #65 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #04 #2F #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #02 #00 #00 #00 #07 #00 #00 #00 #2E #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #49 #00 #6E #00 #66 #00 #6F #00 #72 #00 #6D #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #00 #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #22 #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #47 #00 #72 #00 #6F #00 #75 #00 #70 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #4C #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #34 #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #54 #00 #72 #00 #61 #00 #6E #00 #73 #00 #66 #00 #6F #00 #72 #00 #6D #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #D6 #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #30 #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #4D #00 #6F #00 #64 #00 #69 #00 #66 #00 #69 #00 #63 #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #01 #DC #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #2E #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #52 #00 #65 #00 #6E #00 #75 #00 #6D #00 #62 #00 #65 #00 #72 #00 #69 #00 #6E #00 #67 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #03 #BB #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #30 #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #4D #00 #65 #00 #61 #00 #73 #00 #75 #00 #72 #00 #65 #00 #6D #00 #65 #00 #6E #00 #74 #00 #73 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #04 #07 #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #2E #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #44 #00 #69 #00 #73 #00 #70 #00 #6C #00 #61 #00 #79 #00 #4D #00 #6F #00 #64 #00 #65 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #04 #34 #00 #00 #01 #58 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #02 #00 #00 #00 #04 #00 #00 #00 #30 #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #4E #00 #6F #00 #64 #00 #65 #00 #43 #00 #6F #00 #6E #00 #74 #00 #72 #00 #6F #00 #6C #00 #73 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #00 #00 #00 #00 #00 #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #30 #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #45 #00 #64 #00 #67 #00 #65 #00 #43 #00 #6F #00 #6E #00 #74 #00 #72 #00 #6F #00 #6C #00 #73 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #00 #00 #00 #00 #00 #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #30 #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #46 #00 #61 #00 #63 #00 #65 #00 #43 #00 #6F #00 #6E #00 #74 #00 #72 #00 #6F #00 #6C #00 #73 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #00 #00 #00 #00 #00 #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #34 #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #56 #00 #6F #00 #6C #00 #75 #00 #6D #00 #65 #00 #43 #00 #6F #00 #6E #00 #74 #00 #72 #00 #6F #00 #6C #00 #73 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #00 #00 #00 #00 #00 #00 #00 #02 #AA #00 #00 #00 #00 #00 #00 #00 #00"/>
  </section>
  <section name="windows_visibility">
-  <parameter name="SMESH" value="#00 #00 #00 #00 #15 #FF #FF #FF #FF #00 #00 #00 #02 #00 #00 #00 #00 #00 #00 #01 #00 #00 #00 #02 #44 #FC #02 #00 #00 #00 #01 #FC #00 #00 #00 #7B #00 #00 #02 #44 #00 #00 #00 #97 #01 #00 #00 #14 #FA #00 #00 #00 #00 #01 #00 #00 #00 #02 #FB #00 #00 #00 #10 #00 #77 #00 #69 #00 #6E #00 #64 #00 #6F #00 #77 #00 #5F #00 #30 #01 #00 #00 #00 #00 #FF #FF #FF #FF #00 #00 #00 #46 #00 #FF #FF #FF #FB #00 #00 #00 #10 #00 #77 #00 #69 #00 #6E #00 #64 #00 #6F #00 #77 #00 #5F #00 #33 #01 #00 #00 #00 #00 #00 #00 #01 #00 #00 #00 #00 #C0 #00 #FF #FF #FF #00 #00 #00 #03 #00 #00 #05 #40 #00 #00 #00 #53 #FC #01 #00 #00 #00 #01 #FB #00 #00 #00 #10 #00 #77 #00 #69 #00 #6E #00 #64 #00 #6F #00 #77 #00 #5F #00 #31 #01 #00 #00 #00 #00 #00 #00 #05 #40 #00 #00 #00 #46 #00 #FF #FF #FF #00 #00 #04 #38 #00 #00 #02 #44 #00 #00 #00 #04 #00 #00 #00 #04 #00 #00 #00 #08 #00 #00 #00 #08 #FC #00 #00 #00 #05 #00 #00 #00 #02 #00 #00 #00 #02 #00 #00 #00 #10 #00 #53 #00 #74 #00 #61 #00 #6E #00 #64 #00 #61 #00 #72 #00 #64 #01 #00 #00 #00 #00 #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #0E #00 #4D #00 #6F #00 #64 #00 #75 #00 #6C #00 #65 #00 #73 #01 #00 #00 #00 #CE #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #02 #00 #00 #00 #07 #00 #00 #00 #2A #00 #4E #00 #6F #00 #64 #00 #65 #00 #20 #00 #43 #00 #6F #00 #6E #00 #74 #00 #72 #00 #6F #00 #6C #00 #73 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #00 #00 #00 #02 #01 #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #2A #00 #45 #00 #64 #00 #67 #00 #65 #00 #20 #00 #43 #00 #6F #00 #6E #00 #74 #00 #72 #00 #6F #00 #6C #00 #73 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #00 #00 #00 #02 #4D #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #2A #00 #46 #00 #61 #00 #63 #00 #65 #00 #20 #00 #43 #00 #6F #00 #6E #00 #74 #00 #72 #00 #6F #00 #6C #00 #73 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #00 #00 #00 #02 #F6 #00 #00 #02 #4A #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #18 #00 #4D #00 #65 #00 #73 #00 #68 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #00 #00 #26 #00 #41 #00 #64 #00 #64 #00 #20 #00 #45 #00 #6C #00 #65 #00 #6D #00 #65 #00 #6E #00 #74 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #3C #00 #41 #00 #64 #00 #64 #00 #20 #00 #4E #00 #6F #00 #6E #00 #20 #00 #4C #00 #69 #00 #6E #00 #65 #00 #61 #00 #72 #00 #20 #00 #45 #00 #6C #00 #65 #00 #6D #00 #65 #00 #6E #00 #74 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #28 #00 #44 #00 #69 #00 #73 #00 #70 #00 #6C #00 #61 #00 #79 #00 #20 #00 #4D #00 #6F #00 #64 #00 #65 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #2A #00 #45 #00 #64 #00 #67 #00 #65 #00 #20 #00 #43 #00 #6F #00 #6E #00 #74 #00 #72 #00 #6F #00 #6C #00 #73 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #00 #00 #00 #00 #2A #00 #46 #00 #61 #00 #63 #00 #65 #00 #20 #00 #43 #00 #6F #00 #6E #00 #74 #00 #72 #00 #6F #00 #6C #00 #73 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #00 #00 #00 #00 #1A #00 #47 #00 #72 #00 #6F #00 #75 #00 #70 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #26 #00 #49 #00 #6E #00 #66 #00 #6F #00 #72 #00 #6D #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #28 #00 #4D #00 #65 #00 #61 #00 #73 #00 #75 #00 #72 #00 #65 #00 #6D #00 #65 #00 #6E #00 #74 #00 #73 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #18 #00 #4D #00 #65 #00 #73 #00 #68 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #28 #00 #4D #00 #6F #00 #64 #00 #69 #00 #66 #00 #69 #00 #63 #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #0E #00 #4D #00 #6F #00 #64 #00 #75 #00 #6C #00 #65 #00 #73 #01 #00 #00 #00 #2A #00 #4E #00 #6F #00 #64 #00 #65 #00 #20 #00 #43 #00 #6F #00 #6E #00 #74 #00 #72 #00 #6F #00 #6C #00 #73 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #00 #00 #00 #00 #28 #00 #52 #00 #65 #00 #63 #00 #6F #00 #72 #00 #64 #00 #69 #00 #6E #00 #67 #00 #20 #00 #4F #00 #70 #00 #65 #00 #72 #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #73 #01 #00 #00 #00 #1C #00 #52 #00 #65 #00 #6D #00 #6F #00 #76 #00 #65 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #26 #00 #52 #00 #65 #00 #6E #00 #75 #00 #6D #00 #62 #00 #65 #00 #72 #00 #69 #00 #6E #00 #67 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #10 #00 #53 #00 #74 #00 #61 #00 #6E #00 #64 #00 #61 #00 #72 #00 #64 #01 #00 #00 #00 #2C #00 #54 #00 #72 #00 #61 #00 #6E #00 #73 #00 #66 #00 #6F #00 #72 #00 #6D #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #1E #00 #56 #00 #69 #00 #65 #00 #77 #00 #20 #00 #4F #00 #70 #00 #65 #00 #72 #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #73 #01 #00 #00 #00 #2E #00 #56 #00 #6F #00 #6C #00 #75 #00 #6D #00 #65 #00 #20 #00 #43 #00 #6F #00 #6E #00 #74 #00 #72 #00 #6F #00 #6C #00 #73 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #00 #01 #00 #00 #00 #06 #00 #00 #00 #18 #00 #6E #00 #6F #00 #74 #00 #65 #00 #42 #00 #6F #00 #6F #00 #6B #00 #44 #00 #6F #00 #63 #00 #6B #01 #00 #00 #00 #22 #00 #6F #00 #62 #00 #6A #00 #65 #00 #63 #00 #74 #00 #42 #00 #72 #00 #6F #00 #77 #00 #73 #00 #65 #00 #72 #00 #44 #00 #6F #00 #63 #00 #6B #01 #00 #00 #00 #22 #00 #70 #00 #79 #00 #74 #00 #68 #00 #6F #00 #6E #00 #43 #00 #6F #00 #6E #00 #73 #00 #6F #00 #6C #00 #65 #00 #44 #00 #6F #00 #63 #00 #6B #01 #00 #00 #00 #10 #00 #77 #00 #69 #00 #6E #00 #64 #00 #6F #00 #77 #00 #5F #00 #30 #01 #00 #00 #00 #10 #00 #77 #00 #69 #00 #6E #00 #64 #00 #6F #00 #77 #00 #5F #00 #31 #01 #00 #00 #00 #10 #00 #77 #00 #69 #00 #6E #00 #64 #00 #6F #00 #77 #00 #5F #00 #33 #01"/>
+  <parameter name="SMESH" value="#00 #00 #00 #00 #35 #FF #FF #FF #FF #00 #00 #00 #02 #00 #00 #00 #00 #00 #00 #01 #00 #00 #00 #02 #44 #FC #02 #00 #00 #00 #01 #FC #00 #00 #00 #7B #00 #00 #02 #44 #00 #00 #00 #97 #01 #00 #00 #14 #FA #00 #00 #00 #00 #01 #00 #00 #00 #02 #FB #00 #00 #00 #10 #00 #77 #00 #69 #00 #6E #00 #64 #00 #6F #00 #77 #00 #5F #00 #30 #01 #00 #00 #00 #00 #FF #FF #FF #FF #00 #00 #00 #46 #00 #FF #FF #FF #FB #00 #00 #00 #10 #00 #77 #00 #69 #00 #6E #00 #64 #00 #6F #00 #77 #00 #5F #00 #33 #01 #00 #00 #00 #00 #00 #00 #01 #00 #00 #00 #00 #C0 #00 #FF #FF #FF #00 #00 #00 #03 #00 #00 #05 #40 #00 #00 #00 #53 #FC #01 #00 #00 #00 #01 #FB #00 #00 #00 #10 #00 #77 #00 #69 #00 #6E #00 #64 #00 #6F #00 #77 #00 #5F #00 #31 #01 #00 #00 #00 #00 #00 #00 #05 #40 #00 #00 #00 #46 #00 #FF #FF #FF #00 #00 #04 #38 #00 #00 #02 #44 #00 #00 #00 #04 #00 #00 #00 #04 #00 #00 #00 #08 #00 #00 #00 #08 #FC #00 #00 #00 #05 #00 #00 #00 #02 #00 #00 #00 #02 #00 #00 #00 #10 #00 #53 #00 #74 #00 #61 #00 #6E #00 #64 #00 #61 #00 #72 #00 #64 #01 #00 #00 #00 #00 #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #0E #00 #4D #00 #6F #00 #64 #00 #75 #00 #6C #00 #65 #00 #73 #01 #00 #00 #00 #CE #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #02 #00 #00 #00 #07 #00 #00 #00 #2A #00 #4E #00 #6F #00 #64 #00 #65 #00 #20 #00 #43 #00 #6F #00 #6E #00 #74 #00 #72 #00 #6F #00 #6C #00 #73 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #00 #00 #00 #02 #01 #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #2A #00 #45 #00 #64 #00 #67 #00 #65 #00 #20 #00 #43 #00 #6F #00 #6E #00 #74 #00 #72 #00 #6F #00 #6C #00 #73 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #00 #00 #00 #02 #4D #FF #FF #FF #FF #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #2A #00 #46 #00 #61 #00 #63 #00 #65 #00 #20 #00 #43 #00 #6F #00 #6E #00 #74 #00 #72 #00 #6F #00 #6C #00 #73 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #00 #00 #00 #02 #F6 #00 #00 #02 #4A #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #00 #18 #00 #4D #00 #65 #00 #73 #00 #68 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #00 #00 #26 #00 #41 #00 #64 #00 #64 #00 #20 #00 #45 #00 #6C #00 #65 #00 #6D #00 #65 #00 #6E #00 #74 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #3C #00 #41 #00 #64 #00 #64 #00 #20 #00 #4E #00 #6F #00 #6E #00 #20 #00 #4C #00 #69 #00 #6E #00 #65 #00 #61 #00 #72 #00 #20 #00 #45 #00 #6C #00 #65 #00 #6D #00 #65 #00 #6E #00 #74 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #28 #00 #44 #00 #69 #00 #73 #00 #70 #00 #6C #00 #61 #00 #79 #00 #20 #00 #4D #00 #6F #00 #64 #00 #65 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #2A #00 #45 #00 #64 #00 #67 #00 #65 #00 #20 #00 #43 #00 #6F #00 #6E #00 #74 #00 #72 #00 #6F #00 #6C #00 #73 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #00 #00 #00 #00 #2A #00 #46 #00 #61 #00 #63 #00 #65 #00 #20 #00 #43 #00 #6F #00 #6E #00 #74 #00 #72 #00 #6F #00 #6C #00 #73 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #00 #00 #00 #00 #12 #00 #47 #00 #45 #00 #4F #00 #4D #00 #42 #00 #61 #00 #73 #00 #69 #00 #63 #01 #00 #00 #00 #2A #00 #47 #00 #45 #00 #4F #00 #4D #00 #42 #00 #6F #00 #6F #00 #6C #00 #65 #00 #61 #00 #6E #00 #4F #00 #70 #00 #65 #00 #72 #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #73 #01 #00 #00 #00 #12 #00 #47 #00 #45 #00 #4F #00 #4D #00 #42 #00 #75 #00 #69 #00 #6C #00 #64 #01 #00 #00 #00 #1C #00 #47 #00 #45 #00 #4F #00 #4D #00 #47 #00 #65 #00 #6E #00 #65 #00 #72 #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #01 #00 #00 #00 #26 #00 #47 #00 #45 #00 #4F #00 #4D #00 #49 #00 #6D #00 #70 #00 #6F #00 #72 #00 #74 #00 #45 #00 #78 #00 #70 #00 #6F #00 #72 #00 #74 #00 #58 #00 #41 #00 #4F #01 #00 #00 #00 #18 #00 #47 #00 #45 #00 #4F #00 #4D #00 #4D #00 #65 #00 #61 #00 #73 #00 #75 #00 #72 #00 #65 #00 #73 #00 #00 #00 #00 #20 #00 #47 #00 #45 #00 #4F #00 #4D #00 #4D #00 #6F #00 #64 #00 #69 #00 #66 #00 #69 #00 #63 #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #01 #00 #00 #00 #1C #00 #47 #00 #45 #00 #4F #00 #4D #00 #4F #00 #70 #00 #65 #00 #72 #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #73 #01 #00 #00 #00 #18 #00 #47 #00 #45 #00 #4F #00 #4D #00 #50 #00 #69 #00 #63 #00 #74 #00 #75 #00 #72 #00 #65 #00 #73 #01 #00 #00 #00 #1C #00 #47 #00 #45 #00 #4F #00 #4D #00 #50 #00 #72 #00 #69 #00 #6D #00 #69 #00 #74 #00 #69 #00 #76 #00 #65 #00 #73 #01 #00 #00 #00 #24 #00 #47 #00 #45 #00 #4F #00 #4D #00 #54 #00 #72 #00 #61 #00 #6E #00 #73 #00 #66 #00 #6F #00 #72 #00 #6D #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #01 #00 #00 #00 #1A #00 #47 #00 #72 #00 #6F #00 #75 #00 #70 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #26 #00 #49 #00 #6E #00 #66 #00 #6F #00 #72 #00 #6D #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #28 #00 #4D #00 #65 #00 #61 #00 #73 #00 #75 #00 #72 #00 #65 #00 #6D #00 #65 #00 #6E #00 #74 #00 #73 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #18 #00 #4D #00 #65 #00 #73 #00 #68 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #28 #00 #4D #00 #6F #00 #64 #00 #69 #00 #66 #00 #69 #00 #63 #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #0E #00 #4D #00 #6F #00 #64 #00 #75 #00 #6C #00 #65 #00 #73 #01 #00 #00 #00 #2A #00 #4E #00 #6F #00 #64 #00 #65 #00 #20 #00 #43 #00 #6F #00 #6E #00 #74 #00 #72 #00 #6F #00 #6C #00 #73 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #00 #00 #00 #00 #32 #00 #4F #00 #43 #00 #43 #00 #56 #00 #69 #00 #65 #00 #77 #00 #65 #00 #72 #00 #33 #00 #44 #00 #56 #00 #69 #00 #65 #00 #77 #00 #4F #00 #70 #00 #65 #00 #72 #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #73 #01 #00 #00 #00 #28 #00 #52 #00 #65 #00 #63 #00 #6F #00 #72 #00 #64 #00 #69 #00 #6E #00 #67 #00 #20 #00 #4F #00 #70 #00 #65 #00 #72 #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #73 #01 #00 #00 #00 #1C #00 #52 #00 #65 #00 #6D #00 #6F #00 #76 #00 #65 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #26 #00 #52 #00 #65 #00 #6E #00 #75 #00 #6D #00 #62 #00 #65 #00 #72 #00 #69 #00 #6E #00 #67 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #2C #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #41 #00 #64 #00 #64 #00 #45 #00 #6C #00 #65 #00 #6D #00 #65 #00 #6E #00 #74 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #2E #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #44 #00 #69 #00 #73 #00 #70 #00 #6C #00 #61 #00 #79 #00 #4D #00 #6F #00 #64 #00 #65 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #30 #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #45 #00 #64 #00 #67 #00 #65 #00 #43 #00 #6F #00 #6E #00 #74 #00 #72 #00 #6F #00 #6C #00 #73 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #00 #00 #00 #00 #30 #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #46 #00 #61 #00 #63 #00 #65 #00 #43 #00 #6F #00 #6E #00 #74 #00 #72 #00 #6F #00 #6C #00 #73 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #00 #00 #00 #00 #22 #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #47 #00 #72 #00 #6F #00 #75 #00 #70 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #2E #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #49 #00 #6E #00 #66 #00 #6F #00 #72 #00 #6D #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #30 #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #4D #00 #65 #00 #61 #00 #73 #00 #75 #00 #72 #00 #65 #00 #6D #00 #65 #00 #6E #00 #74 #00 #73 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #20 #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #4D #00 #65 #00 #73 #00 #68 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #30 #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #4D #00 #6F #00 #64 #00 #69 #00 #66 #00 #69 #00 #63 #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #30 #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #4E #00 #6F #00 #64 #00 #65 #00 #43 #00 #6F #00 #6E #00 #74 #00 #72 #00 #6F #00 #6C #00 #73 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #00 #00 #00 #00 #24 #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #52 #00 #65 #00 #6D #00 #6F #00 #76 #00 #65 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #2E #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #52 #00 #65 #00 #6E #00 #75 #00 #6D #00 #62 #00 #65 #00 #72 #00 #69 #00 #6E #00 #67 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #34 #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #54 #00 #72 #00 #61 #00 #6E #00 #73 #00 #66 #00 #6F #00 #72 #00 #6D #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #34 #00 #53 #00 #4D #00 #45 #00 #53 #00 #48 #00 #56 #00 #6F #00 #6C #00 #75 #00 #6D #00 #65 #00 #43 #00 #6F #00 #6E #00 #74 #00 #72 #00 #6F #00 #6C #00 #73 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #00 #00 #00 #00 #1A #00 #53 #00 #61 #00 #6C #00 #6F #00 #6D #00 #65 #00 #4D #00 #6F #00 #64 #00 #75 #00 #6C #00 #65 #00 #73 #01 #00 #00 #00 #1C #00 #53 #00 #61 #00 #6C #00 #6F #00 #6D #00 #65 #00 #53 #00 #74 #00 #61 #00 #6E #00 #64 #00 #61 #00 #72 #00 #64 #01 #00 #00 #00 #10 #00 #53 #00 #74 #00 #61 #00 #6E #00 #64 #00 #61 #00 #72 #00 #64 #01 #00 #00 #00 #1A #00 #54 #00 #4F #00 #4F #00 #4C #00 #5F #00 #41 #00 #44 #00 #56 #00 #41 #00 #4E #00 #43 #00 #45 #00 #44 #01 #00 #00 #00 #16 #00 #54 #00 #4F #00 #4F #00 #4C #00 #5F #00 #42 #00 #4C #00 #4F #00 #43 #00 #4B #00 #53 #01 #00 #00 #00 #2C #00 #54 #00 #72 #00 #61 #00 #6E #00 #73 #00 #66 #00 #6F #00 #72 #00 #6D #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #01 #00 #00 #00 #2C #00 #56 #00 #54 #00 #4B #00 #52 #00 #65 #00 #63 #00 #6F #00 #72 #00 #64 #00 #69 #00 #6E #00 #67 #00 #4F #00 #70 #00 #65 #00 #72 #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #73 #01 #00 #00 #00 #2E #00 #56 #00 #54 #00 #4B #00 #56 #00 #69 #00 #65 #00 #77 #00 #65 #00 #72 #00 #56 #00 #69 #00 #65 #00 #77 #00 #4F #00 #70 #00 #65 #00 #72 #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #73 #01 #00 #00 #00 #1E #00 #56 #00 #69 #00 #65 #00 #77 #00 #20 #00 #4F #00 #70 #00 #65 #00 #72 #00 #61 #00 #74 #00 #69 #00 #6F #00 #6E #00 #73 #01 #00 #00 #00 #2E #00 #56 #00 #6F #00 #6C #00 #75 #00 #6D #00 #65 #00 #20 #00 #43 #00 #6F #00 #6E #00 #74 #00 #72 #00 #6F #00 #6C #00 #73 #00 #20 #00 #54 #00 #6F #00 #6F #00 #6C #00 #62 #00 #61 #00 #72 #00 #01 #00 #00 #00 #06 #00 #00 #00 #18 #00 #6E #00 #6F #00 #74 #00 #65 #00 #42 #00 #6F #00 #6F #00 #6B #00 #44 #00 #6F #00 #63 #00 #6B #01 #00 #00 #00 #22 #00 #6F #00 #62 #00 #6A #00 #65 #00 #63 #00 #74 #00 #42 #00 #72 #00 #6F #00 #77 #00 #73 #00 #65 #00 #72 #00 #44 #00 #6F #00 #63 #00 #6B #01 #00 #00 #00 #22 #00 #70 #00 #79 #00 #74 #00 #68 #00 #6F #00 #6E #00 #43 #00 #6F #00 #6E #00 #73 #00 #6F #00 #6C #00 #65 #00 #44 #00 #6F #00 #63 #00 #6B #01 #00 #00 #00 #10 #00 #77 #00 #69 #00 #6E #00 #64 #00 #6F #00 #77 #00 #5F #00 #30 #01 #00 #00 #00 #10 #00 #77 #00 #69 #00 #6E #00 #64 #00 #6F #00 #77 #00 #5F #00 #31 #01 #00 #00 #00 #10 #00 #77 #00 #69 #00 #6E #00 #64 #00 #6F #00 #77 #00 #5F #00 #33 #01"/>
  </section>
 </document>
diff --git a/resources/mesh_choose.png b/resources/mesh_choose.png
new file mode 100644 (file)
index 0000000..b5a40ba
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 (file)
index 0000000..5387c84
Binary files /dev/null and b/resources/mesh_choose_all.png differ
index 213dc236d5beed682e224ea6ca6de1dc96a3c50f..6311da713a53cdff7413d67c76f886b75066d35a 100644 (file)
@@ -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 ));
         }
       }
     }
index d57f2a210b0ce44e35bc5a584e1818cca156cc13..c248771a4e3f6441ae59625b706a2a16bb195277 100644 (file)
@@ -28,7 +28,7 @@
 #include <SalomeApp_Application.h>
 #include <SUIT_Session.h>
 
-#include <SALOME_ListIteratorOfListIO.hxx>
+#include <SALOME_ListIO.hxx>
 #include <GEOM_Client.hxx>
 #include <SMESHGUI_Utils.h>
 #include <boost/shared_ptr.hpp>
@@ -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;
index 17e8d7b9cac767d0c5656190cfaa3c5fa6e945ae..a23c8c468a3d071107cb18d412fc9ed8ee3e8c65 100644 (file)
@@ -58,6 +58,7 @@ SET(_link_LIBRARIES
   ${CAS_TKG2d}
   ${CAS_TKCDF}
   ${GEOM_NMTTools}
+  ${GEOM_GEOMUtils}
   ${Boost_LIBRARIES}
   SMESHDS
   SMESHControls
index 732c3e64ae2a9a96bf00ddd29c7e37fdfe5d77cf..5ec1240b00bdcb9c8fd007e413b47c2d9b18a589 100644 (file)
@@ -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) {
index e5d1670641db19c8d03d0099796eb79772ae1ed0..d0125d1e56083efe4f2c89912ffd6333a8196d01 100644 (file)
@@ -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;
index 7692f9f0e1ff690412fddde109d55e491ada1165..72d7ef193b7e9c3950ba27c43e99c3a6db75bfdb 100644 (file)
 #include "DriverCGNS_Write.hxx"
 #endif
 
+#include <GEOMUtils.hxx>
+
 #undef _Precision_HeaderFile
-#include <BRepBndLib.hxx>
+//#include <BRepBndLib.hxx>
 #include <BRepPrimAPI_MakeBox.hxx>
 #include <Bnd_Box.hxx>
 #include <TColStd_MapOfInteger.hxx>
@@ -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;
 }
index 0cf3e0949f34410fb09f32f085c7dae772a0a9f9..c603c6a41ad7ddb549bbb3cf3bcabcd16552e467 100644 (file)
@@ -63,15 +63,15 @@ typedef std::list<TListOfInt> 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
    */
index e216b2e7448f86b80edb40a310c0fba76caab60f..08cc1d9c2338fe8f628a01af17d75fa9593bd045 100644 (file)
@@ -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
     {
index bdd3584513c3f5a1090004a3629b3128938ad1c7..c6c51ab37a9bdf0206d269593b9634ceaab1e929 100644 (file)
@@ -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
index 51ea719deed440d4d7558ea245ed46aa84aecae0..164861c3213fc54b76b6a1fc35c93489720944df 100644 (file)
@@ -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 ) -
index 75d26244d4b88a7ca74356cbad42cb0f85be903f..2264ba3d16503b8664ef57b2cf539d77bf44d631 100644 (file)
@@ -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 );
index 59294a54c8f608fbd6fd4d8791e8c98d209e4262..0d4e2d120877f027f7f48970005a25a6a6963d3b 100644 (file)
@@ -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<const SMESHDS_Hypothesis*> 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;
+      }
     }
   }
 
index d92818942747496b2d24ef0ba22587c8458025e9..59a99865b3a2313c63910c2cacd3cc2df138d383 100644 (file)
@@ -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
index 71ccf611de811de9a9826cb91c3b1989725717b9..7908b4f49b94a457c3ef0b7829f41db3f0a9460e 100644 (file)
@@ -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"
 #include "SMESHGUI_Utils.h"
 #include "SMESHGUI_VTKUtils.h"
 
-#include <SMESH_version.h>
+#include "SMESH_version.h"
 
 #include "SMESH_ControlsDef.hxx"
-#include <SMESH_Actor.h>
-#include <SMESH_ActorUtils.h>
-#include <SMESH_Client.hxx>
-#include <SMESH_ScalarBarActor.h>
-#include <SMESH_TypeFilter.hxx>
+#include "SMESH_Actor.h"
+#include "SMESH_ActorUtils.h"
+#include "SMESH_Client.hxx"
+#include "SMESH_ScalarBarActor.h"
+#include "SMESH_TypeFilter.hxx"
 
 // SALOME GUI includes
 #include <SalomeApp_Application.h>
 #include <QtxFontEdit.h>
 
 #include <SALOME_ListIO.hxx>
-#include <SALOME_ListIteratorOfListIO.hxx>
 
 #ifndef DISABLE_PLOT2DVIEWER
 #include <SPlot2d_ViewModel.h>
@@ -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<int> 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;
index 9cbad861c453b08361e8a96bc38836bd8742ff6c..b053c60998ec2d5b549fb32633f3b75cb5b23029 100644 (file)
@@ -463,9 +463,7 @@ void SMESHGUI_Add0DElemsOnAllNodesOp::onSelTypeChange(int selType)
 
 //================================================================================
 /*!
- * \brief Install 
- * 
- * 
+ * \brief Install filters
  */
 //================================================================================
 
index 79588047cb0abfb36b46746cfd9387503fc559e0..cbc584da5a2d85f976b4b9ad0188877b800dee6c 100644 (file)
@@ -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);
 
index 39665f3a5aa1c179d129e3047a31673e8e6faec2..8a02ddd031d6b44c85f5609a63947c15c7e73f11 100644 (file)
@@ -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);
index 5d0a1ee7d79e20292be6efda627b9077ffad4fe4..f106c0b6661e64c4096e30e03dd1163f565b014c 100644 (file)
@@ -43,7 +43,6 @@
 #include <LightApp_SelectionMgr.h>
 
 #include <SALOME_ListIO.hxx>
-#include <SALOME_ListIteratorOfListIO.hxx>
 
 #include <SVTK_Selection.h>
 #include <SVTK_ViewWindow.h>
diff --git a/src/SMESHGUI/SMESHGUI_DisplayEntitiesDlg.cxx b/src/SMESHGUI/SMESHGUI_DisplayEntitiesDlg.cxx
new file mode 100644 (file)
index 0000000..1e0a288
--- /dev/null
@@ -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 <QLabel>
+#include <QGroupBox>
+#include <QGridLayout>
+#include <QVBoxLayout>
+#include <QCheckBox>
+
+#include <SUIT_Session.h>
+#include <SUIT_MessageBox.h>
+#include <SUIT_ResourceMgr.h>
+#include <LightApp_Application.h>
+#include <LightApp_SelectionMgr.h>
+#include <SALOME_ListIO.hxx>
+
+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 (file)
index 0000000..4b36a6b
--- /dev/null
@@ -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 <SMESH_Actor.h>
+
+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
index ad4997644dd4f5be795d78a3dc9b578ee8e67dfd..57428add241d7cb5f2e65714425fc341cc34bb3f 100644 (file)
@@ -48,7 +48,6 @@
 
 #include <SVTK_ViewWindow.h>
 #include <SALOME_ListIO.hxx>
-#include <SALOME_ListIteratorOfListIO.hxx>
 
 // Qt includes
 #include <QApplication>
index 5dba32360f703511d8bb65eb19559ffd724f2acf..798b6b9eb26a1e2edb676259381e3d83c348c509 100644 (file)
@@ -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();
index 8409afa4a0f54b61bce997949ef38269d7e850d2..8db0a78141b2dac70528ed0d9926c16e7c5537e5 100755 (executable)
@@ -62,8 +62,6 @@
 #include <SalomeApp_DoubleSpinBox.h>
 
 #include <SALOME_ListIO.hxx>
-#include <SALOME_ListIteratorOfListIO.hxx>
-#include <SALOME_DataMapIteratorOfDataMapOfIOMapOfInteger.hxx>
 
 #include <SVTK_ViewWindow.h>
 
@@ -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;
     }
     }
index 88b1819445cb5ace027fd75faba4cb4bead9bcc2..5453a6a1b758608d71a50e4b0eca7221532432ff 100644 (file)
@@ -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 )
index f9cdeafd40acc430f0a58f0b3cc8d5d48ee8492c..0aa10bd7a9bb493a9a431f867eefffab9dca2190 100644 (file)
@@ -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 );
 
index 60095ebe2a7651a7ec543801ba34316e50278c05..7cad3307110b7808401bd9b28896cb2b1f68aa45 100644 (file)
@@ -61,7 +61,6 @@
 #include <LightApp_SelectionMgr.h>
 
 #include <SALOME_ListIO.hxx>
-#include <SALOME_ListIteratorOfListIO.hxx>
 
 #include <SVTK_ViewWindow.h>
 
index 33a4720eae91d96750b9cd35387ec164bc4723a5..bbebee448fd10847fa185fabb658ecbaa459f3b9 100644 (file)
@@ -59,7 +59,6 @@
 #include <QKeyEvent>
 #include <QListWidget>
 #include <QButtonGroup>
-#include <SALOME_ListIteratorOfListIO.hxx>
 #include <QComboBox>
 #include <QtxColorButton.h>
 
index af1377aba7ebc70904b2d6e9fea9948d170433a9..630100e7174f28b7773217b1ded4e0186b0653f0 100644 (file)
@@ -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()));
index 379ed1b2ba3bc6467deddd3fab9f7562b03a4871..fa29da180e0efe8ed73680d34caa0e020d9e08f2 100644 (file)
@@ -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(),
index 2841b7a7f6c412f04d76bb3e91d7e194cdf1ca07..8768e07112e19d35bd31c137facdb367aef08e3f 100644 (file)
@@ -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
index 970500e69d7f60d60c8abd5e20da97d695ab7b48..2754b34a92436c064a1a15b786e5bdc3d0ac919b 100644 (file)
@@ -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);
index e00937aff8a58015ab84f83d1597541fb177a03c..9f7c9bb2674f624b587049dabbce145073aa0980 100644 (file)
@@ -36,7 +36,7 @@
 #include <SUIT_OverrideCursor.h>
 #include <SUIT_ResourceMgr.h>
 #include <SVTK_ViewWindow.h>
-#include <SALOME_ListIteratorOfListIO.hxx>
+#include <SALOME_ListIO.hxx>
 
 #include <QButtonGroup>
 #include <QGridLayout>
index f3a2719d41cfbbcb6e44b4b8f11b9ffb1f95a682..a381acde05148beca0aabdb3259b4ac85151d585 100644 (file)
@@ -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
   {
index ef9ac22ad31e41cc782d610860acdbb2ec97c600..7f8b060c8dc934368925c38cac90ddda89c4424a 100644 (file)
@@ -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;
index 2dca23bbacc452bd8c4466bf80eecfe6629d2b91..e91afa388e3d91e894bc3caf141d2a711369106e 100644 (file)
@@ -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;
index ab8b437a638ddffa68e6aa84c62aeee6b73c6ad4..cdb3bc91921a0b281f767a7c241ceffbf53a4ce9 100644 (file)
 #include "SMESHGUI_MeshOp.h"
 
 #include "SMESHGUI.h"
+#include "SMESHGUI_GEOMGenUtils.h"
+#include "SMESHGUI_Hypotheses.h"
+#include "SMESHGUI_HypothesesUtils.h"
 #include "SMESHGUI_MeshDlg.h"
+#include "SMESHGUI_Operations.h"
 #include "SMESHGUI_ShapeByMeshDlg.h"
-#include "SMESHGUI_HypothesesUtils.h"
-#include "SMESHGUI_Hypotheses.h"
 #include "SMESHGUI_Utils.h"
-#include "SMESHGUI_GEOMGenUtils.h"
-
-#include <SMESH_TypeFilter.hxx>
-#include <SMESH_NumberFilter.hxx>
+#include "SMESH_NumberFilter.hxx"
+#include "SMESH_TypeFilter.hxx"
 
 // SALOME GEOM includes
 #include <GEOM_SelectionFilter.h>
@@ -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<int> 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 );
   }
index b2fdc8bddd064dc8435664c56f39650030c88f28..e42a8389dc2383dfe70e7f75ac97817df9e0ee55 100755 (executable)
@@ -53,7 +53,6 @@
 #include <LightApp_SelectionMgr.h>
 #include <LightApp_Application.h>
 #include <SALOME_ListIO.hxx>
-#include <SALOME_ListIteratorOfListIO.hxx>
 #include <SalomeApp_Tools.h>
 
 #include <SVTK_Selector.h>
index 0d1cfe56a64c4aad922a4ea863a1d0f12273ae88..18c28a441a7ae5f2f0cf851d787fa3237fd76182 100644 (file)
@@ -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
index 41e341cca25d88745de76600f38f7732a3e3b492..064df39099964d8ede3b7d6cefba351ad91a1a07 100644 (file)
@@ -46,7 +46,6 @@
 // SALOME GUI includes
 #include <LightApp_SelectionMgr.h>
 #include <SALOME_ListIO.hxx>
-#include <SALOME_ListIteratorOfListIO.hxx>
 #include <SUIT_Desktop.h>
 #include <SUIT_MessageBox.h>
 #include <SUIT_OverrideCursor.h>
index 936a228c1d60691a4373ea112e7d184a1b1c9861..1a9724012a00cc871ad913e4172f765c8373c473 100644 (file)
@@ -52,7 +52,6 @@
 #include <SVTK_ViewModel.h>
 #include <SVTK_ViewWindow.h>
 #include <SALOME_ListIO.hxx>
-#include <SALOME_ListIteratorOfListIO.hxx>
 
 // SALOME KERNEL includes
 #include <SALOMEDSClient.hxx>
index 9da433c69e549de8b2fd66354087949690232bed..e07177bf1ff7d6463b7dbbfbb0aefcb6d0d3e6ce 100644 (file)
@@ -49,7 +49,6 @@
 #include <SVTK_ViewModel.h>
 #include <SVTK_ViewWindow.h>
 #include <SALOME_ListIO.hxx>
-#include <SALOME_ListIteratorOfListIO.hxx>
 
 // SALOME KERNEL includes
 #include <SALOMEDSClient.hxx>
index 80ca0346658b215125ed614f352ff6779bbe1d81..94331c90156b446112fc6377a8cc3d36f5ab0afd 100644 (file)
@@ -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<n; i++ )
+    for( int i=0, n=count(); i<n; i++ ) {
       myTypes.append( typeName( type( entry( i ), aStudy ) ) );
+      myControls.append( controlMode( i ) );
+    }
   }
 }
 
@@ -122,7 +124,6 @@ QVariant SMESHGUI_Selection::parameter( const int ind, const QString& p ) const
   else if ( p=="labeledTypes" )         val = QVariant( labeledTypes( ind ) );
   else if ( p=="shrinkMode" )           val = QVariant( shrinkMode( ind ) );
   else if ( p=="entityMode" )           val = QVariant( entityMode( ind ) );
-  else if ( p=="controlMode" )          val = QVariant( controlMode( ind ) );
   else if ( p=="isNumFunctor" )         val = QVariant( isNumFunctor( ind ) );
   else if ( p=="displayMode" )          val = QVariant( displayMode( ind ) );
   else if ( p=="isComputable" )         val = QVariant( isComputable( ind ) );
@@ -143,6 +144,21 @@ QVariant SMESHGUI_Selection::parameter( const int ind, const QString& p ) const
     return LightApp_Selection::parameter( ind, p );
 }
 
+//=======================================================================
+//function : parameter
+//purpose  :
+//=======================================================================
+QVariant SMESHGUI_Selection::parameter( const QString& p ) const
+{
+  QVariant val;
+  if ( p=="controlMode" ) val = QVariant( controlMode() );
+
+  if ( val.isValid() )
+    return val;
+  else
+    return LightApp_Selection::parameter( p );
+}
+
 //=======================================================================
 //function : getVtkOwner
 //purpose  : 
@@ -318,6 +334,23 @@ QString SMESHGUI_Selection::controlMode( int ind ) const
   return mode;
 }
 
+//=======================================================================
+//function : controlMode
+//purpose  : gets global control mode; return SMESH_Actor::eControl
+//=======================================================================
+QString SMESHGUI_Selection::controlMode() const
+{
+  if( myControls.count() > 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;
index 0a9d46ccc57805001321ad98643dfb61aca66a34..3ba1bf4cb3809c171ed491c8c565f1fb95a4e4fa 100644 (file)
@@ -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<QVariant> 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<SMESH_Actor*>     myActors;
 };
 
index 0c8486ed2e944befe69846068b34557bf40ff4a7..daf2bf493ff5e4a499d2e05130a58e42b61b6543 100644 (file)
@@ -43,7 +43,6 @@
 #include <SVTK_ViewModel.h>
 
 #include <SALOME_ListIO.hxx>
-#include <SALOME_ListIteratorOfListIO.hxx>
 
 // SALOME KERNEL includes 
 #include <SALOMEDS_SObject.hxx>
@@ -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() );
       }
     }
   }
index 7e1d8d0518e25e811f203d7e1b94cb8f7d709b85..6fcc47a413a11074fb140815d4e0a1c2344ca04d 100644 (file)
@@ -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);
index c887edf8444acb16874fd3e34bbd720ceab7d714..2a014f21ed9a54df8ada71f00949157385da8f66 100644 (file)
@@ -52,7 +52,6 @@
 #include <SVTK_ViewModel.h>
 #include <SVTK_ViewWindow.h>
 #include <SALOME_ListIO.hxx>
-#include <SALOME_ListIteratorOfListIO.hxx>
 
 // SALOME KERNEL includes
 #include <SALOMEDSClient.hxx>
index e4bf823f8c700252996134fb8f92cf1cc4a82332..ae7adcfa03066ff874cd58e8a83bf3b7491a42bb 100644 (file)
@@ -52,7 +52,6 @@
 #include <SVTK_ViewModel.h>
 #include <SVTK_ViewWindow.h>
 #include <SALOME_ListIO.hxx>
-#include <SALOME_ListIteratorOfListIO.hxx>
 
 // SALOME KERNEL includes
 #include <SALOMEDSClient.hxx>
index 58b52c670dc1e928e7a3563df74898fd09e43b61..6c13709434ae964a50a3a0068b71eddcb03a44e6 100644 (file)
@@ -40,7 +40,6 @@
 #include <SUIT_ResourceMgr.h>
 
 #include <SALOME_ListIO.hxx>
-#include <SALOME_ListIteratorOfListIO.hxx>
 
 #include <LightApp_Application.h>
 #include <LightApp_SelectionMgr.h>
index d5ec25ed4a7134897d7371269f4a5a69f47d7e8f..5ac9ee97cfbd402878949c76a0e44dede4930078 100644 (file)
@@ -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) {}
   };
 
index 6b67d5e9cc8cb3ffb6a1d399c1b562bee2dc679f..7ca3e9395fa1940af4733b1a930b37d7f3624821 100644 (file)
@@ -47,7 +47,6 @@
 #include <SUIT_ResourceMgr.h>
 
 #include <SALOME_ListIO.hxx>
-#include <SALOME_ListIteratorOfListIO.hxx>
 
 #include <SVTK_Selector.h>
 #include <SVTK_ViewModel.h>
index b5c53d4b56d516d504ce42e5cc76efb463e07324..cb27cf9b421b3ff4b497bf2ee6cf3a14e549bf23 100644 (file)
@@ -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();
         }
       }
 
index 80c04e7d6fd1047f241b3789b710df71c7834d03..7da6cad1a7362d4d7fe0578db2f06af2dd856bb9 100644 (file)
             <source>ICON_DLG_TRIANGLE</source>
             <translation>mesh_triangle.png</translation>
         </message>
+        <message>
+            <source>ICON_DLG_CHOOSE</source>
+            <translation>mesh_choose.png</translation>
+        </message>
+        <message>
+            <source>ICON_DLG_CHOOSE_ALL</source>
+            <translation>mesh_choose_all.png</translation>
+        </message>
         <message>
             <source>ICON_EDIT_GROUP</source>
             <translation>mesh_edit_group.png</translation>
index fcb37740a87ebffa4867964e67ebe982162ea641..3f8a01c03908d1d8c3edb7e3a8b6b0faf5ff76d9 100644 (file)
         <source>MEN_EDGES</source>
         <translation>Edges</translation>
     </message>
+    <message>
+        <source>MEN_CHOOSE</source>
+        <translation>Choose...</translation>
+    </message>
     <message>
         <source>MEN_EDIT</source>
         <translation>Edit</translation>
@@ -7805,4 +7809,11 @@ as they are of improper type:
         <translation>Shrink coef:</translation>
     </message>
 </context>
+<context>
+    <name>SMESHGUI_DisplayEntitiesDlg</name>
+    <message>
+        <source>WRN_AT_LEAST_ONE</source>
+        <translation>At least one entity type should be chosen!</translation>
+    </message>
+</context>
 </TS>
index f20d819eb85d5e11397a1739dd2aab121e88526d..91596f776723c9a9926310d58804c945bdba7e46 100755 (executable)
         <source>MEN_EDGES</source>
         <translation>Arêtes</translation>
     </message>
+    <message>
+        <source>MEN_CHOOSE</source>
+        <translation type="unfinished">Choose...</translation>
+    </message>
     <message>
         <source>MEN_EDIT</source>
         <translation>Edition</translation>
@@ -7753,4 +7757,11 @@ en raison de leurs types incompatibles:
         <translation>Coef de réduction:</translation>
     </message>
 </context>
+<context>
+    <name>SMESHGUI_DisplayEntitiesDlg</name>
+    <message>
+        <source>WRN_AT_LEAST_ONE</source>
+        <translation type="unfinished">At least one entity type should be chosen!</translation>
+    </message>
+</context>
 </TS>
index 5d6e78d2025c33134a83f2e47c2fcfadc16d0e3f..0332875cf11e700125f20139a3edf7302555e2e2 100644 (file)
       <source>MEN_EDGES</source>
       <translation>エッジ</translation>
     </message>
+    <message>
+        <source>MEN_CHOOSE</source>
+        <translation type="unfinished">Choose...</translation>
+    </message>
     <message>
       <source>MEN_EDIT</source>
       <translation>編集(&amp;E)</translation>
       <translation>減少係数:</translation>
     </message>
   </context>
+  <context>
+    <name>SMESHGUI_DisplayEntitiesDlg</name>
+    <message>
+      <source>WRN_AT_LEAST_ONE</source>
+      <translation type="unfinished">At least one entity type should be chosen!</translation>
+    </message>
+  </context>
 </TS>
index 9fec2e5bd7079b6199259052ce53b59584b4215c..f5dedaec0ce38eb9bae6f96110417e96d25347e3 100644 (file)
@@ -43,7 +43,8 @@ typedef std::map<const SMDS_MeshElement*,
                  std::list<const SMDS_MeshElement*>, TIDCompare > TElemOfElemListMap;
 typedef std::map<const SMDS_MeshElement*,
                  std::list<const SMDS_MeshNode*>,    TIDCompare > TElemOfNodeListMap;
-typedef std::map<const SMDS_MeshNode*, const SMDS_MeshNode*>      TNodeNodeMap;
+typedef std::map<const SMDS_MeshNode*,
+                 const SMDS_MeshNode*,               TIDCompare>  TNodeNodeMap;
 
 //!< Set of elements sorted by ID, to be used to assure predictability of edition
 typedef std::set< const SMDS_MeshElement*, TIDCompare >      TIDSortedElemSet;
index 564632744b8c4f7c98413b5235e91c2183c21ca2..911375f68ea1e59894eb2f13e3fe41268377d9a2 100644 (file)
@@ -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 );
index 4e6531ddee31c3ed6e9785afc58f6e2f9a19853d..04352f24ca3b8c8ff8cb1cb420f7da9476f853f8 100644 (file)
@@ -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; }
index 0293f51a3a6889e011931c5ff38b81e7f6f8c9b9..3d7977cb6969fd9d92e157d5836622b427d78717 100644 (file)
@@ -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();
index b822651b7ee853da1a91cc152f911fc9fba7eb3a..cffb3d57308c54b7f11da79d15613033b745c64f 100644 (file)
@@ -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);
-  // 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();
+  GenericHypothesisCreator_i* aCreator =
+    getHypothesisCreator(theHypName, theLibName, aPlatformLibName);
 
-  // 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
+  // create a new hypothesis object, store its ref. in studyContext
+  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();
 }
 
index 6890bcf08e1f9867328a4ba193256c9305b2a519..b59479fce561d0c5a843b181968fc5604a4b7b76 100644 (file)
@@ -43,6 +43,8 @@
 #include <TCollection_AsciiString.hxx>
 #include <TopoDS_Solid.hxx>
 
+#include <cctype>
+
 #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,
index c54b068cfec6e98d108d6b8001e9c8e626a4c0d3..763f976e4e758859ae76dff901ed5877fb8bd8c2 100644 (file)
@@ -64,6 +64,7 @@
 #include <Utils_CorbaException.hxx>
 #include <SALOMEDS_wrap.hxx>
 #include <SALOME_GenericObj_i.hh>
+#include <Basics_OCCTVersion.hxx>
 
 #include <BRepAdaptor_Surface.hxx>
 #include <BRep_Tool.hxx>
@@ -4746,9 +4747,16 @@ SMESH_MeshEditor_i::scale(SMESH::SMESH_IDSource_ptr  theObject,
   };
   double tol = std::numeric_limits<double>::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;
index 1e9c735332a99c79bbfadde90cb2a50c2a3eeb7f..1496202ffeaaf9884fddc74c4e92c65807e2caac 100644 (file)
@@ -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
index dbbbe973b86b997aef913ba520c1968e4255f6ba..fe63e726b055c95b706df6619fa9836ee80927ae 100644 (file)
@@ -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()
index 3623b51764acc807ff104349556ca42f6a423920..8ce382e179b8b5c93545682b58c1274fc6678b75 100644 (file)
@@ -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
index 62a2cf5a9f1706e34b34896276f4df040b3fc068..7bcfca77d6a8f71eadc62ab64c2a55a45c5955ff 100644 (file)
@@ -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
index 0b7ac0235d3530dc63a1ff914afe938703dfb672..b2e15df8c1a8ec1f5d5b9b782f800150c3047a97 100644 (file)
@@ -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];
index 3cd23ff35d0a619006f38ac457062b5b1104f928..bec175bb39dde87462443df5733713eea0cb90cc 100644 (file)
@@ -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 <BRepIntCurveSurface_Inter.hxx>
-#include <BRepTopAdaptor_TopolTool.hxx>
-#include <BRepAdaptor_HSurface.hxx>
-#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<IntCurveSurface_IntersectionPoint> _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;
 
index aa7ebf1f56ab7095aba68ffb4ec0b746de2fe5c7..3a0a7334ba579666a3e6b17f4f1d31f02098cabb 100644 (file)
@@ -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;
 }
+}
index d5744d2dab1f4454549ce5a9f0614873e746714b..e974e95f7be5708fe4c81cf534d7ef1af1dff972 100644 (file)
@@ -37,7 +37,8 @@
 #include <Expr_Array1OfNamedUnknown.hxx>
 #include <TColStd_Array1OfReal.hxx>
 
-
+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<double>& f, const int conv, const double start, const double end,
                         const int nbSeg, std::vector<double>& data, const double eps );
-
+}
 #endif
index c2596b4b6db521feefb7466ed7c2cbadd1ee138f..84884800b0e0b2ee463b7e34e1e1324018cdbdbd 100644 (file)
@@ -43,6 +43,7 @@
 #include <BRep_Tool.hxx>
 #include <GCPnts_AbscissaPoint.hxx>
 #include <Geom2dAdaptor_Curve.hxx>
+#include <Geom_Line.hxx>
 #include <TopExp.hxx>
 #include <TopExp_Explorer.hxx>
 #include <TopoDS.hxx>
@@ -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 = "<<len<<"  d2 = "<<d2<<"  fabs(2*d2/len-1.0) = "<<fabs(2*d2/len-1.0)<<endl;
-      myIsUniform[i] = !( fabs(2*d2/myEdgeLength[i]-1.0) > 0.01 || fabs(2*d4/d2-1.0) > 0.01 );
-      //if ( !myIsUniform[i] ) to implement Value3d(u)
+      if ( myEdgeLength[i] > DBL_MIN)
       {
-        double fp,lp;
-        Handle(Geom_Curve) C3d = BRep_Tool::Curve(myEdge[i],fp,lp);
-        myC3dAdaptor[i].Load( C3d, fp,lp );
+        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 = "<<len<<"  d2 = "<<d2<<"  fabs(2*d2/len-1.0) = "<<fabs(2*d2/len-1.0)<<endl;
+        myIsUniform[i] = !( fabs(2*d2/myEdgeLength[i]-1.0) > 0.01 || fabs(2*d4/d2-1.0) > 0.01 );
+        Handle(Geom_Curve) C3d = BRep_Tool::Curve(myEdge[i],d2,d4);
+        myC3dAdaptor[i].Load( C3d, d2,d4 );
+      }
+      else
+      {
+        const TopoDS_Vertex& V = TopoDS::Vertex( vExp.Value() );
+        Handle(Geom_Curve) C3d = new Geom_Line( BRep_Tool::Pnt( V ), gp::DX() );
+        myC3dAdaptor[i].Load( C3d, 0, 0.5 * BRep_Tool::Tolerance( V ));
       }
     }
     // reverse a proxy submesh
@@ -988,7 +994,7 @@ gp_Pnt StdMeshers_FaceSide::Value3d(double U) const
   double     r = ( U - prevU )/ ( myNormPar[ i ] - prevU );
 
   double par = myFirst[i] * ( 1 - r ) + myLast[i] * r;
-    
+
   // check parametrization of curve
   if( !myIsUniform[i] )
   {
index f09dc7a10d1cf66ef59c211e80a592008b697b2d..c9e48b7e2d341a5ab0ed9c54ad7a2f96005d83ba 100644 (file)
@@ -53,6 +53,7 @@
 
 #include <Basics_Utils.hxx>
 
+using namespace StdMeshers;
 using namespace std;
 
 const double PRECISION = 1e-7;
index afac9bebe4ec2cc0f4dad6359f90c5ccb5a9aa2f..04cc3aebe9e85e0b65293a7ad8669548b5853a7b 100644 (file)
@@ -49,6 +49,7 @@
 #include <Bnd_B3d.hxx>
 #include <Geom2dAdaptor_Curve.hxx>
 #include <Geom2d_Line.hxx>
+#include <GeomLib_IsPlanarSurface.hxx>
 #include <Geom_Curve.hxx>
 #include <TopExp.hxx>
 #include <TopExp_Explorer.hxx>
@@ -77,7 +78,7 @@ using namespace std;
 #define SHOWYXZ(msg, xyz)
 #endif
 
-namespace TAssocTool = StdMeshers_ProjectionUtils;
+namespace NSProjUtils = StdMeshers_ProjectionUtils;
 
 typedef SMESH_Comment TCom;
 
@@ -157,6 +158,10 @@ namespace {
                                                             fatherAlgo->GetGen() );
       return algo;
     }
+    const NSProjUtils::TNodeNodeMap& GetNodesMap()
+    {
+      return _src2tgtNodes;
+    }
   };
   //=======================================================================
   /*!
@@ -539,7 +544,7 @@ StdMeshers_Prism_3D::StdMeshers_Prism_3D(int hypId, int studyId, SMESH_Gen* gen)
 {
   _name                    = "Prism_3D";
   _shapeType               = (1 << TopAbs_SOLID); // 1 bit per shape type
-  _onlyUnaryInput          = false; // accept all SOLIDs at once
+  _onlyUnaryInput          = false; // mesh all SOLIDs at once
   _requireDiscreteBoundary = false; // mesh FACEs and EDGEs by myself
   _supportSubmeshes        = true;  // "source" FACE must be meshed by other algo
   _neededLowerHyps[ 1 ]    = true;  // suppress warning on hiding a global 1D algo
@@ -578,12 +583,12 @@ bool StdMeshers_Prism_3D::CheckHypothesis(SMESH_Mesh&                          a
   for ( ; exp.More(); exp.Next() ) {
     ++nbFace;
     const TopoDS_Shape& face = exp.Current();
-    nbEdge = TAssocTool::Count( face, TopAbs_EDGE, 0 );
-    nbWire = TAssocTool::Count( face, TopAbs_WIRE, 0 );
+    nbEdge = NSProjUtils::Count( face, TopAbs_EDGE, 0 );
+    nbWire = NSProjUtils::Count( face, TopAbs_WIRE, 0 );
     if (  nbEdge!= 4 || nbWire!= 1 ) {
       if ( !notQuadFaces.empty() ) {
-        if ( TAssocTool::Count( notQuadFaces.back(), TopAbs_EDGE, 0 ) != nbEdge ||
-             TAssocTool::Count( notQuadFaces.back(), TopAbs_WIRE, 0 ) != nbWire )
+        if ( NSProjUtils::Count( notQuadFaces.back(), TopAbs_EDGE, 0 ) != nbEdge ||
+             NSProjUtils::Count( notQuadFaces.back(), TopAbs_WIRE, 0 ) != nbWire )
           RETURN_BAD_RESULT("Different not quad faces");
       }
       notQuadFaces.push_back( face );
@@ -595,7 +600,7 @@ bool StdMeshers_Prism_3D::CheckHypothesis(SMESH_Mesh&                          a
       RETURN_BAD_RESULT("Bad nb not quad faces: " << notQuadFaces.size());
 
     // check total nb faces
-    nbEdge = TAssocTool::Count( notQuadFaces.back(), TopAbs_EDGE, 0 );
+    nbEdge = NSProjUtils::Count( notQuadFaces.back(), TopAbs_EDGE, 0 );
     if ( nbFace != nbEdge + 2 )
       RETURN_BAD_RESULT("Bad nb of faces: " << nbFace << " but must be " << nbEdge + 2);
   }
@@ -657,12 +662,14 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh
 
   Prism_3D::TPrismTopo prism;
   myPropagChains = 0;
+  bool selectBottom = meshedFaces.empty();
 
   if ( nbSolids == 1 )
   {
+    TopoDS_Shape solid = TopExp_Explorer( theShape, TopAbs_SOLID ).Current();
     if ( !meshedFaces.empty() )
       prism.myBottom = meshedFaces.front();
-    return ( initPrism( prism, TopExp_Explorer( theShape, TopAbs_SOLID ).Current() ) &&
+    return ( initPrism( prism, solid, selectBottom ) &&
              compute( prism ));
   }
 
@@ -683,6 +690,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh
 
   TopTools_MapOfShape meshedSolids;
   list< Prism_3D::TPrismTopo > 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<gp_Trsf> 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<TParam2ColumnMap*>
+        ( 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<const TNodeColumn*> & 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
+  if ( !n2nMapPtr || n2nMapPtr->size() < botSMDS->NbNodes() )
+  {
+    // 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 )
       {
-        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() ))
+        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() )
         {
-          TAssocTool::InsertAssociation( botSide->Edge( 0 ),
-                                         topSide->Edge( 0 ), shape2ShapeMap );
-          TAssocTool::InsertAssociation( vb, vt, shape2ShapeMap );
+          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 );
+          }
         }
-        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() ))
+        else
         {
-          TAssocTool::InsertAssociation( botSide->Edge( botSide->NbEdges()-1 ),
-                                         topSide->Edge( topSide->NbEdges()-1 ),
-                                         shape2ShapeMap );
-          TAssocTool::InsertAssociation( vb, vt, shape2ShapeMap );
+          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
-  TNodeNodeMap n2nMap;
-  if ( ! TAssocTool::FindMatchingNodesOnFaces( botFace, myBlock.Mesh(),
-                                               topFace, myBlock.Mesh(),
-                                               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" ));
+    // 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,11 +2237,155 @@ 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<const SMDS_MeshNode*> 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<double>::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<double>::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<double>::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;
+}
+
 //=======================================================================
 //function : project2dMesh
 //purpose  : Project mesh faces from a source FACE of one prism (theSrcFace)
@@ -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;
+}
index f2929c31acd29546d8ceb27831a04a2ac6989e83..546bf4950b92281680bbc424827bcb9da51339ba 100644 (file)
@@ -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;
index 92474f20566a0831457ed48a5278a7a50c62215e..e5ab88a1ecc8c024ef76ab3f972d64b8982d09cc 100644 (file)
@@ -51,6 +51,7 @@
 #include <BRep_Builder.hxx>
 #include <BRep_Tool.hxx>
 #include <Bnd_Box.hxx>
+#include <Geom2d_Curve.hxx>
 #include <TopAbs.hxx>
 #include <TopExp.hxx>
 #include <TopExp_Explorer.hxx>
@@ -66,6 +67,7 @@
 #include <TopoDS_Shape.hxx>
 #include <gp_Pnt.hxx>
 #include <gp_Vec.hxx>
+#include <math_Gauss.hxx>
 
 #include <numeric>
 #include <limits>
@@ -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<double>::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<const SMDS_MeshElement*> Elems1, Elems2;
-  for ( int is2 = 0; is2 < 2; ++is2 )
+  int assocRes;
+  for ( int iAttempt = 0; iAttempt < 2; ++iAttempt )
   {
-    set<const SMDS_MeshElement*> & 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 ))
-    {
-      while ( eIt->more() ) elems.insert( eIt->next() );
-    }
-    else
+    set<const SMDS_MeshElement*> Elems1, Elems2;
+    for ( int is2 = 0; is2 < 2; ++is2 )
     {
-      // 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
-
-      // 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;
-        }
+      set<const SMDS_MeshElement*> & 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 ))
+      {
+        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;
-
-      // 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);
+      {
+        // 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
+
+        // 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
-
-  //  int quadFactor = (*Elems1.begin())->IsQuadratic() ? 2 : 1;
+        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;
+
+        // 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();
+    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
+    }
 
-  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 );
+    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;
+  }
+}
index 31afb072f55f7c5ca029bc2f599f83bc329a12b5..e7ea4423d7e50b07cf92f163d90e1324c3201790 100644 (file)
 
 #include "SMESH_StdMeshers.hxx"
 
+#include "SMDS_MeshElement.hxx"
+
 #include <TopTools_DataMapOfShapeShape.hxx>
 #include <TopoDS_Edge.hxx>
-#include <TopoDS_Vertex.hxx>
 #include <TopoDS_Face.hxx>
+#include <TopoDS_Vertex.hxx>
+#include <gp_Trsf.hxx>
+#include <gp_Trsf2d.hxx>
 
 #include <list>
 #include <map>
@@ -77,7 +81,54 @@ namespace StdMeshers_ProjectionUtils
 {
   typedef StdMeshers_ShapeShapeBiDirectionMap                  TShapeShapeMap;
   typedef TopTools_IndexedDataMapOfShapeListOfShape            TAncestorMap;
-  typedef std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> TNodeNodeMap;
+  typedef std::map<const SMDS_MeshNode*, const SMDS_MeshNode*,
+                   TIDCompare>                                 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
index a0eb3248fb1ba861a06fbb2dc991c4f69672767e..7b3d1e1e1f157ff9157f722b9978e02af6f1dcdd 100644 (file)
 
 #include "utilities.h"
 
+#include <BRepAdaptor_Surface.hxx>
 #include <BRep_Tool.hxx>
 #include <Bnd_B2d.hxx>
+#include <GeomAPI_ProjectPointOnSurf.hxx>
+#include <GeomLib_IsPlanarSurface.hxx>
 #include <TopExp.hxx>
 #include <TopExp_Explorer.hxx>
 #include <TopTools_DataMapIteratorOfDataMapOfShapeShape.hxx>
@@ -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();
 
-    const double tol = 1.e-7 * srcMeshDS->getMaxDim();
+    src2tgtNodes.clear();
 
-    gp_Trsf trsf; // transformation to get location of target nodes from source ones
-    if ( tgtFace.IsPartner( srcFace ))
-    {
-      gp_Trsf srcTrsf = srcFace.Location();
-      gp_Trsf tgtTrsf = tgtFace.Location();
-      trsf = srcTrsf.Inverted() * tgtTrsf;
-    }
-    else
+    // 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 )
     {
-      // Try to find the transformation
-
-      // make any local coord systems of src and tgt faces
-      vector<gp_Pnt> 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 )
+      list< TopoDS_Edge > tgtEdges;
+      StdMeshers_FaceSidePtr srcWire = srcWires[iW];
+      TopTools_IndexedMapOfShape edgeMap; // to detect seam edges
+      for ( int iE = 0; iE < srcWire->NbEdges(); ++iE )
       {
-        srcSM = smIt->next();
-        SMESHDS_SubMesh* srcSmds = srcSM->GetSubMeshDS();
-        if ( !srcSmds ) continue;
-        SMDS_NodeIteratorPtr nIt = srcSmds->GetNodes();
-        while ( nIt->more() )
+        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
         {
-          SMESH_TNodeXYZ p ( nIt->next());
-          bool pOK = false;
-          switch ( srcPP.size() )
+          // check which of edges to reverse, E or one already being in tgtEdges
+          if ( are2dConnected( tgtEdges.back(), tgtE, tgtFace ))
           {
-          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;
-            }
+            list< TopoDS_Edge >::iterator eIt = tgtEdges.begin();
+            std::advance( eIt, index-1 );
+            eIt->Reverse();
           }
-          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 )
+          else
           {
-            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;
+            tgtE.Reverse();
           }
-          else if ( tgtPP.size() > 0 )
+        }
+        if ( srcWire->NbEdges() == 1 && tgtMesh == srcMesh ) // circle
+        {
+          // try to verify ori by propagation
+          pair<int,TopoDS_Edge> 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() )
           {
-            if ( SMESHDS_SubMesh* tgtSmds = tgtMeshDS->MeshElements( tgtShape ))
+            map< double, const SMDS_MeshNode* >::iterator u_tn = tgtNodes.begin();
+            if ( srcE.Orientation() == tgtE.Orientation() )
             {
-              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;
-              }
+              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;
           }
-          if ( !pOK )
-            continue;
-
-          srcPP.push_back( p );
-          tgtPP.push_back( tgtP );
         }
-      }
-      if ( srcPP.size() != 3 )
-        return false;
+      } // loop on EDGEs of a WIRE
 
-      // 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();
-
-      trsf = fromTgtCS * toSrcCS;
-    }
-
-    // Fill map of src to tgt nodes with nodes on edges
+      tgtWires[ iW ].reset( new StdMeshers_FaceSide( tgtFace, tgtEdges, tgtMesh,
+                                                     /*theIsForward = */ true,
+                                                     /*theIgnoreMediumNodes = */false));
+    } // loop on WIREs
 
-    map<const SMDS_MeshNode* , const SMDS_MeshNode*> src2tgtNodes;
-    map<const SMDS_MeshNode* , const SMDS_MeshNode*>::iterator srcN_tgtN;
+    return TError();
+  }
 
-    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();
+  //================================================================================
+  /*!
+   * \brief Preform projection in case if tgtFace.IsPartner( srcFace ) and in case
+   * if projection by 3D transformation is possible
+   */
+  //================================================================================
 
-      if ( srcMesh->GetSubMesh( srcEdge )->IsEmpty() ||
-           tgtMesh->GetSubMesh( tgtEdge )->IsEmpty() )
-        continue;
+  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 );
 
-      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 )
-          )
-        return false;
+    const double tol = 1.e-7 * srcMeshDS->getMaxDim();
 
-      if ( !tgtEdge.IsPartner( srcEdge ))
+    // 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.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 3D transformation
+
+      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 )
       {
-        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 )
+        const double minSegLen = srcWires[iW]->Length() / totNbSeg;
+        for ( int iE = 0; iE < srcWires[iW]->NbEdges(); ++iE )
         {
-          //cout << "KO trsf, 3 dist: "
-          //<< p0T.SquareDistance( p0S.Transformed( trsf ))<< ", "
-          //<< p1T.SquareDistance( p1S.Transformed( trsf ))<< ", "
-          //<< p2T.SquareDistance( p2S.Transformed( trsf ))<< ", "<<endl;
-          return false;
+          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  )
+          {
+            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 ( !tgtNodes.empty() )
-      {
-        map< double, const SMDS_MeshNode* >::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 )
+      if ( !trsf.Solve( srcPnts, tgtPnts ))
         return false;
 
-      if ( !tgtV.IsPartner( srcV ))
+      // check trsf
+
+      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 )
       {
-        // 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;
-        }
+        gp_Pnt trsfTgt = trsf.Transform( srcPnts[i] );
+        trsfIsOK = ( trsfTgt.SquareDistance( tgtPnts[i] ) < tol*tol );
       }
-      src2tgtNodes.insert( make_pair( srcN, tgtN ));
+      // 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;
     }
 
-
     // 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;
-    }
-
-    // 2) Find transformation
+    // 1) Find 2D 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 )
-          return false;
+        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 );
       }
-    }
 
-    // 3) Projection
+      // 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;
 
-    typedef map<const SMDS_MeshNode* , const SMDS_MeshNode*, TIDCompare> TN2NMap;
-    TN2NMap src2tgtNodes;
-    TN2NMap::iterator srcN_tgtN;
+        // check trsf
 
-    // fill src2tgtNodes in with nodes on EDGEs
-    for ( unsigned iW = 0; iW < srcWires.size(); ++iW )
-      if ( is1DComputed )
-      {
-        const vector<UVPtStruct>& srcUVs = srcWires[iW]->GetUVPtStruct();
-        const vector<UVPtStruct>& 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 )
+        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 )
         {
-          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 ));
+          gp_Pnt2d trsfTgt = trsf.Transform( srcPnts[i] );
+          trsfIsOK = ( trsfTgt.Distance( tgtPnts[i] ) < tol );
         }
+        if ( !trsfIsOK )
+          return false;
       }
+    } // "Find transformation" block
 
-    // 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<const SMDS_MeshNode*> 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;
 }
 
index 57e34dbc4d46f20599d30c56178008c1439612ed..878d2184900fa340be5c8eea8f0d4a2a00fe8b3b 100644 (file)
@@ -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;
 
 };
 
index 3079c7bd86a70d4a5f05a9c3274fc6db2418603b..93969dfeb75d9b13ed9288d91ca2e361cef84646 100644 (file)
@@ -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 #")
index a9990e5e7e7aaf475b764d56ac9e684aa8f92205..4d1321497a6d08eb6ad1fe25b8c4b43227dc3647 100644 (file)
@@ -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
       }
+
+      const bool allCornersSame = ( nbC[0] == 3 );
+      if ( allCornersSame && nbHalfDividers > 0 )
+      {
+        // select two halfDivider's as corners
+        TGeoIndex hd1, hd2 = -1;
+        int iC2;
+        for ( iC2 = 0; iC2 < cornerInd.size() && hd2 < 0; ++iC2 )
+        {
+          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  = equalVertices.size();
+      int nbEqualV  = equVerts.size();
       int nbExcessV = nbEqualV - ( 1 + nbC[0] + nbC[1] );
-      if ( nbExcessV > 0 )
+      if ( nbExcessV > 0 ) // there is nbExcessV vertices that can become corners
       {
-        // calculate normalized length of each side enclosed between neighbor equalVertices
-        vector< double > curLengths;
+        // calculate normalized length of each "side" enclosed between neighbor equVerts
+        vector< double > accuLength;
         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 )
+        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 ) )
         {
-          curLengths.push_back( totalLen );
+          // 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;
 }
index 17411417e315f49b649a018489b82e7ff8c00b0b..5ef61aab9cdfc9fb6404afb92aa86410db218f8b 100644 (file)
 #include <TopoDS_Solid.hxx>
 #include <gp.hxx>
 #include <gp_Pnt.hxx>
-#if OCC_VERSION_LARGE > 0x06050400
 #include <BRepClass3d.hxx>
-#else
-#include <BRepTools.hxx>
-#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 )
index cc964cfac209d603d8daf2111fc155f82f734529..a7e67cfeb6fc3c1e2db18cd06ef0acb49c57c714 100644 (file)
@@ -68,6 +68,7 @@
 #include <limits>
 
 using namespace std;
+using namespace StdMeshers;
 
 //=============================================================================
 /*!
index db5469ea228a823a843cc75993ed49714f634883..704144d7a6d3a5c74f9315050c0640226ff920a7 100644 (file)
@@ -44,6 +44,7 @@
 #include "SMESH_subMeshEventListener.hxx"
 #include "StdMeshers_FaceSide.hxx"
 
+#include <Adaptor3d_HSurface.hxx>
 #include <BRepAdaptor_Curve2d.hxx>
 #include <BRepAdaptor_Surface.hxx>
 #include <BRepLProp_SLProps.hxx>
@@ -75,6 +76,8 @@
 #include <TopoDS_Face.hxx>
 #include <TopoDS_Vertex.hxx>
 #include <gp_Ax1.hxx>
+#include <gp_Cone.hxx>
+#include <gp_Sphere.hxx>
 #include <gp_Vec.hxx>
 #include <gp_XY.hxx>
 
 #include <cmath>
 #include <limits>
 
-#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<TGeomID>& 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<double>::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<TGeomID>& 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('"<<fname<<"')"<<endl;
       py = new ofstream(fname);
       *py << "import SMESH" << endl
           << "from salome.smesh import smeshBuilder" << endl
           << "smesh  = smeshBuilder.New(salome.myStudy)" << endl
-          << "meshSO = smesh.GetCurrentStudy().FindObjectID('0:1:2:3')" << endl
+          << "meshSO = smesh.GetCurrentStudy().FindObjectID('0:1:2:" << tag <<"')" << endl
           << "mesh   = smesh.Mesh( meshSO.GetObject() )"<<endl;
-      theNbFunc = 0;
+      theNbPyFunc = 0;
     }
     void Finish() {
       if (py) {
@@ -1181,16 +1336,17 @@ namespace
       }
       delete py; py=0;
     }
-    ~PyDump() { Finish(); cout << "NB FUNCTIONS: " << theNbFunc << endl; }
+    ~PyDump() { Finish(); cout << "NB FUNCTIONS: " << theNbPyFunc << endl; }
   };
 #define dumpFunction(f) { _dumpFunction(f, __LINE__);}
 #define dumpMove(n)     { _dumpMove(n, __LINE__);}
+#define dumpMoveComm(n,txt) { _dumpMove(n, __LINE__, txt);}
 #define dumpCmd(txt)    { _dumpCmd(txt, __LINE__);}
   void _dumpFunction(const string& fun, int ln)
-  { if (py) *py<< "def "<<fun<<"(): # "<< ln <<endl; cout<<fun<<"()"<<endl; ++theNbFunc; }
-  void _dumpMove(const SMDS_MeshNode* n, int ln)
+  { if (py) *py<< "def "<<fun<<"(): # "<< ln <<endl; cout<<fun<<"()"<<endl; ++theNbPyFunc; }
+  void _dumpMove(const SMDS_MeshNode* n, int ln, const char* txt="")
   { if (py) *py<< "  mesh.MoveNode( "<<n->GetID()<< ", "<< n->X()
-               << ", "<<n->Y()<<", "<< n->Z()<< ")\t\t # "<< ln <<endl; }
+               << ", "<<n->Y()<<", "<< n->Z()<< ")\t\t # "<< ln <<" "<< txt << endl; }
   void _dumpCmd(const string& txt, int ln)
   { if (py) *py<< "  "<<txt<<" # "<< ln <<endl; }
   void dumpFunctionEnd()
@@ -1201,9 +1357,10 @@ namespace
       *py << f->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,26 +1704,27 @@ bool _ViscousBuilder::findFacesWithLayers(const bool onlyWith)
     {
       _sdVec[i]._ignoreFaceIds.swap( ignoreFacesOfHyps.back().first );
     }
+  } // loop on _sdVec
+
+  if ( onlyWith ) // is called to check hypotheses compatibility only
+    return true;
 
-    // fill _SolidData::_reversedFaceIds
+  // 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() )
     {
-      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 ))
       {
-        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 );
-        }
+        _sdVec[i]._reversedFaceIds.insert( faceID );
       }
     }
-  } // loop on _sdVec
-
-  if ( onlyWith ) // is called to check hypotheses compatibility only
-    return true;
+  }
 
   // Find faces to shrink mesh on (solution 2 in issue 0020832);
   TopTools_IndexedMapOfShape shapes;
@@ -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_")<<data._index); 
+  dumpFunction(SMESH_Comment("makeLayers_")<<data._index);
 
   data._stepSize = Precision::Infinite();
   data._stepSizeNodes[0] = 0;
@@ -2066,6 +2226,16 @@ bool _ViscousBuilder::makeLayer(_SolidData& data)
     }
   }
 
+  // fix _LayerEdge::_2neibors on EDGEs to smooth
+  map< TGeomID,Handle(Geom_Curve)>::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() )
+    const int dim = isEdge ? 1 : 2;
+
+    for ( size_t iS = 0; iS < edgesByGeom.size(); ++iS )
     {
-    case TopAbs_EDGE: {
+      vector<_LayerEdge*>& eS = edgesByGeom[iS];
+      if ( eS.empty() ) continue;
+      if ( eS[0]->_nodes[0]->GetPosition()->GetDim() != dim ) continue;
 
-      if ( SMESH_Algo::isDegenerated( TopoDS::Edge( S )))
-        break;
-      //bool isShrinkEdge = !eS[0]->_sWOL.IsNull();
-      for ( TopoDS_Iterator vIt( S ); vIt.More() && !needSmooth; vIt.Next() )
-      {
-        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 )
+      const TopoDS_Shape& S = getMeshDS()->IndexToShape( iS );
+      bool needSmooth = false;
+      switch ( S.ShapeType() )
+      {
+      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 );
+
+        // 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 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<TGeomID> 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<TGeomID>::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<TGeomID> 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<TGeomID>::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 ")<<node, data._index);
-    }
-  } // case _sWOL.IsNull()
+  // set _cosin
+  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 );
+    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 ")<<node, data._index);
+  }
 
   double normSize = edge._normal.SquareModulus();
   if ( normSize < numeric_limits<double>::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,24 +3060,41 @@ 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;
   }
 
-  double angles[30];
+  // exclude equal normals
+  //int nbUniqNorms = nbFaces;
   for ( int i = 0; i < nbFaces; ++i )
-  {
-    const TopoDS_Face& F = TopoDS::Face( getMeshDS()->IndexToShape( fId2Normal[i].first ));
-
+    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 = fId2Normal[i].first;
+
     // look for two EDGEs shared by F and other FACEs within fId2Normal
     TopoDS_Edge ee[2];
     int nbE = 0;
@@ -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<TGeomID>&  ingnoreShapes,
-                                    const _SolidData*    dataToCheckOri,
-                                    const bool           toSort)
+void _Simplex::GetSimplices( const SMDS_MeshNode* node,
+                             vector<_Simplex>&    simplices,
+                             const set<TGeomID>&  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")<<data._index<<"_step"<<nbSteps); // debug
         for ( size_t i = 0; i < data._edges.size(); ++i )
         {
@@ -3220,11 +3527,11 @@ bool _ViscousBuilder::inflate(_SolidData& data)
     avgThick /= data._edges.size();
     debugMsg( "-- Thickness " << curThick << " ("<< avgThick*100 << "%) reached" );
 
-    if ( distToIntersection < tgtThick*avgThick*1.5 )
+    if ( distToIntersection < tgtThick * avgThick * safeFactor && avgThick < 0.9 )
     {
       debugMsg( "-- Stop inflation since "
                 << " distToIntersection( "<<distToIntersection<<" ) < avgThick( "
-                << tgtThick*avgThick << " ) * 1.5" );
+                << tgtThick * avgThick << " ) * " << safeFactor );
       break;
     }
     // new step size
@@ -3239,17 +3546,16 @@ bool _ViscousBuilder::inflate(_SolidData& data)
     return error("failed at the very first inflation step", data._index);
 
   if ( avgThick < 0.99 )
-    if ( SMESH_subMesh* sm = _mesh->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")<<data._index); // debug
@@ -3282,6 +3588,7 @@ bool _ViscousBuilder::smoothAndCheck(_SolidData& data,
     return true; // no shapes needing smoothing
 
   bool moved, improved;
+  vector< _LayerEdge* > 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")<<data._index<<"_Fa"<<sInd
                      <<"_InfStep"<<nbSteps<<"_"<<step); // debug
         int oldBadNb = badNb;
-        badNb = 0;
-        moved = false;
-        if ( step % 2 )
+        badSmooEdges.clear();
+
+        if ( step % 2 ) {
           for ( int i = iBeg; i < iEnd; ++i ) // iterate forward
-            moved |= data._edges[i]->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
+
+  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
+ */
+//================================================================================
 
-  // compute new position for the last _pos
+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<double>::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();
 
-  // count quality metrics (orientation) of tetras around _tgtNode
-  int nbOkBefore = 0;
+  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<double>::min() )
+    {
+      newPos += pN;
+      continue;
+    }
+    gp_Vec bisec = edgeDir[i] + edgeDir[i+1];
+    double bisecLen = bisec.SquareMagnitude();
+    if ( bisecLen < numeric_limits<double>::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 )
-    nbOkBefore += _simplices[i].IsForward( _nodes[0], &curPos );
+  {
+    gp_XYZ p = SMESH_TNodeXYZ( _simplices[i]._nPrev );
+    edgeSize.push_back( ( p - pPrev ).Modulus() );
+    if ( edgeSize.back() < numeric_limits<double>::min() )
+    {
+      edgeSize.pop_back();
+    }
+    else
+    {
+      points.push_back( p );
+    }
+    pPrev = p;
+  }
+  edgeSize.push_back( edgeSize[0] );
 
-  int nbOkAfter = 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 )
-    nbOkAfter += _simplices[i].IsForward( _nodes[0], &newPos );
+  {
+    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();
 
-  if ( nbOkAfter < nbOkBefore )
-    return false;
+    sumSize += size;
+    newPos += gc * size;
+  }
+  newPos /= sumSize;
 
-  SMDS_MeshNode* n = const_cast< SMDS_MeshNode* >( _nodes.back() );
+  return newPos;
+}
 
-  _len -= prevPos.Distance(SMESH_TNodeXYZ( n ));
-  _len += prevPos.Distance(newPos);
+//================================================================================
+/*!
+ * \brief Computes a new node position located inside a Nef polygon
+ */
+//================================================================================
 
-  n->setXYZ( newPos.X(), newPos.Y(), newPos.Z());
-  _pos.back() = newPos;
+gp_XYZ _LayerEdge::smoothNefPolygon()
+{
+  gp_XYZ newPos(0,0,0);
 
-  badNb += _simplices.size() - nbOkAfter;
+  // get a plane to seach a solution on
+
+  vector< gp_XYZ > vecs( _simplices.size() + 1 );
+  size_t i;
+  const double tol = numeric_limits<double>::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();
 
-  dumpMove( n );
+  gp_XYZ zAxis(0,0,0);
+  for ( i = 0; i < _simplices.size(); ++i )
+    zAxis += vecs[i] ^ vecs[i+1];
 
-  return true;
+  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;
+  }
+
+  // intersect boundaries of half-planes, define state of intersection points
+  // in relation to all half-planes and calculate internal point of a 2D polygon
+
+  double sumLen = 0;
+  gp_XY newPos2D (0,0);
+
+  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 );
+
+  vector< vector< TIntPntState > > allIntPnts( nbHP );
+  for ( int iHP1 = 0; iHP1 < nbHP; ++iHP1 )
+  {
+    vector< TIntPntState > & intPnts1 = allIntPnts[ iHP1 ];
+    if ( intPnts1.empty() ) intPnts1.resize( nbHP, undefIPS );
+
+    int iPrev = SMESH_MesherHelper::WrapIndex( iHP1 - 1, nbHP );
+    int iNext = SMESH_MesherHelper::WrapIndex( iHP1 + 1, nbHP );
+
+    int nbNotOut = 0;
+    const gp_XY* segEnds[2] = { 0, 0 }; // NOT_OUT points
+
+    for ( int iHP2 = 0; iHP2 < nbHP; ++iHP2 )
+    {
+      if ( iHP1 == iHP2 ) continue;
+
+      TIntPntState & ips1 = intPnts1[ iHP2 ];
+      if ( ips1.second == UNDEF )
+      {
+        // find an intersection point of boundaries of iHP1 and iHP2
+
+        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")<<f2sd->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<gp_XY>& 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<gp_XY>& uv,
       distToN = -distToN;
 
     newPos += ( p + bisec * distToN ) * ( edgeSize[i1] + edgeSize[i] );
-    ++nbEdges;
+    //++nbEdges;
     sumSize += edgeSize[i1] + edgeSize[i];
   }
   newPos /= /*nbEdges * */sumSize;
index 4cdd2b92ef943cb9fc99d28cd705adf41e9dbc60..0c5ad56fb6aa56a495f227cd3adb5603eab12665 100644 (file)
@@ -40,7 +40,6 @@
 #include <QtxComboBox.h>
 #include <SALOME_InteractiveObject.hxx>
 #include <SALOME_ListIO.hxx>
-#include <SALOME_ListIteratorOfListIO.hxx>
 #include <SUIT_ResourceMgr.h>
 #include <SalomeApp_IntSpinBox.h>
 #include <SalomeApp_Tools.h>
index 9e5768402b62d3a3b6a735ac28e558dc8f7f0113..7960a968632c304ccc0199ce37be03b4c2009225 100644 (file)
@@ -35,7 +35,6 @@
 #include <LightApp_SelectionMgr.h>
 #include <SVTK_ViewWindow.h>
 #include <SALOME_ListIO.hxx>
-#include <SALOME_ListIteratorOfListIO.hxx>
 
 // SALOME KERNEL incldues
 #include <SALOMEDSClient_SObject.hxx>
index a99177bceb2ed0d32217f38da14ffdc21e646316..9db22c2a9face2bf7313e4a21fd19fa1993d89b2 100644 (file)
@@ -29,7 +29,6 @@
 #include <GEOMBase.h>
 #include <LightApp_SelectionMgr.h>
 #include <SALOME_ListIO.hxx>
-#include <SALOME_ListIteratorOfListIO.hxx>
 #include <SUIT_ResourceMgr.h>
 
 // Qt includes
index c481eea7e9b598017fce4bc1e545826bf002bce4..e912e113d1d337b55483d397ac80483c2b4aff4a 100644 (file)
@@ -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() );
index 9cd4ff727ecf397522f681e0509c74b2921c9f41..7986354934dbabdeb02b0353834f5990c5b8b989 100644 (file)
@@ -43,7 +43,6 @@
 // SALOME GUI includes
 #include <SALOME_ListIO.hxx>
 #include <LightApp_SelectionMgr.h>
-#include <SALOME_ListIteratorOfListIO.hxx>
 
 // SUIT Includes
 #include <SUIT_ResourceMgr.h>
index 7f43838c450cd950f209b5d4244041b1b6c6c5ed..3fa65e55796181fb633a6000b9104cce16c1403d 100644 (file)
@@ -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()