Salome HOME
Merge branch 'V9_2_BR'
authorvsr <vsr@opencascade.com>
Mon, 10 Dec 2018 14:29:37 +0000 (17:29 +0300)
committervsr <vsr@opencascade.com>
Mon, 10 Dec 2018 14:30:25 +0000 (17:30 +0300)
65 files changed:
CMakeLists.txt
doc/salome/examples/grouping_elements_ex09.py [new file with mode: 0644]
doc/salome/examples/measurements_ex04.py [new file with mode: 0644]
doc/salome/examples/tests.set
doc/salome/gui/SMESH/images/Nut_sharp_edges.png [new file with mode: 0644]
doc/salome/gui/SMESH/images/angle_measure.png [new file with mode: 0644]
doc/salome/gui/SMESH/images/basic_props.png
doc/salome/gui/SMESH/images/bnd_box.png
doc/salome/gui/SMESH/images/groups_by_sharp_edges_dlg.png [new file with mode: 0644]
doc/salome/gui/SMESH/images/meshexportmesh.png [changed mode: 0755->0644]
doc/salome/gui/SMESH/images/min_distance.png
doc/salome/gui/SMESH/images/pref21.png
doc/salome/gui/SMESH/input/create_groups_from_geometry.rst
doc/salome/gui/SMESH/input/face_groups_by_sharp_edges.rst [new file with mode: 0644]
doc/salome/gui/SMESH/input/grouping_elements.rst
doc/salome/gui/SMESH/input/importing_exporting_meshes.rst
doc/salome/gui/SMESH/input/measurements.rst
doc/salome/gui/SMESH/input/mesh_preferences.rst
doc/salome/gui/SMESH/input/modules.rst
doc/salome/gui/SMESH/input/smesh_module.rst
doc/salome/gui/SMESH/input/tui_grouping_elements.rst
doc/salome/gui/SMESH/input/tui_measurements.rst
doc/salome/gui/SMESH/input/viewing_meshes_overview.rst
idl/SMESH_Measurements.idl
idl/SMESH_Mesh.idl
idl/SMESH_MeshEditor.idl
resources/CMakeLists.txt
resources/SalomeApp.xml.in
resources/mesh_angle_measure.png [new file with mode: 0644]
resources/mesh_face_groups_by_edges.png [new file with mode: 0644]
resources/mesh_plugins_meshcut.png [new file with mode: 0644]
src/DriverMED/DriverMED_W_SMESHDS_Mesh.cxx
src/DriverMED/DriverMED_W_SMESHDS_Mesh.h
src/SMDS/SMDS_Mesh.cxx
src/SMESH/SMESH_Mesh.cxx
src/SMESH/SMESH_Mesh.hxx
src/SMESH/SMESH_MeshEditor.cxx
src/SMESH/SMESH_MeshEditor.hxx
src/SMESHDS/SMESHDS_GroupOnGeom.cxx
src/SMESHGUI/CMakeLists.txt
src/SMESHGUI/SMESHGUI.cxx
src/SMESHGUI/SMESHGUI_ComputeDlg.cxx
src/SMESHGUI/SMESHGUI_FaceGroupsSeparatedByEdgesDlg.cxx [new file with mode: 0644]
src/SMESHGUI/SMESHGUI_FaceGroupsSeparatedByEdgesDlg.h [new file with mode: 0644]
src/SMESHGUI/SMESHGUI_GroupOnShapeDlg.cxx
src/SMESHGUI/SMESHGUI_Measurements.cxx
src/SMESHGUI/SMESHGUI_Measurements.h
src/SMESHGUI/SMESHGUI_Operations.h
src/SMESHGUI/SMESHGUI_VTKUtils.cxx
src/SMESHGUI/SMESH_images.ts
src/SMESHGUI/SMESH_msg_en.ts
src/SMESHUtils/SMESH_MeshAlgos.cxx
src/SMESHUtils/SMESH_MeshAlgos.hxx
src/SMESHUtils/SMESH_Offset.cxx
src/SMESH_I/SMESH_2smeshpy.cxx
src/SMESH_I/SMESH_Measurements_i.cxx
src/SMESH_I/SMESH_Measurements_i.hxx
src/SMESH_I/SMESH_MeshEditor_i.cxx
src/SMESH_I/SMESH_MeshEditor_i.hxx
src/SMESH_I/SMESH_Mesh_i.cxx
src/SMESH_I/SMESH_Mesh_i.hxx
src/SMESH_SWIG/smeshBuilder.py
src/StdMeshers/StdMeshers_QuadToTriaAdaptor.cxx
src/StdMeshers/StdMeshers_RadialPrism_3D.cxx
src/Tools/smesh_plugins.py

index 8b29146d6d5640acb1e00a32aa2d1eba0dea3e22..31936c3074ef267c693a73474c22a85f73ffe44a 100755 (executable)
@@ -37,7 +37,7 @@ SET(${PROJECT_NAME_UC}_MINOR_VERSION 2)
 SET(${PROJECT_NAME_UC}_PATCH_VERSION 0)
 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)
 
 # Common CMake macros
 # ===================
diff --git a/doc/salome/examples/grouping_elements_ex09.py b/doc/salome/examples/grouping_elements_ex09.py
new file mode 100644 (file)
index 0000000..e066dbd
--- /dev/null
@@ -0,0 +1,16 @@
+# Creating groups of faces separated by sharp edges
+
+import salome
+salome.salome_init()
+from salome.geom import geomBuilder
+from salome.smesh import smeshBuilder
+geompy = geomBuilder.New()
+smesh =  smeshBuilder.New()
+
+# create a mesh on a box
+box = geompy.MakeBoxDXDYDZ( 10,10,10, theName="Box" )
+mesh = smesh.Mesh(box,"Mesh")
+mesh.AutomaticHexahedralization()
+
+# create groups of faces of each side of the box
+groups = mesh.FaceGroupsSeparatedByEdges( 89 )
diff --git a/doc/salome/examples/measurements_ex04.py b/doc/salome/examples/measurements_ex04.py
new file mode 100644 (file)
index 0000000..6524ac9
--- /dev/null
@@ -0,0 +1,26 @@
+# Angle measurement
+
+
+import salome
+salome.salome_init()
+from salome.smesh import smeshBuilder
+smesh =  smeshBuilder.New()
+
+# use smeshBuilder.GetAngle() to compute angle between 3 arbitrary points
+
+p0 = [1,0,0]
+p1 = [0,0,0]
+p2 = [0,1,0]
+
+a1 = smesh.GetAngle(p0, p1, p2)
+print("Right angle measure", a1 )
+
+# use Mesh.GetAngle() to compute angle between 3 nodes of a mesh
+
+mesh = smesh.Mesh()
+n0 = mesh.AddNode( *p0 )
+n1 = mesh.AddNode( *p1 )
+n2 = mesh.AddNode( *p2 )
+
+a2 = mesh.GetAngle( n0,n1,n2 )
+
index 72ae83dcb2913b47c26a4aba261da87dbebfddbd..29910eda8917f9ce92ed945eedbf855f559399ed 100644 (file)
@@ -112,8 +112,11 @@ SET(GOOD_TESTS
   grouping_elements_ex06.py
   grouping_elements_ex07.py
   grouping_elements_ex08.py
+  grouping_elements_ex09.py
   measurements_ex01.py
   measurements_ex02.py
+  measurements_ex03.py
+  measurements_ex04.py
   modifying_meshes_ex01.py
   modifying_meshes_ex02.py
   modifying_meshes_ex03.py
diff --git a/doc/salome/gui/SMESH/images/Nut_sharp_edges.png b/doc/salome/gui/SMESH/images/Nut_sharp_edges.png
new file mode 100644 (file)
index 0000000..754710b
Binary files /dev/null and b/doc/salome/gui/SMESH/images/Nut_sharp_edges.png differ
diff --git a/doc/salome/gui/SMESH/images/angle_measure.png b/doc/salome/gui/SMESH/images/angle_measure.png
new file mode 100644 (file)
index 0000000..80a2116
Binary files /dev/null and b/doc/salome/gui/SMESH/images/angle_measure.png differ
index bba200d09384ef4c28feff548144436b2f118132..abf3aa32c3223a28aee7aa6f1716d2cc03c0ba0f 100644 (file)
Binary files a/doc/salome/gui/SMESH/images/basic_props.png and b/doc/salome/gui/SMESH/images/basic_props.png differ
index d079eaaa4b38a970146d8aa085201a8ade3eec78..4c0bbd3e67b057c8956ad386a57daa83838279b5 100644 (file)
Binary files a/doc/salome/gui/SMESH/images/bnd_box.png and b/doc/salome/gui/SMESH/images/bnd_box.png differ
diff --git a/doc/salome/gui/SMESH/images/groups_by_sharp_edges_dlg.png b/doc/salome/gui/SMESH/images/groups_by_sharp_edges_dlg.png
new file mode 100644 (file)
index 0000000..936d0ba
Binary files /dev/null and b/doc/salome/gui/SMESH/images/groups_by_sharp_edges_dlg.png differ
old mode 100755 (executable)
new mode 100644 (file)
index d2997a4..f60679e
Binary files a/doc/salome/gui/SMESH/images/meshexportmesh.png and b/doc/salome/gui/SMESH/images/meshexportmesh.png differ
index 486dab376e386fffbaba4798aa49939daef52d5e..294178f2a2526c05df261acd2a2597bbb1e99cab 100644 (file)
Binary files a/doc/salome/gui/SMESH/images/min_distance.png and b/doc/salome/gui/SMESH/images/min_distance.png differ
index 926c78085b5c7b33de2d1a1bf80981ae001066d3..1f5d63cf92ee2e0b0e7848f4546c6682c2959070 100644 (file)
Binary files a/doc/salome/gui/SMESH/images/pref21.png and b/doc/salome/gui/SMESH/images/pref21.png differ
index 49bc6ed99f65561afd0ca5df5c014f5356499ebb..70f3a58ce566b76edfbb93db023a0d6222ea2d8a 100644 (file)
@@ -9,8 +9,6 @@ This operation allows creating groups on geometry on all selected shapes. Only t
 The type of each new group is defined automatically by the nature of the **Geometry**.
 The group names will be the same as the names of geometrical objects.
 
-.. warning:: It's impossible to create a group of *0D elements* or *ball elements* with this operation. For this, it is necessary to use :ref:`Create group <creating_groups_page>` operation. 
-
 To use this operation, select in the **Mesh** menu or in the contextual menu in the Object browser **Create Groups from Geometry** item.
 
 .. image:: ../images/create_groups_from_geometry.png
diff --git a/doc/salome/gui/SMESH/input/face_groups_by_sharp_edges.rst b/doc/salome/gui/SMESH/input/face_groups_by_sharp_edges.rst
new file mode 100644 (file)
index 0000000..eed6996
--- /dev/null
@@ -0,0 +1,29 @@
+************************************
+Face Groups Separated By Sharp Edges
+************************************
+
+**Face groups separated by sharp edges** operation distributes all faces of the mesh among groups using sharp edges and optionally existing 1D elements as group boundaries. Edges where more than two faces meet are always considered as a group boundary. The operation is available in **Mesh** menu.
+
+The operation dialog looks as follows:
+
+.. image:: ../images/groups_by_sharp_edges_dlg.png
+       :align: center
+
+In this dialog box specify
+
+       * **Mesh** including the faces to distribute among groups.
+        * **Sharp angle** in degrees, by which edges used as group boundaries are detected. An edge is considered as a group boundary if an angle between normals of adjacent faces is more than this angle.
+       * Activate **Create edges** option if you wish that 1D elements to be created (if not yet exist) on the edges that served as group boundaries.
+       * Activate **Use existing edges** option if you wish that existing 1D elements to be used as group boundaries.
+       * Activate **Preview** to see the edges that will be used as group boundaries highlighted in the Viewer.
+
+
+.. image:: ../images/Nut_sharp_edges.png
+       :align: center
+
+.. centered:: 
+       **Preview of boundary edges detected at Sharp Angle = 10 degrees**
+
+**See Also** a sample TUI Script of a :ref:`tui_groups_by_sharp_edges` operation.
+
+
index e0e259ffae2c3f8ee84c9539d071c071636f5900..2846fa94b3d18b37ddeddb15d280aafd084d19fc 100644 (file)
@@ -27,6 +27,7 @@ The following ways of group creation are possible:
 
 * :ref:`Create group <creating_groups_page>` dialog allows creation of a group of any type: :ref:`Standalone group<standalone_group>`, :ref:`Group on geometry <group_on_geom>` and :ref:`Group on filter <group_on_filter>` using dedicated tabs.
 * :ref:`Create Groups from Geometry <create_groups_from_geometry_page>` dialog allows creation of several groups on geometry at once.
+* :doc:`face_groups_by_sharp_edges` operation distributes all faces of the mesh among groups using sharp edges and/or existing 1D elements as group boundaries.
 * Standalone groups of all nodes and elements of the chosen sub-mesh (type of elements depends on dimension of sub-mesh geometry) can be created using **Mesh -> Construct Group** menu item (available from the context menu as well).
 * Standalone groups of any element type can be created basing on nodes of other groups - using :ref:`Group based on nodes of other groups <group_of_underlying_elements_page>` dialog.
 * Standalone groups can be created by applying :ref:`Boolean operations <using_operations_on_groups_page>` to other groups.
@@ -49,6 +50,9 @@ In the Object Browser, if an item contains more than one child group, it is poss
 
 An important tool, providing filters for creation of standalone groups and groups on filter is :ref:`selection_filter_library_page`.
 
+**See Also** sample TUI Scripts of :doc:`tui_grouping_elements` operations.
+
+
 **Table of Contents**
 
 .. toctree::
@@ -56,6 +60,7 @@ An important tool, providing filters for creation of standalone groups and group
 
        creating_groups.rst
        create_groups_from_geometry.rst
+       face_groups_by_sharp_edges.rst
        group_of_underlying_elements.rst
        using_operations_on_groups.rst
        editing_groups.rst
index 054fc3a336e7ae6cc01b02f6cf327ecc906ffbf5..a11e36dbb67747b7b5d919f265dfe7d9a30cc515 100644 (file)
@@ -8,11 +8,12 @@ Importing and exporting meshes
 In MESH there is a functionality allowing import/export of meshes in the following formats:
 
 * **MED**,
+* **SAUV** (format of the CASTEM code),
 * **UNV** (I-DEAS 10),
-* **DAT** (simple ascii format), 
 * **STL**, 
+* **CGNS**,
 * **GMF** (internal format of DISTENE products from the MeshGems suite),
-* **CGNS**.
+* **DAT** (simple ascii format).
 
 You can also export a group as a whole mesh.
 
@@ -42,10 +43,13 @@ If you try to export a group, the warning will be shown:
 
 * **Don't show this warning anymore** check-box allows to switch off the warning. You can re-activate the warning in :ref:`Preferences <group_export_warning_pref>`.
 
+Only MED format supports all types of elements that can be created in the module. If you export a mesh or group that includes elements of types that are not supported by chosen format, you will be warned about that.
+
 There are additional parameters available at export to MED and SAUV format files.
 
 .. _export_auto_groups:
 
+* **Z tolerance** field if enabled specifies distance of nodes from the XOY plane below which the nodes snap to this plane. A default value can be set in :ref:`Preferences <medexport_z_tolerance_pref>`.
 * **Automatically create groups** check-box specifies whether to create groups of all mesh entities of available dimensions or not. The created groups have names like "Group_On_All_Nodes", "Group_On_All_Faces", etc. A default state of this check-box can be set in :ref:`Preferences <export_auto_groups_pref>`.
 * **Automatically define space dimension** check-box specifies whether to define space dimension for export by mesh configuration or not. Usually the mesh is exported as a mesh in 3D space, just as it is in Mesh module. The mesh can be exported as a mesh of a lower dimension in the following cases, provided that this check-box is checked:
 
index ed1426a0ae727d9b0a38a844c9d64aa8350d1906..248ea4f02a9a7841789d18317151d64467030316 100644 (file)
@@ -84,6 +84,17 @@ The result of calculation will be shown in the bottom area of the dialog.
        * As calculation result is a sum of lengths, areas and volumes of all mesh elements, the duplication is not taken into account; i.e. all duplicated elements (elements built on the same set of nodes) will be included into the result.
        * Similarly, intersection of elements is not taken into account.
 
-**See Also** a sample TUI Script of :ref:`tui_measurements_page`.
+.. _angle_anchor:
+
+Angle
+#####
 
+This operation measures angle defined by three nodes. The second of the specified nodes is a vertex of angle. 
 
+You can specify nodes either by clicking them in the Viewer or by typing their IDs in **Tree nodes** field. If the nodes are correctly specified, upon pressing **Compute** button the angle measure will be displayed and the angle will be shown in the Viewer.
+
+.. image:: ../images/angle_measure.png
+       :align: center
+
+
+**See Also** a sample TUI Script of :ref:`tui_measurements_page`.
index d804e4cd79a17057a089a4e8fe4409e0f51f87aa..734011f1b2076ae2f04fcb79919439564d45a616 100644 (file)
@@ -22,7 +22,9 @@ General Preferences
 
 .. _display_mode_pref:
 
-* **Display mode**
+* **Display**
+
+  * **Fit All upon Show Only** - if activated, *Show Only* command additionally performs *Fit All* command.
 
   * **Default display mode** - allows to set Wireframe, Shading, Nodes or Shrink :ref:`presentation mode <display_mode_page>` as default.
 
@@ -52,6 +54,10 @@ General Preferences
 
   * **Show warning when exporting group** - if activated, a warning is displayed when exporting a group.
 
+.. _medexport_z_tolerance_pref:
+
+  * **Z tolerance for MED export** - defines Z tolerance in :ref:`MED Export <export_auto_groups>` dialog.
+
 .. _show_comp_result_pref:
 
 * **Mesh computation**
index 45494b2a5c09d3d1941bc82ba3a184338cb68fe2..6c673f6dbfb4513273465e79ca5e765cffa01194 100644 (file)
@@ -168,6 +168,7 @@ Creating groups
    Mesh.MakeGroupByCriterion
    Mesh.MakeGroupByCriteria
    Mesh.MakeGroupByFilter
+   Mesh.FaceGroupsSeparatedByEdges
    Mesh.GetGroups
    Mesh.NbGroups
    Mesh.GetGroupNames
@@ -305,6 +306,7 @@ Measurements
    smeshBuilder.GetLength
    smeshBuilder.GetArea
    smeshBuilder.GetVolume
+   smeshBuilder.GetAngle
    Mesh.GetFreeBorders
    Mesh.MinDistance
    Mesh.GetMinDistance
@@ -315,6 +317,7 @@ Measurements
    Mesh.GetLength
    Mesh.GetArea
    Mesh.GetVolume
+   Mesh.GetAngle
 
 ****************
 Modifying meshes
index 8c2fda6e6b0996beb175b0eacbecc99e7d106114..1178488c8daa3f0e47ec7957ca21a8e4a24e0c61 100644 (file)
@@ -618,7 +618,7 @@ SMESH_MeshEditor
 
 .. py:class:: SMESH_MeshEditor.Sew_Error
 
-      Enumeration of errors SMESH_MeshEditor.Sewing... methods
+      Enumeration of errors of SMESH_MeshEditor.Sewing... methods
 
       .. py:attribute::
          SEW_OK
index 45e8dcdbfd2bc0328ccea65a17f7183b8aa510b4..58bc4a3b639e948eca750210df1989691ec06502 100644 (file)
@@ -1,5 +1,3 @@
-.. _tui_grouping_elements_page:
-
 *****************
 Grouping Elements
 *****************
@@ -110,8 +108,11 @@ Creating groups of entities basing on nodes of other groups
 .. image:: ../images/dimgroup_tui1.png
        :align: center
 
+Creating face groups separated by sharp edges
+=============================================
 
+.. literalinclude:: ../../../examples/grouping_elements_ex09.py
+    :language: python
 
-
-
+:download:`Download this script <../../../examples/grouping_elements_ex09.py>`
 
index b3f5964509e71cf5f6b01459561bd69add74bf4a..a4e056531e0ed3aff3b0555d4c1338b00f5931a7 100644 (file)
@@ -33,3 +33,11 @@ Basic Properties
     :language: python
 
 :download:`Download this script <../../../examples/measurements_ex03.py>`
+
+Angle
+=====
+
+.. literalinclude:: ../../../examples/measurements_ex04.py
+    :language: python
+
+:download:`Download this script <../../../examples/measurements_ex04.py>`
index 44cb38860a93256031f6d3d6a06c0c3bc2971a75..7dc0dff9872924e2eaf64ecbdc1c65d28471212d 100644 (file)
@@ -47,8 +47,8 @@ right-clicking on the selected mesh.
 * :ref:`Transparency <transparency_page>` - allows to change the transparency of mesh elements.
 * :ref:`Controls <quality_page>` - graphically presents various information about the mesh. 
 * **Hide** - allows to hide the selected mesh from the viewer.
-* **Show Only** - allows to display only the selected mesh, hiding all others from the viewer.
-* :ref:`Clipping <clipping_page>` - allows to create cross-sections of the displayed objects.
+* **Show Only** - allows to display only the selected mesh, hiding all others from the viewer. If :ref:`Fit All upon Show Only <display_mode_pref>` Preference option is active, *Fit All* command is additionally performed.
+* :doc:`clipping` - allows to create cross-sections of the displayed objects.
 * **Dump view** - exports an object from the viewer in bmp, png or jpeg image format.
 * **Change background** - allows to redefine the background color. By default it is black.
 * **View Operations** - allows to show/hide the  visualization toolbar in the Viewer window.
index d3a9c77f450df1aa7798b093e419df296c01c5b5..bf8dc2152282abf0be6053d42efd8e6426a1f5de 100644 (file)
@@ -74,6 +74,11 @@ module SMESH
      * gravity center of the source
      */
     PointStruct GravityCenter(in SMESH_IDSource source);
+
+    /*!
+     * angle in radians defined by 3 points <(p1,p2,p3)
+     */
+    double Angle(in PointStruct p1, in PointStruct p2, in PointStruct p3 );
   };
 };
 
index 9daba34f49191bef5b4bee04fe8bfe772b3d93b4..c8c7bd786c839c2981fc82a4f108291feff927ec 100644 (file)
@@ -516,6 +516,20 @@ module SMESH
                                 in boolean              underlyingOnly )
       raises (SALOME::SALOME_Exception);
 
+    /*!
+     * Distribute all faces of the mesh among groups using sharp edges and optionally
+     * existing 1D elements as group boundaries.
+     *  \param [in] sharpAngle - edge is considered sharp if an angle between normals of
+     *              adjacent faces is more than \a sharpAngle in degrees.
+     *  \param [in] createEdges - to create 1D elements for detected sharp edges.
+     *  \param [in] useExistingEdges - to use existing edges as group boundaries
+     *  \return ListOfGroups - the created groups
+     */
+    ListOfGroups FaceGroupsSeparatedByEdges( in double  sharpAngle,
+                                             in boolean createEdges,
+                                             in boolean useExistingEdges )
+      raises (SALOME::SALOME_Exception);
+
     /*!
      * Convert group on geometry or on filter into standalone group
      */
@@ -665,6 +679,9 @@ module SMESH
      *         - 'e' stands for _edges_ field;
      *         - 'f' stands for _faces_ field;
      *         - 's' stands for _solids_ field.
+     * - ZTolerance : tolerance in Z direction. If Z coordinate of a node is close to zero
+     *                within a given tolerance, the coordinate is set to zero.
+     *                If @a ZTolerance is negative, the node coordinates are kept as is.
      */
     void ExportPartToMED( in SMESH_IDSource     meshPart,
                           in string             fileName,
@@ -673,7 +690,8 @@ module SMESH
                           in boolean            overwrite,
                           in boolean            autoDimension,
                           in GEOM::ListOfFields fields,
-                          in string             geomAssocFields ) raises (SALOME::SALOME_Exception);
+                          in string             geomAssocFields,
+                          in double             ZTolerance) raises (SALOME::SALOME_Exception);
 
     /*!
      * Export Mesh to SAUV formatted file
index 86493fe3464c924ee3110cf4b4eef289efaa867b..85ba8b73ea59558b9a18ba746b96dfe5998b4945 100644 (file)
@@ -60,23 +60,39 @@ module SMESH
   // structure used in MakePolyLine() to define a cutting plane
   struct PolySegment
   {
-    // point 1: if node1ID2 > 0, then the point is in the middle of a face edge defined
-    //          by two nodes, else it is at node1ID1
+    // a point is defined as follows:
+    // ( node*ID1 > 0 && node*ID2 > 0 ) ==> point is in the middle of an edge defined by two nodes
+    // ( node*ID1 > 0 && node*ID2 <=0 ) ==> point is at node*ID1
+    // else                             ==> point is at xyz*
+
+    // point 1
     long node1ID1;
     long node1ID2;
+    PointStruct xyz1;
 
-    // point 2: if node2ID2 > 0, then the point is in the middle of a face edge defined
-    //          by two nodes, else it is at node2ID1
+    // point 2
     long node2ID1;
     long node2ID2;
+    PointStruct xyz2;
 
-    DirStruct vector; // vector on the plane; to use a default plane set vector = (0,0,0)
+    // vector on the plane; to use a default plane set vector = (0,0,0)
+    DirStruct vector;
   };
   typedef sequence<PolySegment> ListOfPolySegments;
 
+  // face edge defined by two nodes + optional medium node
+  struct FaceEdge
+  {
+    long node1;
+    long node2;
+    long medium;
+  };
+  typedef sequence<FaceEdge> ListOfEdges;
+
 
   /*!
    * This interface makes modifications on the Mesh - removing elements and nodes etc.
+   * Also provides some analysis functions.
    */
   interface SMESH_MeshEditor
   {
@@ -773,6 +789,20 @@ module SMESH
                                         in ElementType type) 
       raises (SALOME::SALOME_Exception);
 
+    /*!
+     * Project a point to a mesh object.
+     * Return ID of an element of given type where the given point is projected
+     * and coordinates of the projection point.
+     * In the case if nothing found, return -1 and []
+     */
+    long ProjectPoint(in double         x,
+                      in double         y,
+                      in double         z,
+                      in SMESH_IDSource meshObject,
+                      in ElementType    type,
+                      out double_array  projecton)
+      raises (SALOME::SALOME_Exception);
+
     /*!
      * Return point state in a closed 2D mesh in terms of TopAbs_State enumeration.
      * TopAbs_UNKNOWN state means that either mesh is wrong or the analysis fails.
@@ -792,6 +822,13 @@ module SMESH
     boolean IsCoherentOrientation2D()
       raises (SALOME::SALOME_Exception);
 
+    /*!
+     * Return sharp edges of faces and non-manifold ones. 
+     * Optionally add existing edges. Angle is in degrees.
+     */
+    ListOfEdges FindSharpEdges(in double angle, in boolean addExistingEdges)
+      raises (SALOME::SALOME_Exception);
+
     /*!
      * Returns all or only closed FreeBorder's.
      */
@@ -1241,8 +1278,8 @@ module SMESH
 
     /*!
      * \brief Create a polyline consisting of 1D mesh elements each lying on a 2D element of
-     *        the initial mesh. Positions of new nodes are found by cutting the mesh by the
-     *        plane passing through pairs of points specified by each PolySegment structure.
+     *        the initial triangle mesh. Positions of new nodes are found by cutting the mesh by
+     *        the plane passing through pairs of points specified by each PolySegment structure.
      *        If there are several paths connecting a pair of points, the shortest path is
      *        selected by the module. Position of the cutting plane is defined by the two
      *        points and an optional vector lying on the plane specified by a PolySegment.
index 3bd0b5e78d6c01ec5e02ecc511b1e75d7f9cc657..5108b904732fd022e276602f0ca8213081b9d1b7 100755 (executable)
@@ -77,6 +77,7 @@ SET(SMESH_RESOURCES_FILES
   mesh_octahedron.png
   mesh_orientation.png
   mesh.png
+  mesh_plugins_meshcut.png
   mesh_polygon.png
   mesh_polyhedron.png
   mesh_pyramid_n.png
@@ -231,6 +232,8 @@ SET(SMESH_RESOURCES_FILES
   mesh_hide.png
   mesh_deflection.png
   mesh_offset.png
+  mesh_face_groups_by_edges.png
+  mesh_angle_measure.png
 )
 
 INSTALL(FILES ${SMESH_RESOURCES_FILES} DESTINATION ${SALOME_SMESH_INSTALL_RES_DATA})
index e1434ad4e19da297bd475f46775703e982842cc0..efbe065a336a66ba93d50a36f6ea1e180777aea8 100644 (file)
@@ -84,6 +84,7 @@
     <parameter name="update_limit"                 value="500000" />
     <parameter name="display_entity"               value="true" />
     <parameter name="display_mode"                 value="1"    />
+    <parameter name="fitall_on_displayonly"        value="1"    />
     <parameter name="auto_groups"                  value="false"/>
     <parameter name="show_warning"                 value="true"/>
     <parameter name="show_result_notification"     value="2"/>
diff --git a/resources/mesh_angle_measure.png b/resources/mesh_angle_measure.png
new file mode 100644 (file)
index 0000000..d77b745
Binary files /dev/null and b/resources/mesh_angle_measure.png differ
diff --git a/resources/mesh_face_groups_by_edges.png b/resources/mesh_face_groups_by_edges.png
new file mode 100644 (file)
index 0000000..32175a7
Binary files /dev/null and b/resources/mesh_face_groups_by_edges.png differ
diff --git a/resources/mesh_plugins_meshcut.png b/resources/mesh_plugins_meshcut.png
new file mode 100644 (file)
index 0000000..59145bf
Binary files /dev/null and b/resources/mesh_plugins_meshcut.png differ
index 63c69c992ee921e3a18351a076439b76abd0d968..bfa6eea7ea2a0f148fa33ca899749f5e37c0f099 100644 (file)
@@ -62,7 +62,8 @@ DriverMED_W_SMESHDS_Mesh::DriverMED_W_SMESHDS_Mesh():
   myAutoDimension(false),
   myAddODOnVertices(false),
   myDoAllInGroups(false),
-  myVersion(-1)
+  myVersion(-1),
+  myZTolerance(-1.)
 {}
 
 void DriverMED_W_SMESHDS_Mesh::SetFile(const std::string& theFileName, int theVersion)
@@ -417,6 +418,8 @@ Driver_Mesh::Status DriverMED_W_SMESHDS_Mesh::Perform()
         anIsXDimension = (aBounds[1] - aBounds[0]) + abs(aBounds[1]) + abs(aBounds[0]) > EPS;
         anIsYDimension = (aBounds[3] - aBounds[2]) + abs(aBounds[3]) + abs(aBounds[2]) > EPS;
         anIsZDimension = (aBounds[5] - aBounds[4]) + abs(aBounds[5]) + abs(aBounds[4]) > EPS;
+        if ( myZTolerance > 0 && anIsZDimension )
+          anIsZDimension = (aBounds[5] > myZTolerance || aBounds[4] < -myZTolerance );
         aSpaceDimension = Max( aMeshDimension, anIsXDimension + anIsYDimension + anIsZDimension );
         if ( !aSpaceDimension )
           aSpaceDimension = 3;
@@ -550,6 +553,10 @@ Driver_Mesh::Status DriverMED_W_SMESHDS_Mesh::Perform()
       for(TInt iCoord = 0; iCoord < aSpaceDimension; iCoord++){
         aTCoordSlice[iCoord] = aCoordHelperPtr->GetCoord(iCoord);
       }
+      if ( aSpaceDimension == 3 &&
+           -myZTolerance < aTCoordSlice[2] && aTCoordSlice[2] < myZTolerance )
+        aTCoordSlice[2] = 0.;
+
       // node number
       int aNodeID = aCoordHelperPtr->GetID();
       aNodeInfo->SetElemNum( iNode, aNodeID );
index 2b04c05f9fa3326aea7bbf91a6a9b355d5eaf7e4..9966094959e5829602e390e7f7da353c286b98a1 100644 (file)
@@ -50,6 +50,7 @@ class MESHDRIVERMED_EXPORT DriverMED_W_SMESHDS_Mesh: public Driver_SMESHDS_Mesh
 
   void SetFile(const std::string& theFileName, int theVersion=-1);
   void SetAutoDimension(bool toFindOutDimension) { myAutoDimension = toFindOutDimension; }
+  void SetZTolerance(double tol) { myZTolerance = tol; }
 
   static std::string GetVersionString(int theMinor, int theNbDigits=2);
 
@@ -89,7 +90,8 @@ class MESHDRIVERMED_EXPORT DriverMED_W_SMESHDS_Mesh: public Driver_SMESHDS_Mesh
   bool myAutoDimension;
   bool myAddODOnVertices;
   bool myDoAllInGroups;
-  int myVersion;
+  int  myVersion;
+  double myZTolerance;
 };
 
 #endif
index a117394b97b6184a957ae21c9622fc836441c2ef..1e048ffd8eae1d7c9dff026cc037672cb957689e 100644 (file)
@@ -1542,8 +1542,9 @@ SMDS_NodeIteratorPtr SMDS_Mesh::nodesIterator() const
 
 SMDS_ElemIteratorPtr SMDS_Mesh::elementGeomIterator(SMDSAbs_GeometryType type) const
 {
+  int nbElems = myCellFactory->CompactChangePointers() ? -1 : myInfo.NbElements( type );
   return myCellFactory->GetIterator< SMDS_ElemIterator >( new SMDS_MeshElement::GeomFilter( type ),
-                                                          myInfo.NbElements( type ));
+                                                          nbElems);
 }
 
 SMDS_ElemIteratorPtr SMDS_Mesh::elementEntityIterator(SMDSAbs_EntityType type) const
@@ -1552,8 +1553,9 @@ SMDS_ElemIteratorPtr SMDS_Mesh::elementEntityIterator(SMDSAbs_EntityType type) c
   {
     return myNodeFactory->GetIterator< SMDS_ElemIterator >( new SMDS_MeshElement::NonNullFilter );
   }
+  int nbElems = myCellFactory->CompactChangePointers() ? -1 : myInfo.NbElements( type );
   return myCellFactory->GetIterator<SMDS_ElemIterator>( new SMDS_MeshElement::EntityFilter( type ),
-                                                        myInfo.NbElements( type ));
+                                                        nbElems);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1571,8 +1573,9 @@ SMDS_ElemIteratorPtr SMDS_Mesh::elementsIterator(SMDSAbs_ElementType type) const
     return myNodeFactory->GetIterator< TIterator >( new SMDS_MeshElement::NonNullFilter );
 
   default:
+    int nbElems = myCellFactory->CompactChangePointers() ? -1 : myInfo.NbElements( type );
     return myCellFactory->GetIterator< TIterator >( new SMDS_MeshElement::TypeFilter( type ),
-                                                    myInfo.NbElements( type ));
+                                                    nbElems);
   }
   return SMDS_ElemIteratorPtr();
 }
@@ -1584,8 +1587,9 @@ SMDS_ElemIteratorPtr SMDS_Mesh::elementsIterator(SMDSAbs_ElementType type) const
 SMDS_EdgeIteratorPtr SMDS_Mesh::edgesIterator() const
 {
   typedef SMDS_EdgeIterator TIterator;
+  int nbElems = myCellFactory->CompactChangePointers() ? -1 : myInfo.NbEdges();
   return myCellFactory->GetIterator< TIterator >( new SMDS_MeshElement::TypeFilter( SMDSAbs_Edge ),
-                                                  myInfo.NbEdges());
+                                                  nbElems);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1595,8 +1599,9 @@ SMDS_EdgeIteratorPtr SMDS_Mesh::edgesIterator() const
 SMDS_FaceIteratorPtr SMDS_Mesh::facesIterator() const
 {
   typedef SMDS_FaceIterator TIterator;
+  int nbElems = myCellFactory->CompactChangePointers() ? -1 : myInfo.NbFaces();
   return myCellFactory->GetIterator< TIterator >( new SMDS_MeshElement::TypeFilter( SMDSAbs_Face ),
-                                                  myInfo.NbFaces());
+                                                  nbElems);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1606,9 +1611,10 @@ SMDS_FaceIteratorPtr SMDS_Mesh::facesIterator() const
 SMDS_VolumeIteratorPtr SMDS_Mesh::volumesIterator() const
 {
   typedef SMDS_VolumeIterator TIterator;
+  int nbElems = myCellFactory->CompactChangePointers() ? -1 : myInfo.NbVolumes();
   return
     myCellFactory->GetIterator< TIterator >( new SMDS_MeshElement::TypeFilter( SMDSAbs_Volume ),
-                                             myInfo.NbVolumes());
+                                             nbElems );
 }
 
 SMDS_NodeIteratorPtr SMDS_Mesh::shapeNodesIterator(int                  shapeID,
index d27c878763da7ae88397e73fc80a31731cfe16b5..c03eaa65029870ad03ce6f9d8e22856bb7161cb0 100644 (file)
@@ -1407,25 +1407,29 @@ bool SMESH_Mesh::HasDuplicatedGroupNamesMED()
  *              The major version (x, where version is x.y.z) cannot be changed.
  *  \param [in] meshPart - mesh data to export
  *  \param [in] theAutoDimension - if \c true, a space dimension of a MED mesh can be either
    *         - 1D if all mesh nodes lie on OX coordinate axis, or
    *         - 2D if all mesh nodes lie on XOY coordinate plane, or
    *         - 3D in the rest cases.
    *         If \a theAutoDimension is \c false, the space dimension is always 3.
*              - 1D if all mesh nodes lie on OX coordinate axis, or
*              - 2D if all mesh nodes lie on XOY coordinate plane, or
*              - 3D in the rest cases.
*              If \a theAutoDimension is \c false, the space dimension is always 3.
  *  \param [in] theAddODOnVertices - to create 0D elements on all vertices
  *  \param [in] theAllElemsToGroup - to make every element to belong to any group (PAL23413)
+ *  \param [in] ZTolerance - tolerance in Z direction. If Z coordinate of a node is close to zero
+ *              within a given tolerance, the coordinate is set to zero.
+ *              If \a ZTolerance is negative, the node coordinates are kept as is.
  *  \return int - mesh index in the file
  */
 //================================================================================
 
-void SMESH_Mesh::ExportMED(const char *        file, 
-                           const char*         theMeshName, 
+void SMESH_Mesh::ExportMED(const char *        file,
+                           const char*         theMeshName,
                            bool                theAutoGroups,
                            int                 theVersion,
                            const SMESHDS_Mesh* meshPart,
                            bool                theAutoDimension,
                            bool                theAddODOnVertices,
+                           double              theZTolerance,
                            bool                theAllElemsToGroup)
-  throw(SALOME_Exception)
+throw(SALOME_Exception)
 {
   MESSAGE("MED_VERSION:"<< theVersion);
   SMESH_TRY;
@@ -1435,7 +1439,8 @@ void SMESH_Mesh::ExportMED(const char *        file,
   myWriter.SetMesh         ( meshPart ? (SMESHDS_Mesh*) meshPart : _myMeshDS   );
   myWriter.SetAutoDimension( theAutoDimension );
   myWriter.AddODOnVertices ( theAddODOnVertices );
-  if ( !theMeshName ) 
+  myWriter.SetZTolerance   ( theZTolerance );
+  if ( !theMeshName )
     myWriter.SetMeshId     ( _id         );
   else {
     myWriter.SetMeshId     ( -1          );
@@ -1511,7 +1516,7 @@ void SMESH_Mesh::ExportSAUV(const char *file,
   system(cmd.c_str());
   ExportMED(medfilename.c_str(), theMeshName, theAutoGroups, /*minor=*/-1,
             /*meshPart=*/NULL, /*theAutoDimension=*/false, /*theAddODOnVertices=*/false,
-            /*theAllElemsToGroup=*/true ); // theAllElemsToGroup is for PAL0023413
+            /*zTol=*/-1, /*theAllElemsToGroup=*/true ); // theAllElemsToGroup is for PAL0023413
 #ifdef WIN32
   cmd = "%PYTHONBIN% ";
 #else
index 59ad490b1e0d7fee4a541bfa925ca38f0f48e9f5..54889dedc8878c4906f7fd1dcd6514c593fd0374 100644 (file)
@@ -251,13 +251,14 @@ class SMESH_EXPORT SMESH_Mesh
    */
   bool HasDuplicatedGroupNamesMED();
 
-  void ExportMED(const char *        theFile, 
-                 const char*         theMeshName = NULL, 
-                 bool                theAutoGroups = true, 
+  void ExportMED(const char *        theFile,
+                 const char*         theMeshName = NULL,
+                 bool                theAutoGroups = true,
                  int                 theVersion = -1,
                  const SMESHDS_Mesh* theMeshPart = 0,
                  bool                theAutoDimension = false,
                  bool                theAddODOnVertices = false,
+                 double              theZTolerance = -1.,
                  bool                theAllElemsToGroup = false)
     throw(SALOME_Exception);
 
index ceaeb1acb681d86934f3c211e4b07704a6a7622b..49537015136f4b8b56363d7e984f07c664f3f91a 100644 (file)
@@ -6789,7 +6789,9 @@ SMESH_MeshEditor::PGroupIDs SMESH_MeshEditor::Offset( TIDSortedElemSet & theElem
   for ( size_t i = 0; i < new2OldNodes.size(); ++i )
     if ( const SMDS_MeshNode* n = new2OldNodes[ i ].first )
     {
+#ifndef _DEBUG_
       if ( n->NbInverseElements() > 0 )
+#endif
       {
         const SMDS_MeshNode* n2 =
           tgtMeshDS->AddNodeWithID( n->X(), n->Y(), n->Z(), idShift + n->GetID() );
@@ -11227,8 +11229,8 @@ bool SMESH_MeshEditor::AffectedElemGroupsInRegion( const TIDSortedElemSet& theEl
   else
   {
     const double aTol = Precision::Confusion();
-    auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
-    auto_ptr<_FaceClassifier>              aFaceClassifier;
+    std::unique_ptr< BRepClass3d_SolidClassifier> bsc3d;
+    std::unique_ptr<_FaceClassifier>              aFaceClassifier;
     if ( theShape.ShapeType() == TopAbs_SOLID )
     {
       bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
@@ -13050,14 +13052,15 @@ namespace // utils for MakePolyLine
     std::vector< gp_XYZ >   myPoints;
     double                  myLength;
 
-    int                     mySrcPntInd; //!< start point index
     const SMDS_MeshElement* myFace;
-    SMESH_NodeXYZ           myNode1;
+    SMESH_NodeXYZ           myNode1; // nodes of the edge the path entered myFace
     SMESH_NodeXYZ           myNode2;
     int                     myNodeInd1;
     int                     myNodeInd2;
     double                  myDot1;
     double                  myDot2;
+
+    int                     mySrcPntInd; //!< start point index
     TIDSortedElemSet        myElemSet, myAvoidSet;
 
     Path(): myLength(0.0), myFace(0) {}
@@ -13250,6 +13253,7 @@ namespace // utils for MakePolyLine
       myErrors( theSegments.size() )
     {
     }
+
 #undef SMESH_CAUGHT
 #define SMESH_CAUGHT myErrors[i] =
     void operator() ( const int i ) const
@@ -13259,6 +13263,7 @@ namespace // utils for MakePolyLine
       SMESH_CATCH( SMESH::returnError );
     }
 #undef SMESH_CAUGHT
+
     //================================================================================
     /*!
      * \brief Compute a path of a given segment
@@ -13269,21 +13274,15 @@ namespace // utils for MakePolyLine
     {
       SMESH_MeshEditor::PolySegment& polySeg = mySegments[ iSeg ];
 
-      // get a cutting plane
-
-      gp_XYZ p1 = SMESH_NodeXYZ( polySeg.myNode1[0] );
-      gp_XYZ p2 = SMESH_NodeXYZ( polySeg.myNode1[1] );
-      if ( polySeg.myNode2[0] ) p1 = 0.5 * ( p1 + SMESH_NodeXYZ( polySeg.myNode2[0] ));
-      if ( polySeg.myNode2[1] ) p2 = 0.5 * ( p2 + SMESH_NodeXYZ( polySeg.myNode2[1] ));
-
-      gp_XYZ plnNorm = ( p1 - p2 ) ^ polySeg.myVector.XYZ();
-      gp_XYZ plnOrig = p2;
+      // the cutting plane
+      gp_XYZ plnNorm = ( polySeg.myXYZ[0] - polySeg.myXYZ[1] ) ^ polySeg.myVector.XYZ();
+      gp_XYZ plnOrig = polySeg.myXYZ[1];
 
-      // find paths connecting the 2 end points of polySeg
+      // Find paths connecting the 2 end points of polySeg
 
       std::vector< Path > paths; paths.reserve(10);
 
-      // initialize paths
+      // 1) initialize paths; two paths starts at each end point
 
       for ( int iP = 0; iP < 2; ++iP ) // loop on the polySeg end points
       {
@@ -13291,8 +13290,76 @@ namespace // utils for MakePolyLine
         path.mySrcPntInd = iP;
         size_t nbPaths = paths.size();
 
+        if ( polySeg.myFace[ iP ]) // the end point lies on polySeg.myFace[ iP ]
+        {
+          // check coincidence of polySeg.myXYZ[ iP ] with nodes
+          const double tol = 1e-20;
+          SMESH_NodeXYZ nodes[4];
+          for ( int i = 0; i < 3 &&  !polySeg.myNode1[ iP ]; ++i )
+          {
+            nodes[ i ] = polySeg.myFace[ iP ]->GetNode( i );
+            if (( nodes[ i ] - polySeg.myXYZ[ iP ]).SquareModulus() < tol*tol )
+              polySeg.myNode1[ iP ] = nodes[ i ].Node();
+          }
+          nodes[ 3 ] = nodes[ 0 ];
+
+          // check coincidence of polySeg.myXYZ[ iP ] with edges
+          for ( int i = 0; i < 3 &&  !polySeg.myNode1[ iP ]; ++i )
+          {
+            SMDS_LinearEdge edge( nodes[i].Node(), nodes[i+1].Node() );
+            if ( SMESH_MeshAlgos::GetDistance( &edge, polySeg.myXYZ[ iP ]) < tol )
+            {
+              polySeg.myNode1[ iP ] = nodes[ i     ].Node();
+              polySeg.myNode2[ iP ] = nodes[ i + 1 ].Node();
+            }
+          }
+
+          if ( !polySeg.myNode1[ iP ] ) // polySeg.myXYZ[ iP ] is within polySeg.myFace[ iP ]
+          {
+            double dot[ 4 ];
+            for ( int i = 0; i < 3; ++i )
+              dot[ i ] = plnNorm * ( nodes[ i ] - plnOrig );
+            dot[ 3 ] = dot[ 0 ];
+
+            int iCut = 0; // index of a cut edge
+            if      ( dot[ 1 ] * dot[ 2 ] < 0. ) iCut = 1;
+            else if ( dot[ 2 ] * dot[ 3 ] < 0. ) iCut = 2;
+
+            // initialize path so as if it entered the face via iCut-th edge
+            path.myFace = polySeg.myFace[ iP ];
+            path.myNodeInd1 = iCut;
+            path.myNodeInd2 = iCut + 1;
+            path.myNode1.Set( nodes[ iCut     ].Node() );
+            path.myNode2.Set( nodes[ iCut + 1 ].Node() );
+            path.myDot1 = dot[ iCut ];
+            path.myDot2 = dot[ iCut + 1 ];
+            path.myPoints.clear();
+            path.AddPoint( polySeg.myXYZ[ iP ]);
+            paths.push_back( path );
+
+            path.Extend( plnNorm, plnOrig ); // to get another edge cut
+            path.myFace = polySeg.myFace[ iP ];
+            if ( path.myDot1 == 0. ) // cut at a node
+            {
+              path.myNodeInd1 = ( iCut + 2 ) % 3;
+              path.myNodeInd2 = ( iCut + 3 ) % 3;
+              path.myNode2.Set( path.myFace->GetNode( path.myNodeInd2 ));
+              path.myDot2 = dot[ path.myNodeInd2 ];
+            }
+            else
+            {
+              path.myNodeInd1 = path.myFace->GetNodeIndex( path.myNode1.Node() );
+              path.myNodeInd2 = path.myFace->GetNodeIndex( path.myNode2.Node() );
+            }
+            path.myPoints.clear();
+            path.AddPoint( polySeg.myXYZ[ iP ]);
+            paths.push_back( path );
+          }
+        }
+
         if ( polySeg.myNode2[ iP ] && polySeg.myNode2[ iP ] != polySeg.myNode1[ iP ] )
         {
+          // the end point is on an edge
           while (( path.myFace = SMESH_MeshAlgos::FindFaceInSet( polySeg.myNode1[ iP ],
                                                                  polySeg.myNode2[ iP ],
                                                                  path.myElemSet,
@@ -13305,7 +13372,7 @@ namespace // utils for MakePolyLine
             path.myDot1 = plnNorm * ( path.myNode1 - plnOrig );
             path.myDot2 = plnNorm * ( path.myNode2 - plnOrig );
             path.myPoints.clear();
-            path.AddPoint( 0.5 * ( path.myNode1 + path.myNode2 ));
+            path.AddPoint( polySeg.myXYZ[ iP ]);
             path.myAvoidSet.insert( path.myFace );
             paths.push_back( path );
           }
@@ -13313,7 +13380,7 @@ namespace // utils for MakePolyLine
             throw SALOME_Exception ( SMESH_Comment("No face edge found by point ") << iP+1
                                      << " in a PolySegment " << iSeg );
         }
-        else // an end point is at node
+        else if ( polySeg.myNode1[ iP ] ) // the end point is at a node
         {
           std::set<const SMDS_MeshNode* > nodes;
           SMDS_ElemIteratorPtr fIt = polySeg.myNode1[ iP ]->GetInverseElementIterator(SMDSAbs_Face);
@@ -13340,7 +13407,7 @@ namespace // utils for MakePolyLine
             }
       }
 
-      // extend paths
+      // 2) extend paths and compose the shortest one connecting the two points
 
       myPaths[ iSeg ].myLength = 1e100;
 
@@ -13349,7 +13416,7 @@ namespace // utils for MakePolyLine
         for ( size_t i = 0; i < paths.size(); ++i )
         {
           Path& path = paths[ i ];
-          if ( !path.Extend( plnNorm, plnOrig ) ||         // path reached a mesh boundary
+          if ( !path.Extend( plnNorm, plnOrig ) ||        // path reached a mesh boundary
                path.myLength > myPaths[ iSeg ].myLength ) // path is longer than others
           {
             Path::Remove( paths, i );
@@ -13384,6 +13451,12 @@ namespace // utils for MakePolyLine
       if ( myPaths[ iSeg ].myPoints.empty() )
         throw SALOME_Exception( SMESH_Comment("Can't find a full path for PolySegment #") << iSeg );
 
+      // reverse the path
+      double d00 = ( polySeg.myXYZ[0] - myPaths[ iSeg ].myPoints.front() ).SquareModulus();
+      double d01 = ( polySeg.myXYZ[0] - myPaths[ iSeg ].myPoints.back()  ).SquareModulus();
+      if ( d00 > d01 )
+        std::reverse( myPaths[ iSeg ].myPoints.begin(), myPaths[ iSeg ].myPoints.end() );
+
     } // PolyPathCompute::Compute()
 
   }; // struct PolyPathCompute
@@ -13424,6 +13497,18 @@ void SMESH_MeshEditor::MakePolyLine( TListOfPolySegments&   theSegments,
     if ( polySeg.myNode2[0] ) p1 = 0.5 * ( p1 + SMESH_NodeXYZ( polySeg.myNode2[0] ));
     if ( polySeg.myNode2[1] ) p2 = 0.5 * ( p2 + SMESH_NodeXYZ( polySeg.myNode2[1] ));
 
+    polySeg.myFace[0] = polySeg.myFace[1] = 0;
+    if ( !polySeg.myNode1[0] && !polySeg.myNode2[0] )
+    {
+      p1 = searcher->Project( polySeg.myXYZ[0], SMDSAbs_Face, &polySeg.myFace[0] );
+    }
+    if ( !polySeg.myNode1[1] && !polySeg.myNode2[1] )
+    {
+      p2 = searcher->Project( polySeg.myXYZ[1], SMDSAbs_Face, &polySeg.myFace[1] );
+    }
+    polySeg.myXYZ[0] = p1;
+    polySeg.myXYZ[1] = p2;
+
     gp_XYZ plnNorm = ( p1 - p2 ) ^ polySeg.myVector.XYZ();
 
     isVectorOK[ iSeg ] = ( plnNorm.Modulus() > std::numeric_limits<double>::min() );
index b6c404a156c3d5942ff50d0fbca6854a5df67284..e5e558bee84e2694b1ce18653d3b9c3a63c52c29 100644 (file)
@@ -275,7 +275,7 @@ public:
   typedef TNodeOfNodeListMap::iterator                                     TNodeOfNodeListMapItr;
   typedef std::vector<TNodeOfNodeListMapItr>                               TVecOfNnlmiMap;
   typedef std::map<const SMDS_MeshElement*, TVecOfNnlmiMap, TElemSort >    TElemOfVecOfNnlmiMap;
-  typedef std::auto_ptr< std::list<int> > PGroupIDs;
+  typedef std::unique_ptr< std::list< int > >                              PGroupIDs;
 
   PGroupIDs RotationSweep (TIDSortedElemSet   theElements[2],
                            const gp_Ax1&      theAxis,
@@ -721,12 +721,19 @@ public:
   // structure used in MakePolyLine() to define a cutting plane
   struct PolySegment
   {
-    // 2 points: if myNode2 != 0, then the point is the middle of a face edge defined
-    //           by two nodes, else it is at myNode1
-    const SMDS_MeshNode* myNode1[2];
-    const SMDS_MeshNode* myNode2[2];
-
-    gp_Vec myVector; // vector on the plane; to use a default plane set vector = (0,0,0)
+    // 2 points, each defined as follows:
+    // ( myNode1 &&  myNode2 ) ==> point is in the middle of an edge defined by two nodes
+    // ( myNode1 && !myNode2 ) ==> point is at myNode1
+    // else                    ==> point is at myXYZ
+    const SMDS_MeshNode*    myNode1[2];
+    const SMDS_MeshNode*    myNode2[2];
+    gp_XYZ                  myXYZ  [2];
+
+    // face on which myXYZ projects (found by MakePolyLine())
+    const SMDS_MeshElement* myFace [2];
+
+    // vector on the plane; to use a default plane set vector = (0,0,0)
+    gp_Vec myVector;
 
     // point to return coordinates of a middle of the two points, projected to mesh
     gp_Pnt myMidProjPoint;
index 65a39a7bc2ff79257d8a7f5214fc4e3d7f7e1021..ba68de56754cf59b1f90a3f602c3b4a156ab9445 100644 (file)
@@ -66,13 +66,17 @@ class MyIterator: public SMDS_ElemIterator
   MyIterator(SMDSAbs_ElementType type, const SMESHDS_SubMesh* subMesh)
     : myType(type), myElem(0)
   {
-    if ( subMesh ) {
-      if ( myType == SMDSAbs_Node )
+    if ( subMesh )
+    {
+      if ( myType == SMDSAbs_Node ||
+           myType == SMDSAbs_0DElement ||
+           myType == SMDSAbs_Ball )
         myNodeIt = subMesh->GetNodes();
-      else {
+      else
         myElemIt = subMesh->GetElements();
+
+      if ( myType != SMDSAbs_Node )
         next();
-      }
     }
   }
   bool more()
@@ -85,15 +89,30 @@ class MyIterator: public SMDS_ElemIterator
   {
     if ( myType == SMDSAbs_Node && myNodeIt )
       return myNodeIt->next();
+
     const SMDS_MeshElement* res = myElem;
     myElem = 0;
-    while ( myElemIt && myElemIt->more() ) {
-      myElem = myElemIt->next();
-      if ( myElem && myElem->GetType() == myType )
-        break;
-      else
-        myElem = 0;
-    }
+
+    if ( myElemIt )
+      while ( myElemIt->more() ) {
+        myElem = myElemIt->next();
+        if ( myElem && myElem->GetType() == myType )
+          break;
+        else
+          myElem = 0;
+      }
+
+    if ( !myElem && myNodeIt ) // look for a 0D element
+      while ( myNodeIt->more() ) {
+        const SMDS_MeshNode* n = myNodeIt->next();
+        if (( myElemIt = n->GetInverseElementIterator( myType )) &&
+            ( myElemIt->more() ))
+        {
+          myElem = myElemIt->next();
+          break;
+        }
+      }
+
     return res;
   }
 };
@@ -125,6 +144,10 @@ bool SMESHDS_GroupOnGeom::Contains (const int theID)
 
 bool SMESHDS_GroupOnGeom::Contains (const SMDS_MeshElement* elem)
 {
+  if ( GetType() == SMDSAbs_0DElement ||
+       GetType() == SMDSAbs_Ball )
+    return elem ? mySubMesh->Contains( elem->GetNode(0) ) : false;
+
   return mySubMesh->Contains( elem );
 }
 
index 258033585a049cc6c69990c3755613dd0da04486..497d419541e42214c9c49a31efc6ee012f8e268f 100644 (file)
@@ -103,6 +103,7 @@ SET(_moc_HEADERS
   SMESHGUI_MultiEditDlg.h
   SMESHGUI_DeleteGroupDlg.h
   SMESHGUI_GroupOpDlg.h
+  SMESHGUI_FaceGroupsSeparatedByEdgesDlg.h
   SMESHGUI_SmoothingDlg.h
   SMESHGUI_RenumberingDlg.h
   SMESHGUI_ExtrusionDlg.h
@@ -198,6 +199,7 @@ SET(_other_SOURCES
   SMESHGUI_MultiEditDlg.cxx
   SMESHGUI_DeleteGroupDlg.cxx
   SMESHGUI_GroupOpDlg.cxx
+  SMESHGUI_FaceGroupsSeparatedByEdgesDlg.cxx
   SMESHGUI_SmoothingDlg.cxx
   SMESHGUI_RenumberingDlg.cxx
   SMESHGUI_ExtrusionDlg.cxx
index 48a96827389ec237ae9acd585a2e972eee55f310..a5dc528c275cefb88e646ee7dc0ddaec6ae1975b 100644 (file)
 #include "SMESHGUI_CopyMeshDlg.h"
 #include "SMESHGUI_CreatePolyhedralVolumeDlg.h"
 #include "SMESHGUI_DeleteGroupDlg.h"
+#include "SMESHGUI_DisplayEntitiesDlg.h"
 #include "SMESHGUI_Displayer.h"
 #include "SMESHGUI_DuplicateNodesDlg.h"
 #include "SMESHGUI_ExtrusionAlongPathDlg.h"
 #include "SMESHGUI_ExtrusionDlg.h"
+#include "SMESHGUI_FaceGroupsSeparatedByEdgesDlg.h"
 #include "SMESHGUI_FieldSelectorWdg.h"
 #include "SMESHGUI_FileInfoDlg.h"
 #include "SMESHGUI_FileValidator.h"
 #include "SMESHGUI_FilterDlg.h"
 #include "SMESHGUI_FilterLibraryDlg.h"
+#include "SMESHGUI_FilterUtils.h"
 #include "SMESHGUI_FindElemByPointDlg.h"
+#include "SMESHGUI_GEOMGenUtils.h"
 #include "SMESHGUI_GroupDlg.h"
 #include "SMESHGUI_GroupOnShapeDlg.h"
 #include "SMESHGUI_GroupOpDlg.h"
+#include "SMESHGUI_GroupUtils.h"
 #include "SMESHGUI_Hypotheses.h"
+#include "SMESHGUI_HypothesesUtils.h"
 #include "SMESHGUI_Make2DFrom3DOp.h"
 #include "SMESHGUI_MakeNodeAtPointDlg.h"
 #include "SMESHGUI_Measurements.h"
 #include "SMESHGUI_MeshOp.h"
 #include "SMESHGUI_MeshOrderOp.h"
 #include "SMESHGUI_MeshPatternDlg.h"
+#include "SMESHGUI_MeshUtils.h"
 #include "SMESHGUI_MultiEditDlg.h"
 #include "SMESHGUI_NodesDlg.h"
+#include "SMESHGUI_OffsetDlg.h"
 #include "SMESHGUI_Operations.h"
+#include "SMESHGUI_PatternUtils.h"
 #include "SMESHGUI_Preferences_ScalarBarDlg.h"
 #include "SMESHGUI_PropertiesDlg.h"
 #include "SMESHGUI_RemoveElementsDlg.h"
 #include "SMESHGUI_RevolutionDlg.h"
 #include "SMESHGUI_RotationDlg.h"
 #include "SMESHGUI_ScaleDlg.h"
-#include "SMESHGUI_OffsetDlg.h"
 #include "SMESHGUI_Selection.h"
 #include "SMESHGUI_SewingDlg.h"
 #include "SMESHGUI_SingleEditDlg.h"
 #include "SMESHGUI_SmoothingDlg.h"
+#include "SMESHGUI_SpinBox.h"
+#include "SMESHGUI_SplitBiQuad.h"
 #include "SMESHGUI_SymmetryDlg.h"
 #include "SMESHGUI_TranslationDlg.h"
 #include "SMESHGUI_TransparencyDlg.h"
-#include "SMESHGUI_DisplayEntitiesDlg.h"
-#include "SMESHGUI_SplitBiQuad.h"
-
-#include "SMESHGUI_FilterUtils.h"
-#include "SMESHGUI_GEOMGenUtils.h"
-#include "SMESHGUI_GroupUtils.h"
-#include "SMESHGUI_HypothesesUtils.h"
-#include "SMESHGUI_MeshUtils.h"
-#include "SMESHGUI_PatternUtils.h"
 #include "SMESHGUI_Utils.h"
 #include "SMESHGUI_VTKUtils.h"
 
 #include "SMESH_ActorUtils.h"
 #include "SMESH_Client.hxx"
 #include "SMESH_ScalarBarActor.h"
+#include <SMESH_Comment.hxx>
 #include "SMESH_TypeFilter.hxx"
 
 // SALOME GUI includes
-#include <SalomeApp_Application.h>
-#include <SalomeApp_CheckFileDlg.h>
-#include <SalomeApp_DataObject.h>
-#include <SalomeApp_Study.h>
-#include <SalomeApp_Tools.h>
-
 #include <LightApp_DataOwner.h>
 #include <LightApp_NameDlg.h>
 #include <LightApp_Preferences.h>
 #include <LightApp_SelectionMgr.h>
 #include <LightApp_UpdateFlags.h>
-
-#include <SVTK_ViewManager.h>
-#include <SVTK_ViewModel.h>
-#include <SVTK_ViewWindow.h>
-
-#include <VTKViewer_Algorithm.h>
-
+#include <QtxFontEdit.h>
+#include <QtxPopupMgr.h>
+#include <SALOME_ListIO.hxx>
 #include <SUIT_Desktop.h>
 #include <SUIT_FileDlg.h>
 #include <SUIT_MessageBox.h>
 #include <SUIT_OverrideCursor.h>
 #include <SUIT_ResourceMgr.h>
 #include <SUIT_Session.h>
-
-#include <QtxPopupMgr.h>
-#include <QtxFontEdit.h>
-
-#include <SALOME_ListIO.hxx>
+#include <SVTK_ViewManager.h>
+#include <SVTK_ViewModel.h>
+#include <SVTK_ViewWindow.h>
+#include <SalomeApp_Application.h>
+#include <SalomeApp_CheckFileDlg.h>
+#include <SalomeApp_DataObject.h>
+#include <SalomeApp_Study.h>
+#include <SalomeApp_Tools.h>
+#include <VTKViewer_Algorithm.h>
 
 #ifndef DISABLE_PLOT2DVIEWER
 #include <SPlot2d_ViewModel.h>
 // Qt includes
 // #define       INCLUDE_MENUITEM_DEF // VSR commented ????????
 #include <QApplication>
+#include <QCheckBox>
+#include <QDialogButtonBox>
+#include <QLayout>
+#include <QListView>
 #include <QMenu>
 #include <QTextStream>
-#include <QListView>
 #include <QTreeView>
-#include <QCheckBox>
-#include <QLayout>
-#include <QDialogButtonBox>
 
 // BOOST includes
 #include <boost/shared_ptr.hpp>
@@ -491,17 +487,11 @@ namespace
         QDialogButtonBox* btnbox = msgBox.findChild<QDialogButtonBox*>();
         lt->addWidget(&dontShowCheckBox, lt->rowCount(), lt->columnCount()-1, lt->rowCount(), lt->columnCount());
         lt->addWidget(btnbox, lt->rowCount(), 0, lt->rowCount(), lt->columnCount());
-        if(msgBox.exec() == QMessageBox::Ok)
-        {
-          if(dontShowCheckBox.checkState() == Qt::Checked)
-          {
-            if ( resMgr )
-              resMgr->setValue( "SMESH", "show_warning", false);
-          }
-          aCheckWarn = false;
-        }
-        else
+        if ( msgBox.exec() != QMessageBox::Ok )
           return;
+
+        if ( dontShowCheckBox.checkState() == Qt::Checked && resMgr )
+          resMgr->setValue( "SMESH", "show_warning", false);
       }
 
       QString aMeshName = anIObject->getName();
@@ -665,6 +655,7 @@ namespace
       toCreateGroups = resMgr->booleanValue( "SMESH", "auto_groups", false );
     bool toOverwrite  = true;
     bool toFindOutDim = true;
+    double       zTol = resMgr ? resMgr->doubleValue( "SMESH", "med_ztolerance", 0. ) : 0.;
 
     QString aFilter, aTitle = QObject::tr("SMESH_EXPORT_MESH");
     QString anInitialPath = "";
@@ -749,28 +740,21 @@ namespace
       if ( isMED ) {
         //filters << QObject::tr( "MED_FILES_FILTER" ) + " (*.med)";
         //QString vmed (aMesh->GetVersionString(-1, 2));
-        //MESSAGE("MED version: " << vmed.toStdString());
         SMESH::long_array_var mvok = aMesh->GetMEDVersionsCompatibleForAppend();
-        for ( int i = 0; i < mvok->length(); ++i )  // i=0 must correspond to the current version to set the default filter on it
-          {
-            int versionInt = mvok[i];
-            if (i == 0)
-              defaultVersion = versionInt;
-            std::ostringstream vss;
-            vss << versionInt/10;
-            vss << ".";
-            vss << versionInt%10;
-            QString vs = vss.str().c_str();
-            MESSAGE("MED version: " << vs.toStdString());
-            aFilterMap.insert( QObject::tr( "MED_VX_FILES_FILTER" ).arg( vs ) + " (*.med)",  versionInt);
-          }
+        if ( mvok->length() > 0)
+          defaultVersion = mvok[0]; // the current version to set the default filter on it
+        for ( CORBA::ULong i = 0; i < mvok->length(); ++i )
+        {
+          QString vs = (char*)( SMESH_Comment( mvok[i]/10 ) << "." << mvok[i]%10 );
+          MESSAGE("MED version: " << vs.toStdString());
+          aFilterMap.insert( QObject::tr( "MED_VX_FILES_FILTER" ).arg( vs ) + " (*.med)",  mvok[i]);
+        }
       }
       else { // isSAUV
         aFilterMap.insert("All files (*)", -1 );
         aFilterMap.insert("SAUV files (*.sauv)", defaultVersion ); // 0 = default filter (defaultVersion)
         aFilterMap.insert("SAUV files (*.sauve)", -1 );
       }
-      MESSAGE("default version="<< defaultVersion);
       QStringList filters;
       QMap<QString, int>::const_iterator it = aFilterMap.begin();
       QString aDefaultFilter = it.key();
@@ -787,6 +771,20 @@ namespace
       if ( fieldSelWdg->GetAllFields( aMeshList, aFieldList ))
         wdgList.append( fieldSelWdg );
 
+      QWidget*           zTolWdg = new QWidget();
+      QCheckBox*       zTolCheck = new QCheckBox( QObject::tr( "SMESH_ZTOLERANCE" ), zTolWdg );
+      SMESHGUI_SpinBox* zTolSpin = new SMESHGUI_SpinBox( zTolWdg );
+      QHBoxLayout*    zTolLayout = new QHBoxLayout( zTolWdg );
+      zTolLayout->addWidget( zTolCheck );
+      zTolLayout->addWidget( zTolSpin );
+      zTolLayout->setMargin( 0 );
+      zTolSpin->RangeStepAndValidator( 0, 1e+100, 1., "length_precision" );
+      zTolSpin->setValue( zTol );
+      QObject::connect( zTolCheck, SIGNAL( toggled(bool)), zTolSpin, SLOT( setEnabled(bool)));
+      zTolCheck->setChecked( resMgr->booleanValue( "SMESH", "enable_ztolerance", false ));
+      zTolSpin ->setEnabled( zTolCheck->isChecked() );
+      wdgList.append( zTolWdg );
+
       SalomeApp_CheckFileDlg* fd =
         new SalomeApp_CheckFileDlg ( SMESHGUI::desktop(), false, checkBoxes, true, true, wdgList );
       fd->setWindowTitle( aTitle );
@@ -812,8 +810,9 @@ namespace
       fd->setValidator( fv );
 
       bool is_ok = false;
-      while (!is_ok) {
-        MESSAGE("******* Loop on file dialog ***********");
+      while (!is_ok)
+      {
+        //MESSAGE("******* Loop on file dialog ***********");
         isOkToWrite =true;
         if ( fd->exec() )
           aFilename = fd->selectedFile();
@@ -822,9 +821,9 @@ namespace
           break;
         }
         aFormat = aFilterMap[fd->selectedNameFilter()];
-        MESSAGE("selected version: " << aFormat << " file: " << aFilename.toUtf8().constData());
+        //MESSAGE("selected version: " << aFormat << " file: " << aFilename.toUtf8().constData());
         toOverwrite = fv->isOverwrite(aFilename);
-        MESSAGE("toOverwrite:" << toOverwrite);
+        //MESSAGE("toOverwrite:" << toOverwrite);
         is_ok = true;
         if ( !aFilename.isEmpty() ) {
           if( !toOverwrite ) {
@@ -838,16 +837,16 @@ namespace
                                                   QObject::tr("SMESH_BUT_YES"),
                                                   QObject::tr("SMESH_BUT_NO"), 0, 1);
               if (aRet == 0)
-                {
-                  toOverwrite = true;
-                  MESSAGE("incompatible MED file version for add, overwrite accepted");
-                }
+              {
+                toOverwrite = true;
+                //MESSAGE("incompatible MED file version for add, overwrite accepted");
+              }
               else
-                {
-                  isOkToWrite = false;
-                  is_ok = false;
-                  MESSAGE("incompatible MED file version for add, overwrite refused");
-                }
+              {
+                isOkToWrite = false;
+                is_ok = false;
+                //MESSAGE("incompatible MED file version for add, overwrite refused");
+              }
             }
             QStringList aMeshNamesCollisionList;
             SMESH::string_array_var aMeshNames = SMESHGUI::GetSMESHGen()->GetMeshNames( aFilename.toUtf8().constData() );
@@ -861,7 +860,7 @@ namespace
                 }
               }
             }
-           if( !aMeshNamesCollisionList.isEmpty() ) {
+            if( !aMeshNamesCollisionList.isEmpty() ) {
               isOkToWrite = false;
               QString aMeshNamesCollisionString = aMeshNamesCollisionList.join( ", " );
               int aRet = SUIT_MessageBox::warning(SMESHGUI::desktop(),
@@ -870,8 +869,8 @@ namespace
                                                   QObject::tr("SMESH_BUT_YES"),
                                                   QObject::tr("SMESH_BUT_NO"),
                                                   QObject::tr("SMESH_BUT_CANCEL"), 0, 2);
-             MESSAGE("answer collision name " << aRet);
-             if (aRet == 0) {
+              MESSAGE("answer collision name " << aRet);
+              if (aRet == 0) {
                 toOverwrite = true;
                 isOkToWrite = true;
               }
@@ -881,12 +880,16 @@ namespace
           }
         }
       }
-      MESSAGE(" ****** end of file dialog loop, toOverwrite:" << toOverwrite << " isOkToWrite:" << isOkToWrite);
       toCreateGroups = fd->IsChecked(0);
       toFindOutDim   = fd->IsChecked(1);
+      zTol           = zTolCheck->isChecked() ? zTolSpin->value() : -1;
       fieldSelWdg->GetSelectedFields();
+      if ( resMgr ) resMgr->setValue( "SMESH", "enable_ztolerance", zTolCheck->isChecked() );
+
       if ( !fieldSelWdg->parent() )
         delete fieldSelWdg;
+      if ( !zTolWdg->parent() )
+        delete zTolWdg;
       delete fd;
     }
     else
@@ -905,12 +908,12 @@ namespace
 
       try {
         // Renumbering is not needed since SMDS redesign in V6.2.0 (Nov 2010)
-//         bool Renumber = false;
-//         // PAL 14172  : Check of we have to renumber or not from the preferences before export
-//         if (resMgr)
-//           Renumber= resMgr->booleanValue("renumbering");
-//         if (Renumber){
-//           SMESH::SMESH_MeshEditor_var aMeshEditor = aMesh->GetMeshEditor();
+        //         bool Renumber = false;
+        //         // PAL 14172  : Check of we have to renumber or not from the preferences before export
+        //         if (resMgr)
+        //           Renumber= resMgr->booleanValue("renumbering");
+        //         if (Renumber){
+        //           SMESH::SMESH_MeshEditor_var aMeshEditor = aMesh->GetMeshEditor();
 //           aMeshEditor->RenumberNodes();
 //           aMeshEditor->RenumberElements();
 //           if ( SMESHGUI::automaticUpdate() )
@@ -927,13 +930,14 @@ namespace
             const GEOM::ListOfFields&       fields = aFieldList[ aMeshIndex ].first.in();
             const QString&            geoAssFields = aFieldList[ aMeshIndex ].second;
             const bool                   hasFields = ( fields.length() || !geoAssFields.isEmpty() );
-            if ( !hasFields && aMeshOrGroup->_is_equivalent( aMeshItem ))
+            if ( !hasFields && aMeshOrGroup->_is_equivalent( aMeshItem ) && zTol < 0 )
               aMeshItem->ExportMED( aFilename.toUtf8().data(), toCreateGroups, aFormat,
                                     toOverwrite && aMeshIndex == 0, toFindOutDim );
             else
-              aMeshItem->ExportPartToMED( aMeshOrGroup, aFilename.toUtf8().data(), toCreateGroups, aFormat,
+              aMeshItem->ExportPartToMED( aMeshOrGroup, aFilename.toUtf8().data(),
+                                          toCreateGroups, aFormat,
                                           toOverwrite && aMeshIndex == 0, toFindOutDim,
-                                          fields, geoAssFields.toLatin1().data() );
+                                          fields, geoAssFields.toLatin1().data(), zTol );
           }
         }
         else if ( isSAUV )
@@ -3130,6 +3134,18 @@ bool SMESHGUI::OnGUIEvent( int theCommandID )
       break;
     }
 
+    case SMESHOp::OpFaceGroupsByEdges: // Create face groups separated by sharp edges
+    {
+      if ( isStudyLocked() )
+        break;
+
+      EmitSignalDeactivateDialog();
+      SMESHGUI_FaceGroupsSeparatedByEdgesDlg* aDlg = new SMESHGUI_FaceGroupsSeparatedByEdgesDlg( this );
+      aDlg->show();
+
+      break;
+    }
+
     case SMESHOp::OpDeleteGroup: // Delete groups with their contents
     {
       if ( !vtkwnd )
@@ -3703,6 +3719,7 @@ bool SMESHGUI::OnGUIEvent( int theCommandID )
   case SMESHOp::OpPropertiesVolume:
   case SMESHOp::OpMinimumDistance:
   case SMESHOp::OpBoundingBox:
+  case SMESHOp::OpAngle:
     {
       int page = SMESHGUI_MeasureDlg::MinDistance;
       if ( theCommandID == SMESHOp::OpBoundingBox )
@@ -3713,6 +3730,8 @@ bool SMESHGUI::OnGUIEvent( int theCommandID )
         page = SMESHGUI_MeasureDlg::Area;
       else if ( theCommandID == SMESHOp::OpPropertiesVolume )
         page = SMESHGUI_MeasureDlg::Volume;
+      else if ( theCommandID == SMESHOp::OpAngle )
+        page = SMESHGUI_MeasureDlg::Angle;
 
       EmitSignalDeactivateDialog();
       SMESHGUI_MeasureDlg* dlg = new SMESHGUI_MeasureDlg( SMESHGUI::desktop(), page );
@@ -3907,6 +3926,7 @@ void SMESHGUI::initialize( CAM_Application* app )
   createSMESHAction( SMESHOp::OpIntersectGroups,      "INT_GROUP",               "ICON_INTERSECT" );
   createSMESHAction( SMESHOp::OpCutGroups,            "CUT_GROUP",               "ICON_CUT" );
   createSMESHAction( SMESHOp::OpGroupUnderlyingElem,  "UNDERLYING_ELEMS",        "ICON_UNDERLYING_ELEMS" );
+  createSMESHAction( SMESHOp::OpFaceGroupsByEdges,    "FACE_GROUPS_BY_EDGES",    "ICON_FACE_GROUPS_BY_EDGES" );
   createSMESHAction( SMESHOp::OpAddElemGroupPopup,    "ADD_TO_GROUP" );
   createSMESHAction( SMESHOp::OpRemoveElemGroupPopup, "REMOVE_FROM_GROUP" );
   createSMESHAction( SMESHOp::OpDeleteGroup,          "DEL_GROUP",               "ICON_DEL_GROUP" );
@@ -4046,6 +4066,7 @@ void SMESHGUI::initialize( CAM_Application* app )
   createSMESHAction( SMESHOp::OpPropertiesLength, "MEASURE_LENGTH",   "ICON_MEASURE_LENGTH" );
   createSMESHAction( SMESHOp::OpPropertiesArea,   "MEASURE_AREA",     "ICON_MEASURE_AREA" );
   createSMESHAction( SMESHOp::OpPropertiesVolume, "MEASURE_VOLUME",   "ICON_MEASURE_VOLUME" );
+  createSMESHAction( SMESHOp::OpAngle,            "MEASURE_ANGLE",    "ICON_MEASURE_ANGLE" );
 
   createSMESHAction( SMESHOp::OpHide,     "HIDE", "ICON_HIDE" );
   createSMESHAction( SMESHOp::OpShow,     "SHOW", "ICON_SHOW" );
@@ -4144,6 +4165,7 @@ void SMESHGUI::initialize( CAM_Application* app )
   createMenu( SMESHOp::OpCutGroups,            meshId, -1 );
   createMenu( separator(),                     meshId, -1 );
   createMenu( SMESHOp::OpGroupUnderlyingElem,  meshId, -1 );
+  createMenu( SMESHOp::OpFaceGroupsByEdges,    meshId, -1 );
   createMenu( separator(),                     meshId, -1 );
   createMenu( SMESHOp::OpMeshInformation,      meshId, -1 );
   //createMenu( SMESHOp::OpStdInfo, meshId, -1 );
@@ -4252,6 +4274,7 @@ void SMESHGUI::initialize( CAM_Application* app )
 
   createMenu( SMESHOp::OpMinimumDistance,  measureId,   -1 );
   createMenu( SMESHOp::OpBoundingBox,      measureId,   -1 );
+  createMenu( SMESHOp::OpAngle,            measureId,   -1 );
   createMenu( SMESHOp::OpPropertiesLength, basicPropId, -1 );
   createMenu( SMESHOp::OpPropertiesArea,   basicPropId, -1 );
   createMenu( SMESHOp::OpPropertiesVolume, basicPropId, -1 );
@@ -5063,6 +5086,9 @@ void SMESHGUI::createPreferences()
 
   int dispgroup = addPreference( tr( "PREF_DISPLAY_MODE_GROUP" ), genTab );
   setPreferenceProperty( dispgroup, "columns", 2 );
+
+  addPreference( tr( "PREF_FITALL_ON_DISPLAYONLY" ), dispgroup, LightApp_Preferences::Bool, "SMESH", "fitall_on_displayonly" );
+  
   int dispmode = addPreference( tr( "PREF_DISPLAY_MODE" ), dispgroup, LightApp_Preferences::Selector, "SMESH", "display_mode" );
   QStringList modes;
   modes.append( tr("MEN_WIRE") );
@@ -5117,6 +5143,11 @@ void SMESHGUI::createPreferences()
   setPreferenceProperty( exportgroup, "columns", 2 );
   addPreference( tr( "PREF_AUTO_GROUPS" ), exportgroup, LightApp_Preferences::Bool, "SMESH", "auto_groups" );
   addPreference( tr( "PREF_SHOW_WARN" ), exportgroup, LightApp_Preferences::Bool, "SMESH", "show_warning" );
+  int zTol = addPreference( tr( "PREF_ZTOLERANCE" ), exportgroup, LightApp_Preferences::DblSpin, "SMESH", "med_ztolerance" );
+  setPreferenceProperty( zTol, "precision", 10 );
+  setPreferenceProperty( zTol, "min", 0.0000000001 );
+  setPreferenceProperty( zTol, "max", 1000000.0 );
+  setPreferenceProperty( zTol, "step", 1. );
   //addPreference( tr( "PREF_RENUMBER" ), exportgroup, LightApp_Preferences::Bool, "SMESH", "renumbering" );
 
   int computeGroup = addPreference( tr( "PREF_GROUP_COMPUTE" ), genTab );
@@ -5443,13 +5474,13 @@ void SMESHGUI::preferencesChanged( const QString& sect, const QString& name )
     std::string aWarning;
     SUIT_ResourceMgr* aResourceMgr = SMESH::GetResourceMgr(this);
 
-    if ( name== "selection_object_color" ||
-         name=="selection_element_color" ||
-         name==        "highlight_color" ||
-         name=="selection_precision_node"    ||
-         name=="selection_precision_element" ||
-         name=="selection_precision_object"   ||
-         name=="selection_increment")
+    if ( name ==  "selection_object_color" ||
+         name == "selection_element_color" ||
+         name ==         "highlight_color" ||
+         name == "selection_precision_node"    ||
+         name == "selection_precision_element" ||
+         name == "selection_precision_object"  ||
+         name == "selection_increment")
     {
       SMESH::UpdateSelectionProp( this );
     }
index a40bac0d4053ce841deac240e6f86ad10f518b22..ac325789ffd39033e5fb0ab005496c7cf41b3997 100644 (file)
@@ -988,21 +988,20 @@ void SMESHGUI_BaseComputeOp::computeMesh()
             try {
               OCC_CATCH_SIGNALS;
               bool toDisplay = false;
+              std::string entry = (*anIter).second->GetID();
               if ( !aMesh->_is_nil() ) // display only a mesh
               {
                 toDisplay = true;
                 SMESH_Actor *anActor = SMESH::FindActorByObject( aMesh );
-                if ( !anActor ) anActor = SMESH::CreateActor( (*anIter).second->GetID().c_str(),
-                                                              /*clearLog =*/ true );
+                if ( !anActor ) anActor = SMESH::CreateActor( entry.c_str(), /*clearLog =*/true );
                 if ( anActor ) // actor is not created for an empty mesh
                 {
                   anActor->SetEntityMode( entities );
-                  SMESH::DisplayActor( SMESH::GetActiveWindow(), anActor );
+                  //SMESH::DisplayActor( SMESH::GetActiveWindow(), anActor ); -- 23615
                 }
               }
-              Handle(SALOME_InteractiveObject) anIO = new SALOME_InteractiveObject
-                ( (*anIter).second->GetID().c_str(), "SMESH", (*anIter).second->GetName().c_str() );
-              SMESH::Update(anIO, toDisplay);
+              if ( toDisplay )
+                SMESH::UpdateView( SMESH::eDisplay, entry.c_str() );
 
               if ( SVTK_ViewWindow* vtkWnd = SMESH::GetVtkViewWindow(SMESH::GetActiveWindow() ))
                 if ( vtkWnd->getRenderer() )
diff --git a/src/SMESHGUI/SMESHGUI_FaceGroupsSeparatedByEdgesDlg.cxx b/src/SMESHGUI/SMESHGUI_FaceGroupsSeparatedByEdgesDlg.cxx
new file mode 100644 (file)
index 0000000..c994164
--- /dev/null
@@ -0,0 +1,376 @@
+// Copyright (C) 2007-2016  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_FaceGroupsSeparatedByEdges.cxx
+
+#include "SMESHGUI_FaceGroupsSeparatedByEdgesDlg.h"
+
+#include "SMESHGUI.h"
+#include "SMESHGUI_SpinBox.h"
+#include "SMESHGUI_MeshEditPreview.h"
+#include "SMESHGUI_Utils.h"
+
+// SALOME GUI includes
+#include <LightApp_Application.h>
+#include <LightApp_SelectionMgr.h>
+#include <SALOME_Actor.h>
+#include <SALOME_ListIO.hxx>
+#include <SUIT_MessageBox.h>
+#include <SUIT_OverrideCursor.h>
+#include <SUIT_ResourceMgr.h>
+#include <SUIT_Session.h>
+#include <SalomeApp_Tools.h>
+
+#include <SALOMEDS_SObject.hxx>
+
+// IDL includes
+#include <SALOMEconfig.h>
+#include CORBA_SERVER_HEADER(SMESH_Group)
+
+// Qt includes
+#include <QCheckBox>
+#include <QGridLayout>
+#include <QGroupBox>
+#include <QHBoxLayout>
+#include <QLineEdit>
+#include <QPushButton>
+#include <QRadioButton>
+#include <QToolButton>
+
+#include <Standard_ErrorHandler.hxx>
+
+#define SPACING 6
+#define MARGIN  11
+
+/*!
+  \class SMESHGUI_FaceGroupsSeparatedByEdgesDlg
+  \brief Dialog to create face groups divided by sharp edges
+*/
+
+SMESHGUI_FaceGroupsSeparatedByEdgesDlg::
+SMESHGUI_FaceGroupsSeparatedByEdgesDlg( SMESHGUI* theModule ) :
+  SMESHGUI_PreviewDlg( theModule ),
+  mySelectionMgr( SMESH::GetSelectionMgr( theModule ))
+{
+  setModal(false);
+  setAttribute(Qt::WA_DeleteOnClose, true);
+  setWindowTitle(tr("CAPTION"));
+  setSizeGripEnabled(true);
+
+  QVBoxLayout* dlgLayout = new QVBoxLayout(this);
+  dlgLayout->setSpacing(SPACING);
+  dlgLayout->setMargin(MARGIN);
+
+  /***************************************************************/
+  GroupArgs = new QGroupBox(tr("SMESH_ARGUMENTS"), this);
+  QGridLayout* GroupArgsLayout = new QGridLayout(GroupArgs);
+  GroupArgsLayout->setSpacing(SPACING);
+  GroupArgsLayout->setMargin(MARGIN);
+
+  // mesh
+  QLabel* meshNameLabel = new QLabel(tr("SMESH_MESH"), GroupArgs);
+  myMeshName = new QLineEdit( GroupArgs );
+  myMeshName->setReadOnly( true );
+
+  // angle
+  QLabel* angleLabel = new QLabel( tr("SHARP_ANGLE"), GroupArgs );
+  myAngle = new SMESHGUI_SpinBox( GroupArgs );
+  myAngle->RangeStepAndValidator( 0, 180.0, 10.0, "angle_precision");
+
+  // check-boxes
+  myCreateEdgesCheck = new QCheckBox( tr("CREATE_EDGES" ), GroupArgs);
+  myUseExistingCheck = new QCheckBox( tr("USE_EXISTING_EDGES"), GroupArgs);
+  myPreviewCheckBox  = new QCheckBox(tr("PREVIEW"), GroupArgs);
+
+  // set previous values
+  if ( SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr() )
+  {
+    myAngle->setValue( resMgr->doubleValue( "SMESH", "prev_sharp_angle", 30. ));
+    myCreateEdgesCheck->setChecked( resMgr->booleanValue( "SMESH", "prev_create_edges", false ));
+    myUseExistingCheck->setChecked( resMgr->booleanValue( "SMESH", "prev_use_existing_edges", false ));
+  }
+
+  // layout
+  GroupArgsLayout->addWidget( meshNameLabel,      0, 0);
+  GroupArgsLayout->addWidget( myMeshName,         0, 1);
+  GroupArgsLayout->addWidget( angleLabel,         1, 0);
+  GroupArgsLayout->addWidget( myAngle,            1, 1);
+  GroupArgsLayout->addWidget( myCreateEdgesCheck, 2, 0);
+  GroupArgsLayout->addWidget( myUseExistingCheck, 3, 0);
+  GroupArgsLayout->addWidget( myPreviewCheckBox,  4, 0);
+
+  /***************************************************************/
+  GroupButtons = new QGroupBox(this);
+  QHBoxLayout* GroupButtonsLayout = new QHBoxLayout(GroupButtons);
+  GroupButtonsLayout->setSpacing(SPACING);
+  GroupButtonsLayout->setMargin(MARGIN);
+
+  buttonOk = new QPushButton(tr("SMESH_BUT_APPLY_AND_CLOSE"), GroupButtons);
+  buttonOk->setAutoDefault(true);
+  buttonOk->setDefault(true);
+  buttonApply = new QPushButton(tr("SMESH_BUT_APPLY"), GroupButtons);
+  buttonApply->setAutoDefault(true);
+  buttonCancel = new QPushButton(tr("SMESH_BUT_CLOSE"), GroupButtons);
+  buttonCancel->setAutoDefault(true);
+  buttonHelp = new QPushButton(tr("SMESH_BUT_HELP"), GroupButtons);
+  buttonHelp->setAutoDefault(true);
+
+  GroupButtonsLayout->addWidget(buttonOk);
+  GroupButtonsLayout->addSpacing(10);
+  GroupButtonsLayout->addWidget(buttonApply);
+  GroupButtonsLayout->addSpacing(10);
+  GroupButtonsLayout->addStretch();
+  GroupButtonsLayout->addWidget(buttonCancel);
+  GroupButtonsLayout->addWidget(buttonHelp);
+
+  /***************************************************************/
+  dlgLayout->addWidget(GroupArgs);
+  dlgLayout->addWidget(GroupButtons);
+
+  mySMESHGUI->SetActiveDialogBox(this);
+
+  /* signals and slots connections */
+  connect(buttonOk,     SIGNAL(clicked()), this, SLOT(ClickOnOk()));
+  connect(buttonCancel, SIGNAL(clicked()), this, SLOT(reject()));
+  connect(buttonApply,  SIGNAL(clicked()), this, SLOT(ClickOnApply()));
+  connect(buttonHelp,   SIGNAL(clicked()), this, SLOT(ClickOnHelp()));
+
+  connect(mySMESHGUI, SIGNAL (SignalDeactivateActiveDialog()), this, SLOT(DeactivateActiveDialog()));
+  connect(mySelectionMgr, SIGNAL(currentSelectionChanged()),   this, SLOT(SelectionIntoArgument()));
+  /* to close dialog if study change */
+  connect(mySMESHGUI, SIGNAL(SignalCloseAllDialogs()),      this, SLOT(reject()));
+  connect(mySMESHGUI, SIGNAL(SignalActivatedViewManager()), this, SLOT(onOpenView()));
+  connect(mySMESHGUI, SIGNAL(SignalCloseView()),            this, SLOT(onCloseView()));
+
+  connect( myAngle, SIGNAL(valueChanged(double)),     this, SLOT( onArgChange() ));
+  connect( myCreateEdgesCheck, SIGNAL(toggled(bool)), this, SLOT( onArgChange() ));
+  connect( myUseExistingCheck, SIGNAL(toggled(bool)), this, SLOT( onArgChange() ));
+
+  connectPreviewControl();
+  mySimulation->GetActor()->GetProperty()->SetLineWidth( 5 );
+
+  SelectionIntoArgument();
+}
+
+SMESHGUI_FaceGroupsSeparatedByEdgesDlg::~SMESHGUI_FaceGroupsSeparatedByEdgesDlg()
+{
+}
+
+//=================================================================================
+// function : ClickOnApply()
+// purpose  :
+//=================================================================================
+
+bool SMESHGUI_FaceGroupsSeparatedByEdgesDlg::ClickOnApply()
+{
+  if ( mySMESHGUI->isStudyLocked() )
+    return false;
+
+  SUIT_OverrideCursor aWaitCursor;
+
+  QStringList aParameters, anEntryList;
+  aParameters << myAngle->text();
+
+  try
+  {
+    SMESH::ListOfGroups_var groups =
+      myMesh->FaceGroupsSeparatedByEdges( myAngle->value(),
+                                          myCreateEdgesCheck->isChecked(),
+                                          myUseExistingCheck->isChecked());
+
+    for ( CORBA::ULong i = 0; i < groups->length(); ++i )
+      if( _PTR(SObject) aSObject = SMESH::ObjectToSObject( groups[i].in() ))
+        anEntryList.append( aSObject->GetID().c_str() );
+
+    SUIT_MessageBox::information(this, tr("SMESH_INFORMATION"),
+                                 tr("NB_GROUPS_CREATED").arg( groups->length() ));
+  }
+  catch ( const SALOME::SALOME_Exception& S_ex ) {
+    SalomeApp_Tools::QtCatchCorbaException( S_ex );
+  }
+  catch (...) {
+  }
+
+  mySMESHGUI->updateObjBrowser(true); // new groups may appear
+  if( LightApp_Application* anApp =
+      dynamic_cast<LightApp_Application*>( SUIT_Session::session()->activeApplication() ) )
+  {
+    anApp->browseObjects( anEntryList, isApplyAndClose() );
+  }
+
+  SMESHGUI::Modified();
+
+  return true;
+}
+//=================================================================================
+// function : ClickOnOk()
+// purpose  :
+//=================================================================================
+
+void SMESHGUI_FaceGroupsSeparatedByEdgesDlg::ClickOnOk()
+{
+  setIsApplyAndClose( true );
+  if( ClickOnApply() )
+    reject();
+}
+
+//=================================================================================
+// function : reject()
+// purpose  :
+//=================================================================================
+void SMESHGUI_FaceGroupsSeparatedByEdgesDlg::reject()
+{
+  disconnect(mySelectionMgr, 0, this, 0);
+  mySMESHGUI->ResetState();
+  QDialog::reject();
+}
+//=================================================================================
+// function : ClickOnHelp()
+// purpose  :
+//=================================================================================
+
+void SMESHGUI_FaceGroupsSeparatedByEdgesDlg::ClickOnHelp()
+{
+  static QString myHelpFileName( "face_groups_by_sharp_edges.html" );
+
+  LightApp_Application* app = (LightApp_Application*)(SUIT_Session::session()->activeApplication());
+  if (app)
+    app->onHelpContextModule(mySMESHGUI ? app->moduleName(mySMESHGUI->moduleName()) : QString(""), myHelpFileName);
+  else {
+    QString platform;
+#ifdef WIN32
+    platform = "winapplication";
+#else
+    platform = "application";
+#endif
+    SUIT_MessageBox::warning(this, tr("WRN_WARNING"),
+                             tr("EXTERNAL_BROWSER_CANNOT_SHOW_PAGE").
+                             arg(app->resourceMgr()->stringValue("ExternalBrowser",
+                                                                 platform)).
+                             arg(myHelpFileName));
+  }
+}
+
+//=================================================================================
+// function : SelectionIntoArgument()
+// purpose  : Called when selection as changed or other case
+//=================================================================================
+
+void SMESHGUI_FaceGroupsSeparatedByEdgesDlg::SelectionIntoArgument()
+{
+  if (!GroupButtons->isEnabled()) // inactive
+    return;
+
+  // get selected mesh
+  SALOME_ListIO aList;
+  mySelectionMgr->selectedObjects(aList);
+
+  for ( SALOME_ListIteratorOfListIO it( aList ); it.More(); it.Next() )
+  {
+    Handle(SALOME_InteractiveObject) IO = it.Value();
+    CORBA::Object_var anObj = SMESH::IObjectToObject( IO );
+    SMESH::SMESH_Mesh_var aMesh = SMESH::SMESH_Mesh::_narrow( anObj );
+    if ( aMesh->_is_nil() || aMesh->NbFaces() == 0 )
+      continue;
+
+    if ( !aMesh->_is_equivalent( myMesh ))
+      onDisplaySimulation( false );
+
+    myMesh = aMesh;
+    myMeshName->setText( IO->getName() );
+  }
+
+  bool ok = !myMesh->_is_nil();
+
+  buttonOk->setEnabled( ok );
+  buttonApply->setEnabled( ok );
+
+  onDisplaySimulation( ok );
+}
+
+//=================================================================================
+// function : DeactivateActiveDialog()
+// purpose  :
+//=================================================================================
+
+void SMESHGUI_FaceGroupsSeparatedByEdgesDlg::DeactivateActiveDialog()
+{
+  if (GroupArgs->isEnabled())
+  {
+    GroupArgs->setEnabled(false);
+    GroupButtons->setEnabled(false);
+    mySMESHGUI->ResetState();
+    mySMESHGUI->SetActiveDialogBox(0);
+  }
+}
+
+//=================================================================================
+// function : ActivateThisDialog()
+// purpose  :
+//=================================================================================
+
+void SMESHGUI_FaceGroupsSeparatedByEdgesDlg::ActivateThisDialog()
+{
+  /* Emit a signal to deactivate the active dialog */
+  mySMESHGUI->EmitSignalDeactivateDialog();
+  GroupArgs->setEnabled(true);
+  GroupButtons->setEnabled(true);
+
+  mySMESHGUI->SetActiveDialogBox((QDialog*)this);
+
+  SelectionIntoArgument();
+}
+
+//=================================================================================
+// function : onDisplaySimulation
+// purpose  : Show/Hide preview
+//=================================================================================
+
+void SMESHGUI_FaceGroupsSeparatedByEdgesDlg::onDisplaySimulation( bool toDisplayPreview )
+{
+  SUIT_OverrideCursor aWaitCursor;
+
+  // save current values
+  if ( SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr() )
+  {
+    resMgr->setValue( "SMESH", "prev_sharp_angle",        myAngle->value() );
+    resMgr->setValue( "SMESH", "prev_create_edges",       myCreateEdgesCheck->isChecked() );
+    resMgr->setValue( "SMESH", "prev_use_existing_edges", myUseExistingCheck->isChecked() );
+  }
+
+  if ( myPreviewCheckBox->isChecked() && toDisplayPreview && !myMesh->_is_nil() )
+  {
+    try
+    {
+      SMESH::SMESH_MeshEditor_var aMeshEditor = myMesh->GetMeshEditPreviewer();
+      SMESH::ListOfEdges_var edges = aMeshEditor->FindSharpEdges( myAngle->value(),
+                                                                  myUseExistingCheck->isChecked());
+      SMESH::MeshPreviewStruct_var previewData = aMeshEditor->GetPreviewData();
+
+      mySimulation->SetData( previewData.in() );
+      showPreview();
+
+    } catch (...) {
+      hidePreview();
+    }
+  }
+  else
+  {
+    hidePreview();
+  }
+}
diff --git a/src/SMESHGUI/SMESHGUI_FaceGroupsSeparatedByEdgesDlg.h b/src/SMESHGUI/SMESHGUI_FaceGroupsSeparatedByEdgesDlg.h
new file mode 100644 (file)
index 0000000..55d885d
--- /dev/null
@@ -0,0 +1,81 @@
+// Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef SMESHGUI_FaceGroupsSeparatedByEdges_H
+#define SMESHGUI_FaceGroupsSeparatedByEdges_H
+
+// SMESH includes
+#include "SMESH_SMESHGUI.hxx"
+#include "SMESHGUI_PreviewDlg.h"
+
+#include <SALOMEconfig.h>
+#include CORBA_SERVER_HEADER(SMESH_MeshEditor)
+#include CORBA_SERVER_HEADER(SMESH_Mesh)
+
+class LightApp_SelectionMgr;
+class QCheckBox;
+class QLineEdit;
+class QWidget;
+class QPushButton;
+class SMESHGUI_SpinBox;
+
+/*!
+ * \brief Dialog to create face groups divided by sharp edges
+ */
+
+class SMESHGUI_EXPORT SMESHGUI_FaceGroupsSeparatedByEdgesDlg :  public SMESHGUI_PreviewDlg
+{
+  Q_OBJECT
+
+ public:
+
+  SMESHGUI_FaceGroupsSeparatedByEdgesDlg( SMESHGUI* theModule );
+  virtual ~SMESHGUI_FaceGroupsSeparatedByEdgesDlg();
+
+ private slots:
+  void                   ClickOnOk();
+  bool                   ClickOnApply();
+  void                   ClickOnHelp();
+  void                   SelectionIntoArgument();
+  void                   DeactivateActiveDialog();
+  void                   ActivateThisDialog();
+  void                   reject();
+  void                   onArgChange() { onDisplaySimulation( true ); }
+  virtual void           onDisplaySimulation( bool = true );
+
+ private:
+
+  LightApp_SelectionMgr* mySelectionMgr;
+  QWidget*               GroupArgs;
+  QWidget*               GroupButtons;
+
+  QLineEdit*             myMeshName;
+  SMESHGUI_SpinBox*      myAngle;
+  QCheckBox*             myCreateEdgesCheck;
+  QCheckBox*             myUseExistingCheck;
+
+  QPushButton*           buttonOk;
+  QPushButton*           buttonCancel;
+  QPushButton*           buttonApply;
+  QPushButton*           buttonHelp;
+
+  SMESH::SMESH_Mesh_var  myMesh;
+};
+
+#endif // SMESHGUI_FaceGroupsSeparatedByEdges_H
index 294c3c6b20cfd1438164103c3a4208ea7541b39a..ab7b89b4e00ff8451d4f4190bbdeb785d2b2e9a9 100644 (file)
@@ -210,7 +210,7 @@ static SMESH::ElementType elementType(GEOM::GEOM_Object_var geom)
 {
   if ( !geom->_is_nil() ) {
     switch ( geom->GetShapeType() ) {
-    case GEOM::VERTEX:   return SMESH::NODE;
+    case GEOM::VERTEX:   return SMESH::ELEM0D; // NODE; -- 0023613
     case GEOM::EDGE:     return SMESH::EDGE;
     case GEOM::WIRE:     return SMESH::EDGE;
     case GEOM::FACE:     return SMESH::FACE;
index 1f1d5aa8a0315d1db7057afd6f17ddc92c6f5dcb..8e19cddcaa8afff01f0893db9d55cfd7885da656 100644 (file)
 #include "SMESHGUI.h"
 #include "SMESHGUI_IdValidator.h"
 #include "SMESHGUI_Utils.h"
+#include "SMESHGUI_MeshEditPreview.h"
 #include "SMESHGUI_VTKUtils.h"
 #include <SMESH_TypeFilter.hxx>
+#include <SMESH_MeshAlgos.hxx>
 #include <SMESH_LogicalFilter.hxx>
+#include <SMDS_Mesh.hxx>
+#include <SMDS_MeshNode.hxx>
 
 #include <LightApp_SelectionMgr.h>
 #include <SUIT_OverrideCursor.h>
@@ -59,6 +63,8 @@
 #include <VTKViewer_CellLocationsArray.h>
 #include <vtkProperty.h>
 
+#include <ElCLib.hxx>
+
 #include <SALOMEconfig.h>
 #include CORBA_SERVER_HEADER(SMESH_MeshEditor)
 #include CORBA_SERVER_HEADER(SMESH_Measurements)
@@ -1312,6 +1318,367 @@ void SMESHGUI_BasicProperties::clear()
   myResult->clear();
 }
 
+/*!
+  \class SMESHGUI_Angle
+  \brief Angle measurement widget.
+  
+  Widget to calculate angle between 3 nodes.
+*/
+
+/*!
+  \brief Constructor.
+  \param parent parent widget
+*/
+SMESHGUI_Angle::SMESHGUI_Angle( QWidget* parent )
+  : QWidget( parent )
+{
+  // 3 nodes
+
+  QGroupBox* aNodesGrp = new QGroupBox( tr( "NODES_GROUP" ), this );
+  myNodes = new QLineEdit( aNodesGrp );
+  myNodes->setValidator( new SMESHGUI_IdValidator( this, 3 ));
+  QHBoxLayout* aNodesLayout = new QHBoxLayout( aNodesGrp );
+  aNodesLayout->addWidget( myNodes );
+  
+  // Compute button
+  QPushButton* aCompute = new QPushButton( tr( "COMPUTE" ), this );
+
+  // Angle
+
+  QGroupBox* aResultGrp = new QGroupBox( tr( "RESULT" ), this );
+
+  myResult = new QLineEdit;
+  myResult->setReadOnly( true );
+
+  QHBoxLayout* aResultLayout = new QHBoxLayout( aResultGrp );
+  aResultLayout->addWidget( myResult );
+  
+  // Layout
+
+  QGridLayout* aMainLayout = new QGridLayout( this );
+  aMainLayout->setMargin( MARGIN );
+  aMainLayout->setSpacing( SPACING );
+
+  aMainLayout->addWidget( aNodesGrp,   0, 0, 1, 2 );
+  aMainLayout->addWidget( aCompute,    1, 0 );
+  aMainLayout->addWidget( aResultGrp, 2, 0, 1, 2 );
+  aMainLayout->setColumnStretch( 1, 5 );
+  aMainLayout->setRowStretch( 3, 5 );
+
+  // Connections
+  connect( aCompute, SIGNAL( clicked() ), this, SLOT( compute() ));
+
+  // preview
+  myPreview = 0;
+  if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
+  {
+    myPreview = new SMESHGUI_MeshEditPreview( aViewWindow );
+    if ( myPreview && myPreview->GetActor() )
+      myPreview->GetActor()->GetProperty()->SetLineWidth( 5 );
+  }
+  myActor = 0;
+}
+
+SMESHGUI_Angle::~SMESHGUI_Angle()
+{
+  if ( myPreview )
+    delete myPreview;
+}
+
+/*!
+  \brief Setup selection mode
+*/
+void SMESHGUI_Angle::updateSelection()
+{
+  LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
+
+  disconnect( selMgr, 0, this, 0 );
+  selMgr->clearFilters();
+
+  SMESH::SetPointRepresentation( true );
+  if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
+    aViewWindow->SetSelectionMode( NodeSelection );
+
+  connect( selMgr,  SIGNAL( currentSelectionChanged() ), this, SLOT( selectionChanged() ));
+  connect( myNodes, SIGNAL( textEdited( QString ) ),     this, SLOT( nodesEdited() ));
+
+  if ( myPoints.empty() )
+    selectionChanged();
+}
+
+/*!
+  \brief Called when selection is changed
+*/
+void SMESHGUI_Angle::selectionChanged()
+{
+  clear();
+  QString nodesString;
+
+  TColStd_IndexedMapOfInteger idsMap;
+  SALOME_ListIO selected;
+  SMESHGUI::selectionMgr()->selectedObjects( selected );
+  selected.Reverse(); // to keep order of selection
+
+  SALOME_ListIteratorOfListIO ioIterator( selected );
+  for ( ; ioIterator.More(); ioIterator.Next() )
+  {
+    Handle(SALOME_InteractiveObject) IO = ioIterator.Value();
+
+    idsMap.Clear();
+    if ( SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector() )
+      selector->GetIndex( IO, idsMap );
+
+    if ( SMESH_Actor* actor = SMESH::FindActorByEntry( IO->getEntry() ))
+    {
+      myActor = actor;
+      for ( int i = 1; i <= idsMap.Extent() && myPoints.size() < 3; ++i )
+        if ( addPointByActor( idsMap(i) ))
+          nodesString += QString(" %1").arg( idsMap(i) );
+      idsMap.Clear();
+    }
+    SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
+    if ( !CORBA::is_nil( obj ) )
+    {
+      myIDSrc = obj;
+      for ( int i = 1; i <= idsMap.Extent() && myPoints.size() < 3; ++i )
+        if ( addPointByIDSource( idsMap(i) ))
+          nodesString += QString(" %1").arg( idsMap(i) );
+    }
+  }
+
+  myNodes->setText( nodesString );
+}
+
+//=======================================================================
+//function : clear
+//purpose  : Erase preview and result
+//=======================================================================
+
+void SMESHGUI_Angle::clear()
+{
+  myPoints.clear();
+  myResult->clear();
+  if ( myPreview && myPreview->GetActor())
+  {
+    myPreview->GetActor()->SetVisibility( false );
+    if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
+      aViewWindow->Repaint();
+  }
+}
+
+//=======================================================================
+//function : addPointByActor
+//purpose  : append to myPoints XYZ got from myActor
+//=======================================================================
+
+bool SMESHGUI_Angle::addPointByActor( int id )
+{
+  size_t nbP = myPoints.size();
+
+  if ( myActor )
+  {
+    TVisualObjPtr obj = myActor->GetObject();
+    if ( SMDS_Mesh* mesh = obj->GetMesh() )
+      if ( const SMDS_MeshNode* node = mesh->FindNode( id ))
+      {
+        SMESH::PointStruct p = { node->X(), node->Y(), node->Z() };
+        myPoints.push_back( p );
+      }
+  }
+  return nbP < myPoints.size();
+}
+
+//=======================================================================
+//function : addPointByIDSource
+//purpose  : append to myPoints XYZ got from myIDSrc
+//=======================================================================
+
+bool SMESHGUI_Angle::addPointByIDSource( int id )
+{
+  size_t nbP = myPoints.size();
+
+  if ( !myIDSrc->_is_nil() )
+  {
+    SMESH::SMESH_Mesh_var mesh = myIDSrc->GetMesh();
+    if ( !mesh->_is_nil() )
+    {
+      SMESH::double_array_var xyz = mesh->GetNodeXYZ( id );
+      if ( xyz->length() == 3 )
+      {
+        SMESH::PointStruct p = { xyz[0], xyz[1], xyz[2] };
+        myPoints.push_back( p );
+      }
+    }
+  }
+  return nbP < myPoints.size();
+}
+
+//=======================================================================
+//function : nodesEdited
+//purpose  : SLOT called when the user types node IDs
+//=======================================================================
+
+void SMESHGUI_Angle::nodesEdited()
+{
+  clear();
+
+  TColStd_MapOfInteger ID;
+  QStringList ids = myNodes->text().split( " ", QString::SkipEmptyParts );
+  foreach ( QString idStr, ids )
+  {
+    int id = idStr.trimmed().toLong();
+    if (( !ID.Contains( id )) &&
+        ( addPointByActor( id ) || addPointByIDSource( id )))
+      ID.Add( id );
+  }
+
+  SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
+  if ( myActor && selector )
+  {
+    Handle(SALOME_InteractiveObject) IO = myActor->getIO();
+    selector->AddOrRemoveIndex( IO, ID, false );
+    if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
+      aViewWindow->highlight( IO, true, true );
+  }
+}
+
+//=======================================================================
+//function : compute
+//purpose  : SLOT. Compute angle and show preview
+//=======================================================================
+
+void SMESHGUI_Angle::compute()
+{
+  if ( myPoints.size() != 3 )
+    return;
+
+  // --------------
+  // compute angle
+  // --------------
+
+  SMESH::Measurements_var measure = SMESHGUI::GetSMESHGen()->CreateMeasurements();
+  double radians = measure->Angle( myPoints[0], myPoints[1], myPoints[2] );
+  measure->UnRegister();
+  if ( radians < 0 )
+    return;
+
+  int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
+  myResult->setText( QString::number( radians * 180 / M_PI,
+                                      precision > 0 ? 'f' : 'g', qAbs( precision )));
+
+  // -------------
+  // show preview
+  // -------------
+
+  if ( !myPreview || !myPreview->GetActor() )
+    return;
+
+  SMESH::MeshPreviewStruct preveiwData;
+
+  const double     anglePerSeg = 5 * M_PI/180; // angle per an arc segment
+  const double arcRadiusFactor = 0.5;          // arc position, from p1
+
+  gp_Pnt p0 ( myPoints[0].x, myPoints[0].y, myPoints[0].z );
+  gp_Pnt p1 ( myPoints[1].x, myPoints[1].y, myPoints[1].z );
+  gp_Pnt p2 ( myPoints[2].x, myPoints[2].y, myPoints[2].z );
+  gp_Vec vec10( p1, p0 ), vec12( p1, p2 ), norm( vec10 ^ vec12 );
+
+  if ( norm.Magnitude() <= gp::Resolution() ) // 180 degrees
+    norm = getNormal( vec10 );
+
+  double     len10 = vec10.Magnitude();
+  double     len12 = vec12.Magnitude();
+  double    lenMax = Max( len10, len12 );
+  double arcRadius = arcRadiusFactor * lenMax;
+
+  p0 = p1.Translated( lenMax * vec10.Normalized() );
+  p2 = p1.Translated( lenMax * vec12.Normalized() );
+
+  gp_Circ arc( gp_Ax2( p1, norm, vec10 ), arcRadius );
+
+  int nbRadialSegmensts = ceil( radians / anglePerSeg ) + 1;
+  int           nbNodes = 3 + ( nbRadialSegmensts + 1 );
+
+  // coordinates
+  preveiwData.nodesXYZ.length( nbNodes );
+  int iP = 0;
+  for ( ; iP < nbRadialSegmensts + 1; ++iP )
+  {
+    double u = double( iP ) / nbRadialSegmensts * radians;
+    gp_Pnt p = ElCLib::Value( u, arc );
+    preveiwData.nodesXYZ[ iP ].x = p.X();
+    preveiwData.nodesXYZ[ iP ].y = p.Y();
+    preveiwData.nodesXYZ[ iP ].z = p.Z();
+  }
+  int iP0 = iP;
+  preveiwData.nodesXYZ[ iP ].x = p0.X();
+  preveiwData.nodesXYZ[ iP ].y = p0.Y();
+  preveiwData.nodesXYZ[ iP ].z = p0.Z();
+  int iP1 = ++iP;
+  preveiwData.nodesXYZ[ iP ].x = p1.X();
+  preveiwData.nodesXYZ[ iP ].y = p1.Y();
+  preveiwData.nodesXYZ[ iP ].z = p1.Z();
+  int iP2 = ++iP;
+  preveiwData.nodesXYZ[ iP ].x = p2.X();
+  preveiwData.nodesXYZ[ iP ].y = p2.Y();
+  preveiwData.nodesXYZ[ iP ].z = p2.Z();
+
+  // connectivity
+  preveiwData.elementConnectivities.length( 2 * ( 2 + nbRadialSegmensts ));
+  for ( int iSeg = 0; iSeg < nbRadialSegmensts; ++iSeg )
+  {
+    preveiwData.elementConnectivities[ iSeg * 2 + 0 ] = iSeg;
+    preveiwData.elementConnectivities[ iSeg * 2 + 1 ] = iSeg + 1;
+  }
+  int iSeg = nbRadialSegmensts;
+  preveiwData.elementConnectivities[ iSeg * 2 + 0 ] = iP0;
+  preveiwData.elementConnectivities[ iSeg * 2 + 1 ] = iP1;
+  ++iSeg;
+  preveiwData.elementConnectivities[ iSeg * 2 + 0 ] = iP1;
+  preveiwData.elementConnectivities[ iSeg * 2 + 1 ] = iP2;
+
+  // types
+  preveiwData.elementTypes.length( 2 + nbRadialSegmensts );
+  SMESH::ElementSubType type = { SMESH::EDGE, /*isPoly=*/false, /*nbNodesInElement=*/2 };
+  for ( CORBA::ULong i = 0; i < preveiwData.elementTypes.length(); ++i )
+    preveiwData.elementTypes[ i ] = type;
+
+  myPreview->SetData( preveiwData );
+}
+
+//================================================================================
+/*!
+ * \brief Return normal to a plane of drawing in the case of 180 degrees angle
+ */
+//================================================================================
+
+gp_Vec SMESHGUI_Angle::getNormal(const gp_Vec& vec10 )
+{
+  gp_XYZ norm;
+
+  // try to get normal by a face at the 2nd node
+  if ( myActor && myActor->GetObject()->GetMesh() )
+  {
+    QStringList ids = myNodes->text().split( " ", QString::SkipEmptyParts );
+    SMDS_Mesh* mesh = myActor->GetObject()->GetMesh();
+    if ( const SMDS_MeshNode* n = mesh->FindNode( ids[1].trimmed().toLong() ))
+    {
+      SMDS_ElemIteratorPtr faceIt = n->GetInverseElementIterator( SMDSAbs_Face );
+      while ( faceIt->more() )
+        if ( SMESH_MeshAlgos::FaceNormal( faceIt->next(), norm ))
+          return norm;
+    }
+  }
+  int iMinCoord = 1;
+  if ( vec10.Coord( iMinCoord ) > vec10.Y() ) iMinCoord = 2;
+  if ( vec10.Coord( iMinCoord ) > vec10.Z() ) iMinCoord = 3;
+
+  gp_Vec vec = vec10;
+  vec.SetCoord( iMinCoord, vec10.Coord( iMinCoord ) + 1. );
+
+  return vec ^ vec10;
+}
+
 /*!
   \class SMESHGUI_MeshInfoDlg
   \brief Centralized dialog box for the measurements
@@ -1323,7 +1690,7 @@ void SMESHGUI_BasicProperties::clear()
   \param page specifies the dialog page to be shown at the start-up
 */
 SMESHGUI_MeasureDlg::SMESHGUI_MeasureDlg( QWidget* parent, int page )
-: QDialog( parent )
+  : QDialog( parent )
 {
   setModal( false );
   setAttribute( Qt::WA_DeleteOnClose, true );
@@ -1349,6 +1716,9 @@ SMESHGUI_MeasureDlg::SMESHGUI_MeasureDlg( QWidget* parent, int page )
   myBasicProps = new SMESHGUI_BasicProperties( myTabWidget );
   int aBasicPropInd = myTabWidget->addTab( myBasicProps, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_BASIC_PROPS" ) ), tr( "BASIC_PROPERTIES" ) );
 
+  myAngle = new SMESHGUI_Angle( myTabWidget );
+  int aAngleInd = myTabWidget->addTab( myAngle, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_ANGLE" ) ), tr( "ANGLE" ) );
+
   // buttons
   QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this );
   okBtn->setAutoDefault( true );
@@ -1376,6 +1746,8 @@ SMESHGUI_MeasureDlg::SMESHGUI_MeasureDlg( QWidget* parent, int page )
     anInd = aMinDistInd;
   } else if ( page == BoundingBox ) {
     anInd = aBndBoxInd;
+  } else if ( page == Angle ) {
+    anInd = aAngleInd;
   } else if ( page == Length || page == Area || page == Volume ) {
     myBasicProps->setMode( (SMESHGUI_BasicProperties::Mode)(page - Length) );
     anInd = aBasicPropInd;
@@ -1444,6 +1816,8 @@ void SMESHGUI_MeasureDlg::updateSelection()
     myMinDist->updateSelection();
   else if ( myTabWidget->currentIndex() == BoundingBox )
     myBndBox->updateSelection();
+  else if ( myTabWidget->currentWidget() == myAngle )
+    myAngle->updateSelection();
   else {
     myBndBox->erasePreview();
     myBasicProps->updateSelection();
@@ -1460,6 +1834,8 @@ void SMESHGUI_MeasureDlg::help()
     aHelpFile = "measurements.html#min-distance-anchor";
   } else if ( myTabWidget->currentIndex() == BoundingBox ) {
     aHelpFile = "measurements.html#bounding-box-anchor";
+  } else if ( myTabWidget->currentWidget() == myAngle ) {
+    aHelpFile = "measurements.html#angle-anchor";
   } else {
     aHelpFile = "measurements.html#basic-properties-anchor";
   }
index cadcf1f557dcb2317025fe5f021954c585ad0ed5..3d583f06a55e4995a3bfe5cac5fa020907166d2b 100644 (file)
@@ -37,10 +37,13 @@ class SUIT_SelectionFilter;
 class SALOME_Actor;
 class SMESH_Actor;
 class SMESHGUI_IdValidator;
+class SMESHGUI_MeshEditPreview;
 
 #include <SALOMEconfig.h>
 #include CORBA_SERVER_HEADER(SMESH_Mesh)
 
+#include <gp_Vec.hxx>
+
 class SMESHGUI_EXPORT SMESHGUI_MinDistance : public QWidget
 {
   Q_OBJECT;
@@ -167,6 +170,40 @@ private:
   SUIT_SelectionFilter*     myFilter;
 };
 
+class SMESHGUI_EXPORT SMESHGUI_Angle : public QWidget
+{
+  Q_OBJECT;
+  
+public:
+
+  SMESHGUI_Angle( QWidget* = 0 );
+  ~SMESHGUI_Angle();
+
+  void deactivate();
+  void updateSelection();
+
+private slots:
+  void selectionChanged();
+  void nodesEdited();
+  void compute();
+  void clear();
+
+private:
+
+  bool addPointByActor( int id );
+  bool addPointByIDSource( int id );
+  gp_Vec getNormal(const gp_Vec& vec10 );
+
+  QLineEdit* myNodes;
+  QLineEdit* myResult;
+
+  SMESH::SMESH_IDSource_var myIDSrc;
+  SMESH_Actor*              myActor;
+
+  std::vector< SMESH::PointStruct > myPoints;
+  SMESHGUI_MeshEditPreview*         myPreview;
+};
+
 class SMESHGUI_EXPORT SMESHGUI_MeasureDlg : public QDialog
 { 
   Q_OBJECT;
@@ -180,7 +217,8 @@ public:
     BoundingBox,   //!< bounding box
     Length,        //!< length
     Area,          //!< area
-    Volume         //!< volume
+    Volume,        //!< volume
+    Angle
   };
 
   SMESHGUI_MeasureDlg( QWidget* = 0, int = MinDistance );
@@ -203,6 +241,7 @@ private:
   SMESHGUI_MinDistance* myMinDist;   
   SMESHGUI_BoundingBox* myBndBox;
   SMESHGUI_BasicProperties* myBasicProps;
+  SMESHGUI_Angle*       myAngle;
 };
 
 #endif // SMESHGUI_MEASUREMENTS_H
index 46387cc525a43016dc56f072f71ce1e329a72635..97f79382e665e0297a2886d530813271db3a26a8 100644 (file)
@@ -86,6 +86,7 @@ namespace SMESHOp {
     OpIntersectGroups        = 2061,   // MENU MESH  - INTERSECT GROUPS
     OpCutGroups              = 2062,   // MENU MESH  - CUT GROUPS
     OpGroupUnderlyingElem    = 2070,   // MENU MESH  - GROUP OF UNDERLYING ENTITIES
+    OpFaceGroupsByEdges      = 2071,   // MENU MESH  - FACE GROUPS SEPARATED by EDGES
     OpEditGroupPopup         = 2080,   // POPUP MENU - EDIT GROUP
     OpAddElemGroupPopup      = 2081,   // POPUP MENU - ADD ELEMENTS TO GROUP
     OpRemoveElemGroupPopup   = 2082,   // POPUP MENU - REMOVE ELEMENTS FROM GROUP
@@ -189,6 +190,7 @@ namespace SMESHOp {
     OpPropertiesVolume       = 5002,   // MENU MEASUREMENTS - BASIC PROPERTIES - VOLUME
     OpMinimumDistance        = 5003,   // MENU MEASUREMENTS - MINIMUM DISTANCE
     OpBoundingBox            = 5004,   // MENU MEASUREMENTS - BOUNDING BOX
+    OpAngle                  = 5005,   // MENU MEASUREMENTS - ANGLE
     // Hypothesis ---------------------//--------------------------------
     OpEditHypothesis         = 6000,   // POPUP MENU - EDIT HYPOTHESIS
     OpUnassign               = 6001,   // POPUP MENU - UNASSIGN
index b74d29e50b73237b8359e46843b9b364a6356a8d..a706037bd97b30321e412ceb40252b4a20d5abe1 100644 (file)
@@ -677,6 +677,7 @@ namespace SMESH
     if (!aStudy)
       return OK;
 
+    SUIT_ResourceMgr* resMgr;
     {
       OK = true;
       vtkRenderer *aRenderer = aViewWnd->getRenderer();
@@ -722,6 +723,10 @@ namespace SMESH
               anActor->SetVisibility(true);
               if (theAction == eDisplayOnly) aRenderer->ResetCameraClippingRange();
               aStudy->setVisibilityState(theEntry, Qtx::ShownState);
+              if (( theAction == eDisplayOnly ) &&
+                  ( resMgr = SMESHGUI::resourceMgr() ) &&
+                  ( resMgr->booleanValue( "SMESH", "fitall_on_displayonly", false )))
+                FitAll(); // PAL23615
               break;
             case eErase:
               //MESSAGE("--- erase " << anActor);
@@ -746,8 +751,16 @@ namespace SMESH
                   anActor->SetVisibility(true);
                   aStudy->setVisibilityState(theEntry, Qtx::ShownState);
                   // FitAll(); - PAL16770(Display of a group performs an automatic fit all)
-                  if (needFitAll) FitAll();
-                } else {
+                  if (( !needFitAll ) &&
+                      ( theAction == eDisplayOnly ) &&
+                      ( resMgr = SMESHGUI::resourceMgr() ))
+                  {
+                    needFitAll = resMgr->booleanValue( "SMESH", "fitall_on_displayonly", false );
+                  }
+                  if ( needFitAll )
+                    FitAll();
+                }
+                else {
                   OK = false;
                 }
               }
@@ -883,7 +896,7 @@ namespace SMESH
     SMESH_ActorProps::props()->reset();
 
     QColor
-      aHiColor = mgr->colorValue( "SMESH", "selection_object_color", Qt::white ),
+      //aHiColor = mgr->colorValue( "SMESH", "selection_object_color", Qt::white ),
       aSelColor = mgr->colorValue( "SMESH", "selection_element_color", Qt::yellow ),
       aPreColor = mgr->colorValue( "SMESH", "highlight_color", Qt::cyan );
 
@@ -923,7 +936,7 @@ namespace SMESH
         aCollection->InitTraversal();
         while ( vtkActor *anAct = aCollection->GetNextActor() ) {
           if ( SMESH_Actor *anActor = dynamic_cast<SMESH_Actor*>(anAct) ) {
-           anActor->UpdateSelectionProps();
+            anActor->UpdateSelectionProps();
           }
         }
       }
index 9605001fb82f2c06be7a3c29ae1e6f69a0415da9..0a09a43ecdc43ed1c70082ca9b3e25d4fbe2d652 100644 (file)
             <source>ICON_UNDERLYING_ELEMS</source>
             <translation>mesh_extractGroup.png</translation>
         </message>
+        <message>
+            <source>ICON_FACE_GROUPS_BY_EDGES</source>
+            <translation>mesh_face_groups_by_edges.png</translation>
+        </message>
         <message>
             <source>ICON_2D_FROM_3D</source>
             <translation>mesh_2d_from_3d.png</translation>
             <source>ICON_MEASURE_BND_BOX</source>
             <translation>mesh_bounding_box.png</translation>
         </message>
+        <message>
+            <source>ICON_MEASURE_ANGLE</source>
+            <translation>mesh_angle_measure.png</translation>
+        </message>
         <message>
             <source>ICON_SHOW</source>
             <translation>mesh_show.png</translation>
index bdb5e21d7d7a27ef6cebb02c938c0524097f7e64..41d27f5c0bdfd90daa8ba1865af31fe5c345d23f 100644 (file)
         <source>TOP_MEASURE_VOLUME</source>
         <translation>Volume</translation>
     </message>
+    <message>
+        <source>MEN_MEASURE_ANGLE</source>
+        <translation>Angle</translation>
+    </message>
+    <message>
+        <source>STB_MEASURE_ANGLE</source>
+        <translation>Measure angle defined by three nodes</translation>
+    </message>
+    <message>
+        <source>TOP_MEASURE_ANGLE</source>
+        <translation>Angle</translation>
+    </message>
     <message>
         <source>MEN_MOVE</source>
         <translation>Move Node</translation>
         <source>MEN_UNDERLYING_ELEMS</source>
         <translation>Group based on nodes of other groups</translation>
     </message>
+    <message>
+        <source>MEN_FACE_GROUPS_BY_EDGES</source>
+        <translation>Face groups separated by sharp edges</translation>
+    </message>
     <message>
         <source>MEN_UPDATE</source>
         <translation>Update</translation>
@@ -1466,6 +1482,10 @@ Please enter correct values and try again</translation>
         <source>SMESH_AUTO_DIM</source>
         <translation>Automatically define space dimension</translation>
     </message>
+    <message>
+        <source>SMESH_ZTOLERANCE</source>
+        <translation>Z tolerance</translation>
+    </message>
     <message>
         <source>SMESH_REQUIRED_GROUPS</source>
         <translation>Create groups of required entities</translation>
@@ -3608,6 +3628,10 @@ Use Display Entity menu command to show them.
         <source>STB_UNDERLYING_ELEMS</source>
         <translation>Create groups of entities basing on nodes of other groups</translation>
     </message>
+    <message>
+        <source>STB_FACE_GROUPS_BY_EDGES</source>
+        <translation>Create face groups separated by sharp edges</translation>
+    </message>
     <message>
         <source>STB_UPDATE</source>
         <translation>Update</translation>
@@ -4292,6 +4316,10 @@ Use Display Entity menu command to show them.
         <source>TOP_UNDERLYING_ELEMS</source>
         <translation>Create groups of entities basing on nodes of other groups</translation>
     </message>
+    <message>
+        <source>TOP_FACE_GROUPS_BY_EDGES</source>
+        <translation>Create groups of faces separated by sharp edges</translation>
+    </message>
     <message>
         <source>TOP_UPDATE</source>
         <translation>Update</translation>
@@ -4527,6 +4555,29 @@ It can&apos;t be deleted </translation>
         <translation>Export Fields</translation>
     </message>
 </context>
+<context>
+    <name>SMESHGUI_FaceGroupsSeparatedByEdgesDlg</name>
+    <message>
+        <source>CAPTION</source>
+        <translation>Face groups separated by sharp edges</translation>
+    </message>
+    <message>
+        <source>SHARP_ANGLE</source>
+        <translation>Sharp angle</translation>
+    </message>
+    <message>
+        <source>CREATE_EDGES</source>
+        <translation>Create edges</translation>
+    </message>
+    <message>
+        <source>USE_EXISTING_EDGES</source>
+        <translation>Use existing edges</translation>
+    </message>
+    <message>
+        <source>NB_GROUPS_CREATED</source>
+        <translation>%1 groups of faces created</translation>
+    </message>
+</context>
 <context>
     <name>SMESHGUI_OffsetDlg</name>
     <message>
@@ -4584,6 +4635,10 @@ Please, create VTK viewer and try again</translation>
         <source>PREF_SHOW_WARN</source>
         <translation>Show warning when exporting group</translation>
     </message>
+    <message>
+        <source>PREF_ZTOLERANCE</source>
+        <translation>Z tolerance for MED export</translation>
+    </message>
     <message>
         <source>PREF_GROUP_SEGMENT_LENGTH</source>
         <translation>Automatic parameters</translation>
@@ -4678,12 +4733,16 @@ Please, create VTK viewer and try again</translation>
     </message>
     <message>
         <source>PREF_DISPLAY_MODE_GROUP</source>
-        <translation>Display mode</translation>
+        <translation>Display</translation>
     </message>
     <message>
         <source>PREF_DISPLAY_MODE</source>
         <translation>Default display mode</translation>
     </message>
+    <message>
+        <source>PREF_FITALL_ON_DISPLAYONLY</source>
+        <translation>Fit All upon Show Only</translation>
+    </message>
     <message>
         <source>PREF_ELEMENTS</source>
         <translation>Elements</translation>
@@ -8065,6 +8124,21 @@ as they are of improper type:
         <translation>Compute</translation>
     </message>
 </context>
+<context>
+    <name>SMESHGUI_Angle</name>
+    <message>
+        <source>NODES_GROUP</source>
+        <translation>Three nodes</translation>
+    </message>
+    <message>
+        <source>RESULT</source>
+        <translation>Angle in degrees</translation>
+    </message>
+    <message>
+        <source>COMPUTE</source>
+        <translation>Compute</translation>
+    </message>
+</context>
 <context>
     <name>SMESHGUI_CopyMeshDlg</name>
     <message>
@@ -8121,6 +8195,10 @@ with red in the Object Browser.</translation>
         <source>BASIC_PROPERTIES</source>
         <translation>Basic Properties</translation>
     </message>
+    <message>
+        <source>ANGLE</source>
+        <translation>Angle</translation>
+    </message>
 </context>
 <context>
     <name>SMESHGUI_BoundingBox</name>
index 91f6984a343f8054b23bce2d3587a8fdf90d475d..019f57762e2202d03910ca782171f1cb672dad20 100644 (file)
@@ -45,6 +45,7 @@
 #include <IntAna_Quadric.hxx>
 #include <gp_Lin.hxx>
 #include <gp_Pln.hxx>
+#include <NCollection_DataMap.hxx>
 
 #include <limits>
 #include <numeric>
@@ -1243,11 +1244,11 @@ gp_XYZ SMESH_ElementSearcherImpl::Project(const gp_Pnt&            point,
 
   ElementBndBoxTree*& ebbTree = _ebbTree[ _elementType ];
   if ( !ebbTree )
-    ebbTree = new ElementBndBoxTree( *_mesh, _elementType );
+    ebbTree = new ElementBndBoxTree( *_mesh, _elementType, _meshPartIt );
 
   gp_XYZ p = point.XYZ();
   ElementBndBoxTree* ebbLeaf = ebbTree->getLeafAtPoint( p );
-  const Bnd_B3d* box = ebbLeaf->getBox();
+  const Bnd_B3d* box = ebbLeaf ? ebbLeaf->getBox() : ebbTree->getBox();
   double radius = ( box->CornerMax() - box->CornerMin() ).Modulus();
 
   ElementBndBoxTree::TElemSeq elems;
@@ -1476,9 +1477,9 @@ namespace
 
   //================================================================================
   /*!
-   * \brief Return of a point relative to a segment
+   * \brief Return position of a point relative to a segment
    *  \param point2D      - the point to analyze position of
-   *  \param xyVec        - end points of segments
+   *  \param segEnds      - end points of segments
    *  \param index0       - 0-based index of the first point of segment
    *  \param posToFindOut - flags of positions to detect
    *  \retval PointPos - point position
@@ -1607,46 +1608,63 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face,
   }
 
   // compute distance
-  PointPos pos = *pntPosSet.begin();
-  switch ( pos._name )
-  {
-  case POS_LEFT:
-  {
-    // point is most close to an edge
-    gp_Vec edge( xyz[ pos._index ], xyz[ pos._index+1 ]);
-    gp_Vec n1p ( xyz[ pos._index ], point  );
-    double u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge
-    // projection of the point on the edge
-    gp_XYZ proj = xyz[ pos._index ] + u * edge.XYZ();
-    if ( closestPnt ) *closestPnt = proj;
-    return point.Distance( proj );
-  }
-  case POS_RIGHT:
+
+  double minDist2 = Precision::Infinite();
+  for ( std::set< PointPos >::iterator posIt = pntPosSet.begin(); posIt != pntPosSet.end(); ++posIt)
   {
-    // point is inside the face
-    double distToFacePlane = Abs( tmpPnt.Y() );
-    if ( closestPnt )
+    PointPos pos = *posIt;
+    if ( pos._name != pntPosSet.begin()->_name )
+      break;
+    switch ( pos._name )
+    {
+    case POS_LEFT: // point is most close to an edge
+    {
+      gp_Vec edge( xyz[ pos._index ], xyz[ pos._index+1 ]);
+      gp_Vec n1p ( xyz[ pos._index ], point  );
+      double u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge
+      // projection of the point on the edge
+      gp_XYZ proj = xyz[ pos._index ] + u * edge.XYZ();
+      double dist2 = point.SquareDistance( proj );
+      if ( dist2 < minDist2 )
+      {
+        if ( closestPnt ) *closestPnt = proj;
+        minDist2 = dist2;
+      }
+      break;
+    }
+
+    case POS_RIGHT: // point is inside the face
     {
-      if ( distToFacePlane < std::numeric_limits<double>::min() ) {
-        *closestPnt = point.XYZ();
+      double distToFacePlane = Abs( tmpPnt.Y() );
+      if ( closestPnt )
+      {
+        if ( distToFacePlane < std::numeric_limits<double>::min() ) {
+          *closestPnt = point.XYZ();
+        }
+        else {
+          tmpPnt.SetY( 0 );
+          trsf.Inverted().Transforms( tmpPnt );
+          *closestPnt = tmpPnt;
+        }
       }
-      else {
-        tmpPnt.SetY( 0 );
-        trsf.Inverted().Transforms( tmpPnt );
-        *closestPnt = tmpPnt;
+      return distToFacePlane;
+    }
+
+    case POS_VERTEX: // point is most close to a node
+    {
+      double dist2 = point.SquareDistance( xyz[ pos._index ]);
+      if ( dist2 < minDist2 )
+      {
+        if ( closestPnt ) *closestPnt = xyz[ pos._index ];
+        minDist2 = dist2;
       }
+      break;
+    }
+    default:;
+      return badDistance;
     }
-    return distToFacePlane;
-  }
-  case POS_VERTEX:
-  {
-    // point is most close to a node
-    gp_Vec distVec( point, xyz[ pos._index ]);
-    return distVec.Magnitude();
-  }
-  default:;
   }
-  return badDistance;
+  return Sqrt( minDist2 );
 }
 
 //=======================================================================
@@ -1858,6 +1876,222 @@ SMESH_MeshAlgos::FindFaceInSet(const SMDS_MeshNode*    n1,
   return face;
 }
 
+//================================================================================
+/*!
+ * Return sharp edges of faces and non-manifold ones. Optionally adds existing edges.
+ */
+//================================================================================
+
+std::vector< SMESH_MeshAlgos::Edge >
+SMESH_MeshAlgos::FindSharpEdges( SMDS_Mesh* theMesh,
+                                 double     theAngle,
+                                 bool       theAddExisting )
+{
+  std::vector< Edge > resultEdges;
+  if ( !theMesh ) return resultEdges;
+
+  typedef std::pair< bool, const SMDS_MeshNode* >                            TIsSharpAndMedium;
+  typedef NCollection_DataMap< SMESH_TLink, TIsSharpAndMedium, SMESH_TLink > TLinkSharpMap;
+
+  TLinkSharpMap linkIsSharp( theMesh->NbFaces() );
+  TIsSharpAndMedium sharpMedium( true, 0 );
+  bool                 & isSharp = sharpMedium.first;
+  const SMDS_MeshNode* & nMedium = sharpMedium.second;
+
+  if ( theAddExisting )
+  {
+    for ( SMDS_EdgeIteratorPtr edgeIt = theMesh->edgesIterator(); edgeIt->more(); )
+    {
+      const SMDS_MeshElement* edge = edgeIt->next();
+      nMedium = ( edge->IsQuadratic() ) ? edge->GetNode(2) : 0;
+      linkIsSharp.Bind( SMESH_TLink( edge->GetNode(0), edge->GetNode(1)), sharpMedium );
+    }
+  }
+
+  // check angles between face normals
+
+  const double angleCos = Cos( theAngle * M_PI / 180. ), angleCos2 = angleCos * angleCos;
+  gp_XYZ norm1, norm2;
+  std::vector< const SMDS_MeshNode* > faceNodes, linkNodes(2);
+  std::vector<const SMDS_MeshElement *> linkFaces;
+
+  int nbSharp = linkIsSharp.Extent();
+  for ( SMDS_FaceIteratorPtr faceIt = theMesh->facesIterator(); faceIt->more(); )
+  {
+    const SMDS_MeshElement* face = faceIt->next();
+    size_t             nbCorners = face->NbCornerNodes();
+
+    faceNodes.assign( face->begin_nodes(), face->end_nodes() );
+    if ( faceNodes.size() == nbCorners )
+      faceNodes.resize( nbCorners * 2, 0 );
+
+    const SMDS_MeshNode* nPrev = faceNodes[ nbCorners-1 ];
+    for ( size_t i = 0; i < nbCorners; ++i )
+    {
+      SMESH_TLink link( nPrev, faceNodes[i] );
+      if ( !linkIsSharp.IsBound( link ))
+      {
+        linkNodes[0] = link.node1();
+        linkNodes[1] = link.node2();
+        linkFaces.clear();
+        theMesh->GetElementsByNodes( linkNodes, linkFaces, SMDSAbs_Face );
+
+        isSharp = false;
+        if ( linkFaces.size() > 2 )
+        {
+          isSharp = true;
+        }
+        else if ( linkFaces.size() == 2 &&
+                  FaceNormal( linkFaces[0], norm1, /*normalize=*/false ) &&
+                  FaceNormal( linkFaces[1], norm2, /*normalize=*/false ))
+        {
+          double dot = norm1 * norm2; // == cos * |norm1| * |norm2|
+          if (( dot < 0 ) == ( angleCos < 0 ))
+          {
+            double cos2 = dot * dot / norm1.SquareModulus() / norm2.SquareModulus();
+            isSharp = ( angleCos < 0 ) ? ( cos2 > angleCos2 ) : ( cos2 < angleCos2 );
+          }
+          else
+          {
+            isSharp = ( angleCos > 0 );
+          }
+        }
+        nMedium = faceNodes[( i-1+nbCorners ) % nbCorners + nbCorners ];
+
+        linkIsSharp.Bind( link, sharpMedium );
+        nbSharp += isSharp;
+      }
+
+      nPrev = faceNodes[i];
+    }
+  }
+
+  resultEdges.resize( nbSharp );
+  TLinkSharpMap::Iterator linkIsSharpIter( linkIsSharp );
+  for ( int i = 0; linkIsSharpIter.More() && i < nbSharp; linkIsSharpIter.Next() )
+  {
+    const SMESH_TLink&                link = linkIsSharpIter.Key();
+    const TIsSharpAndMedium& isSharpMedium = linkIsSharpIter.Value();
+    if ( isSharpMedium.first )
+    {
+      Edge & edge  = resultEdges[ i++ ];
+      edge._node1  = link.node1();
+      edge._node2  = link.node2();
+      edge._medium = isSharpMedium.second;
+    }
+  }
+
+  return resultEdges;
+}
+
+//================================================================================
+/*!
+ * Distribute all faces of the mesh between groups using given edges as group boundaries
+ */
+//================================================================================
+
+std::vector< std::vector< const SMDS_MeshElement* > >
+SMESH_MeshAlgos::SeparateFacesByEdges( SMDS_Mesh* theMesh, const std::vector< Edge >& theEdges )
+{
+  std::vector< std::vector< const SMDS_MeshElement* > > groups;
+  if ( !theMesh ) return groups;
+
+  // build map of face edges (SMESH_TLink) and their faces
+
+  typedef std::vector< const SMDS_MeshElement* >                    TFaceVec;
+  typedef NCollection_DataMap< SMESH_TLink, TFaceVec, SMESH_TLink > TFacesByLinks;
+  TFacesByLinks facesByLink( theMesh->NbFaces() );
+
+  std::vector< const SMDS_MeshNode* > faceNodes;
+  for ( SMDS_FaceIteratorPtr faceIt = theMesh->facesIterator(); faceIt->more(); )
+  {
+    const SMDS_MeshElement* face = faceIt->next();
+    size_t             nbCorners = face->NbCornerNodes();
+
+    faceNodes.assign( face->begin_nodes(), face->end_nodes() );
+    faceNodes.resize( nbCorners + 1 );
+    faceNodes[ nbCorners ] = faceNodes[0];
+
+    face->setIsMarked( false );
+
+    for ( size_t i = 0; i < nbCorners; ++i )
+    {
+      SMESH_TLink link( faceNodes[i], faceNodes[i+1] );
+      TFaceVec* linkFaces = facesByLink.ChangeSeek( link );
+      if ( !linkFaces )
+      {
+        linkFaces = facesByLink.Bound( link, TFaceVec() );
+        linkFaces->reserve(2);
+      }
+      linkFaces->push_back( face );
+    }
+  }
+
+  // remove the given edges from facesByLink map
+
+  for ( size_t i = 0; i < theEdges.size(); ++i )
+  {
+    SMESH_TLink link( theEdges[i]._node1, theEdges[i]._node2 );
+    facesByLink.UnBind( link );
+  }
+
+  // faces connected via links of facesByLink map form a group
+
+  while ( !facesByLink.IsEmpty() )
+  {
+    groups.push_back( TFaceVec() );
+    TFaceVec & group = groups.back();
+
+    group.push_back( TFacesByLinks::Iterator( facesByLink ).Value()[0] );
+    group.back()->setIsMarked( true );
+
+    for ( size_t iF = 0; iF < group.size(); ++iF )
+    {
+      const SMDS_MeshElement* face = group[iF];
+      size_t             nbCorners = face->NbCornerNodes();
+      faceNodes.assign( face->begin_nodes(), face->end_nodes() );
+      faceNodes.resize( nbCorners + 1 );
+      faceNodes[ nbCorners ] = faceNodes[0];
+
+      for ( size_t iN = 0; iN < nbCorners; ++iN )
+      {
+        SMESH_TLink link( faceNodes[iN], faceNodes[iN+1] );
+        if ( const TFaceVec* faces = facesByLink.Seek( link ))
+        {
+          const TFaceVec& faceNeighbors = *faces;
+          for ( size_t i = 0; i < faceNeighbors.size(); ++i )
+            if ( !faceNeighbors[i]->isMarked() )
+            {
+              group.push_back( faceNeighbors[i] );
+              faceNeighbors[i]->setIsMarked( true );
+            }
+          facesByLink.UnBind( link );
+        }
+      }
+    }
+  }
+
+  // find faces that are alone in its group; they were not in facesByLink
+
+  int nbInGroups = 0;
+  for ( size_t i = 0; i < groups.size(); ++i )
+    nbInGroups += groups[i].size();
+  if ( nbInGroups < theMesh->NbFaces() )
+  {
+    for ( SMDS_FaceIteratorPtr faceIt = theMesh->facesIterator(); faceIt->more(); )
+    {
+      const SMDS_MeshElement* face = faceIt->next();
+      if ( !face->isMarked() )
+      {
+        groups.push_back( TFaceVec() );
+        groups.back().push_back( face );
+      }
+    }
+  }
+
+  return groups;
+}
+
 //================================================================================
 /*!
  * \brief Calculate normal of a mesh face
index 3b1097a66002f67e43fb836fa4caf53d63f04e42..6a507f1b1d6fa67604d5b1cea4bde94a93693e0f 100644 (file)
@@ -198,7 +198,6 @@ namespace SMESH_MeshAlgos
   bool IsRightOrder( const SMDS_MeshElement* face,
                      const SMDS_MeshNode*    node0,
                      const SMDS_MeshNode*    node1 );
-
   /*!
    * \brief Mark elements given by SMDS_Iterator
    */
@@ -247,6 +246,29 @@ namespace SMESH_MeshAlgos
         MarkElems( (*it)->nodesIterator(), isMarked );
   }
 
+  // 2 nodes + optional medium node
+  struct Edge
+  {
+    const SMDS_MeshNode* _node1;
+    const SMDS_MeshNode* _node2;
+    const SMDS_MeshNode* _medium;
+  };
+
+  /*!
+   * Return sharp edges of faces and non-manifold ones.
+   * Optionally adds existing edges to the result. Angle is in degrees.
+   */
+  SMESHUtils_EXPORT
+  std::vector< Edge > FindSharpEdges( SMDS_Mesh* mesh,
+                                      double     angle,
+                                      bool       addExisting );
+
+  /*!
+   * Distribute all faces of the mesh between groups using given edges.
+   */
+  SMESHUtils_EXPORT
+  std::vector< std::vector< const SMDS_MeshElement* > >
+  SeparateFacesByEdges( SMDS_Mesh* mesh, const std::vector< Edge >& edges );
 
 
   typedef std::vector<const SMDS_MeshNode*> TFreeBorder;
index faefc439db2bb5716f2d4c571077b655d59a7cb7..33d5b1c786200678be1ca53797c1ff1fec26a4f0 100644 (file)
@@ -2747,8 +2747,9 @@ SMDS_Mesh* SMESH_MeshAlgos::MakeOffset( SMDS_ElemIteratorPtr theFaceIt,
       normals[i].SetCoord( 0,0,0 ); // TODO find norm by neighbors
   }
 
-  const double  tol = 1e-3 * Sqrt( minNodeDist );
   const double sign = ( theOffset < 0 ? -1 : +1 );
+  const double  tol = Min( 1e-3 * Sqrt( minNodeDist ),
+                           1e-2 * theOffset * sign );
 
   // translate new nodes by normal to input faces
   gp_XYZ newXYZ;
index cef6517ce435f1c1da81d5ff84e9eda198e69580..e76d1b34348c834654574b015197fd239b7fbb3b 100644 (file)
@@ -2478,7 +2478,7 @@ void _pyMeshEditor::Process( const Handle(_pyCommand)& theCommand)
       "MergeElements","MergeEqualElements","SewFreeBorders","SewConformFreeBorders",
       "FindCoincidentFreeBorders", "SewCoincidentFreeBorders",
       "SewBorderToSide","SewSideElements","ChangeElemNodes","GetLastCreatedNodes",
-      "GetLastCreatedElems",
+      "GetLastCreatedElems", "FaceGroupsSeparatedByEdges",
       "MirrorMakeMesh","MirrorObjectMakeMesh","TranslateMakeMesh","TranslateObjectMakeMesh",
       "Scale","ScaleMakeMesh","RotateMakeMesh","RotateObjectMakeMesh","MakeBoundaryMesh",
       "MakeBoundaryElements", "SplitVolumesIntoTetra","SplitHexahedraIntoPrisms",
index 2fcac5a7f9122551b4efb276f0f3c77fd0daf3a0..45f5f0b7fd3c60f11988d47d950e25fcd003221b 100644 (file)
@@ -346,3 +346,30 @@ SMESH::PointStruct Measurements_i::GravityCenter(SMESH::SMESH_IDSource_ptr theSo
 
   return grCenter;
 }
+
+//=======================================================================
+//function : Angle
+//purpose  : Return angle in radians defined by 3 points <(p1,p2,p3)
+//=======================================================================
+
+CORBA::Double Measurements_i::Angle(const SMESH::PointStruct& p1,
+                                    const SMESH::PointStruct& p2,
+                                    const SMESH::PointStruct& p3 )
+{
+  gp_Vec v1( p1.x - p2.x, p1.y - p2.y, p1.z - p2.z );
+  gp_Vec v2( p3.x - p2.x, p3.y - p2.y, p3.z - p2.z );
+
+  double angle = -1;
+
+  try
+  {
+    angle = v1.Angle( v2 );
+  }
+  catch(...)
+  {
+  }
+  if ( isnan( angle ))
+    angle = -1;
+
+  return angle;
+}
index bb696eb92421822a1fdb858a6349b1cb3a60a88a..3ba642ca62434912f99e5a61e3ce2ef591675993 100644 (file)
@@ -78,6 +78,13 @@ namespace SMESH
      * gravity center of the source
      */
     SMESH::PointStruct GravityCenter(SMESH::SMESH_IDSource_ptr  theSource);
+
+    /*!
+     * angle in radians defined by 3 points <(p1,p2,p3)
+     */
+    CORBA::Double Angle(const SMESH::PointStruct& p1,
+                        const SMESH::PointStruct& p2,
+                        const SMESH::PointStruct& p3 );
   };
 }
 
index 1628af333ae73581417b70eca80a566662b9c023..2e8fda89b3e2baa5565f81f6fd92a3970ee50e9a 100644 (file)
@@ -178,7 +178,7 @@ namespace MeshEditor_I {
 
   //=============================================================================
   /*!
-   * \brief Deleter of theNodeSearcher at any compute event occurred
+   * \brief Deleter of theNodeSearcher and theElementSearcher at any compute event occurred
    */
   //=============================================================================
 
@@ -381,7 +381,7 @@ namespace MeshEditor_I {
    */
   //================================================================================
 
-  string getPartIOR( SMESH::SMESH_IDSource_ptr theMeshPart, SMESH::ElementType type)
+  string getPartIOR( SMESH::SMESH_IDSource_ptr theMeshPart, SMESH::ElementType type = SMESH::ALL )
   {
     string partIOR = SMESH_Gen_i::GetORB()->object_to_string( theMeshPart );
     if ( SMESH_Group_i* group_i = SMESH::DownCast<SMESH_Group_i*>( theMeshPart ))
@@ -4652,6 +4652,68 @@ SMESH_MeshEditor_i::FindAmongElementsByPoint(SMESH::SMESH_IDSource_ptr elementID
   return 0;
 }
 
+//=======================================================================
+//function : ProjectPoint
+//purpose  : Project a point to a mesh object.
+//           Return ID of an element of given type where the given point is projected
+//           and coordinates of the projection point.
+//           In the case if nothing found, return -1 and []
+//=======================================================================
+
+CORBA::Long SMESH_MeshEditor_i::ProjectPoint(CORBA::Double             x,
+                                             CORBA::Double             y,
+                                             CORBA::Double             z,
+                                             SMESH::SMESH_IDSource_ptr meshObject,
+                                             SMESH::ElementType        type,
+                                             SMESH::double_array_out   projecton)
+  throw (SALOME::SALOME_Exception)
+{
+  if ( CORBA::is_nil( meshObject ))
+    THROW_SALOME_CORBA_EXCEPTION("NULL meshObject", SALOME::BAD_PARAM);
+
+  SMESH_TRY;
+
+  SMESH::SMESH_Mesh_var mesh = meshObject->GetMesh();
+  SMESH_Mesh_i*       mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
+  if ( mesh_i != myMesh_i )
+  {
+    SMESH::SMESH_MeshEditor_var editor=
+      myIsPreviewMode ? mesh_i->GetMeshEditPreviewer() : mesh_i->GetMeshEditor();
+    return editor->ProjectPoint( x,y,z, meshObject, type, projecton );
+  }
+
+
+  theSearchersDeleter.Set( myMesh, getPartIOR( meshObject ));
+  if ( !theElementSearcher )
+  {
+    // create a searcher from meshObject
+
+    SMDS_ElemIteratorPtr elemIt;
+    if ( ! SMESH::DownCast<SMESH_Mesh_i*>( meshObject ))
+      elemIt = myMesh_i->GetElements( meshObject, type );
+
+    theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), elemIt );
+  }
+
+  const SMDS_MeshElement* elem = 0;
+  gp_XYZ pProj = theElementSearcher->Project( gp_Pnt( x,y,z ),
+                                              SMDSAbs_ElementType( type ),
+                                              &elem );
+
+  projecton = new SMESH::double_array();
+  if ( elem && !elem->IsNull() )
+  {
+    projecton->length( 3 );
+    projecton[0] = pProj.X();
+    projecton[1] = pProj.Y();
+    projecton[2] = pProj.Z();
+    return elem->GetID();
+  }
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return -1;
+}
+
 //=======================================================================
 //function : GetPointState
 //purpose  : Return point state in a closed 2D mesh in terms of TopAbs_State enumeration.
@@ -4717,6 +4779,58 @@ CORBA::Boolean SMESH_MeshEditor_i::IsCoherentOrientation2D()
   return isGoodOri;
 }
 
+//=======================================================================
+//function : FindSharpEdges
+//purpose  : Return sharp edges of faces and non-manifold ones. Optionally add existing edges.
+//=======================================================================
+
+SMESH::ListOfEdges* SMESH_MeshEditor_i::FindSharpEdges(CORBA::Double  theAngle,
+                                                       CORBA::Boolean theAddExisting)
+  throw (SALOME::SALOME_Exception)
+{
+  SMESH::ListOfEdges_var resultEdges = new SMESH::ListOfEdges;
+  SMESH_TRY;
+
+  initData();
+
+  std::vector< SMESH_MeshAlgos::Edge > edges =
+    SMESH_MeshAlgos::FindSharpEdges( getMeshDS(), theAngle, theAddExisting );
+
+  if ( myIsPreviewMode ) // fill a preview mesh with edges
+  {
+    TPreviewMesh* mesh = getPreviewMesh( SMDSAbs_Edge );
+    SMDS_Mesh*  meshDS = mesh->GetMeshDS();
+    for ( size_t i = 0; i < edges.size(); ++i )
+    {
+      SMESH_NodeXYZ xyz1( edges[i]._node1), xyz2( edges[i]._node2);
+      SMDS_MeshNode* n1 = meshDS->AddNode( xyz1.X(), xyz1.Y(), xyz1.Z() );
+      SMDS_MeshNode* n2 = meshDS->AddNode( xyz2.X(), xyz2.Y(), xyz2.Z() );
+      if ( edges[i]._medium )
+      {
+        xyz1.Set( edges[i]._medium );
+        SMDS_MeshNode* nm = meshDS->AddNode( xyz1.X(), xyz1.Y(), xyz1.Z() );
+        mesh->GetMeshDS()->AddEdge( n1, n2, nm );
+      }
+      else
+      {
+        mesh->GetMeshDS()->AddEdge( n1, n2 );
+      }
+    }
+  }
+  else
+  {
+    resultEdges->length( edges.size() );
+    for ( size_t i = 0; i < edges.size(); ++i )
+    {
+      resultEdges[ i ].node1  = edges[i]._node1->GetID();
+      resultEdges[ i ].node2  = edges[i]._node2->GetID();
+      resultEdges[ i ].medium = edges[i]._medium ? edges[i]._medium->GetID() : 0;
+    }
+  }
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return resultEdges._retn();
+}
+
 //=======================================================================
 //function : FindFreeBorders
 //purpose  : Returns all or only closed FreeBorder's.
@@ -5562,7 +5676,7 @@ void SMESH_MeshEditor_i::dumpGroupsList(TPythonDump &               theDumpPytho
 */
 //================================================================================
 
-std::string SMESH_MeshEditor_i::generateGroupName(const std::string& thePrefix)
+std::string SMESH_MeshEditor_i::GenerateGroupName(const std::string& thePrefix)
 {
   SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
   set<std::string> groupNames;
@@ -5884,7 +5998,7 @@ SMESH_MeshEditor_i::DoubleNodeGroupNew( SMESH::SMESH_GroupBase_ptr theNodes,
     SMESH::long_array_var anIds = GetLastCreatedNodes();
     if (anIds->length() > 0) {
       std::string anUnindexedName (theNodes->GetName());
-      std::string aNewName = generateGroupName(anUnindexedName + "_double");
+      std::string aNewName = GenerateGroupName(anUnindexedName + "_double");
       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
       aNewGroup->Add(anIds);
       pyDump << aNewGroup << " = ";
@@ -5983,7 +6097,7 @@ SMESH_MeshEditor_i::DoubleNodeGroupsNew( const SMESH::ListOfGroups& theNodes,
     SMESH::long_array_var anIds = GetLastCreatedNodes();
     if (anIds->length() > 0) {
       std::string anUnindexedName (theNodes[0]->GetName());
-      std::string aNewName = generateGroupName(anUnindexedName + "_double");
+      std::string aNewName = GenerateGroupName(anUnindexedName + "_double");
       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
       aNewGroup->Add(anIds);
       pyDump << aNewGroup << " = ";
@@ -6207,7 +6321,7 @@ SMESH_MeshEditor_i::DoubleNodeElemGroup2New(SMESH::SMESH_GroupBase_ptr theElems,
   {
     // Create group with newly created elements
     CORBA::String_var elemGroupName = theElems->GetName();
-    std::string aNewName = generateGroupName( std::string(elemGroupName.in()) + "_double");
+    std::string aNewName = GenerateGroupName( std::string(elemGroupName.in()) + "_double");
     if ( !getEditor().GetLastCreatedElems().empty() && theElemGroupNeeded )
     {
       SMESH::long_array_var anIds = GetLastCreatedElems();
@@ -6439,7 +6553,7 @@ SMESH_MeshEditor_i::DoubleNodeElemGroups2New(const SMESH::ListOfGroups& theElems
   {
     // Create group with newly created elements
     CORBA::String_var elemGroupName = theElems[0]->GetName();
-    std::string aNewName = generateGroupName( std::string(elemGroupName.in()) + "_double");
+    std::string aNewName = GenerateGroupName( std::string(elemGroupName.in()) + "_double");
     if ( !getEditor().GetLastCreatedElems().empty() && theElemGroupNeeded )
     {
       SMESH::long_array_var anIds = GetLastCreatedElems();
@@ -6595,7 +6709,7 @@ SMESH_MeshEditor_i::AffectedElemGroupsInRegion( const SMESH::ListOfGroups& theEl
     if ( ivol > 0 )
     {
       aNewVolumeGroup = myMesh_i->CreateGroup(SMESH::VOLUME,
-                                              generateGroupName("affectedVolumes").c_str());
+                                              GenerateGroupName("affectedVolumes").c_str());
       aNewVolumeGroup->Add(volumeIds);
       aListOfGroups->length( nbGroups+1 );
       aListOfGroups[ nbGroups++ ] = aNewVolumeGroup._retn();
@@ -6603,7 +6717,7 @@ SMESH_MeshEditor_i::AffectedElemGroupsInRegion( const SMESH::ListOfGroups& theEl
     if ( iface > 0 )
     {
       aNewFaceGroup = myMesh_i->CreateGroup(SMESH::FACE,
-                                            generateGroupName("affectedFaces").c_str());
+                                            GenerateGroupName("affectedFaces").c_str());
       aNewFaceGroup->Add(faceIds);
       aListOfGroups->length( nbGroups+1 );
       aListOfGroups[ nbGroups++ ] = aNewFaceGroup._retn();
@@ -6611,7 +6725,7 @@ SMESH_MeshEditor_i::AffectedElemGroupsInRegion( const SMESH::ListOfGroups& theEl
     if ( iedge > 0 )
     {
       aNewEdgeGroup = myMesh_i->CreateGroup(SMESH::EDGE,
-                                            generateGroupName("affectedEdges").c_str());
+                                            GenerateGroupName("affectedEdges").c_str());
       aNewEdgeGroup->Add(edgeIds);
       aListOfGroups->length( nbGroups+1 );
       aListOfGroups[ nbGroups++ ] = aNewEdgeGroup._retn();
@@ -7162,15 +7276,15 @@ void SMESH_MeshEditor_i::MakePolyLine(SMESH::ListOfPolySegments& theSegments,
     segOut.myNode2[0] = meshDS->FindNode( segIn.node1ID2 );
     segOut.myNode1[1] = meshDS->FindNode( segIn.node2ID1 );
     segOut.myNode2[1] = meshDS->FindNode( segIn.node2ID2 );
+    segOut.myXYZ[0].SetCoord( segIn.xyz1.x,
+                              segIn.xyz1.y,
+                              segIn.xyz1.z);
+    segOut.myXYZ[1].SetCoord( segIn.xyz2.x,
+                              segIn.xyz2.y,
+                              segIn.xyz2.z);
     segOut.myVector.SetCoord( segIn.vector.PS.x,
                               segIn.vector.PS.y,
                               segIn.vector.PS.z );
-    if ( !segOut.myNode1[0] )
-      THROW_SALOME_CORBA_EXCEPTION( SMESH_Comment( "Invalid node ID: ") << segIn.node1ID1,
-                                    SALOME::BAD_PARAM );
-    if ( !segOut.myNode1[1] )
-      THROW_SALOME_CORBA_EXCEPTION( SMESH_Comment( "Invalid node ID: ") << segIn.node2ID1,
-                                    SALOME::BAD_PARAM );
   }
 
   // get a static ElementSearcher
index 44a87ba45aea27eaa79a66b0a48c8f3019acd7fc..89c730f7b1b768af52869d9372b48a10b548a4a4 100644 (file)
@@ -95,6 +95,11 @@ public:
   static bool               IsTemporaryIDSource( SMESH::SMESH_IDSource_ptr& idSource );
   static CORBA::Long*       GetTemporaryIDs( SMESH::SMESH_IDSource_ptr& idSource, int& nbIds );
 
+  /*!
+   * \brief Generates the unique group name
+   */
+  std::string GenerateGroupName(const std::string& thePrefix);
+
   CORBA::Boolean RemoveElements(const SMESH::long_array & IDsOfElements)
     throw (SALOME::SALOME_Exception);
   CORBA::Boolean RemoveNodes   (const SMESH::long_array & IDsOfNodes)
@@ -546,6 +551,20 @@ public:
                                               SMESH::ElementType        type)
     throw (SALOME::SALOME_Exception);
 
+  /*!
+   * Project a point to a mesh object.
+   * Return ID of an element of given type where the given point is projected
+   * and coordinates of the projection point.
+   * In the case if nothing found, return -1 and []
+   */
+  CORBA::Long ProjectPoint(CORBA::Double             x,
+                           CORBA::Double             y,
+                           CORBA::Double             z,
+                           SMESH::SMESH_IDSource_ptr meshObject,
+                           SMESH::ElementType        type,
+                           SMESH::double_array_out   projecton)
+    throw (SALOME::SALOME_Exception);
+
   /*!
    * Return point state in a closed 2D mesh in terms of TopAbs_State enumeration.
    * TopAbs_UNKNOWN state means that either mesh is wrong or the analysis fails.
@@ -565,6 +584,12 @@ public:
   CORBA::Boolean IsCoherentOrientation2D()
     throw (SALOME::SALOME_Exception);
 
+  /*!
+   * Return sharp edges of faces and non-manifold ones. Optionally adds existing edges.
+   */
+  SMESH::ListOfEdges* FindSharpEdges(CORBA::Double angle, CORBA::Boolean addExisting)
+    throw (SALOME::SALOME_Exception);
+
   /*!
    * Returns all or only closed FreeBorder's.
    */
@@ -959,8 +984,6 @@ public:
   void dumpGroupsList(SMESH::TPythonDump &        theDumpPython,
                       const SMESH::ListOfGroups * theGroupList);
 
-  std::string generateGroupName(const std::string& thePrefix);
-
   void prepareIdSource(SMESH::SMESH_IDSource_ptr theObject);
 
 
index e387bff170c2293c3141521ca095729a19dc152f..802186aab106fbe5927e3a90d2d6bad42bf1192c 100644 (file)
@@ -96,6 +96,7 @@ static int MYDEBUG = 0;
 
 using namespace std;
 using SMESH::TPythonDump;
+using SMESH::TVar;
 
 int SMESH_Mesh_i::_idGenerator = 0;
 
@@ -1868,6 +1869,89 @@ SMESH_Mesh_i::CreateDimGroup(const SMESH::ListOfIDSources& theGroups,
   return aResGrp._retn();
 }
 
+//================================================================================
+/*!
+ * \brief Distribute all faces of the mesh between groups using sharp edges and optionally
+ *        existing 1D elements as group boundaries.
+ *  \param [in] theSharpAngle - edge is considered sharp if an angle between normals of
+ *              adjacent faces is more than \a sharpAngle in degrees.
+ *  \param [in] theCreateEdges - to create 1D elements for detected sharp edges.
+ *  \param [in] theUseExistingEdges - to use existing edges as group boundaries
+ *  \return ListOfGroups - the created groups
+ */
+//================================================================================
+
+SMESH::ListOfGroups*
+SMESH_Mesh_i::FaceGroupsSeparatedByEdges( CORBA::Double  theSharpAngle,
+                                          CORBA::Boolean theCreateEdges,
+                                          CORBA::Boolean theUseExistingEdges )
+  throw (SALOME::SALOME_Exception)
+{
+  if ( theSharpAngle < 0 || theSharpAngle > 180 )
+    THROW_SALOME_CORBA_EXCEPTION("Invalid sharp angle, it must be between 0 and 180 degrees",
+                                 SALOME::BAD_PARAM);
+
+  SMESH::ListOfGroups_var resultGroups = new SMESH::ListOfGroups;
+
+  TPythonDump pyDump;
+
+  SMESH_TRY;
+  if ( _preMeshInfo )
+    _preMeshInfo->FullLoadFromFile();
+
+  SMESHDS_Mesh* meshDS = _impl->GetMeshDS();
+
+  std::vector< SMESH_MeshAlgos::Edge > edges =
+    SMESH_MeshAlgos::FindSharpEdges( meshDS, theSharpAngle, theUseExistingEdges );
+
+  if ( theCreateEdges )
+  {
+    std::vector<const SMDS_MeshNode *> nodes(2);
+    for ( size_t i = 0; i < edges.size(); ++i )
+    {
+      nodes[0] = edges[i]._node1;
+      nodes[1] = edges[i]._node2;
+      if ( meshDS->FindElement( nodes, SMDSAbs_Edge ))
+        continue;
+      if ( edges[i]._medium )
+        meshDS->AddEdge( edges[i]._node1, edges[i]._node2, edges[i]._medium );
+      else
+        meshDS->AddEdge( edges[i]._node1, edges[i]._node2 );
+    }
+  }
+
+  std::vector< std::vector< const SMDS_MeshElement* > > faceGroups =
+    SMESH_MeshAlgos::SeparateFacesByEdges( meshDS, edges );
+
+  SMESH::SMESH_MeshEditor_var editor = GetMeshEditor(); // create _editor
+
+  resultGroups->length( faceGroups.size() );
+  for ( size_t iG = 0; iG < faceGroups.size(); ++iG )
+  {
+    SMESH::SMESH_Group_var group = CreateGroup( SMESH::FACE,
+                                                _editor->GenerateGroupName("Group").c_str());
+    resultGroups[iG] = SMESH::SMESH_Group::_duplicate( group );
+
+    SMESHDS_GroupBase* groupBaseDS =
+      SMESH::DownCast<SMESH_GroupBase_i*>( group )->GetGroupDS();
+    SMDS_MeshGroup& groupCore = static_cast< SMESHDS_Group* >( groupBaseDS )->SMDSGroup();
+
+    std::vector< const SMDS_MeshElement* >& faces = faceGroups[ iG ];
+    for ( size_t i = 0; i < faces.size(); ++i )
+      groupCore.Add( faces[i] );
+  }
+
+  pyDump << resultGroups << " = " << SMESH::SMESH_Mesh_var(_this())
+         << ".FaceGroupsSeparatedByEdges( "
+         << TVar( theSharpAngle ) << ", "
+         << theCreateEdges << ", "
+         << theUseExistingEdges << " )";
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return resultGroups._retn();
+
+}
+
 //================================================================================
 /*!
  * \brief Remember GEOM group data
@@ -3212,7 +3296,8 @@ void SMESH_Mesh_i::ExportPartToMED(SMESH::SMESH_IDSource_ptr meshPart,
                                    CORBA::Boolean            overwrite,
                                    CORBA::Boolean            autoDimension,
                                    const GEOM::ListOfFields& fields,
-                                   const char*               geomAssocFields)
+                                   const char*               geomAssocFields,
+                                   CORBA::Double             ZTolerance)
   throw (SALOME::SALOME_Exception)
 {
   MESSAGE("MED version: "<< version);
@@ -3263,7 +3348,8 @@ void SMESH_Mesh_i::ExportPartToMED(SMESH::SMESH_IDSource_ptr meshPart,
   {
     aMeshName = prepareMeshNameAndGroups(file, overwrite);
     _impl->ExportMED( file, aMeshName.c_str(), auto_groups, version,
-                      0, autoDimension, /*addODOnVertices=*/have0dField);
+                      0, autoDimension, /*addODOnVertices=*/have0dField,
+                      ZTolerance);
     meshDS = _impl->GetMeshDS();
   }
   else
@@ -3281,7 +3367,7 @@ void SMESH_Mesh_i::ExportPartToMED(SMESH::SMESH_IDSource_ptr meshPart,
 
     SMESH_MeshPartDS* partDS = new SMESH_MeshPartDS( meshPart );
     _impl->ExportMED( file, aMeshName.c_str(), auto_groups, version,
-                      partDS, autoDimension, /*addODOnVertices=*/have0dField);
+                      partDS, autoDimension, /*addODOnVertices=*/have0dField, ZTolerance);
     meshDS = tmpDSDeleter._obj = partDS;
   }
 
@@ -3313,7 +3399,9 @@ void SMESH_Mesh_i::ExportPartToMED(SMESH::SMESH_IDSource_ptr meshPart,
                 << overwrite << ", "
                 << autoDimension << ", "
                 << goList << ", '"
-                << ( geomAssocFields ? geomAssocFields : "" ) << "'" << " )";
+                << ( geomAssocFields ? geomAssocFields : "" ) << "',"
+                << TVar( ZTolerance )
+                << " )";
 
   SMESH_CATCH( SMESH::throwCorbaException );
 }
index 41bbce48b96c2038c4cc1dfa790cd0bd738cfb1c..d06a704eb67a5547c775852f3e0882f821bfa1cc 100644 (file)
@@ -167,6 +167,10 @@ public:
                                          CORBA::Boolean                theUnderlyingOnly )
     throw (SALOME::SALOME_Exception);
 
+  SMESH::ListOfGroups* FaceGroupsSeparatedByEdges( CORBA::Double  theSharpAngle,
+                                                   CORBA::Boolean theCreateEdges,
+                                                   CORBA::Boolean theUseExistingEdges )
+    throw (SALOME::SALOME_Exception);
 
   SMESH::SMESH_Group_ptr ConvertToStandalone( SMESH::SMESH_GroupBase_ptr theGroupOn )
     throw (SALOME::SALOME_Exception);
@@ -263,7 +267,8 @@ public:
                        CORBA::Boolean            overwrite,
                        CORBA::Boolean            autoDim,
                        const GEOM::ListOfFields& fields,
-                       const char*               geomAssocFields) throw (SALOME::SALOME_Exception);
+                       const char*               geomAssocFields,
+                       CORBA::Double             ZTolerance) throw (SALOME::SALOME_Exception);
   void ExportPartToDAT(SMESH::SMESH_IDSource_ptr meshPart,
                        const char*               file) throw (SALOME::SALOME_Exception);
   void ExportPartToUNV(SMESH::SMESH_IDSource_ptr meshPart,
index 1a39b452b4e7378b542b51589fcad7ae194f24f0..35198fe5982de2249dd3d1d675afb30775877e74 100755 (executable)
@@ -1443,6 +1443,28 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ):
         aMeasurements.UnRegister()
         return pointStruct.x, pointStruct.y, pointStruct.z
 
+    def GetAngle(self, p1, p2, p3 ):
+        """
+        Computes a radian measure of an angle defined by 3 points: <(p1,p2,p3)
+
+        Parameters:            
+                p1,p2,p3: coordinates of 3 points defined by either SMESH.PointStruct 
+                          or list [x,y,z]
+
+        Returns:        
+            Angle in radians
+        """
+        if isinstance( p1, list ): p1 = PointStruct(*p1)
+        if isinstance( p2, list ): p2 = PointStruct(*p2)
+        if isinstance( p3, list ): p3 = PointStruct(*p3)
+
+        aMeasurements = self.CreateMeasurements()
+        angle = aMeasurements.Angle(p1,p2,p3)
+        aMeasurements.UnRegister()
+
+        return angle
+
+
     pass # end of class smeshBuilder
 
 import omniORB
@@ -2225,12 +2247,17 @@ class Mesh(metaclass = MeshMeta):
                         If *autoDimension* is *False*, the space dimension is always 3.
                 fields: list of GEOM fields defined on the shape to mesh.
                 geomAssocFields: each character of this string means a need to export a 
-                        corresponding field; correspondence between fields and characters is following:
+                        corresponding field; correspondence between fields and characters 
+                        is following:
 
                         - 'v' stands for "_vertices_" field;
                         - 'e' stands for "_edges_" field;
                         - 'f' stands for "_faces_" field;
                         - 's' stands for "_solids_" field.
+
+                zTolerance (float): tolerance in Z direction. If Z coordinate of a node is 
+                             close to zero within a given tolerance, the coordinate is set to zero.
+                             If *ZTolerance* is negative (default), the node coordinates are kept as is.
         """
         # process positional arguments
         #args = [i for i in args if i not in [SMESH.MED_V2_1, SMESH.MED_V2_2]] # backward compatibility
@@ -2242,6 +2269,7 @@ class Mesh(metaclass = MeshMeta):
         autoDimension   = args[5] if len(args) > 5 else True
         fields          = args[6] if len(args) > 6 else []
         geomAssocFields = args[7] if len(args) > 7 else ''
+        z_tolerance     = args[8] if len(args) > 8 else -1.
         # process keywords arguments
         auto_groups     = kwargs.get("auto_groups", auto_groups)
         minor           = kwargs.get("minor", minor)
@@ -2250,14 +2278,20 @@ class Mesh(metaclass = MeshMeta):
         autoDimension   = kwargs.get("autoDimension", autoDimension)
         fields          = kwargs.get("fields", fields)
         geomAssocFields = kwargs.get("geomAssocFields", geomAssocFields)
+        z_tolerance     = kwargs.get("zTolerance", z_tolerance)
+
         # invoke engine's function
-        if meshPart or fields or geomAssocFields:
+        if meshPart or fields or geomAssocFields or z_tolerance > 0:
             unRegister = genObjUnRegister()
             if isinstance( meshPart, list ):
                 meshPart = self.GetIDSource( meshPart, SMESH.ALL )
                 unRegister.set( meshPart )
+
+            z_tolerance,Parameters,hasVars = ParseParameters(z_tolerance)
+            self.mesh.SetParameters(Parameters)
+
             self.mesh.ExportPartToMED( meshPart, fileName, auto_groups, minor, overwrite, autoDimension,
-                                       fields, geomAssocFields)
+                                       fields, geomAssocFields, z_tolerance)
         else:
             self.mesh.ExportMED(fileName, auto_groups, minor, overwrite, autoDimension)
 
@@ -2873,6 +2907,22 @@ class Mesh(metaclass = MeshMeta):
             groups = [groups]
         return self.mesh.CreateDimGroup(groups, elemType, name, nbCommonNodes, underlyingOnly)
 
+    def FaceGroupsSeparatedByEdges( self, sharpAngle, createEdges=False, useExistingEdges=False ):
+        """
+        Distribute all faces of the mesh among groups using sharp edges and optionally
+        existing 1D elements as group boundaries.
+
+        Parameters:
+                sharpAngle: edge is considered sharp if an angle between normals of
+                            adjacent faces is more than \a sharpAngle in degrees.
+                createEdges (boolean): to create 1D elements for detected sharp edges.
+                useExistingEdges (boolean): to use existing edges as group boundaries
+        Returns:
+                ListOfGroups - the created :class:`groups <SMESH.SMESH_Group>`
+        """
+        sharpAngle,Parameters,hasVars = ParseParameters( sharpAngle )
+        self.mesh.SetParameters(Parameters)
+        return self.mesh.FaceGroupsSeparatedByEdges( sharpAngle, createEdges, useExistingEdges );
 
     def ConvertToStandalone(self, group):
         """
@@ -4228,6 +4278,17 @@ class Mesh(metaclass = MeshMeta):
         else:
             return self.editor.FindElementsByPoint(x, y, z, elementType)
 
+    def ProjectPoint(self, x,y,z, meshObject, elementType):
+        """
+        Project a point to a mesh object.
+        Return ID of an element of given type where the given point is projected
+        and coordinates of the projection point.
+        In the case if nothing found, return -1 and []
+        """
+        if ( isinstance( meshObject, Mesh )):
+            meshObject = meshObject.GetMesh()
+        return self.editor.ProjectPoint( x,y,z, meshObject, elementType )
+
     def GetPointState(self, x, y, z):
         """
         Return point state in a closed 2D mesh in terms of TopAbs_State enumeration:
@@ -4251,6 +4312,21 @@ class Mesh(metaclass = MeshMeta):
 
         return self.editor.IsCoherentOrientation2D()
 
+    def FindSharpEdges( self, angle, addExisting=False ):
+        """
+        Return sharp edges of faces and non-manifold ones.
+        Optionally add existing edges.
+
+        Parameters:
+                angle: angle (in degrees) between normals of adjacent faces to detect sharp edges
+                addExisting: to return existing edges (1D elements) as well
+
+        Returns:
+            list of FaceEdge structures
+        """
+        angle = ParseParameters( angle )[0]
+        return self.editor.FindSharpEdges( angle, addExisting )
+
     def MeshToPassThroughAPoint(self, x, y, z):
         """
         Find the node closest to a point and moves it to a point location
@@ -4525,7 +4601,7 @@ class Mesh(metaclass = MeshMeta):
 
         Parameters:
                 IDsOfElements: the faces to be splitted
-                Diag13:        is used to choose a diagonal for splitting.
+                Diag13 (boolean):        is used to choose a diagonal for splitting.
 
         Returns:
             True in case of success, False otherwise.
@@ -4541,7 +4617,7 @@ class Mesh(metaclass = MeshMeta):
         Parameters:
                 theObject: the object from which the list of elements is taken,
                         this is :class:`mesh, sub-mesh, group or filter <SMESH.SMESH_IDSource>`
-                Diag13:    is used to choose a diagonal for splitting.
+                Diag13 (boolean):    is used to choose a diagonal for splitting.
 
         Returns:
             True in case of success, False otherwise.
@@ -6654,7 +6730,7 @@ class Mesh(metaclass = MeshMeta):
     def MakePolyLine(self, segments, groupName='', isPreview=False ):
         """    
         Create a polyline consisting of 1D mesh elements each lying on a 2D element of
-        the initial mesh. Positions of new nodes are found by cutting the mesh by the
+        the initial triangle mesh. Positions of new nodes are found by cutting the mesh by the
         plane passing through pairs of points specified by each :class:`SMESH.PolySegment` structure.
         If there are several paths connecting a pair of points, the shortest path is
         selected by the module. Position of the cutting plane is defined by the two
@@ -6664,12 +6740,12 @@ class Mesh(metaclass = MeshMeta):
         The vector goes from the middle point to the projection point. In case of planar
         mesh, the vector is normal to the mesh.
 
-        *segments* [i].vector returns the used vector which goes from the middle point to its projection.
+        In preview mode, *segments* [i].vector returns the used vector which goes from the middle point to its projection.
 
-        Parameters:        
+        Parameters:
             segments: list of :class:`SMESH.PolySegment` defining positions of cutting planes.
             groupName: optional name of a group where created mesh segments will be added.
-            
+
         """    
         editor = self.editor
         if isPreview:
@@ -6772,6 +6848,20 @@ class Mesh(metaclass = MeshMeta):
             volume = self.FunctorValue(SMESH.FT_Volume3D, elemId)
         return volume
 
+    def GetAngle(self, node1, node2, node3 ):
+        """
+        Computes a radian measure of an angle defined by 3 nodes: <(node1,node2,node3)
+
+        Parameters:            
+                node1,node2,node3: IDs of the three nodes
+
+        Returns:        
+            Angle in radians
+        """
+        return self.smeshpyD.GetAngle( self.GetNodeXYZ( node1 ),
+                                       self.GetNodeXYZ( node2 ),
+                                       self.GetNodeXYZ( node3 ))
+
     def GetMaxElementLength(self, elemId):
         """
         Get maximum element length.
index 95617d10a6979ea00e6ffe0f33946fd4e7fffb80..a06fde4952fab068e6da774cedde2a2c3cc27fa9 100644 (file)
@@ -1025,7 +1025,7 @@ bool StdMeshers_QuadToTriaAdaptor::Compute(SMESH_Mesh& aMesh)
 
   if ( !myElemSearcher )
     myElemSearcher = SMESH_MeshAlgos::GetElementSearcher( *meshDS );
-  SMESH_ElementSearcher* searcher = const_cast<SMESH_ElementSearcher*>(myElemSearcher);
+  SMESH_ElementSearcher* searcher = const_cast<SMESH_ElementSearcher*>( myElemSearcher );
   SMESHUtils::Deleter<SMESH_ElementSearcher>
     volSearcher( SMESH_MeshAlgos::GetElementSearcher( *meshDS ));
   vector< const SMDS_MeshElement* > suspectFaces, foundVolumes;
@@ -1044,7 +1044,7 @@ bool StdMeshers_QuadToTriaAdaptor::Compute(SMESH_Mesh& aMesh)
     gp_Pnt PC;
     gp_Vec VNorm;
     const SMDS_MeshElement* volumes[2];
-    int what = Preparation(face, PN, VN, FNodes, PC, VNorm, volumes);
+    int what = Preparation( face, PN, VN, FNodes, PC, VNorm, volumes );
     if ( what == NOT_QUAD )
       continue;
     if ( volumes[0] && volumes[1] )
@@ -1163,7 +1163,7 @@ bool StdMeshers_QuadToTriaAdaptor::Compute(SMESH_Mesh& aMesh)
 
     if ( toFindVolumes && 0 ) // non-conformal mesh is not suitable for any mesher so far
     {
-      // there are volumes in the mesh, in a non-conformal mesh an neighbor
+      // there are volumes in the mesh, in a non-conformal mesh a neighbor
       // volume can be not found yet
       for ( int isRev = 0; isRev < 2; ++isRev )
       {
@@ -1192,7 +1192,7 @@ bool StdMeshers_QuadToTriaAdaptor::Compute(SMESH_Mesh& aMesh)
       gp_Pnt intP;
       for ( int isRev = 0; isRev < 2; ++isRev )
       {
-        if( !volumes[isRev] && HasIntersection(farPnt[isRev], PC, intP, aContour) )
+        if( !volumes[isRev] && HasIntersection( farPnt[isRev], PC, intP, aContour ))
         {
           double d = PC.Distance( intP );
           if ( d < dist2int[isRev] )
index aac2bfa4171b2db4fd451753185ebbd008428a82..157ba9e8981f449e334627b6f219986a1ca09e55 100644 (file)
@@ -159,7 +159,7 @@ bool StdMeshers_RadialPrism_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& a
   myHelper = new SMESH_MesherHelper( aMesh );
   myHelper->IsQuadraticSubMesh( aShape );
   // to delete helper at exit from Compute()
-  std::auto_ptr<SMESH_MesherHelper> helperDeleter( myHelper );
+  std::unique_ptr<SMESH_MesherHelper> helperDeleter( myHelper );
 
   // get 2 shells
   TopoDS_Solid solid = TopoDS::Solid( aShape );
index 8393e6a8b8117e7da6c4711964e569af217a4b36..3ee272dd2effdf0855cfd186999c3074bf12a4d2 100644 (file)
@@ -21,6 +21,7 @@
 #
 import salome_pluginsmanager
 import os
+from qtsalome import QIcon
 
 try:
   from spadderPlugin import runSpadderPlugin
@@ -33,9 +34,10 @@ except Exception as e:
 
 try:
   from meshcut_plugin import MeshCut
+  icon_file = os.path.join(os.getenv('SMESH_ROOT_DIR'),'share', 'salome', 'resources', 'smesh', 'mesh_plugins_meshcut.png')
   salome_pluginsmanager.AddFunction('MeshCut',
                                     'Cut a tetrahedron mesh by a plane',
-                                    MeshCut)
+                                    MeshCut, icon=QIcon(icon_file))
 
 except Exception as e:
   salome_pluginsmanager.logger.info('ERROR: MeshCut plug-in is unavailable: {}'.format(e))