Salome HOME
refs #256: 7.5.7. Quality check algorithms
authoreap <eap@opencascade.com>
Thu, 19 Oct 2017 17:01:16 +0000 (20:01 +0300)
committereap <eap@opencascade.com>
Thu, 19 Oct 2017 17:01:16 +0000 (20:01 +0300)
Implement Deflection quality control

refs #254: 7.5.5. Mesh generation for semi-analytical boundaries

Implement HoleFiller needed for NETGEN Remesher

46 files changed:
doc/salome/examples/quality_controls_defl.py [new file with mode: 0644]
doc/salome/gui/SMESH/images/deflection_2d.png [new file with mode: 0644]
doc/salome/gui/SMESH/input/about_filters.doc
doc/salome/gui/SMESH/input/about_quality_controls.doc
doc/salome/gui/SMESH/input/deflection_2d.doc [new file with mode: 0644]
doc/salome/gui/SMESH/input/selection_filter_library.doc
doc/salome/gui/SMESH/input/tui_quality_controls.doc
idl/SMESH_Filter.idl
idl/SMESH_MeshEditor.idl
resources/CMakeLists.txt
resources/StdMeshers.xml.in
resources/mesh_deflection.png [new file with mode: 0644]
resources/mesh_hide.png [new file with mode: 0644]
resources/mesh_quality.png [new file with mode: 0644]
resources/mesh_show.png [new file with mode: 0644]
resources/mesh_tree_hypo_cartesian.png [new file with mode: 0644]
resources/mesh_tree_hypo_quadratic.png [new file with mode: 0644]
src/Controls/SMESH_Controls.cxx
src/Controls/SMESH_ControlsDef.hxx
src/OBJECT/SMESH_Actor.cxx
src/OBJECT/SMESH_Actor.h
src/SMESH/SMESH_Gen.cxx
src/SMESH/SMESH_subMesh.cxx
src/SMESH/SMESH_subMesh.hxx
src/SMESHGUI/SMESHGUI.cxx
src/SMESHGUI/SMESHGUI_FilterDlg.cxx
src/SMESHGUI/SMESHGUI_MeshInfo.cxx
src/SMESHGUI/SMESHGUI_MeshInfo.h
src/SMESHGUI/SMESHGUI_MeshOp.cxx
src/SMESHGUI/SMESHGUI_Operations.h
src/SMESHGUI/SMESHGUI_Selection.cxx
src/SMESHGUI/SMESH_images.ts
src/SMESHGUI/SMESH_msg_en.ts
src/SMESHUtils/CMakeLists.txt
src/SMESHUtils/SMESH_FillHole.cxx [new file with mode: 0644]
src/SMESHUtils/SMESH_FreeBorders.cxx
src/SMESHUtils/SMESH_MeshAlgos.cxx
src/SMESHUtils/SMESH_MeshAlgos.hxx
src/SMESH_I/SMESH_2smeshpy.cxx
src/SMESH_I/SMESH_DumpPython.cxx
src/SMESH_I/SMESH_Filter_i.cxx
src/SMESH_I/SMESH_Filter_i.hxx
src/SMESH_I/SMESH_MeshEditor_i.cxx
src/SMESH_I/SMESH_MeshEditor_i.hxx
src/SMESH_SWIG/smeshBuilder.py
src/StdMeshersGUI/StdMeshers_msg_en.ts

diff --git a/doc/salome/examples/quality_controls_defl.py b/doc/salome/examples/quality_controls_defl.py
new file mode 100644 (file)
index 0000000..9105fee
--- /dev/null
@@ -0,0 +1,45 @@
+# Deflection 2D
+
+
+import salome
+salome.salome_init()
+from salome.geom import geomBuilder
+geompy = geomBuilder.New(salome.myStudy)
+
+import SMESH
+from salome.smesh import smeshBuilder
+smesh =  smeshBuilder.New(salome.myStudy)
+
+# fuse a box and a sphere
+Sphere_1 = geompy.MakeSphereR(100)
+Box_1 = geompy.MakeBoxDXDYDZ(200, 200, 200)
+Fuse = geompy.MakeFuse( Sphere_1, Box_1, theName="box + sphere" )
+
+# create a mesh
+mesh = smesh.Mesh( Fuse, "Deflection_2D")
+algo = mesh.Segment()
+algo.LocalLength(35)
+algo = mesh.Triangle()
+mesh.Compute()
+
+# get min and max deflection
+minMax = mesh.GetMinMax( SMESH.FT_Deflection2D )
+print "min and max deflection: ", minMax
+
+# get deflection of a certain face
+faceID = mesh.NbEdges() + mesh.NbFaces()
+defl = mesh.FunctorValue( SMESH.FT_Deflection2D, faceID )
+print "deflection of face %s = %s" % ( faceID, defl )
+
+margin = minMax[1] / 2
+
+# get all faces with deflection LESS than the margin
+aFilter = smesh.GetFilter(SMESH.FACE, SMESH.FT_Deflection2D, '<', margin, mesh=mesh)
+anIds = aFilter.GetIDs()
+print "%s faces have deflection less than %s" %( len(anIds), margin )
+
+# create a group of faces with deflection MORE than the margin
+aGroup = mesh.MakeGroup("Deflection > " + `margin`, SMESH.FACE, SMESH.FT_Deflection2D,'>',margin)
+print "%s faces have deflection more than %s: %s ..." %( aGroup.Size(), margin, aGroup.GetIDs()[:10] )
+
+salome.sg.updateObjBrowser(True)
diff --git a/doc/salome/gui/SMESH/images/deflection_2d.png b/doc/salome/gui/SMESH/images/deflection_2d.png
new file mode 100644 (file)
index 0000000..e69de29
index 7468931a1e4d646742db40318891272f79dcaf4b..0519da4f5cc6227ff98b2ef9d38d7d2efa7e8796 100644 (file)
@@ -7,21 +7,22 @@ specific condition or a set of conditions. Filters can be used to create
 or edit mesh groups, remove elements from the mesh, control
 mesh quality by different parameters, etc.
 
-Several criteria can be combined together by using logical operators \a
-AND and \a OR. In addition, a filter criterion can be reverted
-using logical operator \a NOT.
+Several \ref filtering_criteria "filtering criteria" can be combined
+together by using logical operators \a AND and \a OR. In addition, a
+filter criterion can be reverted using logical operator \a NOT.
 
-Some filtering criteria use the functionality of \ref quality_page "mesh quality controls"
-to filter mesh nodes / elements by specific characteristic (Area, Length, etc).
+Some filtering criteria use the functionality of \ref quality_page
+"mesh quality controls" to filter mesh nodes / elements by specific
+characteristic (Area, Length, etc).
 
 The functinality of mesh filters is available in both GUI and TUI
 modes:
 
-- In GUI, filters are available in some dialog boxes via
-"Set Filters" button, clicking on which opens the dialog box
+- In GUI, filters are available in some dialog boxes via "Set Filters"
+button, clicking on which opens the \ref filtering_elements "dialog box"
 allowing to specify the list of filter criteria to be applied to the
-current selection. See \subpage selection_filter_library_page page to learn more
-about selection filters and their usage in GUI.
+current selection. See \subpage selection_filter_library_page page to
+learn more about selection filters and their usage in GUI.
 
 - In Python scripts, filters can be used to choose only some mesh
   entities (nodes or elements) for the operations, which require the
index 9dbb5c9923cff006424fe84e3a5c4867d98aa570..84bcf0d4d71aa33f285d32a7774950801756f211 100644 (file)
@@ -37,6 +37,7 @@ Face quality controls:
 <li>\subpage bare_border_faces_page "Bare border faces"</li>
 <li>\subpage over_constrained_faces_page "Over-constrained faces"</li>
 <li>\subpage length_2d_page "Length 2D"</li>
+<li>\subpage deflection_2d_page "Deflection 2D"</li>
 <li>\subpage borders_at_multi_connection_2d_page "Borders at multi-connection 2D"</li>
 <li>\subpage area_page "Area"</li>
 <li>\subpage taper_page "Taper"</li>
diff --git a/doc/salome/gui/SMESH/input/deflection_2d.doc b/doc/salome/gui/SMESH/input/deflection_2d.doc
new file mode 100644 (file)
index 0000000..a9d38cd
--- /dev/null
@@ -0,0 +1,25 @@
+/*!
+
+\page deflection_2d_page Deflection 2D
+
+\n This quality control criterion consists of calculation of distance
+between a mesh face gravity corner and the surface the face discretizes.
+
+<em>To apply the Deflection 2D quality criterion to your mesh:</em>
+<ol>
+<li>Display your mesh in the viewer. </li>
+
+<li>Choose <b>Controls > Face Controls > Deflection 2D</b> or click
+<em>"Deflection 2D"</em> button in the toolbar. 
+
+Your mesh will be displayed in the viewer with faces colored according
+to the applied mesh quality control criterion:
+
+\image html deflection_2d.png
+</li>
+</ol>
+
+<br><b>See Also</b> a sample TUI Script of a 
+\ref tui_deflection_2d "Deflection 2D quality control" operation.  
+
+*/
index 03438c490dbea3f1504627e5a48a2a92a4c83eae..97d63ec029bad9cbdeff7c0f67826e1e075cef0e 100644 (file)
@@ -2,6 +2,10 @@
 
 \page selection_filter_library_page Selection filter library
 
+\tableofcontents
+
+\section selection_filter_library Filter library
+
 \n Selection filter library allows creating and storing in files
 the filters that can be later reused for operations on meshes. You can
 access it from the Main Menu via <b>Tools / Selection filter library</b>.
@@ -18,8 +22,7 @@ the current study. You can \b Add or \b Delete filters.
 \n In <b>Filter name</b> box you can specify the name for your
 filter. By default it is prefixed with the corresponding entity type.
 
-\anchor filtering_elements
-<h2>Filter Dialog</h2>
+\section filtering_elements Filter Dialog
 
 When we use filters during group creation or another operation (by 
 clicking <b>Set Filter</b> button in the corresponding dialog), the
@@ -64,6 +67,8 @@ in the Library.
 is no selected mesh in the Object Browser and the filter can not be
 created. You have to select the mesh and the button will be enabled.
 
+\section filtering_criteria Filtering Criteria
+
 Some criteria are applicable to all <b>Entity types</b>:
 <ul><li>
 <b>Belong to Geom</b> selects entities whose all nodes lie on the
@@ -231,6 +236,10 @@ normal to the neighboring face and the normal to the selected face is less then
 angular tolerance (defined in degrees). Selection continues among all neighbor faces of already 
 selected ones.<br>
 </li><li>
+<b>Deflection 2D</b> selects 2D mesh elements having distance between their gravity
+centers and underlying surfaces, which is more, less or equal (within a given <b>Tolerance</b>) to the predefined <b>Threshold Value</b>. See also a
+\ref deflection_2d_page "Deflection 2D quality control".
+</li><li>
 <b>Element Diameter 2D</b> selects triangles and quadrangles composed of the edges and
 diagonals with a value of length, which is more, less or equal
 (within a given <b>Tolerance</b>) to the predefined <b>Threshold Value</b>. See also a
index 1434c9b07230ba47bfc3d6ffb5905b8cdb1543cc..cb1632c1e230e95548bdb5b78763e43de4b69f54 100644 (file)
@@ -37,6 +37,9 @@
 \section tui_length_2d Length 2D
 \tui_script{quality_controls_ex11.py}
 
+\section tui_deflection_2d Deflection 2D
+\tui_script{quality_controls_defl.py}
+
 \section tui_borders_at_multiconnection_2d Borders at Multiconnection 2D
 \tui_script{quality_controls_ex12.py}
 
index f5c5645224f1ddca9e6f834c561cf345e6e560ee..d2c019379a9d59140114310445d239a5fbe48f22 100644 (file)
@@ -61,6 +61,7 @@ module SMESH
     FT_MultiConnection2D,
     FT_Length,
     FT_Length2D,
+    FT_Deflection2D,
     FT_NodeConnectivityNumber,
     FT_BelongToMeshGroup,
     FT_BelongToGeom,
@@ -150,6 +151,7 @@ module SMESH
     typedef sequence<Value> Values;
     Values GetValues();
   };
+  interface Deflection2D      : NumericalFunctor{};
   interface MultiConnection   : NumericalFunctor{};
   interface MultiConnection2D : NumericalFunctor
   {
@@ -585,6 +587,7 @@ module SMESH
     MaxElementLength3D CreateMaxElementLength3D();
     Length             CreateLength();
     Length2D           CreateLength2D();
+    Deflection2D       CreateDeflection2D();
     MultiConnection    CreateMultiConnection();
     MultiConnection2D  CreateMultiConnection2D();
     BallDiameter       CreateBallDiameter();
index 7cbe67bfff19fb3b076c7cb1f0129664fc0866f1..0a157b8ad8cd58d21950010042f8736240654348 100644 (file)
@@ -750,7 +750,31 @@ module SMESH
      * 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.
      */
-    short GetPointState(in double x, in double y, in double z) 
+    short GetPointState(in double x, in double y, in double z)
+      raises (SALOME::SALOME_Exception);
+
+    /*!
+     * Check if a 2D mesh is manifold
+     */
+    boolean IsManifold()
+      raises (SALOME::SALOME_Exception);
+
+    /*!
+     * Check if orientation of 2D elements is coherent
+     */
+    boolean IsCoherentOrientation2D()
+      raises (SALOME::SALOME_Exception);
+
+    /*!
+     * Returns all or only closed FreeBorder's.
+     */
+    ListOfFreeBorders FindFreeBorders(in boolean closedOnly)
+      raises (SALOME::SALOME_Exception);
+
+    /*!
+     * Fill with 2D elements a hole defined by a FreeBorder.
+     */
+    void FillHole(in FreeBorder hole)
       raises (SALOME::SALOME_Exception);
 
     /*!
index 9975b95b238d0e9561cdde77553f72e32020d836..6db2127ebc5281ba2d5417353c72c47b2b18e684 100755 (executable)
@@ -109,6 +109,7 @@ SET(SMESH_RESOURCES_FILES
   mesh_tree_hypo.png
   mesh_tree_hypo_segment.png
   mesh_tree_hypo_volume.png
+  mesh_tree_hypo_cartesian.png
   mesh_tree_mesh.png
   mesh_tree_importedmesh.png
   mesh_tree_mesh_warn.png
@@ -192,6 +193,7 @@ SET(SMESH_RESOURCES_FILES
   mesh_tree_hypo_source_3d_shape.png
   mesh_tree_hypo_projection_3d.png
   mesh_tree_hypo_projection_2d.png
+  mesh_tree_hypo_quadratic.png
   mesh_build_compound.png
   copy_mesh.png
   mesh_node_to_point.png
@@ -223,6 +225,10 @@ SET(SMESH_RESOURCES_FILES
   mesh_extmeth_node_offset.png
   mesh_extmeth_surf_offset_smooth.png
   mesh_extmeth_face_offset.png
+  mesh_quality.png
+  mesh_show.png
+  mesh_hide.png
+  mesh_deflection.png
 )
 
 INSTALL(FILES ${SMESH_RESOURCES_FILES} DESTINATION ${SALOME_SMESH_INSTALL_RES_DATA})
index 19b9f895a099be52c9a210a5bed7c70a2092d1d3..5a858500da2682406b1cddb619d69cb554c95c54 100644 (file)
                 label-id ="Quadratic Mesh"
                 icon-id  ="mesh_algo_quad.png"
                 dim      ="1"
-                context  ="GLOBAL"
                 auxiliary="true"/>                
 
     <hypothesis type     ="MaxElementArea"
diff --git a/resources/mesh_deflection.png b/resources/mesh_deflection.png
new file mode 100644 (file)
index 0000000..f9d8542
Binary files /dev/null and b/resources/mesh_deflection.png differ
diff --git a/resources/mesh_hide.png b/resources/mesh_hide.png
new file mode 100644 (file)
index 0000000..31c505d
Binary files /dev/null and b/resources/mesh_hide.png differ
diff --git a/resources/mesh_quality.png b/resources/mesh_quality.png
new file mode 100644 (file)
index 0000000..9a5c974
Binary files /dev/null and b/resources/mesh_quality.png differ
diff --git a/resources/mesh_show.png b/resources/mesh_show.png
new file mode 100644 (file)
index 0000000..61ebe47
Binary files /dev/null and b/resources/mesh_show.png differ
diff --git a/resources/mesh_tree_hypo_cartesian.png b/resources/mesh_tree_hypo_cartesian.png
new file mode 100644 (file)
index 0000000..d34ea42
Binary files /dev/null and b/resources/mesh_tree_hypo_cartesian.png differ
diff --git a/resources/mesh_tree_hypo_quadratic.png b/resources/mesh_tree_hypo_quadratic.png
new file mode 100644 (file)
index 0000000..6516bf8
Binary files /dev/null and b/resources/mesh_tree_hypo_quadratic.png differ
index bf8c097c0037c7ec85b048bd7f02d66fc3f6c5ff..d7087a7373346a69900bfb015a03f907dd8613c3 100644 (file)
@@ -23,6 +23,7 @@
 #include "SMESH_ControlsDef.hxx"
 
 #include "SMDS_BallElement.hxx"
+#include "SMDS_FacePosition.hxx"
 #include "SMDS_Iterator.hxx"
 #include "SMDS_Mesh.hxx"
 #include "SMDS_MeshElement.hxx"
 #include <BRepAdaptor_Surface.hxx>
 #include <BRepBndLib.hxx>
 #include <BRepBuilderAPI_Copy.hxx>
+#include <BRepClass3d_SolidClassifier.hxx>
 #include <BRepClass_FaceClassifier.hxx>
 #include <BRep_Tool.hxx>
+#include <GeomLib_IsPlanarSurface.hxx>
 #include <Geom_CylindricalSurface.hxx>
 #include <Geom_Plane.hxx>
 #include <Geom_Surface.hxx>
 #include <NCollection_Map.hxx>
 #include <Precision.hxx>
+#include <ShapeAnalysis_Surface.hxx>
 #include <TColStd_MapIteratorOfMapOfInteger.hxx>
 #include <TColStd_MapOfInteger.hxx>
 #include <TColStd_SequenceOfAsciiString.hxx>
@@ -134,7 +138,7 @@ namespace {
     //  +-----+------+  +-----+------+ 
     //  |            |  |            |
     //  |            |  |            |
-    // result sould be 2 in both cases
+    // result should be 2 in both cases
     //
     int aResult0 = 0, aResult1 = 0;
      // last node, it is a medium one in a quadratic edge
@@ -261,13 +265,10 @@ bool NumericalFunctor::GetPoints(const SMDS_MeshElement* anElem,
   }
 
   if ( anIter ) {
-    double xyz[3];
+    SMESH_NodeXYZ p;
     while( anIter->more() ) {
-      if ( const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( anIter->next() ))
-      {
-        aNode->GetXYZ( xyz );
-        theRes.push_back( gp_XYZ( xyz[0], xyz[1], xyz[2] ));
-      }
+      if ( p.Set( anIter->next() ))
+        theRes.push_back( p );
     }
   }
 
@@ -616,7 +617,8 @@ double MaxElementLength3D::GetValue( long theElementId )
       aVal = Max(aVal,Max(L7,L8));
       break;
     }
-    case SMDSEntity_Quad_Penta: { // quadratic pentas
+    case SMDSEntity_Quad_Penta:
+    /*case SMDSEntity_BiQuad_Penta:*/ { // quadratic pentas
       double L1 = getDistance(P( 1 ),P( 7 )) + getDistance(P( 7 ),P( 2 ));
       double L2 = getDistance(P( 2 ),P( 8 )) + getDistance(P( 8 ),P( 3 ));
       double L3 = getDistance(P( 3 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
@@ -1552,246 +1554,240 @@ SMDSAbs_ElementType Length::GetType() const
 */
 //================================================================================
 
-double Length2D::GetValue( long theElementId )
+double Length2D::GetValue( const TSequenceOfXYZ& P )
 {
-  TSequenceOfXYZ P;
-
-  if ( GetPoints( theElementId, P ))
-  {
-    double aVal = 0;
-    int len = P.size();
-    SMDSAbs_EntityType aType = P.getElementEntity();
+  double aVal = 0;
+  int len = P.size();
+  SMDSAbs_EntityType aType = P.getElementEntity();
 
-    switch (aType) {
-    case SMDSEntity_Edge:
-      if (len == 2)
-        aVal = getDistance( P( 1 ), P( 2 ) );
-      break;
-    case SMDSEntity_Quad_Edge:
-      if (len == 3) // quadratic edge
-        aVal = getDistance(P( 1 ),P( 3 )) + getDistance(P( 3 ),P( 2 ));
-      break;
-    case SMDSEntity_Triangle:
-      if (len == 3){ // triangles
-        double L1 = getDistance(P( 1 ),P( 2 ));
-        double L2 = getDistance(P( 2 ),P( 3 ));
-        double L3 = getDistance(P( 3 ),P( 1 ));
-        aVal = Min(L1,Min(L2,L3));
-      }
-      break;
-    case SMDSEntity_Quadrangle:
-      if (len == 4){ // quadrangles
-        double L1 = getDistance(P( 1 ),P( 2 ));
-        double L2 = getDistance(P( 2 ),P( 3 ));
-        double L3 = getDistance(P( 3 ),P( 4 ));
-        double L4 = getDistance(P( 4 ),P( 1 ));
-        aVal = Min(Min(L1,L2),Min(L3,L4));
-      }
-      break;
-    case SMDSEntity_Quad_Triangle:
-    case SMDSEntity_BiQuad_Triangle:
-      if (len >= 6){ // quadratic triangles
-        double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 ));
-        double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 ));
-        double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 1 ));
-        aVal = Min(L1,Min(L2,L3));
-      }
-      break;
-    case SMDSEntity_Quad_Quadrangle:
-    case SMDSEntity_BiQuad_Quadrangle:
-      if (len >= 8){ // quadratic quadrangles
-        double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 ));
-        double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 ));
-        double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 7 ));
-        double L4 = getDistance(P( 7 ),P( 8 )) + getDistance(P( 8 ),P( 1 ));
-        aVal = Min(Min(L1,L2),Min(L3,L4));
-      }
-      break;
-    case SMDSEntity_Tetra:
-      if (len == 4){ // tetrahedra
-        double L1 = getDistance(P( 1 ),P( 2 ));
-        double L2 = getDistance(P( 2 ),P( 3 ));
-        double L3 = getDistance(P( 3 ),P( 1 ));
-        double L4 = getDistance(P( 1 ),P( 4 ));
-        double L5 = getDistance(P( 2 ),P( 4 ));
-        double L6 = getDistance(P( 3 ),P( 4 ));
-        aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
-      }
-      break;
-    case SMDSEntity_Pyramid:
-      if (len == 5){ // piramids
-        double L1 = getDistance(P( 1 ),P( 2 ));
-        double L2 = getDistance(P( 2 ),P( 3 ));
-        double L3 = getDistance(P( 3 ),P( 4 ));
-        double L4 = getDistance(P( 4 ),P( 1 ));
-        double L5 = getDistance(P( 1 ),P( 5 ));
-        double L6 = getDistance(P( 2 ),P( 5 ));
-        double L7 = getDistance(P( 3 ),P( 5 ));
-        double L8 = getDistance(P( 4 ),P( 5 ));
-
-        aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
-        aVal = Min(aVal,Min(L7,L8));
-      }
-      break;
-    case SMDSEntity_Penta:
-      if (len == 6) { // pentaidres
-        double L1 = getDistance(P( 1 ),P( 2 ));
-        double L2 = getDistance(P( 2 ),P( 3 ));
-        double L3 = getDistance(P( 3 ),P( 1 ));
-        double L4 = getDistance(P( 4 ),P( 5 ));
-        double L5 = getDistance(P( 5 ),P( 6 ));
-        double L6 = getDistance(P( 6 ),P( 4 ));
-        double L7 = getDistance(P( 1 ),P( 4 ));
-        double L8 = getDistance(P( 2 ),P( 5 ));
-        double L9 = getDistance(P( 3 ),P( 6 ));
-
-        aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
-        aVal = Min(aVal,Min(Min(L7,L8),L9));
-      }
-      break;
-    case SMDSEntity_Hexa:
-      if (len == 8){ // hexahedron
-        double L1 = getDistance(P( 1 ),P( 2 ));
-        double L2 = getDistance(P( 2 ),P( 3 ));
-        double L3 = getDistance(P( 3 ),P( 4 ));
-        double L4 = getDistance(P( 4 ),P( 1 ));
-        double L5 = getDistance(P( 5 ),P( 6 ));
-        double L6 = getDistance(P( 6 ),P( 7 ));
-        double L7 = getDistance(P( 7 ),P( 8 ));
-        double L8 = getDistance(P( 8 ),P( 5 ));
-        double L9 = getDistance(P( 1 ),P( 5 ));
-        double L10= getDistance(P( 2 ),P( 6 ));
-        double L11= getDistance(P( 3 ),P( 7 ));
-        double L12= getDistance(P( 4 ),P( 8 ));
-
-        aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
-        aVal = Min(aVal,Min(Min(L7,L8),Min(L9,L10)));
-        aVal = Min(aVal,Min(L11,L12));
-      }
-      break;
-    case SMDSEntity_Quad_Tetra:
-      if (len == 10){ // quadratic tetraidrs
-        double L1 = getDistance(P( 1 ),P( 5 )) + getDistance(P( 5 ),P( 2 ));
-        double L2 = getDistance(P( 2 ),P( 6 )) + getDistance(P( 6 ),P( 3 ));
-        double L3 = getDistance(P( 3 ),P( 7 )) + getDistance(P( 7 ),P( 1 ));
-        double L4 = getDistance(P( 1 ),P( 8 )) + getDistance(P( 8 ),P( 4 ));
-        double L5 = getDistance(P( 2 ),P( 9 )) + getDistance(P( 9 ),P( 4 ));
-        double L6 = getDistance(P( 3 ),P( 10 )) + getDistance(P( 10 ),P( 4 ));
-        aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
-      }
-      break;
-    case SMDSEntity_Quad_Pyramid:
-      if (len == 13){ // quadratic piramids
-        double L1 = getDistance(P( 1 ),P( 6 )) + getDistance(P( 6 ),P( 2 ));
-        double L2 = getDistance(P( 2 ),P( 7 )) + getDistance(P( 7 ),P( 3 ));
-        double L3 = getDistance(P( 3 ),P( 8 )) + getDistance(P( 8 ),P( 4 ));
-        double L4 = getDistance(P( 4 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
-        double L5 = getDistance(P( 1 ),P( 10 )) + getDistance(P( 10 ),P( 5 ));
-        double L6 = getDistance(P( 2 ),P( 11 )) + getDistance(P( 11 ),P( 5 ));
-        double L7 = getDistance(P( 3 ),P( 12 )) + getDistance(P( 12 ),P( 5 ));
-        double L8 = getDistance(P( 4 ),P( 13 )) + getDistance(P( 13 ),P( 5 ));
-        aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
-        aVal = Min(aVal,Min(L7,L8));
-      }
-      break;
-    case SMDSEntity_Quad_Penta:
-      if (len == 15){ // quadratic pentaidres
-        double L1 = getDistance(P( 1 ),P( 7 )) + getDistance(P( 7 ),P( 2 ));
-        double L2 = getDistance(P( 2 ),P( 8 )) + getDistance(P( 8 ),P( 3 ));
-        double L3 = getDistance(P( 3 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
-        double L4 = getDistance(P( 4 ),P( 10 )) + getDistance(P( 10 ),P( 5 ));
-        double L5 = getDistance(P( 5 ),P( 11 )) + getDistance(P( 11 ),P( 6 ));
-        double L6 = getDistance(P( 6 ),P( 12 )) + getDistance(P( 12 ),P( 4 ));
-        double L7 = getDistance(P( 1 ),P( 13 )) + getDistance(P( 13 ),P( 4 ));
-        double L8 = getDistance(P( 2 ),P( 14 )) + getDistance(P( 14 ),P( 5 ));
-        double L9 = getDistance(P( 3 ),P( 15 )) + getDistance(P( 15 ),P( 6 ));
-        aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
-        aVal = Min(aVal,Min(Min(L7,L8),L9));
-      }
-      break;
-    case SMDSEntity_Quad_Hexa:
-    case SMDSEntity_TriQuad_Hexa:
-      if (len >= 20) { // quadratic hexaider
-        double L1 = getDistance(P( 1 ),P( 9 )) + getDistance(P( 9 ),P( 2 ));
-        double L2 = getDistance(P( 2 ),P( 10 )) + getDistance(P( 10 ),P( 3 ));
-        double L3 = getDistance(P( 3 ),P( 11 )) + getDistance(P( 11 ),P( 4 ));
-        double L4 = getDistance(P( 4 ),P( 12 )) + getDistance(P( 12 ),P( 1 ));
-        double L5 = getDistance(P( 5 ),P( 13 )) + getDistance(P( 13 ),P( 6 ));
-        double L6 = getDistance(P( 6 ),P( 14 )) + getDistance(P( 14 ),P( 7 ));
-        double L7 = getDistance(P( 7 ),P( 15 )) + getDistance(P( 15 ),P( 8 ));
-        double L8 = getDistance(P( 8 ),P( 16 )) + getDistance(P( 16 ),P( 5 ));
-        double L9 = getDistance(P( 1 ),P( 17 )) + getDistance(P( 17 ),P( 5 ));
-        double L10= getDistance(P( 2 ),P( 18 )) + getDistance(P( 18 ),P( 6 ));
-        double L11= getDistance(P( 3 ),P( 19 )) + getDistance(P( 19 ),P( 7 ));
-        double L12= getDistance(P( 4 ),P( 20 )) + getDistance(P( 20 ),P( 8 ));
-        aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
-        aVal = Min(aVal,Min(Min(L7,L8),Min(L9,L10)));
-        aVal = Min(aVal,Min(L11,L12));
-      }
-      break;
-    case SMDSEntity_Polygon:
-      if ( len > 1 ) {
-        aVal = getDistance( P(1), P( P.size() ));
-        for ( size_t i = 1; i < P.size(); ++i )
-          aVal = Min( aVal, getDistance( P( i ), P( i+1 )));
-      }
-      break;
-    case SMDSEntity_Quad_Polygon:
-      if ( len > 2 ) {
-        aVal = getDistance( P(1), P( P.size() )) + getDistance( P(P.size()), P( P.size()-1 ));
-        for ( size_t i = 1; i < P.size()-1; i += 2 )
-          aVal = Min( aVal, getDistance( P( i ), P( i+1 )) + getDistance( P( i+1 ), P( i+2 )));
-      }
-      break;
-    case SMDSEntity_Hexagonal_Prism:
-      if (len == 12) { // hexagonal prism
-        double L1 = getDistance(P( 1 ),P( 2 ));
-        double L2 = getDistance(P( 2 ),P( 3 ));
-        double L3 = getDistance(P( 3 ),P( 4 ));
-        double L4 = getDistance(P( 4 ),P( 5 ));
-        double L5 = getDistance(P( 5 ),P( 6 ));
-        double L6 = getDistance(P( 6 ),P( 1 ));
-
-        double L7 = getDistance(P( 7 ), P( 8 ));
-        double L8 = getDistance(P( 8 ), P( 9 ));
-        double L9 = getDistance(P( 9 ), P( 10 ));
-        double L10= getDistance(P( 10 ),P( 11 ));
-        double L11= getDistance(P( 11 ),P( 12 ));
-        double L12= getDistance(P( 12 ),P( 7 ));
-
-        double L13 = getDistance(P( 1 ),P( 7 ));
-        double L14 = getDistance(P( 2 ),P( 8 ));
-        double L15 = getDistance(P( 3 ),P( 9 ));
-        double L16 = getDistance(P( 4 ),P( 10 ));
-        double L17 = getDistance(P( 5 ),P( 11 ));
-        double L18 = getDistance(P( 6 ),P( 12 ));
-        aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
-        aVal = Min(aVal, Min(Min(Min(L7,L8),Min(L9,L10)),Min(L11,L12)));
-        aVal = Min(aVal, Min(Min(Min(L13,L14),Min(L15,L16)),Min(L17,L18)));
-      }
-      break;
-    case SMDSEntity_Polyhedra:
-    {
+  switch (aType) {
+  case SMDSEntity_Edge:
+    if (len == 2)
+      aVal = getDistance( P( 1 ), P( 2 ) );
+    break;
+  case SMDSEntity_Quad_Edge:
+    if (len == 3) // quadratic edge
+      aVal = getDistance(P( 1 ),P( 3 )) + getDistance(P( 3 ),P( 2 ));
+    break;
+  case SMDSEntity_Triangle:
+    if (len == 3){ // triangles
+      double L1 = getDistance(P( 1 ),P( 2 ));
+      double L2 = getDistance(P( 2 ),P( 3 ));
+      double L3 = getDistance(P( 3 ),P( 1 ));
+      aVal = Min(L1,Min(L2,L3));
     }
     break;
-    default:
-      return 0;
+  case SMDSEntity_Quadrangle:
+    if (len == 4){ // quadrangles
+      double L1 = getDistance(P( 1 ),P( 2 ));
+      double L2 = getDistance(P( 2 ),P( 3 ));
+      double L3 = getDistance(P( 3 ),P( 4 ));
+      double L4 = getDistance(P( 4 ),P( 1 ));
+      aVal = Min(Min(L1,L2),Min(L3,L4));
     }
+    break;
+  case SMDSEntity_Quad_Triangle:
+  case SMDSEntity_BiQuad_Triangle:
+    if (len >= 6){ // quadratic triangles
+      double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 ));
+      double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 ));
+      double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 1 ));
+      aVal = Min(L1,Min(L2,L3));
+    }
+    break;
+  case SMDSEntity_Quad_Quadrangle:
+  case SMDSEntity_BiQuad_Quadrangle:
+    if (len >= 8){ // quadratic quadrangles
+      double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 ));
+      double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 ));
+      double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 7 ));
+      double L4 = getDistance(P( 7 ),P( 8 )) + getDistance(P( 8 ),P( 1 ));
+      aVal = Min(Min(L1,L2),Min(L3,L4));
+    }
+    break;
+  case SMDSEntity_Tetra:
+    if (len == 4){ // tetrahedra
+      double L1 = getDistance(P( 1 ),P( 2 ));
+      double L2 = getDistance(P( 2 ),P( 3 ));
+      double L3 = getDistance(P( 3 ),P( 1 ));
+      double L4 = getDistance(P( 1 ),P( 4 ));
+      double L5 = getDistance(P( 2 ),P( 4 ));
+      double L6 = getDistance(P( 3 ),P( 4 ));
+      aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
+    }
+    break;
+  case SMDSEntity_Pyramid:
+    if (len == 5){ // pyramid
+      double L1 = getDistance(P( 1 ),P( 2 ));
+      double L2 = getDistance(P( 2 ),P( 3 ));
+      double L3 = getDistance(P( 3 ),P( 4 ));
+      double L4 = getDistance(P( 4 ),P( 1 ));
+      double L5 = getDistance(P( 1 ),P( 5 ));
+      double L6 = getDistance(P( 2 ),P( 5 ));
+      double L7 = getDistance(P( 3 ),P( 5 ));
+      double L8 = getDistance(P( 4 ),P( 5 ));
 
-    if (aVal < 0 ) {
-      return 0.;
+      aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
+      aVal = Min(aVal,Min(L7,L8));
     }
+    break;
+  case SMDSEntity_Penta:
+    if (len == 6) { // pentahedron
+      double L1 = getDistance(P( 1 ),P( 2 ));
+      double L2 = getDistance(P( 2 ),P( 3 ));
+      double L3 = getDistance(P( 3 ),P( 1 ));
+      double L4 = getDistance(P( 4 ),P( 5 ));
+      double L5 = getDistance(P( 5 ),P( 6 ));
+      double L6 = getDistance(P( 6 ),P( 4 ));
+      double L7 = getDistance(P( 1 ),P( 4 ));
+      double L8 = getDistance(P( 2 ),P( 5 ));
+      double L9 = getDistance(P( 3 ),P( 6 ));
 
-    if ( myPrecision >= 0 )
-    {
-      double prec = pow( 10., (double)( myPrecision ) );
-      aVal = floor( aVal * prec + 0.5 ) / prec;
+      aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
+      aVal = Min(aVal,Min(Min(L7,L8),L9));
     }
+    break;
+  case SMDSEntity_Hexa:
+    if (len == 8){ // hexahedron
+      double L1 = getDistance(P( 1 ),P( 2 ));
+      double L2 = getDistance(P( 2 ),P( 3 ));
+      double L3 = getDistance(P( 3 ),P( 4 ));
+      double L4 = getDistance(P( 4 ),P( 1 ));
+      double L5 = getDistance(P( 5 ),P( 6 ));
+      double L6 = getDistance(P( 6 ),P( 7 ));
+      double L7 = getDistance(P( 7 ),P( 8 ));
+      double L8 = getDistance(P( 8 ),P( 5 ));
+      double L9 = getDistance(P( 1 ),P( 5 ));
+      double L10= getDistance(P( 2 ),P( 6 ));
+      double L11= getDistance(P( 3 ),P( 7 ));
+      double L12= getDistance(P( 4 ),P( 8 ));
 
-    return aVal;
+      aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
+      aVal = Min(aVal,Min(Min(L7,L8),Min(L9,L10)));
+      aVal = Min(aVal,Min(L11,L12));
+    }
+    break;
+  case SMDSEntity_Quad_Tetra:
+    if (len == 10){ // quadratic tetrahedron
+      double L1 = getDistance(P( 1 ),P( 5 )) + getDistance(P( 5 ),P( 2 ));
+      double L2 = getDistance(P( 2 ),P( 6 )) + getDistance(P( 6 ),P( 3 ));
+      double L3 = getDistance(P( 3 ),P( 7 )) + getDistance(P( 7 ),P( 1 ));
+      double L4 = getDistance(P( 1 ),P( 8 )) + getDistance(P( 8 ),P( 4 ));
+      double L5 = getDistance(P( 2 ),P( 9 )) + getDistance(P( 9 ),P( 4 ));
+      double L6 = getDistance(P( 3 ),P( 10 )) + getDistance(P( 10 ),P( 4 ));
+      aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
+    }
+    break;
+  case SMDSEntity_Quad_Pyramid:
+    if (len == 13){ // quadratic pyramid
+      double L1 = getDistance(P( 1 ),P( 6 )) + getDistance(P( 6 ),P( 2 ));
+      double L2 = getDistance(P( 2 ),P( 7 )) + getDistance(P( 7 ),P( 3 ));
+      double L3 = getDistance(P( 3 ),P( 8 )) + getDistance(P( 8 ),P( 4 ));
+      double L4 = getDistance(P( 4 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
+      double L5 = getDistance(P( 1 ),P( 10 )) + getDistance(P( 10 ),P( 5 ));
+      double L6 = getDistance(P( 2 ),P( 11 )) + getDistance(P( 11 ),P( 5 ));
+      double L7 = getDistance(P( 3 ),P( 12 )) + getDistance(P( 12 ),P( 5 ));
+      double L8 = getDistance(P( 4 ),P( 13 )) + getDistance(P( 13 ),P( 5 ));
+      aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
+      aVal = Min(aVal,Min(L7,L8));
+    }
+    break;
+  case SMDSEntity_Quad_Penta:
+    //case SMDSEntity_BiQuad_Penta:
+    if (len >= 15){ // quadratic pentahedron
+      double L1 = getDistance(P( 1 ),P( 7 )) + getDistance(P( 7 ),P( 2 ));
+      double L2 = getDistance(P( 2 ),P( 8 )) + getDistance(P( 8 ),P( 3 ));
+      double L3 = getDistance(P( 3 ),P( 9 )) + getDistance(P( 9 ),P( 1 ));
+      double L4 = getDistance(P( 4 ),P( 10 )) + getDistance(P( 10 ),P( 5 ));
+      double L5 = getDistance(P( 5 ),P( 11 )) + getDistance(P( 11 ),P( 6 ));
+      double L6 = getDistance(P( 6 ),P( 12 )) + getDistance(P( 12 ),P( 4 ));
+      double L7 = getDistance(P( 1 ),P( 13 )) + getDistance(P( 13 ),P( 4 ));
+      double L8 = getDistance(P( 2 ),P( 14 )) + getDistance(P( 14 ),P( 5 ));
+      double L9 = getDistance(P( 3 ),P( 15 )) + getDistance(P( 15 ),P( 6 ));
+      aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
+      aVal = Min(aVal,Min(Min(L7,L8),L9));
+    }
+    break;
+  case SMDSEntity_Quad_Hexa:
+  case SMDSEntity_TriQuad_Hexa:
+    if (len >= 20) { // quadratic hexahedron
+      double L1 = getDistance(P( 1 ),P( 9 )) + getDistance(P( 9 ),P( 2 ));
+      double L2 = getDistance(P( 2 ),P( 10 )) + getDistance(P( 10 ),P( 3 ));
+      double L3 = getDistance(P( 3 ),P( 11 )) + getDistance(P( 11 ),P( 4 ));
+      double L4 = getDistance(P( 4 ),P( 12 )) + getDistance(P( 12 ),P( 1 ));
+      double L5 = getDistance(P( 5 ),P( 13 )) + getDistance(P( 13 ),P( 6 ));
+      double L6 = getDistance(P( 6 ),P( 14 )) + getDistance(P( 14 ),P( 7 ));
+      double L7 = getDistance(P( 7 ),P( 15 )) + getDistance(P( 15 ),P( 8 ));
+      double L8 = getDistance(P( 8 ),P( 16 )) + getDistance(P( 16 ),P( 5 ));
+      double L9 = getDistance(P( 1 ),P( 17 )) + getDistance(P( 17 ),P( 5 ));
+      double L10= getDistance(P( 2 ),P( 18 )) + getDistance(P( 18 ),P( 6 ));
+      double L11= getDistance(P( 3 ),P( 19 )) + getDistance(P( 19 ),P( 7 ));
+      double L12= getDistance(P( 4 ),P( 20 )) + getDistance(P( 20 ),P( 8 ));
+      aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
+      aVal = Min(aVal,Min(Min(L7,L8),Min(L9,L10)));
+      aVal = Min(aVal,Min(L11,L12));
+    }
+    break;
+  case SMDSEntity_Polygon:
+    if ( len > 1 ) {
+      aVal = getDistance( P(1), P( P.size() ));
+      for ( size_t i = 1; i < P.size(); ++i )
+        aVal = Min( aVal, getDistance( P( i ), P( i+1 )));
+    }
+    break;
+  case SMDSEntity_Quad_Polygon:
+    if ( len > 2 ) {
+      aVal = getDistance( P(1), P( P.size() )) + getDistance( P(P.size()), P( P.size()-1 ));
+      for ( size_t i = 1; i < P.size()-1; i += 2 )
+        aVal = Min( aVal, getDistance( P( i ), P( i+1 )) + getDistance( P( i+1 ), P( i+2 )));
+    }
+    break;
+  case SMDSEntity_Hexagonal_Prism:
+    if (len == 12) { // hexagonal prism
+      double L1 = getDistance(P( 1 ),P( 2 ));
+      double L2 = getDistance(P( 2 ),P( 3 ));
+      double L3 = getDistance(P( 3 ),P( 4 ));
+      double L4 = getDistance(P( 4 ),P( 5 ));
+      double L5 = getDistance(P( 5 ),P( 6 ));
+      double L6 = getDistance(P( 6 ),P( 1 ));
+
+      double L7 = getDistance(P( 7 ), P( 8 ));
+      double L8 = getDistance(P( 8 ), P( 9 ));
+      double L9 = getDistance(P( 9 ), P( 10 ));
+      double L10= getDistance(P( 10 ),P( 11 ));
+      double L11= getDistance(P( 11 ),P( 12 ));
+      double L12= getDistance(P( 12 ),P( 7 ));
+
+      double L13 = getDistance(P( 1 ),P( 7 ));
+      double L14 = getDistance(P( 2 ),P( 8 ));
+      double L15 = getDistance(P( 3 ),P( 9 ));
+      double L16 = getDistance(P( 4 ),P( 10 ));
+      double L17 = getDistance(P( 5 ),P( 11 ));
+      double L18 = getDistance(P( 6 ),P( 12 ));
+      aVal = Min(Min(Min(L1,L2),Min(L3,L4)),Min(L5,L6));
+      aVal = Min(aVal, Min(Min(Min(L7,L8),Min(L9,L10)),Min(L11,L12)));
+      aVal = Min(aVal, Min(Min(Min(L13,L14),Min(L15,L16)),Min(L17,L18)));
+    }
+    break;
+  case SMDSEntity_Polyhedra:
+  {
+  }
+  break;
+  default:
+    return 0;
+  }
 
+  if (aVal < 0 ) {
+    return 0.;
   }
-  return 0.;
+
+  if ( myPrecision >= 0 )
+  {
+    double prec = pow( 10., (double)( myPrecision ) );
+    aVal = floor( aVal * prec + 0.5 ) / prec;
+  }
+
+  return aVal;
 }
 
 double Length2D::GetBadRate( double Value, int /*nbNodes*/ ) const
@@ -1906,6 +1902,97 @@ void Length2D::GetValues(TValues& theValues)
   }
 }
 
+//================================================================================
+/*
+  Class       : Deflection2D
+  Description : Functor for calculating number of faces conneted to the edge
+*/
+//================================================================================
+
+double Deflection2D::GetValue( const TSequenceOfXYZ& P )
+{
+  if ( myMesh && P.getElement() )
+  {
+    // get underlying surface
+    if ( myShapeIndex != P.getElement()->getshapeId() )
+    {
+      mySurface.Nullify();
+      myShapeIndex = P.getElement()->getshapeId();
+      const TopoDS_Shape& S =
+        static_cast< const SMESHDS_Mesh* >( myMesh )->IndexToShape( myShapeIndex );
+      if ( !S.IsNull() && S.ShapeType() == TopAbs_FACE )
+      {
+        mySurface = new ShapeAnalysis_Surface( BRep_Tool::Surface( TopoDS::Face( S )));
+
+        GeomLib_IsPlanarSurface isPlaneCheck( mySurface->Surface() );
+        if ( isPlaneCheck.IsPlanar() )
+          myPlane.reset( new gp_Pln( isPlaneCheck.Plan() ));
+        else
+          myPlane.reset();
+      }
+    }
+    // project gravity center to the surface
+    if ( !mySurface.IsNull() )
+    {
+      gp_XYZ gc(0,0,0);
+      gp_XY  uv(0,0);
+      int nbUV = 0;
+      for ( size_t i = 0; i < P.size(); ++i )
+      {
+        gc += P(i+1);
+
+        if ( const SMDS_FacePosition* fPos = dynamic_cast<const SMDS_FacePosition*>
+             ( P.getElement()->GetNode( i )->GetPosition() ))
+        {
+          uv.ChangeCoord(1) += fPos->GetUParameter();
+          uv.ChangeCoord(2) += fPos->GetVParameter();
+          ++nbUV;
+        }
+      }
+      gc /= P.size();
+      if ( nbUV ) uv /= nbUV;
+
+      double maxLen = MaxElementLength2D().GetValue( P );
+      double    tol = 1e-3 * maxLen;
+      double dist;
+      if ( myPlane )
+      {
+        dist = myPlane->Distance( gc );
+        if ( dist < tol )
+          dist = 0;
+      }
+      else
+      {
+        if ( uv.X() != 0 && uv.Y() != 0 ) // faster way
+          mySurface->NextValueOfUV( uv, gc, tol, 0.5 * maxLen );
+        else
+          mySurface->ValueOfUV( gc, tol );
+        dist = mySurface->Gap();
+      }
+      return Round( dist );
+    }
+  }
+  return 0;
+}
+
+void Deflection2D::SetMesh( const SMDS_Mesh* theMesh )
+{
+  NumericalFunctor::SetMesh( dynamic_cast<const SMESHDS_Mesh* >( theMesh ));
+  myShapeIndex = -100;
+  myPlane.reset();
+}
+
+SMDSAbs_ElementType Deflection2D::GetType() const
+{
+  return SMDSAbs_Face;
+}
+
+double Deflection2D::GetBadRate( double Value, int /*nbNodes*/ ) const
+{
+  // meaningless as it is not quality control functor
+  return Value;
+}
+
 //================================================================================
 /*
   Class       : MultiConnection
@@ -2650,7 +2737,7 @@ bool FreeFaces::IsSatisfy( long theId )
   for ( ; volItr != volEnd; ++volItr )
     if ( (*volItr).second >= nbNode )
        nbVol++;
-  // face is not free if number of volumes constructed on thier nodes more than one
+  // face is not free if number of volumes constructed on their nodes more than one
   return (nbVol < 2);
 }
 
@@ -2698,7 +2785,7 @@ SMDSAbs_ElementType LinearOrQuadratic::GetType() const
 //================================================================================
 /*
   Class       : GroupColor
-  Description : Functor for check color of group to whic mesh element belongs to
+  Description : Functor for check color of group to which mesh element belongs to
 */
 //================================================================================
 
@@ -4287,6 +4374,7 @@ void ElementsOnShape::SetShape (const TopoDS_Shape&       theShape,
 
   if ( shapeChanges )
   {
+    // find most complex shapes
     TopTools_IndexedMapOfShape shapesMap;
     TopAbs_ShapeEnum shapeTypes[4] = { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE, TopAbs_VERTEX };
     TopExp_Explorer sub;
@@ -4329,10 +4417,18 @@ void ElementsOnShape::clearClassifiers()
 
 bool ElementsOnShape::IsSatisfy( long elemId )
 {
-  const SMDS_Mesh*        mesh = myMeshModifTracer.GetMesh();
-  const SMDS_MeshElement* elem =
-    ( myType == SMDSAbs_Node ? mesh->FindNode( elemId ) : mesh->FindElement( elemId ));
-  if ( !elem || myClassifiers.empty() )
+  if ( myClassifiers.empty() )
+    return false;
+
+  const SMDS_Mesh* mesh = myMeshModifTracer.GetMesh();
+  if ( myType == SMDSAbs_Node )
+    return IsSatisfy( mesh->FindNode( elemId ));
+  return IsSatisfy( mesh->FindElement( elemId ));
+}
+
+bool ElementsOnShape::IsSatisfy (const SMDS_MeshElement* elem)
+{
+  if ( !elem )
     return false;
 
   bool isSatisfy = myAllNodesFlag, isNodeOut;
@@ -4396,6 +4492,60 @@ bool ElementsOnShape::IsSatisfy( long elemId )
   return isSatisfy;
 }
 
+bool ElementsOnShape::IsSatisfy (const SMDS_MeshNode* node,
+                                 TopoDS_Shape*        okShape)
+{
+  if ( !node )
+    return false;
+
+  if ( !myOctree && myClassifiers.size() > 5 )
+  {
+    myWorkClassifiers.resize( myClassifiers.size() );
+    for ( size_t i = 0; i < myClassifiers.size(); ++i )
+      myWorkClassifiers[ i ] = & myClassifiers[ i ];
+    myOctree = new OctreeClassifier( myWorkClassifiers );
+  }
+
+  bool isNodeOut = true;
+
+  if ( okShape || !getNodeIsOut( node, isNodeOut ))
+  {
+    SMESH_NodeXYZ aPnt = node;
+    if ( myOctree )
+    {
+      myWorkClassifiers.clear();
+      myOctree->GetClassifiersAtPoint( aPnt, myWorkClassifiers );
+
+      for ( size_t i = 0; i < myWorkClassifiers.size(); ++i )
+        myWorkClassifiers[i]->SetChecked( false );
+
+      for ( size_t i = 0; i < myWorkClassifiers.size(); ++i )
+        if ( !myWorkClassifiers[i]->IsChecked() &&
+             !myWorkClassifiers[i]->IsOut( aPnt ))
+        {
+          isNodeOut = false;
+          if ( okShape )
+            *okShape = myWorkClassifiers[i]->Shape();
+          break;
+        }
+    }
+    else
+    {
+      for ( size_t i = 0; i < myClassifiers.size(); ++i )
+        if ( !myClassifiers[i].IsOut( aPnt ))
+        {
+          isNodeOut = false;
+          if ( okShape )
+            *okShape = myWorkClassifiers[i]->Shape();
+          break;
+        }
+    }
+    setNodeIsOut( node, isNodeOut );
+  }
+
+  return !isNodeOut;
+}
+
 void ElementsOnShape::Classifier::Init( const TopoDS_Shape& theShape,
                                         double              theTol,
                                         const Bnd_B3d*      theBox )
@@ -4493,7 +4643,7 @@ bool ElementsOnShape::Classifier::isOutOfFace  (const gp_Pnt& p)
   if ( myProjFace.IsDone() && myProjFace.LowerDistance() <= myTol )
   {
     // check relatively to the face
-    Quantity_Parameter u, v;
+    Standard_Real u, v;
     myProjFace.LowerDistanceParameters(u, v);
     gp_Pnt2d aProjPnt (u, v);
     BRepClass_FaceClassifier aClsf ( TopoDS::Face( myShape ), aProjPnt, myTol );
index 830d43b81b4d9777bcc6f5ebd34100167283ea97..452b27a39216186bc307386159484f824f34b9ca 100644 (file)
@@ -27,7 +27,6 @@
 
 #include "SMESH_TypeDefs.hxx"
 
-#include <BRepClass3d_SolidClassifier.hxx>
 #include <Bnd_B3d.hxx>
 #include <GeomAPI_ProjectPointOnCurve.hxx>
 #include <GeomAPI_ProjectPointOnSurf.hxx>
@@ -54,6 +53,9 @@ class SMESHDS_Mesh;
 class SMESHDS_SubMesh;
 class SMESHDS_GroupBase;
 
+class BRepClass3d_SolidClassifier;
+class ShapeAnalysis_Surface;
+class gp_Pln;
 class gp_Pnt;
 
 namespace SMESH{
@@ -293,7 +295,7 @@ namespace SMESH{
     */
     class SMESHCONTROLS_EXPORT Length2D: public virtual NumericalFunctor{
     public:
-      virtual double GetValue( long theElementId );
+      virtual double GetValue( const TSequenceOfXYZ& thePoints );
       virtual double GetBadRate( double Value, int nbNodes ) const;
       virtual SMDSAbs_ElementType GetType() const;
       struct Value{
@@ -307,6 +309,22 @@ namespace SMESH{
     };
     typedef boost::shared_ptr<Length2D> Length2DPtr;
 
+    /*
+      Class       : Deflection2D
+      Description : Functor for calculating distance between a face and geometry
+    */
+    class SMESHCONTROLS_EXPORT Deflection2D: public virtual NumericalFunctor{
+    public:
+      virtual void   SetMesh( const SMDS_Mesh* theMesh );
+      virtual double GetValue( const TSequenceOfXYZ& thePoints );
+      virtual double GetBadRate( double Value, int nbNodes ) const;
+      virtual SMDSAbs_ElementType GetType() const;
+    private:
+      Handle(ShapeAnalysis_Surface) mySurface;
+      int                           myShapeIndex;
+      boost::shared_ptr<gp_Pln>     myPlane;
+    };
+
     /*
       Class       : MultiConnection
       Description : Functor for calculating number of faces connected to the edge
@@ -902,6 +920,8 @@ namespace SMESH{
       bool    GetAllNodes() const { return myAllNodesFlag; }
       void    SetShape (const TopoDS_Shape& theShape,
                         const SMDSAbs_ElementType theType);
+      bool    IsSatisfy (const SMDS_MeshElement* elem);
+      bool    IsSatisfy (const SMDS_MeshNode* node, TopoDS_Shape* okShape=0);
 
     private:
 
@@ -1041,7 +1061,7 @@ namespace SMESH{
 
     /*
       Class       : GroupColor
-      Description : Functor for check color of group to whic mesh element belongs to
+      Description : Functor for check color of group to which mesh element belongs to
     */
     class SMESHCONTROLS_EXPORT GroupColor: public virtual Predicate{
     public:
index 5c2e918ab00908321c1b5a94d495cea394842f48..b011a74129785265cc0a49e728e7bf55af3570a8 100644 (file)
@@ -841,11 +841,9 @@ void SMESH_ActorDef::SetControlMode( eControl theMode, bool theCheckEntityMode )
       break;
     }
     case eLength2D:
-    {
       myFunctor.reset(new SMESH::Controls::Length2D());
       myControlActor = my2DActor;
       break;
-    }
     case eFreeBorders:
       myFunctor.reset(new SMESH::Controls::FreeBorders());
       myControlActor = my1DActor;
@@ -955,6 +953,14 @@ void SMESH_ActorDef::SetControlMode( eControl theMode, bool theCheckEntityMode )
       myControlActor = my3DActor;
       break;
     }
+    case eDeflection2D:
+    {
+      SMESH::Controls::Deflection2D* aControl = new SMESH::Controls::Deflection2D();
+      aControl->SetPrecision( myControlsPrecision );
+      myFunctor.reset( aControl );
+      myControlActor = my2DActor;
+      break;
+    }
     case eBareBorderVolume:
     {
       myFunctor.reset(new SMESH::Controls::BareBorderVolume());
index f49d55cbbbe27377753c29b53f0f2e654627ffa7..e8818e4d50b344f94edbb1feef52b8383d1c4e75 100644 (file)
@@ -141,7 +141,7 @@ class SMESHOBJECT_EXPORT SMESH_Actor: public SALOME_Actor
   virtual void SetFacesOrientation3DVectors(bool theState) = 0;
   virtual bool GetFacesOrientation3DVectors() = 0;
 
-  enum eControl{eNone, eLength, eLength2D, eFreeBorders, eFreeEdges, eFreeNodes,
+  enum eControl{eNone, eLength, eLength2D, eDeflection2D, eFreeBorders, eFreeEdges, eFreeNodes,
                 eFreeFaces, eMultiConnection, eArea, eTaper, eAspectRatio,
                 eMinimumAngle, eWarping, eSkew, eAspectRatio3D, eMultiConnection2D, eVolume3D,
                 eMaxElementLength2D, eMaxElementLength3D, eBareBorderFace, eBareBorderVolume,
index 752b5f6ebaded468801dc43866724e1972e05ace..bd5654c89588eb1bd05ddde3ae963e978e7cd8eb 100644 (file)
@@ -73,6 +73,19 @@ SMESH_Gen::SMESH_Gen()
   //vtkDebugLeaks::SetExitError(0);
 }
 
+namespace
+{
+  // a structure used to nullify SMESH_Gen field of SMESH_Hypothesis,
+  // which is needed for SMESH_Hypothesis not deleted before ~SMESH_Gen()
+  struct _Hyp : public SMESH_Hypothesis
+  {
+    void NullifyGen()
+    {
+      _gen = 0;
+    }
+  };
+}
+
 //=============================================================================
 /*!
  * Destructor
@@ -84,9 +97,16 @@ SMESH_Gen::~SMESH_Gen()
   std::map < int, StudyContextStruct * >::iterator i_sc = _mapStudyContext.begin();
   for ( ; i_sc != _mapStudyContext.end(); ++i_sc )
   {
-    delete i_sc->second->myDocument;
-    delete i_sc->second;
-  }  
+    StudyContextStruct* context = i_sc->second;
+    std::map < int, SMESH_Hypothesis * >::iterator i_hyp = context->mapHypothesis.begin();
+    for ( ; i_hyp != context->mapHypothesis.end(); ++i_hyp )
+    {
+      if ( _Hyp* h = static_cast< _Hyp*>( i_hyp->second ))
+        h->NullifyGen();
+    }
+    delete context->myDocument;
+    delete context;
+  }
 }
 
 //=============================================================================
@@ -148,6 +168,8 @@ bool SMESH_Gen::Compute(SMESH_Mesh &          aMesh,
   // one face only.
   SMESH_subMesh::compute_event computeEvent =
     aShapeOnly ? SMESH_subMesh::COMPUTE_SUBMESH : SMESH_subMesh::COMPUTE;
+  if ( !aMesh.HasShapeToMesh() )
+    computeEvent = SMESH_subMesh::COMPUTE_NOGEOM; // if several algos and no geometry
 
   if ( anUpward ) // is called from the below code in this method
   {
@@ -584,7 +606,6 @@ bool SMESH_Gen::Evaluate(SMESH_Mesh &          aMesh,
     ret = Evaluate( aMesh, aShape, aResMap, /*anUpward=*/true, aShapesId );
   }
 
-  MESSAGE( "VSR - SMESH_Gen::Evaluate() finished, OK = " << ret);
   return ret;
 }
 
@@ -1058,7 +1079,8 @@ SMESH_Algo *SMESH_Gen::GetAlgo(SMESH_subMesh * aSubMesh,
   SMESH_Mesh&          aMesh  = *aSubMesh->GetFather();
 
   SMESH_HypoFilter filter( SMESH_HypoFilter::IsAlgo() );
-  filter.And( filter.IsApplicableTo( aShape ));
+  if ( aMesh.HasShapeToMesh() )
+    filter.And( filter.IsApplicableTo( aShape ));
 
   typedef SMESH_Algo::Features AlgoData;
 
@@ -1166,7 +1188,7 @@ int SMESH_Gen::GetShapeDim(const TopAbs_ShapeEnum & aShapeType)
 
 //=============================================================================
 /*!
- * Genarate a new id unique withing this Gen
+ * Genarate a new id unique within this Gen
  */
 //=============================================================================
 
index 19f10229a442b7929e16a2c930e80312d21541e1..22fa65b99d5e44273d574cf5b00fe4a95e25ecce 100644 (file)
 
 using namespace std;
 
+#ifdef _DEBUG_
+// enable printing algo + shape id + hypo used while meshing
+//#define PRINT_WHO_COMPUTE_WHAT
+#endif
+
 //=============================================================================
 /*!
  * \brief Allocate some memory at construction and release it at destruction.
@@ -488,7 +493,7 @@ const TopoDS_Shape & SMESH_subMesh::GetSubShape() const
 //=======================================================================
 //function : CanAddHypothesis
 //purpose  : return true if theHypothesis can be attached to me:
-//           its dimention is checked
+//           its dimension is checked
 //=======================================================================
 
 bool SMESH_subMesh::CanAddHypothesis(const SMESH_Hypothesis* theHypothesis) const
@@ -510,7 +515,20 @@ bool SMESH_subMesh::CanAddHypothesis(const SMESH_Hypothesis* theHypothesis) cons
 
 //=======================================================================
 //function : IsApplicableHypotesis
-//purpose  :
+//purpose  : check if this sub-mesh can be computed using a hypothesis
+//=======================================================================
+
+bool SMESH_subMesh::IsApplicableHypotesis(const SMESH_Hypothesis* theHypothesis) const
+{
+  if ( !_father->HasShapeToMesh() && _subShape.ShapeType() == TopAbs_SOLID )
+    return true; // true for the PseudoShape
+
+  return IsApplicableHypotesis( theHypothesis, _subShape.ShapeType() );
+}
+
+//=======================================================================
+//function : IsApplicableHypotesis
+//purpose  : compare shape type and hypothesis type
 //=======================================================================
 
 bool SMESH_subMesh::IsApplicableHypotesis(const SMESH_Hypothesis* theHypothesis,
@@ -628,7 +646,7 @@ SMESH_Hypothesis::Hypothesis_Status
       filter.Or( SMESH_HypoFilter::HasType( algo->GetType()+1 ));
       filter.Or( SMESH_HypoFilter::HasType( algo->GetType()+2 ));
       if ( SMESH_Algo * curAlgo = (SMESH_Algo*)_father->GetHypothesis( this, filter, true ))
-        if ( !curAlgo->NeedDiscreteBoundary() )
+        if ( !curAlgo->NeedDiscreteBoundary() && curAlgo != anHyp )
           algoRequiringCleaning = curAlgo;
     }
   }
@@ -1436,6 +1454,31 @@ bool SMESH_subMesh::ComputeStateEngine(compute_event event)
           _computeState = READY_TO_COMPUTE;
       }
       break;
+
+    case COMPUTE_NOGEOM:  // no geometry; can be several algos
+      if ( !_father->HasShapeToMesh() )
+      {
+        algo = GetAlgo(); // current algo
+        if ( algo )
+        {
+          // apply algos in the order of increasing dimension
+          std::list< const SMESHDS_Hypothesis * > algos = _father->GetHypothesisList( _subShape );
+          for ( int t = SMESHDS_Hypothesis::ALGO_1D; t <= SMESHDS_Hypothesis::ALGO_3D; ++t )
+          {
+            std::list<const SMESHDS_Hypothesis *>::iterator al = algos.begin();
+            for ( ; al != algos.end(); ++al )
+              if ( (*al)->GetType() == t )
+              {
+                _algo = (SMESH_Algo*) *al;
+                _computeState = READY_TO_COMPUTE;
+                if ( !ComputeStateEngine( COMPUTE ))
+                  break;
+              }
+          }
+          _algo = algo; // restore
+        }
+        break;
+      }
     case COMPUTE:
     case COMPUTE_SUBMESH:
       {
@@ -1575,6 +1618,23 @@ bool SMESH_subMesh::ComputeStateEngine(compute_event event)
                    !algo->isDegenerated( TopoDS::Edge( subS.Current() ))))
               ret = false;
         }
+#ifdef PRINT_WHO_COMPUTE_WHAT
+        for (subS.ReInit(); subS.More(); subS.Next())
+        {
+          const std::list <const SMESHDS_Hypothesis *> & hyps =
+            _algo->GetUsedHypothesis( *_father, _subShape );
+          SMESH_Comment hypStr;
+          if ( !hyps.empty() )
+          {
+            hypStr << hyps.front()->GetName() << " ";
+            ((SMESHDS_Hypothesis*)hyps.front())->SaveTo( hypStr.Stream() );
+            hypStr << " ";
+          }
+          cout << _algo->GetName()
+               << " " << _father->GetSubMesh( subS.Current() )->GetId()
+               << " " << hypStr << endl;
+        }
+#endif
         // Set _computeError
         if ( !ret && !isComputeErrorSet )
         {
@@ -1708,7 +1768,7 @@ bool SMESH_subMesh::ComputeStateEngine(compute_event event)
     case COMPUTE_CANCELED:      // nothing to do
       break;
     case CLEAN:
-      cleanDependants();  // clean sub-meshes, dependant on this one, with event CLEAN
+      cleanDependants();  // clean sub-meshes, dependent on this one, with event CLEAN
       removeSubMeshElementsAndNodes();
       _computeState = NOT_READY;
       if ( _algoState == HYP_OK )
@@ -2157,8 +2217,6 @@ const SMESH_Hypothesis* SMESH_subMesh::getSimilarAttached(const TopoDS_Shape&
 SMESH_Hypothesis::Hypothesis_Status
   SMESH_subMesh::CheckConcurentHypothesis (const int theHypType)
 {
-  MESSAGE ("SMESH_subMesh::CheckConcurentHypothesis");
-
   // is there local hypothesis on me?
   if ( getSimilarAttached( _subShape, 0, theHypType ) )
     return SMESH_Hypothesis::HYP_OK;
@@ -2328,7 +2386,7 @@ EventListenerData* SMESH_subMesh::GetEventListenerData(const string& listenerNam
 
 //================================================================================
 /*!
- * \brief Notify stored event listeners on the occured event
+ * \brief Notify stored event listeners on the occurred event
  * \param event - algo_event or compute_event itself
  * \param eventType - algo_event or compute_event
  * \param hyp - hypothesis, if eventType is algo_event
@@ -2434,7 +2492,7 @@ void SMESH_subMesh::loadDependentMeshes()
  * \brief Do something on a certain event
  * \param event - algo_event or compute_event itself
  * \param eventType - algo_event or compute_event
- * \param subMesh - the submesh where the event occures
+ * \param subMesh - the submesh where the event occurs
  * \param data - listener data stored in the subMesh
  * \param hyp - hypothesis, if eventType is algo_event
  * 
index 05890e8cef1ac776e7bab1caee33890127abb1ef..ef3cb629f46f3da9e982fa4f59f3bcfb81e9f01c 100644 (file)
@@ -112,7 +112,7 @@ class SMESH_EXPORT SMESH_subMesh
   };
   enum compute_event
   {
-    MODIF_ALGO_STATE, COMPUTE, COMPUTE_SUBMESH, COMPUTE_CANCELED,
+    MODIF_ALGO_STATE, COMPUTE, COMPUTE_SUBMESH, COMPUTE_NOGEOM, COMPUTE_CANCELED,
     CLEAN, SUBMESH_COMPUTED, SUBMESH_RESTORED, SUBMESH_LOADED,
     MESH_ENTITY_REMOVED, CHECK_COMPUTE_STATE
   };
@@ -190,7 +190,7 @@ protected:
   void setEventListener(EventListener* listener, EventListenerData* data);
 
   /*!
-   * \brief Notify stored event listeners on the occured event
+   * \brief Notify stored event listeners on the occurred event
    * \param event - algo_event or compute_event itself
    * \param eventType - algo_event or compute_event
    * \param hyp - hypothesis, if eventType is algo_event
@@ -236,13 +236,12 @@ public:
 
   bool CanAddHypothesis(const SMESH_Hypothesis* theHypothesis) const;
   // return true if theHypothesis can be attached to me:
-  // its dimention is checked
+  // its dimension is checked
 
   static bool IsApplicableHypotesis(const SMESH_Hypothesis* theHypothesis,
                                     const TopAbs_ShapeEnum  theShapeType);
 
-  bool IsApplicableHypotesis(const SMESH_Hypothesis* theHypothesis) const
-  { return IsApplicableHypotesis( theHypothesis, _subShape.ShapeType() ); }
+  bool IsApplicableHypotesis(const SMESH_Hypothesis* theHypothesis) const;
   // return true if theHypothesis can be used to mesh me:
   // its shape type is checked
   
index 1803c634dfa3d4da6cf9b6304aaa1601b722bffb..89262f1b5801302bd014aa9fde9811886c843304 100644 (file)
@@ -1115,6 +1115,8 @@ namespace
       type = QObject::tr( "LENGTH_EDGES" );
     else if ( dynamic_cast< SMESH::Controls::Length2D* >( f.get() ) )
       type = QObject::tr( "LENGTH2D_EDGES" );
+    else if ( dynamic_cast< SMESH::Controls::Deflection2D* >( f.get() ) )
+      type = QObject::tr( "DEFLECTION2D_FACES" );
     else if ( dynamic_cast< SMESH::Controls::MultiConnection* >( f.get() ) )
       type = QObject::tr( "MULTI_BORDERS" );
     else if ( dynamic_cast< SMESH::Controls::MultiConnection2D* >( f.get() ) )
@@ -1650,6 +1652,7 @@ namespace
     ActionControl.Bind( SMESHOp::OpBareBorderFace,        SMESH_Actor::eBareBorderFace );
     ActionControl.Bind( SMESHOp::OpOverConstrainedFace,   SMESH_Actor::eOverConstrainedFace );
     ActionControl.Bind( SMESHOp::OpLength2D,              SMESH_Actor::eLength2D );
+    ActionControl.Bind( SMESHOp::OpDeflection2D,          SMESH_Actor::eDeflection2D );
     ActionControl.Bind( SMESHOp::OpConnection2D,          SMESH_Actor::eMultiConnection2D );
     ActionControl.Bind( SMESHOp::OpArea,                  SMESH_Actor::eArea );
     ActionControl.Bind( SMESHOp::OpTaper,                 SMESH_Actor::eTaper );
@@ -3593,6 +3596,7 @@ bool SMESHGUI::OnGUIEvent( int theCommandID )
   case SMESHOp::OpBareBorderFace:
   case SMESHOp::OpOverConstrainedFace:
   case SMESHOp::OpLength2D:
+  case SMESHOp::OpDeflection2D:
   case SMESHOp::OpConnection2D:
   case SMESHOp::OpArea:
   case SMESHOp::OpTaper:
@@ -3886,6 +3890,7 @@ void SMESHGUI::initialize( CAM_Application* app )
   createSMESHAction( SMESHOp::OpBareBorderFace,        "BARE_BORDER_FACE",        "ICON_BARE_BORDER_FACE",        0, true );
   createSMESHAction( SMESHOp::OpOverConstrainedFace,   "OVER_CONSTRAINED_FACE",   "ICON_OVER_CONSTRAINED_FACE",   0, true );
   createSMESHAction( SMESHOp::OpLength2D,              "LENGTH_2D",               "ICON_LENGTH_2D",     0, true );
+  createSMESHAction( SMESHOp::OpDeflection2D,          "DEFLECTION_2D",           "ICON_DEFLECTION_2D", 0, true );
   createSMESHAction( SMESHOp::OpConnection2D,          "CONNECTION_2D",           "ICON_CONNECTION_2D", 0, true );
   createSMESHAction( SMESHOp::OpArea,                  "AREA",                    "ICON_AREA",          0, true );
   createSMESHAction( SMESHOp::OpTaper,                 "TAPER",                   "ICON_TAPER",         0, true );
@@ -4014,6 +4019,7 @@ void SMESHGUI::initialize( CAM_Application* app )
                << SMESHOp::OpNodeConnectivityNb                                         // node controls
                << SMESHOp::OpFreeEdge << SMESHOp::OpFreeBorder
                << SMESHOp::OpLength << SMESHOp::OpConnection << SMESHOp::OpEqualEdge    // edge controls
+               << SMESHOp::OpDeflection2D
                << SMESHOp::OpFreeFace << SMESHOp::OpLength2D << SMESHOp::OpConnection2D
                << SMESHOp::OpArea << SMESHOp::OpTaper << SMESHOp::OpAspectRatio
                << SMESHOp::OpMinimumAngle << SMESHOp::OpWarpingAngle << SMESHOp::OpSkew
@@ -4127,6 +4133,7 @@ void SMESHGUI::initialize( CAM_Application* app )
   createMenu( SMESHOp::OpSkew,                  faceId,   -1 );
   createMenu( SMESHOp::OpMaxElementLength2D,    faceId,   -1 );
   createMenu( SMESHOp::OpEqualFace,             faceId,   -1 );
+  createMenu( SMESHOp::OpDeflection2D,          faceId,   -1 );
   createMenu( SMESHOp::OpAspectRatio3D,         volumeId, -1 );
   createMenu( SMESHOp::OpVolume,                volumeId, -1 );
   createMenu( SMESHOp::OpMaxElementLength3D,    volumeId, -1 );
@@ -4275,6 +4282,7 @@ void SMESHGUI::initialize( CAM_Application* app )
   createTool( SMESHOp::OpSkew,                ctrl2dTb );
   createTool( SMESHOp::OpMaxElementLength2D,  ctrl2dTb );
   createTool( SMESHOp::OpEqualFace,           ctrl2dTb );
+  createTool( SMESHOp::OpDeflection2D,        ctrl2dTb );
 
   createTool( SMESHOp::OpAspectRatio3D,         ctrl3dTb );
   createTool( SMESHOp::OpVolume,                ctrl3dTb );
@@ -4672,10 +4680,15 @@ void SMESHGUI::initialize( CAM_Application* app )
   popupMgr()->insert ( action( SMESHOp::OpOverConstrainedFace ), aSubId, -1 );
   popupMgr()->setRule( action( SMESHOp::OpOverConstrainedFace ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule );
   popupMgr()->setRule( action( SMESHOp::OpOverConstrainedFace ), "controlMode = 'eOverConstrainedFace'", QtxPopupMgr::ToggleRule );
+
   popupMgr()->insert ( action( SMESHOp::OpEqualFace ), aSubId, -1 );
   popupMgr()->setRule( action( SMESHOp::OpEqualFace ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule );
   popupMgr()->setRule( action( SMESHOp::OpEqualFace ), "controlMode = 'eCoincidentElems2D'", QtxPopupMgr::ToggleRule );
 
+  popupMgr()->insert ( action( SMESHOp::OpDeflection2D ), aSubId, -1 );
+  popupMgr()->setRule( action( SMESHOp::OpDeflection2D ), aMeshInVtkHasFaces + " && hasGeomReference", QtxPopupMgr::VisibleRule );
+  popupMgr()->setRule( action( SMESHOp::OpDeflection2D ), "controlMode = 'eDeflection2D'", QtxPopupMgr::ToggleRule );
+
   aSubId = popupMgr()->insert( tr( "MEN_VOLUME_CTRL" ), anId, -1 ); // VOLUME CONTROLS
 
   popupMgr()->insert ( action( SMESHOp::OpAspectRatio3D  ), aSubId, -1 );
index d182aa07cbb4d6d9b2e82908d30065bbe9a717f8..28aa244e4d1bec6d239c2c98730e43f154ba9553 100755 (executable)
@@ -1572,6 +1572,7 @@ void SMESHGUI_FilterTable::updateAdditionalWidget()
                  aCriterion == SMESH::FT_MaxElementLength3D ||
                  aCriterion == SMESH::FT_Length             ||
                  aCriterion == SMESH::FT_Length2D           ||
+                 aCriterion == SMESH::FT_Deflection2D       ||
                  aCriterion == SMESH::FT_BallDiameter );
 
   bool toEnable = (( isDbl && ((ComboItem*)aTable->item(aRow, 1))->value() == SMESH::FT_EqualTo) ||
@@ -1618,6 +1619,7 @@ const char* SMESHGUI_FilterTable::getPrecision( const int aType )
     retval = "len_tol_precision"; break;
   case SMESH::FT_Length:
   case SMESH::FT_Length2D:
+  case SMESH::FT_Deflection2D:
   case SMESH::FT_MaxElementLength2D:
   case SMESH::FT_MaxElementLength3D:
   case SMESH::FT_BallDiameter:
@@ -1792,13 +1794,13 @@ void SMESHGUI_FilterTable::onCriterionChanged (const int row, const int col, con
   }
 
   // find out a type of item required by a new criterion and other table features
-  int aCriterionType       = GetCriterionType(row);
+  int  aCriterionType      = GetCriterionType(row);
   bool anIsDoubleCriterion = false;
   bool anIsIntCriterion    = false;
   bool anIsComboCriterion  = false;
   // other features:
   QList<int> comboIDs; // values to show in a combo item
-  int nbCompareSigns = 0; // possible values are 0,1,3
+  int  nbCompareSigns      = 0; // possible values are 0,1,3
   bool isThresholdEditable = false; // actual for "simple" item types
   switch ( aCriterionType )
   {
@@ -1811,8 +1813,7 @@ void SMESHGUI_FilterTable::onCriterionChanged (const int row, const int col, con
   case SMESH::FT_Area:
   case SMESH::FT_Volume3D:
   case SMESH::FT_MaxElementLength2D:
-  case SMESH::FT_MaxElementLength3D:
-    anIsDoubleCriterion = true; break;
+  case SMESH::FT_MaxElementLength3D: anIsDoubleCriterion = true; break;
 
   case SMESH::FT_FreeBorders:
   case SMESH::FT_FreeEdges:
@@ -1828,7 +1829,8 @@ void SMESHGUI_FilterTable::onCriterionChanged (const int row, const int col, con
   case SMESH::FT_MultiConnection2D: anIsIntCriterion = true; nbCompareSigns = 3; break;
 
   case SMESH::FT_Length:
-  case SMESH::FT_Length2D: anIsDoubleCriterion = true; break;
+  case SMESH::FT_Length2D:
+  case SMESH::FT_Deflection2D: anIsDoubleCriterion = true; break;
 
   case SMESH::FT_BelongToMeshGroup: break;
 
@@ -2240,6 +2242,7 @@ const QMap<int, QString>& SMESHGUI_FilterTable::getCriteria (const int theType)
       aCriteria[ SMESH::FT_BelongToGenSurface ] = tr("BELONG_TO_GENSURFACE");
       aCriteria[ SMESH::FT_LyingOnGeom        ] = tr("LYING_ON_GEOM");
       aCriteria[ SMESH::FT_Length2D           ] = tr("LENGTH2D");
+      aCriteria[ SMESH::FT_Deflection2D       ] = tr("DEFLECTION2D");
       aCriteria[ SMESH::FT_MultiConnection2D  ] = tr("MULTI2D_BORDERS");
       aCriteria[ SMESH::FT_FreeFaces          ] = tr("FREE_FACES");
       aCriteria[ SMESH::FT_BareBorderFace     ] = tr("BARE_BORDER_FACE");
index db07868adc8aa84375d316c348700b8cf074deff..226f785943123572bbc5d003f3e0d01317608bc6 100644 (file)
@@ -959,11 +959,13 @@ SMESHGUI_ElemInfo::~SMESHGUI_ElemInfo()
   \brief Set mesh data source (actor)
   \param actor mesh object actor
 */
-void SMESHGUI_ElemInfo::setSource( SMESH_Actor* actor )
+void SMESHGUI_ElemInfo::setSource( SMESH_Actor* actor, SMESH::SMESH_IDSource_var obj )
 {
   if ( myActor != actor ) {
     myActor = actor;
     myIsElement = -1;
+    SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
+    myMeshHasShape = ( !mesh->_is_nil() && mesh->HasShapeToMesh() );
     clear();
   }
 }
@@ -1453,25 +1455,29 @@ void SMESHGUI_SimpleElemInfo::information( const QList<long>& ids )
           afunctor.reset( new SMESH::Controls::AspectRatio() );
           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "ASPECTRATIO_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
-          //Minimum angle         
+          //Minimum angle
           afunctor.reset( new SMESH::Controls::MinimumAngle() );
           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
           afunctor->SetPrecision( cprecision );
           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "MINIMUMANGLE_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
-          //Wraping angle        
+          //Wraping angle
           afunctor.reset( new SMESH::Controls::Warping() );
           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
           afunctor->SetPrecision( cprecision );
           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "WARP_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
-          //Skew         
+          //Skew
           afunctor.reset( new SMESH::Controls::Skew() );
           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
           afunctor->SetPrecision( cprecision );
           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "SKEW_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
-          //ElemDiam2D   
+          //ElemDiam2D
           afunctor.reset( new SMESH::Controls::MaxElementLength2D() );
           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "MAX_ELEMENT_LENGTH_2D" ) ).arg( afunctor->GetValue( id ) ) );
+          //min edge length
+          afunctor.reset( new SMESH::Controls::Length2D() );
+          afunctor->SetMesh( actor()->GetObject()->GetMesh() );
+          myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "MIN_ELEM_EDGE" )).arg( afunctor->GetValue( id )) );
         }
         if( e->GetType() == SMDSAbs_Volume ) {
           //AspectRatio3D
@@ -1998,20 +2004,29 @@ void SMESHGUI_TreeElemInfo::information( const QList<long>& ids )
           afunctor->SetPrecision( cprecision );
           QTreeWidgetItem* warpItem = createItem( cntrItem, Bold );
           warpItem->setText( 0, tr( "WARP_ELEMENTS" ));
-          warpItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );        
-          //Skew          
+          warpItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );
+          //Skew
           afunctor.reset( new SMESH::Controls::Skew() );
           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
           afunctor->SetPrecision( cprecision );
           QTreeWidgetItem* skewItem = createItem( cntrItem, Bold );
           skewItem->setText( 0, tr( "SKEW_ELEMENTS" ) );
-          skewItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );       
-          //ElemDiam2D    
+          skewItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );
+          //Deflection
+          if ( hasShapeToMesh() )
+          {
+            afunctor.reset( new SMESH::Controls::Deflection2D() );
+            afunctor->SetMesh( actor()->GetObject()->GetMesh() );
+            QTreeWidgetItem* deflItem = createItem( cntrItem, Bold );
+            deflItem->setText( 0, tr( "DEFLECTION_2D" ));
+            deflItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id )) );
+          }
+          //ElemDiam2D
           afunctor.reset( new SMESH::Controls::MaxElementLength2D() );
           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
           QTreeWidgetItem* diamItem = createItem( cntrItem, Bold );
           diamItem->setText( 0, tr( "MAX_ELEMENT_LENGTH_2D" ));
-          diamItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );       
+          diamItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );
         }
         if( e->GetType() == SMDSAbs_Volume ) {
           //AspectRatio3D
@@ -2019,7 +2034,7 @@ void SMESHGUI_TreeElemInfo::information( const QList<long>& ids )
           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
           QTreeWidgetItem* ratlItem3 = createItem( cntrItem, Bold );
           ratlItem3->setText( 0, tr( "ASPECTRATIO_3D_ELEMENTS" ) );
-          ratlItem3->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );      
+          ratlItem3->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );
           //Volume
           afunctor.reset( new SMESH::Controls::Volume() );
           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
@@ -2034,6 +2049,13 @@ void SMESHGUI_TreeElemInfo::information( const QList<long>& ids )
           diam3Item->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );     
         }
 
+        //min edge length
+        afunctor.reset( new SMESH::Controls::Length2D() );
+        afunctor->SetMesh( actor()->GetObject()->GetMesh() );
+        QTreeWidgetItem* minEdgeItem = createItem( cntrItem, Bold );
+        minEdgeItem->setText( 0, tr( "MIN_ELEM_EDGE" ));
+        minEdgeItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id )) );
+
         // gravity center
         XYZ gc = gravityCenter( e );
         QTreeWidgetItem* gcItem = createItem( elemItem, Bold );
@@ -2940,7 +2962,7 @@ void SMESHGUI_MeshInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& IO
           SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
           SMESH::GetNameOfSelectedNodes( selector, IO, ID );
       }
-      myElemInfo->setSource( myActor ) ;
+      myElemInfo->setSource( myActor, obj ) ;
       if ( nb > 0 ) {
         myID->setText( ID.trimmed() );
         QSet<long> ids;
index 2edf2e58a42033271e1121d5b1fe1fe792cafd75..84aac8abf6e68be4c51869704684a5069055d934 100644 (file)
@@ -151,7 +151,7 @@ public:
   SMESHGUI_ElemInfo( QWidget* = 0 );
   ~SMESHGUI_ElemInfo();
 
-  void         setSource( SMESH_Actor* );
+  void         setSource( SMESH_Actor*, SMESH::SMESH_IDSource_var );
   void         showInfo( long, bool );
   void         showInfo( QSet<long>, bool );
   void         clear();
@@ -174,6 +174,7 @@ protected:
   QWidget*     frame() const;
   SMESH_Actor* actor() const;
   bool         isElements() const;
+  bool         hasShapeToMesh() const { return myMeshHasShape; }
 
   virtual void information( const QList<long>& ) = 0;
   virtual void clearInternal();
@@ -199,6 +200,7 @@ private:
   QWidget*         myFrame;
   ExtraWidget*     myExtra;
   int              myIndex;
+  bool             myMeshHasShape;
 };
 
 class SMESHGUI_EXPORT SMESHGUI_SimpleElemInfo : public SMESHGUI_ElemInfo
index 52920773b97b13cffbbbc363a74c6fc4775f4fe5..43d92b9fc96c191ae3db98324bbbf30fb1e3a2f5 100644 (file)
@@ -271,7 +271,7 @@ void SMESHGUI_MeshOp::startOperation()
 /*!
  * \brief Selects a recently created mesh or sub-mesh if necessary
  *
- * Virtual method redefined from base class called when operation is commited
+ * Virtual method redefined from base class called when operation is committed
  * selects a recently created mesh or sub-mesh if necessary. Allows to perform
  * selection when the custom selection filters are removed.
  */
@@ -709,15 +709,14 @@ void SMESHGUI_MeshOp::selectionDone()
       }
     }
     else { // no geometry defined
-      myDlg->enableTab( SMESH::DIM_3D );
-      QStringList hypList;
-      availableHyps( SMESH::DIM_3D, Algo, hypList,
-                     myAvailableHypData[SMESH::DIM_3D][Algo]);
 
-      SMESHGUI_MeshTab* aTab = myDlg->tab( SMESH::DIM_3D );
-      aTab->setAvailableHyps( Algo, hypList );
-      for (int i = SMESH::DIM_0D;i < SMESH::DIM_3D; ++i) {
-        myDlg->disableTab(i);
+      QStringList hypList;
+      for ( int dim = SMESH::DIM_0D; dim <= SMESH::DIM_3D; dim++ )
+      {
+        availableHyps( dim, Algo, hypList, myAvailableHypData[dim][Algo]);
+        myDlg->tab( dim )->setAvailableHyps( Algo, hypList );
+        if ( hypList.empty() ) myDlg->disableTab( dim );
+        else                   myDlg->enableTab( dim );
       }
       myMaxShapeDim = -1;
       //Hide labels and fields (Mesh and Geometry)
@@ -1245,10 +1244,10 @@ void SMESHGUI_MeshOp::initHypCreator( SMESHGUI_GenericHypothesisCreator* theCrea
 
 //================================================================================
 /*!
- * \Brief Returns tab dimention
+ * \Brief Returns tab dimension
   * \param tab - the tab in the dlg
   * \param dlg - my dialogue
-  * \retval int - dimention
+  * \retval int - dimension
  */
 //================================================================================
 static int getTabDim (const QObject* tab, SMESHGUI_MeshDlg* dlg )
@@ -1505,7 +1504,8 @@ void SMESHGUI_MeshOp::onAlgoSelected( const int theIndex,
   if ( myIgnoreAlgoSelection )
     return;
 
-  int aDim = theDim < 0 ? getTabDim( sender(), myDlg ): theDim;
+  int curDim = getTabDim( sender(), myDlg );
+  int aDim = theDim < 0 ? curDim : theDim;
   if (aDim == -1)
     return;
 
@@ -1587,7 +1587,7 @@ void SMESHGUI_MeshOp::onAlgoSelected( const int theIndex,
       myDlg->tab( dim )->setAvailableHyps( Algo, anAvailable );
       noCompatible = anAvailable.isEmpty();
       algoIndex = myAvailableHypData[dim][Algo].indexOf( curAlgo );
-      if ( !isSubmesh && algoIndex < 0 && soleCompatible && !forward && dim != SMESH::DIM_0D) {
+      if ( !isSubmesh && algoIndex < 0 && soleCompatible && !forward && dim == curDim ) {
         // select the sole compatible algo
         algoIndex = 0;
       }
@@ -1682,7 +1682,8 @@ void SMESHGUI_MeshOp::onAlgoSelected( const int theIndex,
         hypIndex = this->find( curHyp, myExistingHyps[ dim ][ type ]);
       else
         hypIndex = -1;
-      if ( !isSubmesh && myToCreate && hypIndex < 0 && anExisting.count() == 1 ) {
+      if ( !isSubmesh && myToCreate && hypIndex < 0 && anExisting.count() == 1 && dim == curDim )
+      {
         // none is yet selected => select the sole existing if it is not optional
         CORBA::String_var hypTypeName = myExistingHyps[ dim ][ type ].first().first->GetName();
         bool isOptional = true;
@@ -2184,7 +2185,7 @@ SMESH::SMESH_Hypothesis_var SMESHGUI_MeshOp::getAlgo( const int theDim )
       {
         // Call hypothesis creation server method (without GUI)
         SMESH::SMESH_Hypothesis_var aHyp =
-          SMESH::CreateHypothesis(aHypName, aHypName, true);
+          SMESH::CreateHypothesis(aHypName, aHypData->Label, true);
         aHyp.out();
       }
       else
@@ -2197,7 +2198,7 @@ SMESH::SMESH_Hypothesis_var SMESHGUI_MeshOp::getAlgo( const int theDim )
           aCreator->create( true, aHypName, myDlg, 0, QString::null );
         else {
           SMESH::SMESH_Hypothesis_var aHyp =
-            SMESH::CreateHypothesis(aHypName, aHypName, true);
+            SMESH::CreateHypothesis(aHypName, aHypData->Label, true);
           aHyp.out();
         }
         delete aCreator;
@@ -2260,7 +2261,7 @@ void SMESHGUI_MeshOp::readMesh()
 
   // Get hypotheses and algorithms assigned to the mesh/sub-mesh
   QStringList anExisting;
-  const int lastDim = ( myIsOnGeometry ) ? SMESH::DIM_0D : SMESH::DIM_3D;
+  const int lastDim = ( myIsOnGeometry ) ? SMESH::DIM_0D : SMESH::DIM_2D;
   bool algoFound = false;
   for ( int dim = SMESH::DIM_3D; dim >= lastDim; --dim )
   {
@@ -2384,7 +2385,7 @@ int SMESHGUI_MeshOp::find( const SMESH::SMESH_Hypothesis_var& theHyp,
 /*!
  * \brief Edits mesh or sub-mesh
   * \param theMess - Output parameter intended for returning error message
-  * \retval bool  - TRUE if mesh is edited succesfully, FALSE otherwise
+  * \retval bool  - TRUE if mesh is edited successfully, FALSE otherwise
  *
  * Assigns new name hypotheses and algoriths to the mesh or sub-mesh
  */
@@ -2407,7 +2408,7 @@ bool SMESHGUI_MeshOp::editMeshOrSubMesh( QString& theMess )
   // Set new name
   QString aName = myDlg->objectText( SMESHGUI_MeshDlg::Obj );
   SMESH::SetName( pObj, aName );
-  int aDim = ( myIsOnGeometry ) ? SMESH::DIM_0D : SMESH::DIM_3D;
+  int aDim = ( myIsOnGeometry ) ? SMESH::DIM_0D : SMESH::DIM_2D;
 
   // First, remove old algos in order to avoid messages on algorithm hiding
   for ( int dim = aDim; dim <= SMESH::DIM_3D; dim++ )
@@ -2554,7 +2555,7 @@ bool SMESHGUI_MeshOp::checkSubMeshConcurrency(SMESH::SMESH_Mesh_ptr    mesh,
  *
  * method redefined from base class verifies whether given operator is valid for
  * this one (i.e. can be started "above" this operator). In current implementation method
- * retuns false if theOtherOp operation is not intended for deleting objects or mesh
+ * returns false if theOtherOp operation is not intended for deleting objects or mesh
  * elements.
  */
 //================================================================================
@@ -2743,8 +2744,9 @@ void SMESHGUI_MeshOp::setFilteredAlgoData( const int theTabIndex, const int theI
     }
     if ( !myIsOnGeometry )
       for ( int i = SMESH::DIM_0D; i <= SMESH::DIM_3D; i++ ) {
-        if ( i < SMESH::DIM_3D ) myDlg->disableTab( i );
-        else                     myDlg->enableTab( i );
+        bool disable = myAvailableHypData[i][Algo].isEmpty();
+        if ( disable ) myDlg->disableTab( i );
+        else           myDlg->enableTab( i );
       }
     else
       for ( int i = SMESH::DIM_0D; i <= SMESH::DIM_3D; i++ ) {
index df810f7dfe4391c706b2924c86f3011ab4c5174e..b32aff54bc0320ba50c5d8c94343cc53e38a824a 100644 (file)
@@ -117,6 +117,7 @@ namespace SMESHOp {
     OpSkew                   = 3210,   // MENU CONTROLS - SKEW
     OpMaxElementLength2D     = 3211,   // MENU CONTROLS - ELEMENT DIAMETER 2D
     OpEqualFace              = 3212,   // MENU CONTROLS - DOUBLE FACES
+    OpDeflection2D           = 3213,   // MENU CONTROLS - DEFLECTION 2D
     OpAspectRatio3D          = 3300,   // MENU CONTROLS - ASPECT RATIO 3D
     OpVolume                 = 3301,   // MENU CONTROLS - VOLUME
     OpMaxElementLength3D     = 3302,   // MENU CONTROLS - ELEMENT DIAMETER 3D
index 757238eab9af524f9f3240ebd82fe8b8fa7b9cb5..ce969aea5f2f1f177894fee4b671f642d2adad7f 100644 (file)
@@ -337,6 +337,7 @@ QString SMESHGUI_Selection::controlMode( int ind ) const
     switch( actor->GetControlMode() ) {
     case SMESH_Actor::eLength:                mode = "eLength";                break;
     case SMESH_Actor::eLength2D:              mode = "eLength2D";              break;
+    case SMESH_Actor::eDeflection2D:          mode = "eDeflection2D";          break;
     case SMESH_Actor::eFreeEdges:             mode = "eFreeEdges";             break;
     case SMESH_Actor::eFreeNodes:             mode = "eFreeNodes";             break;
     case SMESH_Actor::eFreeBorders:           mode = "eFreeBorders";           break;
@@ -384,6 +385,11 @@ QString SMESHGUI_Selection::controlMode() const
   return "eNone";
 }
 
+//=======================================================================
+//function : isNumFunctor
+//purpose  : return true if a given actor is shown using a numeric functor
+//=======================================================================
+
 bool SMESHGUI_Selection::isNumFunctor( int ind ) const
 {
   bool result = false;
@@ -392,6 +398,7 @@ bool SMESHGUI_Selection::isNumFunctor( int ind ) const
     switch( actor->GetControlMode() ) {
     case SMESH_Actor::eLength:
     case SMESH_Actor::eLength2D:
+    case SMESH_Actor::eDeflection2D:
     case SMESH_Actor::eMultiConnection:
     case SMESH_Actor::eMultiConnection2D:
     case SMESH_Actor::eArea:
@@ -415,7 +422,7 @@ bool SMESHGUI_Selection::isNumFunctor( int ind ) const
 
 //=======================================================================
 //function : facesOrientationMode
-//purpose  : 
+//purpose  :
 //=======================================================================
 
 QString SMESHGUI_Selection::facesOrientationMode( int ind ) const
index a0c988e6c11c36ef49c160a5ad539f8f33255856..509dd4e303fb16f89f7b93e9c321183d7c3dec52 100644 (file)
             <source>ICON_LENGTH_2D</source>
             <translation>mesh_length_2d.png</translation>
         </message>
+        <message>
+            <source>ICON_DEFLECTION_2D</source>
+            <translation>mesh_deflection.png</translation>
+        </message>
         <message>
             <source>ICON_MAP</source>
             <translation>mesh_pattern.png</translation>
index 5d052e3dd296932b0c7a220c48ad1d9b49c0e717..afe29f3affb55a40f24a8c4bf54656649faee7f4 100644 (file)
         <source>MIN_DIAG_ELEMENTS</source>
         <translation>Minimum diagonal</translation>
     </message>
+    <message>
+        <source>MIN_ELEM_EDGE</source>
+        <translation>Minimum Edge Length</translation>
+    </message>
     <message>
         <source>ASPECTRATIO_3D_ELEMENTS</source>
         <translation>Aspect Ratio 3D</translation>
         <source>LENGTH2D_EDGES</source>
         <translation>Length 2D</translation>
     </message>
+    <message>
+        <source>DEFLECTION2D_FACES</source>
+        <translation>Deflection 2D</translation>
+    </message>
     <message>
         <source>LENGTH_EDGES</source>
         <translation>Length</translation>
         <source>MAX_ELEMENT_LENGTH_3D</source>
         <translation>Element Diameter 3D</translation>
     </message>
+    <message>
+        <source>DEFLECTION_2D</source>
+        <translation>Deflection 2D</translation>
+    </message>
     <message>
         <source>MEN_ADD</source>
         <translation>Add</translation>
         <source>MEN_LENGTH_2D</source>
         <translation>Length 2D</translation>
     </message>
+    <message>
+        <source>MEN_DEFLECTION_2D</source>
+        <translation>Deflection 2D</translation>
+    </message>
     <message>
         <source>MEN_MAP</source>
         <translation>Pattern Mapping</translation>
@@ -3242,6 +3258,10 @@ Use Display Entity menu command to show them.
         <source>STB_LENGTH_2D</source>
         <translation>Length 2D</translation>
     </message>
+    <message>
+        <source>STB_DEFLECTION_2D</source>
+        <translation>Deflection 2D</translation>
+    </message>
     <message>
         <source>STB_MAP</source>
         <translation>Pattern mapping</translation>
@@ -3918,6 +3938,10 @@ Use Display Entity menu command to show them.
         <source>TOP_LENGTH_2D</source>
         <translation>Length 2D</translation>
     </message>
+    <message>
+        <source>TOP_DEFLECTION_2D</source>
+        <translation>Deflection 2D</translation>
+    </message>
     <message>
         <source>TOP_MAP</source>
         <translation>Pattern mapping</translation>
@@ -5817,6 +5841,10 @@ Please enter correct value and try again</translation>
         <source>LENGTH2D</source>
         <translation>Length 2D</translation>
     </message>
+    <message>
+        <source>DEFLECTION2D</source>
+        <translation>Deflection 2D</translation>
+    </message>
     <message>
         <source>LESS_THAN</source>
         <translation>Less than</translation>
index c21a8a6d5c4d8e8493a50531b66bb1eff76f0e87..032194e633cd3c318c39eb9acda42ef2b139b41f 100644 (file)
@@ -47,7 +47,7 @@ SET(_link_LIBRARIES
   ${CAS_TKMesh}
   ${Boost_LIBRARIES}
   SMDS
-)
+  )
 
 # --- headers ---
 
@@ -83,6 +83,7 @@ SET(SMESHUtils_SOURCES
   SMESH_MAT2d.cxx
   SMESH_FreeBorders.cxx
   SMESH_ControlPnt.cxx
+  SMESH_FillHole.cxx
 )
 
 # --- rules ---
diff --git a/src/SMESHUtils/SMESH_FillHole.cxx b/src/SMESHUtils/SMESH_FillHole.cxx
new file mode 100644 (file)
index 0000000..902cd03
--- /dev/null
@@ -0,0 +1,514 @@
+// Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+// File      : SMESH_FillHole.cxx
+// Created   : Tue Sep 26 15:11:17 2017
+// Author    : Edward AGAPOV (eap)
+//
+
+#include "SMESH_MeshAlgos.hxx"
+
+#include "SMESH_Comment.hxx"
+
+#include "SMESH_TypeDefs.hxx"
+#include "SMDS_Mesh.hxx"
+
+#include <Utils_SALOME_Exception.hxx>
+
+#include <boost/intrusive/circular_list_algorithms.hpp>
+#include <boost/container/flat_map.hpp>
+
+#include <Bnd_B3d.hxx>
+
+namespace
+{
+  bool isSmallAngle( double cos2 )
+  {
+    // cosine of min angle at which adjacent faces are considered overlapping
+    const double theMinCos2 = 0.996 * 0.996; // ~5 degrees
+    return ( cos2 > theMinCos2 );
+  }
+
+  struct BEdge;
+  typedef std::multimap< double, BEdge* >          TAngleMap;
+  typedef std::map< const SMDS_MeshElement*, int > TFaceIndMap;
+
+  //--------------------------------------------------------------------------------
+  /*!
+   * \brief Edge of a free border
+   */
+  struct BEdge
+  {
+    const SMDS_MeshNode*    myNode1;
+    const SMDS_MeshNode*    myNode2;
+    const SMDS_MeshElement* myFace;   // face adjacent to the border
+
+    gp_XYZ                  myFaceNorm;
+    gp_XYZ                  myDir;     // myNode1 -> myNode2
+    double                  myDirCoef; // 1. or -1, to make myDir oriented as myNodes in myFace
+    double                  myLength;  // between nodes
+    double                  myAngleWithPrev; // between myDir and -myPrev->myDir
+    double                  myMinMaxRatio; // of a possible triangle sides
+    TAngleMap::iterator     myAngleMapPos;
+    double                  myOverlapAngle;  // angle delta due to overlapping
+    const SMDS_MeshNode*    myNode1Shift;    // nodes created to avoid overlapping of faces
+    const SMDS_MeshNode*    myNode2Shift;
+
+    BEdge*                  myPrev; // neighbors in the border
+    BEdge*                  myNext;
+
+    BEdge(): myNode1Shift(0), myNode2Shift(0) {}
+    void   Init( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2,
+                 const SMDS_MeshElement* f=0,
+                 const SMDS_MeshNode* nf1=0, const SMDS_MeshNode* nf2=0 );
+    void   ComputeAngle( bool reverseAngle = false );
+    void   ShiftOverlapped( const SMDS_MeshNode*                  oppNode,
+                            const TFaceIndMap&                    capFaceWithBordInd,
+                            SMDS_Mesh&                            mesh,
+                            std::vector<const SMDS_MeshElement*>& newFaces);
+    void   MakeShiftfFaces( SMDS_Mesh&                            mesh,
+                            std::vector<const SMDS_MeshElement*>& newFaces,
+                            const bool                            isReverse );
+    gp_XYZ GetInFaceDir() const { return myFaceNorm ^ myDir * myDirCoef; }
+    double ShapeFactor()  const { return 0.5 * ( 1. - myMinMaxRatio ); }
+    void   InsertSelf(TAngleMap& edgesByAngle, bool isReverseFaces, bool reBind, bool useOverlap )
+    {
+      if ( reBind ) edgesByAngle.erase( myAngleMapPos );
+      double key = (( isReverseFaces ? 2 * M_PI - myAngleWithPrev : myAngleWithPrev )
+                    + myOverlapAngle * useOverlap
+                    + ShapeFactor() );
+      myAngleMapPos = edgesByAngle.insert( std::make_pair( key, this ));
+    }
+
+    // traits used by boost::intrusive::circular_list_algorithms
+    typedef BEdge         node;
+    typedef BEdge *       node_ptr;
+    typedef const BEdge * const_node_ptr;
+    static node_ptr get_next(const_node_ptr n)             {  return n->myNext;  }
+    static void     set_next(node_ptr n, node_ptr next)    {  n->myNext = next;  }
+    static node_ptr get_previous(const_node_ptr n)         {  return n->myPrev;  }
+    static void     set_previous(node_ptr n, node_ptr prev){  n->myPrev = prev;  }
+  };
+
+  //================================================================================
+  /*!
+   * \brief Initialize a border edge data
+   */
+  //================================================================================
+
+  void BEdge::Init( const SMDS_MeshNode*    n1,
+                    const SMDS_MeshNode*    n2,
+                    const SMDS_MeshElement* newFace, // new cap face
+                    const SMDS_MeshNode*    nf1,
+                    const SMDS_MeshNode*    nf2 )
+  {
+    myNode1  = n1;
+    myNode2  = n2;
+    myDir    = SMESH_NodeXYZ( n2 ) - SMESH_NodeXYZ( n1 );
+    myLength = myDir.Modulus();
+    if ( myLength > std::numeric_limits<double>::min() )
+      myDir /= myLength;
+
+    myFace = newFace;
+    if ( !myFace )
+    {
+      TIDSortedElemSet elemSet, avoidSet;
+      int ind1, ind2;
+      myFace = SMESH_MeshAlgos::FindFaceInSet( n1, n2, elemSet, avoidSet, &ind1, &ind2 );
+      if ( !myFace )
+        throw SALOME_Exception( SMESH_Comment("No face sharing nodes #")
+                                << myNode1->GetID() << " and #" << myNode2->GetID());
+      avoidSet.insert( myFace );
+      if ( SMESH_MeshAlgos::FindFaceInSet( n1, n2, elemSet, avoidSet ))
+        throw SALOME_Exception( SMESH_Comment("No free border between nodes #")
+                                << myNode1->GetID() << " and #" << myNode2->GetID());
+
+      myDirCoef = SMESH_MeshAlgos::IsRightOrder( myFace, myNode1, myNode2 ) ? 1. : -1.;
+    }
+
+    if (! SMESH_MeshAlgos::FaceNormal( myFace, myFaceNorm, /*normalized=*/false ))
+    {
+      SMDS_ElemIteratorPtr fIt = myNode1->GetInverseElementIterator( SMDSAbs_Face );
+      while ( fIt->more() )
+        if ( SMESH_MeshAlgos::FaceNormal( fIt->next(), myFaceNorm, /*normalized=*/false ))
+          break;
+    }
+
+    if ( newFace )
+    {
+      myFace    = 0;
+      myDirCoef = SMESH_MeshAlgos::IsRightOrder( newFace, nf1, nf2 ) ? 1. : -1.;
+      if ( myPrev->myNode2 == n1 )
+        myNode1Shift = myPrev->myNode2Shift;
+      if ( myNext->myNode1 == n2 )
+        myNode2Shift = myNext->myNode1Shift;
+    }
+    else if ( myDirCoef * myPrev->myDirCoef < 0 ) // different orientation of faces
+    {
+      myFaceNorm *= -1;
+      myDirCoef  *= -1;
+    }
+  }
+
+  //================================================================================
+  /*!
+   * \brief Compute myAngleWithPrev
+   */
+  //================================================================================
+
+  void BEdge::ComputeAngle( bool theReverseAngle )
+  {
+    myAngleWithPrev = acos( myDir.Dot( myPrev->myDir.Reversed() ));
+
+    bool isObtuse;
+    gp_XYZ inFaceDirNew = myDir - myPrev->myDir;
+    gp_XYZ   inFaceDir1 = myPrev->GetInFaceDir();
+    gp_XYZ   inFaceDir2 = this->GetInFaceDir();
+    double         dot1 = inFaceDirNew * inFaceDir1;
+    double         dot2 = inFaceDirNew * inFaceDir2;
+    bool     isOverlap1 = ( dot1 > 0 );
+    bool     isOverlap2 = ( dot2 > 0 );
+    if ( !myPrev->myFace )
+      isObtuse = isOverlap1;
+    else if  ( !myFace )
+      isObtuse = isOverlap2;
+    else
+    {
+      double dt1 = myDir.Dot( myPrev->myFaceNorm );
+      double dt2 = myPrev->myDir.Dot( myFaceNorm );
+      isObtuse = ( dt1 > 0 || dt2 < 0 ); // suppose face normals point outside the border
+      if ( theReverseAngle )
+        isObtuse = !isObtuse;
+    }
+    if ( isObtuse )
+    {
+      myAngleWithPrev = 2 * M_PI - myAngleWithPrev;
+    }
+
+    // if ( ! isObtuse )
+    //   isObtuse =
+    //     isSmallAngle( 1 - myDir.CrossSquareMagnitude( myPrev->myDir )); // edges co-directed
+
+    myOverlapAngle = 0;
+    //if ( !isObtuse )
+    {
+      // check if myFace and a triangle built on this and prev edges overlap
+      if ( isOverlap1 )
+      {
+        double cos2 = dot1 * dot1 / inFaceDirNew.SquareModulus() / inFaceDir1.SquareModulus();
+        myOverlapAngle += 1. * M_PI * cos2;
+      }
+      if ( isOverlap2 )
+      {
+        double cos2 = dot2 * dot2 / inFaceDirNew.SquareModulus() / inFaceDir2.SquareModulus();
+        myOverlapAngle += 1. * M_PI * cos2;
+      }
+    }
+
+    {
+      double len3 = SMESH_NodeXYZ( myPrev->myNode1 ).Distance( myNode2 );
+      double minLen = Min( myLength, Min( myPrev->myLength, len3 ));
+      double maxLen = Max( myLength, Max( myPrev->myLength, len3 ));
+      myMinMaxRatio = minLen / maxLen;
+    }
+  }
+
+  //================================================================================
+  /*!
+   * \brief Check if myFace is overlapped by a triangle formed by myNode's and a
+   *        given node. If so, create shifted nodes to avoid overlapping
+   */
+  //================================================================================
+
+  void BEdge::ShiftOverlapped( const SMDS_MeshNode*                  theOppNode,
+                               const TFaceIndMap&                    theCapFaceWithBordInd,
+                               SMDS_Mesh&                            theMesh,
+                               std::vector<const SMDS_MeshElement*>& theNewFaces )
+  {
+    if ( myNode1Shift && myNode2Shift )
+      return;
+
+    gp_XYZ inNewFaceDir = SMESH_NodeXYZ( theOppNode ) - SMESH_NodeXYZ( myNode1 );
+    double          dot = inNewFaceDir.Dot( myFaceNorm );
+    double         cos2 = dot * dot / myFaceNorm.SquareModulus() / inNewFaceDir.SquareModulus();
+    bool      isOverlap = ( isSmallAngle( 1 - cos2 ) && GetInFaceDir() * inNewFaceDir > 0 );
+
+    if ( isOverlap )
+    {
+      gp_XYZ shift = myFaceNorm / myLength / 4;
+      if ( myFace )
+        shift.Reverse();
+      if ( !myNode1Shift )
+      {
+        gp_XYZ p = SMESH_NodeXYZ( myNode1 ) + shift;
+        myNode1Shift = theMesh.AddNode( p.X(), p.Y(), p.Z() );
+        myPrev->myNode2Shift = myNode1Shift;
+      }
+      if ( !myNode2Shift )
+      {
+        gp_XYZ p = SMESH_NodeXYZ( myNode2 ) + shift;
+        myNode2Shift = theMesh.AddNode( p.X(), p.Y(), p.Z() );
+        myNext->myNode1Shift = myNode2Shift;
+      }
+
+      // MakeShiftfFaces() for already created cap faces
+      for ( int is2nd = 0; is2nd < 2; ++is2nd )
+      {
+        const SMDS_MeshNode* ns = is2nd ? myNode2Shift : myNode1Shift;
+        const SMDS_MeshNode* n  = is2nd ? myNode2 : myNode1;
+        if ( !ns ) continue;
+
+        SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator( SMDSAbs_Face );
+        while ( fIt->more() )
+        {
+          const SMDS_MeshElement* f = fIt->next();
+          if ( !f->isMarked() ) continue;
+
+          TFaceIndMap::const_iterator f2i = theCapFaceWithBordInd.find( f );
+          if ( f2i == theCapFaceWithBordInd.end() )
+            continue;
+          const SMDS_MeshNode* nf1 = f->GetNode(  f2i->second );
+          const SMDS_MeshNode* nf2 = f->GetNode(( f2i->second+1 ) % f->NbNodes() );
+          if ( nf1 == n || nf2 == n )
+          {
+            BEdge tmpE;
+            tmpE.myPrev = tmpE.myNext = this;
+            tmpE.Init( nf1, nf2, f, nf1, nf2 );
+            if ( !tmpE.myNode1Shift && !tmpE.myNode2Shift )
+              tmpE.Init( nf2, nf1, f, nf2, nf1 );
+            tmpE.myFace = f;
+            tmpE.MakeShiftfFaces( theMesh, theNewFaces, tmpE.myDirCoef < 0 );
+          }
+          std::vector< const SMDS_MeshNode* > nodes( f->begin_nodes(), f->end_nodes() );
+          nodes[ f->GetNodeIndex( n ) ] = ns;
+          theMesh.ChangeElementNodes( f, &nodes[0], nodes.size() );
+        }
+      }
+    }
+  }
+
+  //================================================================================
+  /*!
+   * \brief Create a triangle
+   */
+  //================================================================================
+
+  const SMDS_MeshElement* MakeTria( SMDS_Mesh&           mesh,
+                                    const SMDS_MeshNode* n1,
+                                    const SMDS_MeshNode* n2,
+                                    const SMDS_MeshNode* n3,
+                                    const bool           isReverse )
+  {
+    if ( isReverse )
+      return mesh.AddFace( n1, n3, n2 );
+    return mesh.AddFace( n1, n2, n3 );
+  }
+
+  //================================================================================
+  /*!
+   * \brief Create a quadrangle
+   */
+  //================================================================================
+
+  // const SMDS_MeshElement* MakeQuad( SMDS_Mesh&           mesh,
+  //                                   const SMDS_MeshNode* n1,
+  //                                   const SMDS_MeshNode* n2,
+  //                                   const SMDS_MeshNode* n3,
+  //                                   const SMDS_MeshNode* n4,
+  //                                   const bool           isReverse )
+  // {
+  //   if ( isReverse )
+  //     return mesh.AddFace( n4, n3, n2, n1 );
+  //   return mesh.AddFace( n1, n2, n3, n4 );
+  // }
+
+  //================================================================================
+  /*!
+   * \brief Create faces on myNode* and myNode*Shift
+   */
+  //================================================================================
+
+  void BEdge::MakeShiftfFaces(SMDS_Mesh&                            mesh,
+                              std::vector<const SMDS_MeshElement*>& newFaces,
+                              const bool                            isReverse )
+  {
+    if ( !myFace )
+      return;
+    if ( myNode1Shift && myNode2Shift )
+    {
+      newFaces.push_back( MakeTria( mesh, myNode1, myNode2, myNode2Shift, isReverse ));
+      newFaces.push_back( MakeTria( mesh, myNode1, myNode2Shift, myNode1Shift, isReverse ));
+    }
+    else if ( myNode1Shift )
+    {
+      newFaces.push_back( MakeTria( mesh, myNode1, myNode2, myNode1Shift, isReverse ));
+    }
+    else if ( myNode2Shift )
+    {
+      newFaces.push_back( MakeTria( mesh, myNode1, myNode2, myNode2Shift, isReverse ));
+    }
+  }
+
+} // namespace
+
+//================================================================================
+/*!
+ * \brief Fill with 2D elements a hole defined by a TFreeBorder
+ */
+//================================================================================
+
+void SMESH_MeshAlgos::FillHole(const SMESH_MeshAlgos::TFreeBorder &  theFreeBorder,
+                               SMDS_Mesh&                            theMesh,
+                               std::vector<const SMDS_MeshElement*>& theNewFaces)
+{
+  if ( theFreeBorder.size() < 4 ||                // at least 3 nodes
+       theFreeBorder[0] != theFreeBorder.back() ) // the hole must be closed
+    return;
+
+  // prepare data of the border
+
+  ObjectPool< BEdge > edgeAllocator(1024);
+  boost::intrusive::circular_list_algorithms< BEdge > circularList;
+  BEdge* edge;
+  BEdge* edge0 = edgeAllocator.getNew();
+  BEdge* edgePrev = edge0;
+  circularList.init_header( edge0 );
+  edge0->Init( theFreeBorder[0], theFreeBorder[1], 0 );
+  Bnd_B3d box;
+  box.Add( SMESH_NodeXYZ( edge0->myNode1 ));
+  for ( size_t i = 2; i < theFreeBorder.size(); ++i )
+  {
+    edge = edgeAllocator.getNew();
+    circularList.link_after( edgePrev, edge );
+    edge->Init( theFreeBorder[i-1], theFreeBorder[i] );
+    edge->ComputeAngle();
+    edgePrev = edge;
+    box.Add( SMESH_NodeXYZ( edge->myNode1 ));
+  }
+  edge0->ComputeAngle();
+
+  // check if face normals point outside the border
+
+  gp_XYZ hSize = 0.5 * ( box.CornerMax() - box.CornerMin() );
+  const double hDelta = 1e-6 * hSize.Modulus();
+  hSize -= gp_XYZ( hDelta, hDelta, hDelta );
+  if ( hSize.X() < 0 ) hSize.SetX(hDelta);
+  if ( hSize.Y() < 0 ) hSize.SetY(hDelta);
+  if ( hSize.Z() < 0 ) hSize.SetZ(hDelta);
+  box.SetHSize( hSize ); // decrease the box by hDelta
+
+  size_t nbEdges = theFreeBorder.size() - 1;
+  edge = edge0;
+  int nbRev = 0, nbFrw = 0;
+  double angTol = M_PI - ( nbEdges - 2 ) * M_PI / nbEdges, sumDirCoeff = 0;
+  for ( size_t i = 0; i < nbEdges; ++i, edge = edge->myNext )
+  {
+    if ( box.IsOut( SMESH_NodeXYZ( edge->myNode1 )) &&
+         edge->myOverlapAngle < 0.1 * M_PI )
+    {
+      nbRev += edge->myAngleWithPrev > M_PI + angTol;
+      nbFrw += edge->myAngleWithPrev < M_PI - angTol;
+    }
+    sumDirCoeff += edge->myDirCoef;
+
+    // unmark all adjacent faces, new faces will be marked
+    SMDS_ElemIteratorPtr fIt = edge->myNode1->GetInverseElementIterator( SMDSAbs_Face );
+    while ( fIt->more() )
+      fIt->next()->setIsMarked( false );
+  }
+  bool isReverseAngle = ( nbRev > nbFrw ); // true == face normals point inside the border
+  //std::cout << "nbRev="<< nbRev << ", nbFrw="<< nbFrw<<std::endl;
+
+  // sort border edges by myAngleWithPrev
+
+  TAngleMap edgesByAngle;
+  bool useOverlap = true; // to add BEdge.myOverlapAngle when filling edgesByAngle
+  edge = edge0;
+  for ( size_t i = 0; i < nbEdges; ++i, edge = edge->myNext )
+    edge->InsertSelf( edgesByAngle, isReverseAngle, /*reBind=*/false, useOverlap );
+
+  // create triangles to fill the hole
+
+  //compare order of nodes in the edges with their order in faces
+  bool isReverse = sumDirCoeff > 0.5 * nbEdges;
+
+  // faces filling the hole (cap faces) and indices of border edges in them
+  TFaceIndMap capFaceWithBordInd;
+
+  theNewFaces.reserve( nbEdges - 2 );
+  std::vector< const SMDS_MeshNode* > nodes(3);
+  while ( edgesByAngle.size() > 2 )
+  {
+    TAngleMap::iterator a2e = edgesByAngle.begin();
+    edge = a2e->second;
+    if ( useOverlap &&
+         a2e->first - edge->ShapeFactor() > M_PI - angTol ) // all new triangles need shift
+    {
+      // re-sort the edges w/o overlap consideration
+      useOverlap = false;
+      nbEdges = edgesByAngle.size();
+      edgesByAngle.clear();
+      for ( size_t i = 0; i < nbEdges; ++i, edge = edge->myNext )
+        edge->InsertSelf( edgesByAngle, isReverseAngle, /*reBind=*/false, useOverlap );
+      a2e = edgesByAngle.begin();
+    }
+    edge     = a2e->second;
+    edgePrev = edge->myPrev;
+
+    // create shift nodes and faces
+    edgePrev->ShiftOverlapped( edge->myNode2, capFaceWithBordInd, theMesh, theNewFaces );
+    edge->ShiftOverlapped( edgePrev->myNode1, capFaceWithBordInd, theMesh, theNewFaces );
+    edge    ->MakeShiftfFaces( theMesh, theNewFaces, isReverse );
+    edgePrev->MakeShiftfFaces( theMesh, theNewFaces, isReverse );
+
+    // make a cap face
+    //nodes.resize( 3 );
+    nodes[0] = edgePrev->myNode1Shift ? edgePrev->myNode1Shift : edgePrev->myNode1;
+    nodes[1] = edgePrev->myNode2Shift ? edgePrev->myNode2Shift : edgePrev->myNode2;
+    nodes[2] = edge->myNode2Shift     ? edge->myNode2Shift     : edge->myNode2;
+    theNewFaces.push_back( MakeTria( theMesh, nodes[0], nodes[1], nodes[2], isReverse ));
+    // std::cout << nodes[1]->GetID() << " "  << nodes[0]->GetID() << " "  << nodes[2]->GetID()
+    //           << " " << edge->myAngleWithPrev << std::endl;
+
+    // remember a border edge within the new cap face
+    theNewFaces.back()->setIsMarked( true );
+    if ( edgePrev->myFace )
+      capFaceWithBordInd.insert( std::make_pair( theNewFaces.back(), isReverse ? 2 : 0 ));
+    if ( edge->myFace )
+      capFaceWithBordInd.insert( std::make_pair( theNewFaces.back(), 1 ));
+
+    // remove edgePrev from the list and update <edge>
+    edgesByAngle.erase( edgePrev->myAngleMapPos );
+    circularList.unlink( edgePrev ); // remove edgePrev from the border
+
+    edge->Init( edgePrev->myNode1, edge->myNode2, theNewFaces.back(), nodes[0], nodes[2] );
+    edge->ComputeAngle( isReverseAngle );
+    edge->InsertSelf( edgesByAngle, /*isReverse=*/false, /*reBind=*/true, useOverlap );
+    edge->myNext->ComputeAngle( isReverseAngle );
+    edge->myNext->InsertSelf( edgesByAngle, /*isReverse=*/false, /*reBind=*/true, useOverlap );
+    // std::cout << "A " << edge->myNode1->GetID() << " " << edge->myAngleWithPrev
+    //           << " " << edge->myNext->myNode1->GetID() << " " << edge->myNext->myAngleWithPrev
+    //           << std::endl;
+  }
+  edge = edgesByAngle.begin()->second;
+  edge->        MakeShiftfFaces( theMesh, theNewFaces, isReverse );
+  edge->myNext->MakeShiftfFaces( theMesh, theNewFaces, isReverse );
+}
index ae6efa6db59278e06f30a04153a023fdbedb271a..d098604656bde77db45f5dd3de814c60cdbfd816 100644 (file)
@@ -131,8 +131,11 @@ namespace
       if ( myID < 0 )
       {
         myID = id;
-        if ( myNext )
-          myNext->SetID( id + 1 );
+
+        for ( BEdge* be = myNext; be && be->myID < 0; be = be->myNext )
+        {
+          be->myID = ++id;
+        }
       }
     }
     //================================================================================
@@ -821,3 +824,136 @@ void SMESH_MeshAlgos::FindCoincidentFreeBorders(SMDS_Mesh&              mesh,
 
 } // SMESH_MeshAlgos::FindCoincidentFreeBorders()
 
+//================================================================================
+/*
+ * Returns all TFreeBorder's. Optionally check if the mesh is manifold
+ * and if faces are correctly oriented.
+ */
+//================================================================================
+
+void SMESH_MeshAlgos::FindFreeBorders(SMDS_Mesh&       theMesh,
+                                      TFreeBorderVec & theFoundFreeBordes,
+                                      const bool       theClosedOnly,
+                                      bool*            theIsManifold,
+                                      bool*            theIsGoodOri)
+{
+  bool isManifold = true;
+
+  // find free links
+  typedef NCollection_DataMap<SMESH_TLink, const SMDS_MeshElement*, SMESH_TLink > TLink2FaceMap;
+  TLink2FaceMap linkMap;
+  int nbSharedLinks = 0;
+  SMDS_FaceIteratorPtr faceIt = theMesh.facesIterator();
+  while ( faceIt->more() )
+  {
+    const SMDS_MeshElement* face = faceIt->next();
+    if ( !face ) continue;
+
+    const SMDS_MeshNode*     n0 = face->GetNode( face->NbNodes() - 1 );
+    SMDS_NodeIteratorPtr nodeIt = face->interlacedNodesIterator();
+    while ( nodeIt->more() )
+    {
+      const SMDS_MeshNode* n1 = nodeIt->next();
+      SMESH_TLink link( n0, n1 );
+      if ( const SMDS_MeshElement** faceInMap = linkMap.ChangeSeek( link ))
+      {
+        if ( *faceInMap )
+        {
+          if ( theIsGoodOri && *theIsGoodOri && !IsRightOrder( *faceInMap, n1, n0 ))
+            *theIsGoodOri = false;
+        }
+        else
+        {
+          isManifold = false;
+        }
+        nbSharedLinks += bool( *faceInMap );
+        *faceInMap = 0;
+      }
+      else
+      {
+        linkMap.Bind( link, face );
+      }
+      n0 = n1;
+    }
+  }
+  if ( theIsManifold )
+    *theIsManifold = isManifold;
+
+  if ( linkMap.Extent() == nbSharedLinks )
+    return;
+
+  // form free borders
+  std::set   < BNode > bNodes;
+  std::vector< BEdge > bEdges( linkMap.Extent() - nbSharedLinks );
+
+  TLink2FaceMap::Iterator linkIt( linkMap );
+  for ( int iEdge = 0; linkIt.More(); linkIt.Next() )
+  {
+    if ( !linkIt.Value() ) continue;
+    const SMESH_TLink & link = linkIt.Key();
+    std::set< BNode >::iterator n1 = bNodes.insert( BNode( link.node1() )).first;
+    std::set< BNode >::iterator n2 = bNodes.insert( BNode( link.node2() )).first;
+    bEdges[ iEdge ].Set( &*n1, &*n2, linkIt.Value(), iEdge+1 );
+    n1->AddLinked( & bEdges[ iEdge ] );
+    n2->AddLinked( & bEdges[ iEdge ] );
+    ++iEdge;
+  }
+  linkMap.Clear();
+
+  // assign IDs to borders
+  std::vector< BEdge* > borders; // 1st of connected (via myPrev and myNext) edges
+  std::set< BNode >::iterator bn = bNodes.begin();
+  for ( ; bn != bNodes.end(); ++bn )
+  {
+    for ( size_t i = 0; i < bn->myLinkedEdges.size(); ++i )
+    {
+      if ( bn->myLinkedEdges[i]->myBorderID < 0 )
+      {
+        BEdge* be = bn->myLinkedEdges[i];
+        int borderID = borders.size();
+        borders.push_back( be );
+        for ( ; be && be->myBorderID < 0; be = be->myNext )
+        {
+          be->myBorderID = borderID;
+          be->Orient();
+        }
+        bool isClosed = ( be == bn->myLinkedEdges[i] );
+        if ( !isClosed && theClosedOnly )
+        {
+          borders.pop_back();
+          continue;
+        }
+        be = bn->myLinkedEdges[i]->myPrev;
+        for ( ; be && be->myBorderID < 0; be = be->myPrev )
+        {
+          be->myBorderID = borderID;
+          be->Orient();
+        }
+        if ( !isClosed )
+          while ( borders.back()->myPrev )
+            borders.back() = borders.back()->myPrev;
+      }
+    }
+  }
+  theFoundFreeBordes.resize( borders.size() );
+  for ( size_t i = 0; i < borders.size(); ++i )
+  {
+    TFreeBorder & bordNodes = theFoundFreeBordes[ i ];
+    BEdge*               be = borders[i];
+
+    size_t cnt = 1;
+    for ( be = be->myNext; be && be != borders[i]; be = be->myNext )
+      ++cnt;
+    bordNodes.resize( cnt + 1 );
+
+    BEdge* beLast;
+    for ( be = borders[i], cnt = 0;
+          be && cnt < bordNodes.size()-1;
+          be = be->myNext, ++cnt )
+    {
+      bordNodes[ cnt ] = be->myBNode1->Node();
+      beLast = be;
+    }
+    bordNodes.back() = beLast->myBNode2->Node();
+  }
+}
index 6670e509e9d00a8d06677dd91ee726145a6a8902..eea7912c7e3303c67e6f4eaf77742fe248f81a39 100644 (file)
@@ -35,6 +35,8 @@
 #include "SMDS_VolumeTool.hxx"
 #include "SMESH_OctreeNode.hxx"
 
+#include <Utils_SALOME_Exception.hxx>
+
 #include <GC_MakeSegment.hxx>
 #include <GeomAPI_ExtremaCurveCurve.hxx>
 #include <Geom_Line.hxx>
@@ -228,15 +230,15 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
                       SMDSAbs_ElementType  elemType,
                       SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(),
                       double               tolerance = NodeRadius );
-    void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems );
-    void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
-    void getElementsInSphere ( const gp_XYZ& center,
-                               const double  radius, TIDSortedElemSet& foundElems);
-    size_t getSize() { return std::max( _size, _elements.size() ); }
-    virtual ~ElementBndBoxTree();
+    void getElementsNearPoint( const gp_Pnt& point, vector<const SMDS_MeshElement*>& foundElems );
+    void getElementsNearLine ( const gp_Ax1& line,  vector<const SMDS_MeshElement*>& foundElems);
+    void getElementsInSphere ( const gp_XYZ&                    center,
+                               const double                     radius,
+                               vector<const SMDS_MeshElement*>& foundElems);
+    ElementBndBoxTree* getLeafAtPoint( const gp_XYZ& point );
 
   protected:
-    ElementBndBoxTree():_size(0) {}
+    ElementBndBoxTree() {}
     SMESH_Octree* newChild() const { return new ElementBndBoxTree; }
     void          buildChildrenData();
     Bnd_B3d*      buildRootBox();
@@ -245,11 +247,25 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
     struct ElementBox : public Bnd_B3d
     {
       const SMDS_MeshElement* _element;
-      int                     _refCount; // an ElementBox can be included in several tree branches
-      ElementBox(const SMDS_MeshElement* elem, double tolerance);
+      bool                    _isMarked;
+      void init(const SMDS_MeshElement* elem, double tolerance);
     };
     vector< ElementBox* > _elements;
-    size_t                _size;
+
+    typedef ObjectPool< ElementBox > TElementBoxPool;
+
+    //!< allocator of ElementBox's and SMESH_TreeLimit
+    struct LimitAndPool : public SMESH_TreeLimit
+    {
+      TElementBoxPool            _elBoPool;
+      std::vector< ElementBox* > _markedElems;
+      LimitAndPool():SMESH_TreeLimit( MaxLevel, /*minSize=*/0. ), _elBoPool(1024) {}
+    };
+    LimitAndPool* getLimitAndPool() const
+    {
+      SMESH_TreeLimit* limitAndPool = const_cast< SMESH_TreeLimit* >( myLimit );
+      return static_cast< LimitAndPool* >( limitAndPool );
+    }
   };
 
   //================================================================================
@@ -258,32 +274,27 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
    */
   //================================================================================
 
-  ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
-    :SMESH_Octree( new SMESH_TreeLimit( MaxLevel, /*minSize=*/0. ))
+  ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh&     mesh,
+                                       SMDSAbs_ElementType  elemType,
+                                       SMDS_ElemIteratorPtr theElemIt,
+                                       double               tolerance)
+    :SMESH_Octree( new LimitAndPool() )
   {
     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
     _elements.reserve( nbElems );
 
+    TElementBoxPool& elBoPool = getLimitAndPool()->_elBoPool;
+
     SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
     while ( elemIt->more() )
-      _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
-
+    {
+      ElementBox* eb = elBoPool.getNew();
+      eb->init( elemIt->next(), tolerance );
+      _elements.push_back( eb );
+    }
     compute();
   }
 
-  //================================================================================
-  /*!
-   * \brief Destructor
-   */
-  //================================================================================
-
-  ElementBndBoxTree::~ElementBndBoxTree()
-  {
-    for ( size_t i = 0; i < _elements.size(); ++i )
-      if ( --_elements[i]->_refCount <= 0 )
-        delete _elements[i];
-  }
-
   //================================================================================
   /*!
    * \brief Return the maximal box
@@ -311,14 +322,10 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
       for (int j = 0; j < 8; j++)
       {
         if ( !_elements[i]->IsOut( *myChildren[j]->getBox() ))
-        {
-          _elements[i]->_refCount++;
           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
-        }
       }
-      _elements[i]->_refCount--;
     }
-    _size = _elements.size();
+    //_size = _elements.size();
     SMESHUtils::FreeVector( _elements ); // = _elements.clear() + free memory
 
     for (int j = 0; j < 8; j++)
@@ -327,7 +334,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
       if ((int) child->_elements.size() <= MaxNbElemsInLeaf )
         child->myIsLeaf = true;
 
-      if ( child->_elements.capacity() - child->_elements.size() > 1000 )
+      if ( child->isLeaf() && child->_elements.capacity() > child->_elements.size() )
         SMESHUtils::CompactVector( child->_elements );
     }
   }
@@ -338,22 +345,37 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
    */
   //================================================================================
 
-  void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
-                                                TIDSortedElemSet& foundElems)
+  void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&                    point,
+                                                vector<const SMDS_MeshElement*>& foundElems)
   {
     if ( getBox()->IsOut( point.XYZ() ))
       return;
 
     if ( isLeaf() )
     {
+      LimitAndPool* pool = getLimitAndPool();
+
       for ( size_t i = 0; i < _elements.size(); ++i )
-        if ( !_elements[i]->IsOut( point.XYZ() ))
-          foundElems.insert( _elements[i]->_element );
+        if ( !_elements[i]->IsOut( point.XYZ() ) &&
+             !_elements[i]->_isMarked )
+        {
+          foundElems.push_back( _elements[i]->_element );
+          _elements[i]->_isMarked = true;
+          pool->_markedElems.push_back( _elements[i] );
+        }
     }
     else
     {
       for (int i = 0; i < 8; i++)
         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
+
+      if ( level() == 0 )
+      {
+        LimitAndPool* pool = getLimitAndPool();
+        for ( size_t i = 0; i < pool->_markedElems.size(); ++i )
+          pool->_markedElems[i]->_isMarked = false;
+        pool->_markedElems.clear();
+      }
     }
   }
 
@@ -363,22 +385,37 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
    */
   //================================================================================
 
-  void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
-                                               TIDSortedElemSet& foundElems)
+  void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&                    line,
+                                               vector<const SMDS_MeshElement*>& foundElems)
   {
     if ( getBox()->IsOut( line ))
       return;
 
     if ( isLeaf() )
     {
+      LimitAndPool* pool = getLimitAndPool();
+
       for ( size_t i = 0; i < _elements.size(); ++i )
-        if ( !_elements[i]->IsOut( line ))
-          foundElems.insert( _elements[i]->_element );
+        if ( !_elements[i]->IsOut( line ) &&
+             !_elements[i]->_isMarked )
+        {
+          foundElems.push_back( _elements[i]->_element );
+          _elements[i]->_isMarked = true;
+          pool->_markedElems.push_back( _elements[i] );
+        }
     }
     else
     {
       for (int i = 0; i < 8; i++)
         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
+
+      if ( level() == 0 )
+      {
+        LimitAndPool* pool = getLimitAndPool();
+        for ( size_t i = 0; i < pool->_markedElems.size(); ++i )
+          pool->_markedElems[i]->_isMarked = false;
+        pool->_markedElems.clear();
+      }
     }
   }
 
@@ -388,24 +425,63 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
    */
   //================================================================================
 
-  void ElementBndBoxTree::getElementsInSphere ( const gp_XYZ&     center,
-                                                const double      radius,
-                                                TIDSortedElemSet& foundElems)
+  void ElementBndBoxTree::getElementsInSphere ( const gp_XYZ&                    center,
+                                                const double                     radius,
+                                                vector<const SMDS_MeshElement*>& foundElems)
   {
     if ( getBox()->IsOut( center, radius ))
       return;
 
     if ( isLeaf() )
     {
+      LimitAndPool* pool = getLimitAndPool();
+
       for ( size_t i = 0; i < _elements.size(); ++i )
-        if ( !_elements[i]->IsOut( center, radius ))
-          foundElems.insert( _elements[i]->_element );
+        if ( !_elements[i]->IsOut( center, radius ) &&
+             !_elements[i]->_isMarked )
+        {
+          foundElems.push_back( _elements[i]->_element );
+          _elements[i]->_isMarked = true;
+          pool->_markedElems.push_back( _elements[i] );
+        }
     }
     else
     {
       for (int i = 0; i < 8; i++)
         ((ElementBndBoxTree*) myChildren[i])->getElementsInSphere( center, radius, foundElems );
+
+      if ( level() == 0 )
+      {
+        LimitAndPool* pool = getLimitAndPool();
+        for ( size_t i = 0; i < pool->_markedElems.size(); ++i )
+          pool->_markedElems[i]->_isMarked = false;
+        pool->_markedElems.clear();
+      }
+    }
+  }
+
+  //================================================================================
+  /*!
+   * \brief Return a leaf including a point
+   */
+  //================================================================================
+
+  ElementBndBoxTree* ElementBndBoxTree::getLeafAtPoint( const gp_XYZ& point )
+  {
+    if ( getBox()->IsOut( point ))
+      return 0;
+
+    if ( isLeaf() )
+    {
+      return this;
     }
+    else
+    {
+      for (int i = 0; i < 8; i++)
+        if ( ElementBndBoxTree* l = ((ElementBndBoxTree*) myChildren[i])->getLeafAtPoint( point ))
+          return l;
+    }
+    return 0;
   }
 
   //================================================================================
@@ -414,13 +490,13 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
    */
   //================================================================================
 
-  ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
+  void ElementBndBoxTree::ElementBox::init(const SMDS_MeshElement* elem, double tolerance)
   {
     _element  = elem;
-    _refCount = 1;
+    _isMarked = false;
     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
     while ( nIt->more() )
-      Add( SMESH_TNodeXYZ( nIt->next() ));
+      Add( SMESH_NodeXYZ( nIt->next() ));
     Enlarge( tolerance );
   }
 
@@ -441,8 +517,8 @@ struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
 {
   SMDS_Mesh*                   _mesh;
   SMDS_ElemIteratorPtr         _meshPartIt;
-  ElementBndBoxTree*           _ebbTree;
-  int                          _ebbTreeHeight;
+  ElementBndBoxTree*           _ebbTree      [SMDSAbs_NbElementTypes];
+  int                          _ebbTreeHeight[SMDSAbs_NbElementTypes];
   SMESH_NodeSearcherImpl*      _nodeSearcher;
   SMDSAbs_ElementType          _elementType;
   double                       _tolerance;
@@ -452,10 +528,21 @@ struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
   SMESH_ElementSearcherImpl( SMDS_Mesh&           mesh,
                              double               tol=-1,
                              SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
-    : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_ebbTreeHeight(-1),_nodeSearcher(0),_tolerance(tol),_outerFacesFound(false) {}
+    : _mesh(&mesh),_meshPartIt(elemIt),_nodeSearcher(0),_tolerance(tol),_outerFacesFound(false)
+  {
+    for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
+    {
+      _ebbTree[i] = NULL;
+      _ebbTreeHeight[i] = -1;
+    }
+    _elementType = SMDSAbs_All;
+  }
   virtual ~SMESH_ElementSearcherImpl()
   {
-    if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
+    for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
+    {
+      delete _ebbTree[i]; _ebbTree[i] = NULL;
+    }
     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
   }
   virtual int FindElementsByPoint(const gp_Pnt&                      point,
@@ -465,13 +552,16 @@ struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
   virtual const SMDS_MeshElement* FindClosestTo( const gp_Pnt&       point,
                                                  SMDSAbs_ElementType type );
 
-  void GetElementsNearLine( const gp_Ax1&                      line,
-                            SMDSAbs_ElementType                type,
-                            vector< const SMDS_MeshElement* >& foundElems);
-  void GetElementsInSphere( const gp_XYZ&                      center,
-                            const double                       radius,
-                            SMDSAbs_ElementType                type,
-                            vector< const SMDS_MeshElement* >& foundElems);
+  virtual void GetElementsNearLine( const gp_Ax1&                      line,
+                                    SMDSAbs_ElementType                type,
+                                    vector< const SMDS_MeshElement* >& foundElems);
+  virtual void GetElementsInSphere( const gp_XYZ&                      center,
+                                    const double                       radius,
+                                    SMDSAbs_ElementType                type,
+                                    vector< const SMDS_MeshElement* >& foundElems);
+  virtual gp_XYZ Project(const gp_Pnt&            point,
+                         SMDSAbs_ElementType      type,
+                         const SMDS_MeshElement** closestElem);
   double getTolerance();
   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
                             const double tolerance, double & param);
@@ -482,9 +572,9 @@ struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
   }
   int getTreeHeight()
   {
-    if ( _ebbTreeHeight < 0 )
-      _ebbTreeHeight = _ebbTree->getHeight();
-    return _ebbTreeHeight;
+    if ( _ebbTreeHeight[ _elementType ] < 0 )
+      _ebbTreeHeight[ _elementType ] = _ebbTree[ _elementType ]->getHeight();
+    return _ebbTreeHeight[ _elementType ];
   }
 
   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
@@ -528,9 +618,9 @@ double SMESH_ElementSearcherImpl::getTolerance()
       double boxSize = _nodeSearcher->getTree()->maxSize();
       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
     }
-    else if ( _ebbTree && meshInfo.NbElements() > 0 )
+    else if ( _ebbTree[_elementType] && meshInfo.NbElements() > 0 )
     {
-      double boxSize = _ebbTree->maxSize();
+      double boxSize = _ebbTree[_elementType]->maxSize();
       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
     }
     if ( _tolerance == 0 )
@@ -551,10 +641,9 @@ double SMESH_ElementSearcherImpl::getTolerance()
       }
       else
       {
-        SMDS_ElemIteratorPtr elemIt =
-            _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
+        SMDS_ElemIteratorPtr  elemIt = _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
         const SMDS_MeshElement* elem = elemIt->next();
-        SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
+        SMDS_ElemIteratorPtr  nodeIt = elem->nodesIterator();
         SMESH_TNodeXYZ n1( nodeIt->next() );
         elemSize = 0;
         while ( nodeIt->more() )
@@ -594,7 +683,7 @@ bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           lin
     anExtCC.Init( lineCurve, edge.Value() );
     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
     {
-      Quantity_Parameter pl, pe;
+      Standard_Real pl, pe;
       anExtCC.LowerDistanceParameters( pl, pe );
       param += pl;
       if ( ++nbInts == 2 )
@@ -679,7 +768,7 @@ void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerF
           outerFace2 = angle2Face.begin()->second;
       }
     }
-    // store the found outer face and add its links to continue seaching from
+    // store the found outer face and add its links to continue searching from
     if ( outerFace2 )
     {
       _outerFaces.insert( outerFace2 );
@@ -723,6 +812,7 @@ FindElementsByPoint(const gp_Pnt&                      point,
                     vector< const SMDS_MeshElement* >& foundElements)
 {
   foundElements.clear();
+  _elementType = type;
 
   double tolerance = getTolerance();
 
@@ -756,14 +846,13 @@ FindElementsByPoint(const gp_Pnt&                      point,
   // =================================================================================
   else // elements more complex than 0D
   {
-    if ( !_ebbTree || _elementType != type )
+    if ( !_ebbTree[type] )
     {
-      if ( _ebbTree ) delete _ebbTree;
-      _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
+      _ebbTree[_elementType] = new ElementBndBoxTree( *_mesh, type, _meshPartIt, tolerance );
     }
-    TIDSortedElemSet suspectElems;
-    _ebbTree->getElementsNearPoint( point, suspectElems );
-    TIDSortedElemSet::iterator elem = suspectElems.begin();
+    vector< const SMDS_MeshElement* > suspectElems;
+    _ebbTree[ type ]->getElementsNearPoint( point, suspectElems );
+    vector< const SMDS_MeshElement* >::iterator elem = suspectElems.begin();
     for ( ; elem != suspectElems.end(); ++elem )
       if ( !SMESH_MeshAlgos::IsOut( *elem, point, tolerance ))
         foundElements.push_back( *elem );
@@ -784,35 +873,37 @@ SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt&       point,
                                           SMDSAbs_ElementType type )
 {
   const SMDS_MeshElement* closestElem = 0;
+  _elementType = type;
 
-  if ( type == SMDSAbs_Face || type == SMDSAbs_Volume )
+  if ( type == SMDSAbs_Face ||
+       type == SMDSAbs_Volume ||
+       type == SMDSAbs_Edge )
   {
-    if ( !_ebbTree || _elementType != type )
-    {
-      if ( _ebbTree ) delete _ebbTree;
-      _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
-    }
-    TIDSortedElemSet suspectElems;
-    _ebbTree->getElementsNearPoint( point, suspectElems );
+    ElementBndBoxTree*& ebbTree = _ebbTree[ type ];
+    if ( !ebbTree )
+      ebbTree = new ElementBndBoxTree( *_mesh, type, _meshPartIt );
 
-    if ( suspectElems.empty() && _ebbTree->maxSize() > 0 )
+    vector<const SMDS_MeshElement*> suspectElems;
+    ebbTree->getElementsNearPoint( point, suspectElems );
+
+    if ( suspectElems.empty() && ebbTree->maxSize() > 0 )
     {
-      gp_Pnt boxCenter = 0.5 * ( _ebbTree->getBox()->CornerMin() +
-                                 _ebbTree->getBox()->CornerMax() );
+      gp_Pnt boxCenter = 0.5 * ( ebbTree->getBox()->CornerMin() +
+                                 ebbTree->getBox()->CornerMax() );
       double radius = -1;
-      if ( _ebbTree->getBox()->IsOut( point.XYZ() ))
-        radius = point.Distance( boxCenter ) - 0.5 * _ebbTree->maxSize();
+      if ( ebbTree->getBox()->IsOut( point.XYZ() ))
+        radius = point.Distance( boxCenter ) - 0.5 * ebbTree->maxSize();
       if ( radius < 0 )
-        radius = _ebbTree->maxSize() / pow( 2., getTreeHeight()) / 2;
+        radius = ebbTree->maxSize() / pow( 2., getTreeHeight()) / 2;
       while ( suspectElems.empty() )
       {
-        _ebbTree->getElementsInSphere( point.XYZ(), radius, suspectElems );
+        ebbTree->getElementsInSphere( point.XYZ(), radius, suspectElems );
         radius *= 1.1;
       }
     }
     double minDist = std::numeric_limits<double>::max();
     multimap< double, const SMDS_MeshElement* > dist2face;
-    TIDSortedElemSet::iterator elem = suspectElems.begin();
+    vector<const SMDS_MeshElement*>::iterator elem = suspectElems.begin();
     for ( ; elem != suspectElems.end(); ++elem )
     {
       double dist = SMESH_MeshAlgos::GetDistance( *elem, point );
@@ -869,12 +960,14 @@ SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt&       point,
 
 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
 {
+  _elementType = SMDSAbs_Face;
+
   double tolerance = getTolerance();
-  if ( !_ebbTree || _elementType != SMDSAbs_Face )
-  {
-    if ( _ebbTree ) delete _ebbTree;
-    _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
-  }
+
+  ElementBndBoxTree*& ebbTree = _ebbTree[ SMDSAbs_Face ];
+  if ( !ebbTree )
+    ebbTree = new ElementBndBoxTree( *_mesh, _elementType, _meshPartIt );
+
   // Algo: analyse transition of a line starting at the point through mesh boundary;
   // try three lines parallel to axis of the coordinate system and perform rough
   // analysis. If solution is not clear perform thorough analysis.
@@ -889,13 +982,13 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
     gp_Ax1 lineAxis( point, axisDir[axis]);
     gp_Lin line    ( lineAxis );
 
-    TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
-    _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
+    vector<const SMDS_MeshElement*> suspectFaces; // faces possibly intersecting the line
+    ebbTree->getElementsNearLine( lineAxis, suspectFaces );
 
     // Intersect faces with the line
 
     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
-    TIDSortedElemSet::iterator face = suspectFaces.begin();
+    vector<const SMDS_MeshElement*>::iterator face = suspectFaces.begin();
     for ( ; face != suspectFaces.end(); ++face )
     {
       // get face plane
@@ -1098,14 +1191,12 @@ void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&
                                                      SMDSAbs_ElementType                type,
                                                      vector< const SMDS_MeshElement* >& foundElems)
 {
-  if ( !_ebbTree || _elementType != type )
-  {
-    if ( _ebbTree ) delete _ebbTree;
-    _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
-  }
-  TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
-  _ebbTree->getElementsNearLine( line, suspectFaces );
-  foundElems.assign( suspectFaces.begin(), suspectFaces.end());
+  _elementType = type;
+  ElementBndBoxTree*& ebbTree = _ebbTree[ type ];
+  if ( !ebbTree )
+    ebbTree = new ElementBndBoxTree( *_mesh, _elementType, _meshPartIt );
+
+  ebbTree->getElementsNearLine( line, foundElems );
 }
 
 //=======================================================================
@@ -1119,14 +1210,61 @@ void SMESH_ElementSearcherImpl::GetElementsInSphere( const gp_XYZ&
                                                      SMDSAbs_ElementType                type,
                                                      vector< const SMDS_MeshElement* >& foundElems)
 {
-  if ( !_ebbTree || _elementType != type )
+  _elementType = type;
+  ElementBndBoxTree*& ebbTree = _ebbTree[ type ];
+  if ( !ebbTree )
+    ebbTree = new ElementBndBoxTree( *_mesh, _elementType, _meshPartIt );
+
+  ebbTree->getElementsInSphere( center, radius, foundElems );
+}
+
+//=======================================================================
+/*
+ * \brief Return a projection of a given point to a mesh.
+ *        Optionally return the closest element
+ */
+//=======================================================================
+
+gp_XYZ SMESH_ElementSearcherImpl::Project(const gp_Pnt&            point,
+                                          SMDSAbs_ElementType      type,
+                                          const SMDS_MeshElement** closestElem)
+{
+  _elementType = type;
+  if ( _mesh->GetMeshInfo().NbElements( _elementType ) == 0 )
+    throw SALOME_Exception( LOCALIZED( "No elements of given type in the mesh" ));
+
+  ElementBndBoxTree*& ebbTree = _ebbTree[ _elementType ];
+  if ( !ebbTree )
+    ebbTree = new ElementBndBoxTree( *_mesh, _elementType );
+
+  gp_XYZ p = point.XYZ();
+  ElementBndBoxTree* ebbLeaf = ebbTree->getLeafAtPoint( p );
+  const Bnd_B3d* box = ebbLeaf->getBox();
+  double radius = ( box->CornerMax() - box->CornerMin() ).Modulus();
+
+  vector< const SMDS_MeshElement* > elems;
+  ebbTree->getElementsInSphere( p, radius, elems );
+  while ( elems.empty() )
   {
-    if ( _ebbTree ) delete _ebbTree;
-    _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
+    radius *= 1.5;
+    ebbTree->getElementsInSphere( p, radius, elems );
   }
-  TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
-  _ebbTree->getElementsInSphere( center, radius, suspectFaces );
-  foundElems.assign( suspectFaces.begin(), suspectFaces.end() );
+  gp_XYZ proj, bestProj;
+  const SMDS_MeshElement* elem = 0;
+  double minDist = 2 * radius;
+  for ( size_t i = 0; i < elems.size(); ++i )
+  {
+    double d = SMESH_MeshAlgos::GetDistance( elems[i], p, &proj );
+    if ( d < minDist )
+    {
+      bestProj = proj;
+      elem = elems[i];
+      minDist = d;
+    }
+  }
+  if ( closestElem ) *closestElem = elem;
+
+  return bestProj;
 }
 
 //=======================================================================
@@ -1163,8 +1301,8 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin
       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
       faceNorm += edge1 ^ edge2;
     }
-    double normSize = faceNorm.Magnitude();
-    if ( normSize <= tol )
+    double fNormSize = faceNorm.Magnitude();
+    if ( fNormSize <= tol )
     {
       // degenerated face: point is out if it is out of all face edges
       for ( i = 0; i < nbNodes; ++i )
@@ -1175,7 +1313,7 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin
       }
       return true;
     }
-    faceNorm /= normSize;
+    faceNorm /= fNormSize;
 
     // check if the point lays on face plane
     gp_Vec n2p( xyz[0], point );
@@ -1204,9 +1342,10 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin
     // to find intersections of the ray with the boundary.
     gp_Vec ray = n2p;
     gp_Vec plnNorm = ray ^ faceNorm;
-    normSize = plnNorm.Magnitude();
-    if ( normSize <= tol ) return false; // point coincides with the first node
-    plnNorm /= normSize;
+    double n2pSize = plnNorm.Magnitude();
+    if ( n2pSize <= tol ) return false; // point coincides with the first node
+    if ( n2pSize * n2pSize > fNormSize * 100 ) return true; // point is very far
+    plnNorm /= n2pSize;
     // for each node of the face, compute its signed distance to the cutting plane
     vector<double> dist( nbNodes + 1);
     for ( i = 0; i < nbNodes; ++i )
@@ -1252,7 +1391,7 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin
     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
       return out;
 
-    // ray pass through a face node; analyze transition through an adjacent edge
+    // the ray passes through a face node; analyze transition through an adjacent edge
     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
     gp_Vec edgeAdjacent( p1, p2 );
@@ -1375,17 +1514,19 @@ namespace
 //=======================================================================
 
 double SMESH_MeshAlgos::GetDistance( const SMDS_MeshElement* elem,
-                                     const gp_Pnt&           point )
+                                     const gp_Pnt&           point,
+                                     gp_XYZ*                 closestPnt )
 {
   switch ( elem->GetType() )
   {
   case SMDSAbs_Volume:
-    return GetDistance( dynamic_cast<const SMDS_MeshVolume*>( elem ), point);
+    return GetDistance( dynamic_cast<const SMDS_MeshVolume*>( elem ), point, closestPnt );
   case SMDSAbs_Face:
-    return GetDistance( dynamic_cast<const SMDS_MeshFace*>( elem ), point);
+    return GetDistance( dynamic_cast<const SMDS_MeshFace*>( elem ), point, closestPnt );
   case SMDSAbs_Edge:
-    return GetDistance( dynamic_cast<const SMDS_MeshEdge*>( elem ), point);
+    return GetDistance( dynamic_cast<const SMDS_MeshEdge*>( elem ), point, closestPnt );
   case SMDSAbs_Node:
+    if ( closestPnt ) *closestPnt = SMESH_TNodeXYZ( elem );
     return point.Distance( SMESH_TNodeXYZ( elem ));
   default:;
   }
@@ -1401,9 +1542,10 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshElement* elem,
 //=======================================================================
 
 double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face,
-                                     const gp_Pnt&        point )
+                                     const gp_Pnt&        point,
+                                     gp_XYZ*              closestPnt )
 {
-  double badDistance = -1;
+  const double badDistance = -1;
   if ( !face ) return badDistance;
 
   // coordinates of nodes (medium nodes, if any, ignored)
@@ -1447,7 +1589,7 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face,
   trsf.Transforms( tmpPnt );
   gp_XY point2D( tmpPnt.X(), tmpPnt.Z() );
 
-  // loop on segments of the face to analyze point position ralative to the face
+  // loop on edges of the face to analyze point position ralative to the face
   set< PointPos > pntPosSet;
   for ( size_t i = 1; i < xy.size(); ++i )
   {
@@ -1457,31 +1599,40 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face,
 
   // compute distance
   PointPos pos = *pntPosSet.begin();
-  // cout << "Face " << face->GetID() << " DIST: ";
   switch ( pos._name )
   {
-  case POS_LEFT: {
-    // point is most close to a segment
-    gp_Vec p0p1( point, xyz[ pos._index ] );
-    gp_Vec p1p2( xyz[ pos._index ], xyz[ pos._index+1 ]); // segment vector
-    p1p2.Normalize();
-    double projDist = p0p1 * p1p2; // distance projected to the segment
-    gp_Vec projVec = p1p2 * projDist;
-    gp_Vec distVec = p0p1 - projVec;
-    // cout << distVec.Magnitude()  << ", SEG " << face->GetNode(pos._index)->GetID()
-    //      << " - " << face->GetNodeWrap(pos._index+1)->GetID() << endl;
-    return distVec.Magnitude();
+  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 = ( 1. - u ) * xyz[ pos._index ] + u * xyz[ pos._index+1 ];
+    if ( closestPnt ) *closestPnt = proj;
+    return point.Distance( proj );
   }
-  case POS_RIGHT: {
+  case POS_RIGHT:
+  {
     // point is inside the face
-    double distToFacePlane = tmpPnt.Y();
-    // cout << distToFacePlane << ", INSIDE " << endl;
-    return Abs( distToFacePlane );
+    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;
+      }
+    }
+    return distToFacePlane;
   }
-  case POS_VERTEX: {
+  case POS_VERTEX:
+  {
     // point is most close to a node
     gp_Vec distVec( point, xyz[ pos._index ]);
-    // cout << distVec.Magnitude()  << " VERTEX " << face->GetNode(pos._index)->GetID() << endl;
     return distVec.Magnitude();
   }
   default:;
@@ -1495,7 +1646,9 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face,
  */
 //=======================================================================
 
-double SMESH_MeshAlgos::GetDistance( const SMDS_MeshEdge* seg, const gp_Pnt& point )
+double SMESH_MeshAlgos::GetDistance( const SMDS_MeshEdge* seg,
+                                     const gp_Pnt&        point,
+                                     gp_XYZ*              closestPnt )
 {
   double dist = Precision::Infinite();
   if ( !seg ) return dist;
@@ -1511,16 +1664,25 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshEdge* seg, const gp_Pnt& poi
   {
     gp_Vec edge( xyz[i-1], xyz[i] );
     gp_Vec n1p ( xyz[i-1], point  );
-    double u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge
+    double d, u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge
     if ( u <= 0. ) {
-      dist = Min( dist, n1p.SquareMagnitude() );
+      if (( d = n1p.SquareMagnitude() ) < dist ) {
+        dist = d;
+        if ( closestPnt ) *closestPnt = xyz[i-1];
+      }
     }
     else if ( u >= 1. ) {
-      dist = Min( dist, point.SquareDistance( xyz[i] ));
+      if (( d = point.SquareDistance( xyz[i] )) < dist ) {
+        dist = d;
+        if ( closestPnt ) *closestPnt = xyz[i];
+      }
     }
     else {
-      gp_XYZ proj = ( 1. - u ) * xyz[i-1] + u * xyz[i]; // projection of the point on the edge
-      dist = Min( dist, point.SquareDistance( proj ));
+      gp_XYZ proj = xyz[i-1] + u * edge.XYZ(); // projection of the point on the edge
+      if (( d = point.SquareDistance( proj )) < dist ) {
+        dist = d;
+        if ( closestPnt ) *closestPnt = proj;
+      }
     }
   }
   return Sqrt( dist );
@@ -1534,7 +1696,9 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshEdge* seg, const gp_Pnt& poi
  */
 //=======================================================================
 
-double SMESH_MeshAlgos::GetDistance( const SMDS_MeshVolume* volume, const gp_Pnt& point )
+double SMESH_MeshAlgos::GetDistance( const SMDS_MeshVolume* volume,
+                                     const gp_Pnt&          point,
+                                     gp_XYZ*                closestPnt )
 {
   SMDS_VolumeTool vTool( volume );
   vTool.SetExternalNormal();
@@ -1542,6 +1706,8 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshVolume* volume, const gp_Pnt
 
   double n[3], bc[3];
   double minDist = 1e100, dist;
+  gp_XYZ closeP = point.XYZ();
+  bool isOut = false;
   for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
   {
     // skip a facet with normal not "looking at" the point
@@ -1558,23 +1724,34 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshVolume* volume, const gp_Pnt
     case 3:
     {
       SMDS_FaceOfNodes tmpFace( nodes[0], nodes[ 1*iQ ], nodes[ 2*iQ ] );
-      dist = GetDistance( &tmpFace, point );
+      dist = GetDistance( &tmpFace, point, closestPnt );
       break;
     }
     case 4:
     {
       SMDS_FaceOfNodes tmpFace( nodes[0], nodes[ 1*iQ ], nodes[ 2*iQ ], nodes[ 3*iQ ]);
-      dist = GetDistance( &tmpFace, point );
+      dist = GetDistance( &tmpFace, point, closestPnt );
       break;
     }
     default:
       vector<const SMDS_MeshNode *> nvec( nodes, nodes + vTool.NbFaceNodes( iF ));
       SMDS_PolygonalFaceOfNodes tmpFace( nvec );
-      dist = GetDistance( &tmpFace, point );
+      dist = GetDistance( &tmpFace, point, closestPnt );
     }
-    minDist = Min( minDist, dist );
+    if ( dist < minDist )
+    {
+      minDist = dist;
+      isOut = true;
+      if ( closestPnt ) closeP = *closestPnt;
+    }
+  }
+  if ( isOut )
+  {
+    if ( closestPnt ) *closestPnt = closeP;
+    return minDist;
   }
-  return minDist;
+
+  return 0; // point is inside the volume
 }
 
 //================================================================================
@@ -1718,6 +1895,34 @@ vector< const SMDS_MeshNode*> SMESH_MeshAlgos::GetCommonNodes(const SMDS_MeshEle
       common.push_back( e1->GetNode( i ));
   return common;
 }
+//================================================================================
+/*!
+ * \brief Return true if node1 encounters first in the face and node2, after
+ */
+//================================================================================
+
+bool SMESH_MeshAlgos::IsRightOrder( const SMDS_MeshElement* face,
+                                    const SMDS_MeshNode*    node0,
+                                    const SMDS_MeshNode*    node1 )
+{
+  int i0 = face->GetNodeIndex( node0 );
+  int i1 = face->GetNodeIndex( node1 );
+  if ( face->IsQuadratic() )
+  {
+    if ( face->IsMediumNode( node0 ))
+    {
+      i0 -= ( face->NbNodes()/2 - 1 );
+      i1 *= 2;
+    }
+    else
+    {
+      i1 -= ( face->NbNodes()/2 - 1 );
+      i0 *= 2;
+    }
+  }
+  int diff = i1 - i0;
+  return ( diff == 1 ) || ( diff == -face->NbNodes()+1 );
+}
 
 //=======================================================================
 /*!
index b6c3661b0965ddae6725e62a7d78d095e7d23b46..66b3aa45c1243a30deb6e2795b9f80899514fc1e 100644 (file)
@@ -100,6 +100,15 @@ struct SMESHUtils_EXPORT SMESH_ElementSearcher
    * \brief Find out if the given point is out of closed 2D mesh.
    */
   virtual TopAbs_State GetPointState(const gp_Pnt& point) = 0;
+
+  /*!
+   * \brief Return a projection of a given point to a 2D mesh.
+   *        Optionally return the closest face
+   */
+  virtual gp_XYZ Project(const gp_Pnt&            point,
+                         SMDSAbs_ElementType      type,
+                         const SMDS_MeshElement** closestFace= 0) = 0;
+
   virtual ~SMESH_ElementSearcher();
 };
 
@@ -112,16 +121,16 @@ namespace SMESH_MeshAlgos
   bool IsOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol );
 
   SMESHUtils_EXPORT
-  double GetDistance( const SMDS_MeshElement* elem, const gp_Pnt& point );
+  double GetDistance( const SMDS_MeshElement* elem, const gp_Pnt& point, gp_XYZ* closestPnt = 0 );
 
   SMESHUtils_EXPORT
-  double GetDistance( const SMDS_MeshEdge* edge, const gp_Pnt& point );
+  double GetDistance( const SMDS_MeshEdge* edge, const gp_Pnt& point, gp_XYZ* closestPnt = 0 );
 
   SMESHUtils_EXPORT
-  double GetDistance( const SMDS_MeshFace* face, const gp_Pnt& point );
+  double GetDistance( const SMDS_MeshFace* face, const gp_Pnt& point, gp_XYZ* closestPnt = 0 );
 
   SMESHUtils_EXPORT
-  double GetDistance( const SMDS_MeshVolume* volume, const gp_Pnt& point );
+  double GetDistance( const SMDS_MeshVolume* volume, const gp_Pnt& point, gp_XYZ* closestPnt = 0 );
 
   SMESHUtils_EXPORT
   void GetBarycentricCoords( const gp_XY& point,
@@ -153,6 +162,14 @@ namespace SMESH_MeshAlgos
   SMESHUtils_EXPORT
   std::vector< const SMDS_MeshNode*> GetCommonNodes(const SMDS_MeshElement* e1,
                                                     const SMDS_MeshElement* e2);
+  /*!
+   * \brief Return true if node1 encounters first in the face and node2, after.
+   *        The nodes are supposed to be neighbor nodes in the face.
+   */
+  SMESHUtils_EXPORT
+  bool IsRightOrder( const SMDS_MeshElement* face,
+                     const SMDS_MeshNode*    node0,
+                     const SMDS_MeshNode*    node1 );
 
   /*!
    * \brief Return SMESH_NodeSearcher. The caller is responsible for deleteing it
@@ -204,7 +221,28 @@ namespace SMESH_MeshAlgos
   void FindCoincidentFreeBorders(SMDS_Mesh&              mesh,
                                  double                  tolerance,
                                  CoincidentFreeBorders & foundFreeBordes);
-  
+  /*!
+   * Returns all or only closed TFreeBorder's.
+   * Optionally check if the mesh is manifold and if faces are correctly oriented.
+   *
+   * (Implemented in ./SMESH_FreeBorders.cxx)
+   */
+  SMESHUtils_EXPORT
+  void FindFreeBorders(SMDS_Mesh&       mesh,
+                       TFreeBorderVec & foundFreeBordes,
+                       const bool       closedOnly,
+                       bool*            isManifold = 0,
+                       bool*            isGoodOri = 0);
+  /*!
+   * Fill a hole defined by a TFreeBorder with 2D elements.
+   *
+   * (Implemented in ./SMESH_FillHole.cxx)
+   */
+  SMESHUtils_EXPORT
+  void FillHole(const TFreeBorder &                   freeBorder,
+                SMDS_Mesh&                            mesh,
+                std::vector<const SMDS_MeshElement*>& newFaces);
+
 
 } // SMESH_MeshAlgos
 
index d5dadd0e1a15447ff2fa4633c9b3b19adf8be59f..cc185c698c5b24f16a1597dabd8760cecac1936d 100644 (file)
@@ -294,6 +294,8 @@ namespace {
     //   - FT_BelongToMeshGroup     = 22
     // v 8.1.0: FT_Undefined == 48, new items:
     //   - FT_NodeConnectivityNumber= 22
+    // v 8.5.0: FT_Undefined == 49, new items:
+    //   - FT_Deflection2D          = 22
     //
     // It's necessary to continue recording this history and to fill
     // undef2newItems (see below) accordingly.
@@ -316,6 +318,7 @@ namespace {
       undef2newItems[ 46 ].push_back( 39 );
       undef2newItems[ 47 ].push_back( 22 );
       undef2newItems[ 48 ].push_back( 22 );
+      undef2newItems[ 49 ].push_back( 22 );
 
       ASSERT( undef2newItems.rbegin()->first == SMESH::FT_Undefined );
     }
@@ -2425,7 +2428,7 @@ void _pyMeshEditor::Process( const Handle(_pyCommand)& theCommand)
       "ExtrusionAlongPathX","ExtrusionAlongPathObject1D","ExtrusionAlongPathObject2D",
       "ExtrusionSweepObjects","RotationSweepObjects","ExtrusionAlongPathObjects",
       "Mirror","MirrorObject","Translate","TranslateObject","Rotate","RotateObject",
-      "FindCoincidentNodes","MergeNodes","FindEqualElements",
+      "FindCoincidentNodes","MergeNodes","FindEqualElements","FillHole",
       "MergeElements","MergeEqualElements","SewFreeBorders","SewConformFreeBorders",
       "FindCoincidentFreeBorders", "SewCoincidentFreeBorders",
       "SewBorderToSide","SewSideElements","ChangeElemNodes","GetLastCreatedNodes",
index e22a87c775c723d496a38bcfa515e8a9ebc08668..972f9bb576561296cd44c1a4f4958fc5df98729d 100644 (file)
@@ -430,6 +430,7 @@ namespace SMESH
       case FT_MultiConnection2D:     myStream<< "aMultiConnection2D";     break;
       case FT_Length:                myStream<< "aLength";                break;
       case FT_Length2D:              myStream<< "aLength2D";              break;
+      case FT_Deflection2D:          myStream<< "aDeflection2D";          break;
       case FT_NodeConnectivityNumber:myStream<< "aNodeConnectivityNumber";break;
       case FT_BelongToMeshGroup:     myStream<< "aBelongToMeshGroup";     break;
       case FT_BelongToGeom:          myStream<< "aBelongToGeom";          break;
index 3e46a2039b7c68cb4297caeb543d23da3ce793f5..c6b1369bd37fedf7efbaaff04c66084324a443eb 100644 (file)
@@ -534,6 +534,21 @@ SMESH::Length2D::Values* Length2D_i::GetValues()
   return aResult._retn();
 }
 
+/*
+  Class       : Deflection2D_i
+  Description : Functor for calculating distance between a face and geometry
+*/
+Deflection2D_i::Deflection2D_i()
+{
+  myNumericalFunctorPtr.reset( new Controls::Deflection2D() );
+  myFunctorPtr = myNumericalFunctorPtr;
+}
+
+FunctorType Deflection2D_i::GetFunctorType()
+{
+  return SMESH::FT_Deflection2D;
+}
+
 /*
   Class       : MultiConnection_i
   Description : Functor for calculating number of faces conneted to the edge
@@ -2113,6 +2128,14 @@ Length2D_ptr FilterManager_i::CreateLength2D()
   return anObj._retn();
 }
 
+Deflection2D_ptr FilterManager_i::CreateDeflection2D()
+{
+  SMESH::Deflection2D_i* aServant = new SMESH::Deflection2D_i();
+  SMESH::Deflection2D_var   anObj = aServant->_this();
+  TPythonDump()<<aServant<<" = "<<this<<".CreateLength2D()";
+  return anObj._retn();
+}
+
 MultiConnection_ptr FilterManager_i::CreateMultiConnection()
 {
   SMESH::MultiConnection_i* aServant = new SMESH::MultiConnection_i();
@@ -2956,6 +2979,9 @@ CORBA::Boolean Filter_i::SetCriteria( const SMESH::Filter::Criteria& theCriteria
       case SMESH::FT_Length2D:
         aFunctor = aFilterMgr->CreateLength2D();
         break;
+      case SMESH::FT_Deflection2D:
+        aFunctor = aFilterMgr->CreateDeflection2D();
+        break;
       case SMESH::FT_AspectRatio:
         aFunctor = aFilterMgr->CreateAspectRatio();
         break;
@@ -3451,9 +3477,10 @@ static inline LDOMString toString( CORBA::Long theType )
     case FT_EqualFaces            : return "Equal faces";
     case FT_EqualVolumes          : return "Equal volumes";
     case FT_MultiConnection       : return "Borders at multi-connections";
-    case FT_MultiConnection2D     :return "Borders at multi-connections 2D";
+    case FT_MultiConnection2D     : return "Borders at multi-connections 2D";
     case FT_Length                : return "Length";
     case FT_Length2D              : return "Length 2D";
+    case FT_Deflection2D          : return "Deflection 2D";
     case FT_LessThan              : return "Less than";
     case FT_MoreThan              : return "More than";
     case FT_EqualTo               : return "Equal to";
@@ -3502,6 +3529,7 @@ static inline SMESH::FunctorType toFunctorType( const LDOMString& theStr )
   //  else if ( theStr.equals( "Borders at multi-connections 2D" ) ) return FT_MultiConnection2D;
   else if ( theStr.equals( "Length"                       ) ) return FT_Length;
   //  else if ( theStr.equals( "Length2D"                     ) ) return FT_Length2D;
+  else if ( theStr.equals( "Deflection"                   ) ) return FT_Deflection2D;
   else if ( theStr.equals( "Range of IDs"                 ) ) return FT_RangeOfIds;
   else if ( theStr.equals( "Bad Oriented Volume"          ) ) return FT_BadOrientedVolume;
   else if ( theStr.equals( "Volumes with bare border"     ) ) return FT_BareBorderVolume;
@@ -4078,6 +4106,7 @@ static const char** getFunctNames()
     "FT_MultiConnection2D",
     "FT_Length",
     "FT_Length2D",
+    "FT_Deflection2D",
     "FT_NodeConnectivityNumber",
     "FT_BelongToMeshGroup",
     "FT_BelongToGeom",
@@ -4094,7 +4123,7 @@ static const char** getFunctNames()
     "FT_LinearOrQuadratic",
     "FT_GroupColor",
     "FT_ElemGeomType",
-    "FT_EntityType", 
+    "FT_EntityType",
     "FT_CoplanarFaces",
     "FT_BallDiameter",
     "FT_ConnectedElements",
index b9d290c47d0bd55c731e09828cd742ebdb14f148..2e043b43ecb4a6fd4165b359763a0988fa94685c 100644 (file)
@@ -266,11 +266,23 @@ namespace SMESH
     Length2D_i();
     SMESH::Length2D::Values*        GetValues();
     FunctorType                     GetFunctorType();
-    
+
   protected:
     Controls::Length2DPtr          myLength2DPtr;
   };
-  
+
+  /*
+    Class       : Deflection2D_i
+    Description : Functor for calculating distance between a face and geometry
+  */
+  class SMESH_I_EXPORT Deflection2D_i: public virtual POA_SMESH::Deflection2D,
+                                       public virtual NumericalFunctor_i
+  {
+  public:
+    Deflection2D_i();
+    FunctorType                     GetFunctorType();
+  };
+
   /*
     Class       : MultiConnection_i
     Description : Functor for calculating number of faces conneted to the edge
@@ -1087,6 +1099,7 @@ namespace SMESH
     MaxElementLength3D_ptr    CreateMaxElementLength3D();
     Length_ptr                CreateLength();
     Length2D_ptr              CreateLength2D();
+    Deflection2D_ptr          CreateDeflection2D();
     NodeConnectivityNumber_ptr CreateNodeConnectivityNumber();
     MultiConnection_ptr       CreateMultiConnection();
     MultiConnection2D_ptr     CreateMultiConnection2D();
index a0c252bd3c9770a33337b94f906d561da80bdb84..48ec9f667594c928800e21860f75af76db92b13d 100644 (file)
@@ -4009,7 +4009,7 @@ SMESH_MeshEditor_i::ScaleMakeMesh(SMESH::SMESH_IDSource_ptr  theObject,
     // and then "GetGroups" using SMESH_Mesh::GetGroups()
 
     TPythonDump pydump; // to prevent dump at mesh creation
-    mesh = makeMesh( theMeshName );
+    mesh   = makeMesh( theMeshName );
     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
 
     if ( mesh_i )
@@ -4595,6 +4595,151 @@ CORBA::Short SMESH_MeshEditor_i::GetPointState(CORBA::Double x,
   return 0;
 }
 
+//=======================================================================
+//function : IsManifold
+//purpose  : Check if a 2D mesh is manifold
+//=======================================================================
+
+CORBA::Boolean SMESH_MeshEditor_i::IsManifold()
+  throw (SALOME::SALOME_Exception)
+{
+  bool isManifold = true;
+
+  SMESH_TRY;
+  SMESH_MeshAlgos::TFreeBorderVec foundFreeBordes;
+  SMESH_MeshAlgos::FindFreeBorders( *getMeshDS(),
+                                    foundFreeBordes,
+                                    /*closedOnly=*/true,
+                                    &isManifold );
+  SMESH_CATCH( SMESH::throwCorbaException );
+
+  return isManifold;
+}
+
+//=======================================================================
+//function : IsCoherentOrientation2D
+//purpose  : Check if orientation of 2D elements is coherent
+//=======================================================================
+
+CORBA::Boolean SMESH_MeshEditor_i::IsCoherentOrientation2D()
+  throw (SALOME::SALOME_Exception)
+{
+  bool isGoodOri = true;
+
+  SMESH_TRY;
+  SMESH_MeshAlgos::TFreeBorderVec foundFreeBordes;
+  SMESH_MeshAlgos::FindFreeBorders( *getMeshDS(),
+                                    foundFreeBordes,
+                                    /*closedOnly=*/true,
+                                    /*isManifold=*/0,
+                                    &isGoodOri);
+  SMESH_CATCH( SMESH::throwCorbaException );
+
+  return isGoodOri;
+}
+
+//=======================================================================
+//function : FindFreeBorders
+//purpose  : Returns all or only closed FreeBorder's.
+//=======================================================================
+
+SMESH::ListOfFreeBorders* SMESH_MeshEditor_i::FindFreeBorders(CORBA::Boolean closedOnly)
+  throw (SALOME::SALOME_Exception)
+{
+  SMESH::ListOfFreeBorders_var resBorders = new SMESH::ListOfFreeBorders;
+  SMESH_TRY;
+
+  SMESH_MeshAlgos::TFreeBorderVec foundFreeBordes;
+  SMESH_MeshAlgos::FindFreeBorders( *getMeshDS(), foundFreeBordes, closedOnly );
+
+  resBorders->length( foundFreeBordes.size() );
+  for ( size_t i = 0; i < foundFreeBordes.size(); ++i )
+  {
+    const SMESH_MeshAlgos::TFreeBorder& bordNodes = foundFreeBordes[i];
+    SMESH::FreeBorder&                    bordOut = resBorders[i];
+    bordOut.nodeIDs.length( bordNodes.size() );
+    for ( size_t iN = 0; iN < bordNodes.size(); ++iN )
+      bordOut.nodeIDs[ iN ] = bordNodes[ iN ]->GetID();
+  }
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+
+  return resBorders._retn();
+}
+
+//=======================================================================
+//function : FillHole
+//purpose  : Fill with 2D elements a hole defined by a FreeBorder.
+//=======================================================================
+
+void SMESH_MeshEditor_i::FillHole(const SMESH::FreeBorder& theHole)
+  throw (SALOME::SALOME_Exception)
+{
+  initData();
+
+  if ( theHole.nodeIDs.length() < 4 )
+    THROW_SALOME_CORBA_EXCEPTION("A hole should be bound by at least 3 nodes", SALOME::BAD_PARAM);
+  if ( theHole.nodeIDs[0] != theHole.nodeIDs[ theHole.nodeIDs.length()-1 ] )
+    THROW_SALOME_CORBA_EXCEPTION("Not closed hole boundary. "
+                                 "First and last nodes must be same", SALOME::BAD_PARAM);
+
+  SMESH_MeshAlgos::TFreeBorder bordNodes;
+  bordNodes.resize( theHole.nodeIDs.length() );
+  for ( size_t iN = 0; iN < theHole.nodeIDs.length(); ++iN )
+  {
+    bordNodes[ iN ] = getMeshDS()->FindNode( theHole.nodeIDs[ iN ]);
+    if ( !bordNodes[ iN ] )
+      THROW_SALOME_CORBA_EXCEPTION(SMESH_Comment("Node #") << theHole.nodeIDs[ iN ]
+                                   << " does not exist", SALOME::BAD_PARAM);
+  }
+
+  SMESH_TRY;
+
+  MeshEditor_I::TPreviewMesh* previewMesh = 0;
+  SMDS_Mesh* meshDS = getMeshDS();
+  if ( myIsPreviewMode )
+  {
+    // copy faces sharing nodes of theHole
+    TIDSortedElemSet holeFaces;
+    previewMesh = getPreviewMesh( SMDSAbs_Face );
+    for ( size_t i = 0; i < bordNodes.size(); ++i )
+    {
+      SMDS_ElemIteratorPtr fIt = bordNodes[i]->GetInverseElementIterator( SMDSAbs_Face );
+      while ( fIt->more() )
+      {
+        const SMDS_MeshElement* face = fIt->next();
+        if ( holeFaces.insert( face ).second )
+          previewMesh->Copy( face );
+      }
+      bordNodes[i] = previewMesh->GetMeshDS()->FindNode( bordNodes[i]->GetID() );
+      ASSERT( bordNodes[i] );
+    }
+    meshDS = previewMesh->GetMeshDS();
+  }
+
+  std::vector<const SMDS_MeshElement*> newFaces;
+  SMESH_MeshAlgos::FillHole( bordNodes, *meshDS, newFaces );
+
+  if ( myIsPreviewMode )
+  {
+    previewMesh->Clear();
+    for ( size_t i = 0; i < newFaces.size(); ++i )
+      previewMesh->Copy( newFaces[i] );
+  }
+  else
+  {
+    getEditor().ClearLastCreated();
+    SMESH_SequenceOfElemPtr& aSeq =
+      const_cast<SMESH_SequenceOfElemPtr&>( getEditor().GetLastCreatedElems() );
+    for ( size_t i = 0; i < newFaces.size(); ++i )
+      aSeq.Append( newFaces[i] );
+
+    TPythonDump() << this << ".FillHole( SMESH.FreeBorder(" << theHole.nodeIDs << " ))";
+  }
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+}
+
 //=======================================================================
 //function : convError
 //purpose  :
index dd1212d8c602ee089d674495ced42429d2c3b727..292c2e8526d52ec0a821d6811c857b461853a9e6 100644 (file)
@@ -526,7 +526,7 @@ public:
                                          SMESH::ElementType type)
     throw (SALOME::SALOME_Exception);
   /*!
-   * Searching among the given elements, return elements of given type 
+   * Searching among the given elements, return elements of given type
    * where the given point is IN or ON.
    * 'ALL' type means elements of any type excluding nodes
    */
@@ -544,6 +544,30 @@ public:
   CORBA::Short GetPointState(CORBA::Double x, CORBA::Double y, CORBA::Double z)
     throw (SALOME::SALOME_Exception);
 
+  /*!
+   * Check if a 2D mesh is manifold
+   */
+  CORBA::Boolean IsManifold()
+    throw (SALOME::SALOME_Exception);
+
+  /*!
+   * Check if orientation of 2D elements is coherent
+   */
+  CORBA::Boolean IsCoherentOrientation2D()
+    throw (SALOME::SALOME_Exception);
+
+  /*!
+   * Returns all or only closed FreeBorder's.
+   */
+  SMESH::ListOfFreeBorders* FindFreeBorders(CORBA::Boolean closedOnly)
+    throw (SALOME::SALOME_Exception);
+
+  /*!
+   * Fill with 2D elements a hole defined by a FreeBorder.
+   */
+  void FillHole(const SMESH::FreeBorder& hole)
+    throw (SALOME::SALOME_Exception);
+
   SMESH::CoincidentFreeBorders* FindCoincidentFreeBorders(CORBA::Double tolerance);
   CORBA::Short SewCoincidentFreeBorders(const SMESH::CoincidentFreeBorders& freeBorders,
                                         CORBA::Boolean                      createPolygons,
@@ -551,35 +575,35 @@ public:
     throw (SALOME::SALOME_Exception);
 
   SMESH::SMESH_MeshEditor::Sew_Error
-  SewFreeBorders(CORBA::Long FirstNodeID1,
-                 CORBA::Long SecondNodeID1,
-                 CORBA::Long LastNodeID1,
-                 CORBA::Long FirstNodeID2,
-                 CORBA::Long SecondNodeID2,
-                 CORBA::Long LastNodeID2,
-                 CORBA::Boolean CreatePolygons,
-                 CORBA::Boolean CreatePolyedrs) throw (SALOME::SALOME_Exception);
+    SewFreeBorders(CORBA::Long FirstNodeID1,
+                   CORBA::Long SecondNodeID1,
+                   CORBA::Long LastNodeID1,
+                   CORBA::Long FirstNodeID2,
+                   CORBA::Long SecondNodeID2,
+                   CORBA::Long LastNodeID2,
+                   CORBA::Boolean CreatePolygons,
+                   CORBA::Boolean CreatePolyedrs) throw (SALOME::SALOME_Exception);
   SMESH::SMESH_MeshEditor::Sew_Error
-  SewConformFreeBorders(CORBA::Long FirstNodeID1,
-                        CORBA::Long SecondNodeID1,
-                        CORBA::Long LastNodeID1,
-                        CORBA::Long FirstNodeID2,
-                        CORBA::Long SecondNodeID2) throw (SALOME::SALOME_Exception);
+    SewConformFreeBorders(CORBA::Long FirstNodeID1,
+                          CORBA::Long SecondNodeID1,
+                          CORBA::Long LastNodeID1,
+                          CORBA::Long FirstNodeID2,
+                          CORBA::Long SecondNodeID2) throw (SALOME::SALOME_Exception);
   SMESH::SMESH_MeshEditor::Sew_Error
-  SewBorderToSide(CORBA::Long FirstNodeIDOnFreeBorder,
-                  CORBA::Long SecondNodeIDOnFreeBorder,
-                  CORBA::Long LastNodeIDOnFreeBorder,
-                  CORBA::Long FirstNodeIDOnSide,
-                  CORBA::Long LastNodeIDOnSide,
-                  CORBA::Boolean CreatePolygons,
-                  CORBA::Boolean CreatePolyedrs) throw (SALOME::SALOME_Exception);
+    SewBorderToSide(CORBA::Long FirstNodeIDOnFreeBorder,
+                    CORBA::Long SecondNodeIDOnFreeBorder,
+                    CORBA::Long LastNodeIDOnFreeBorder,
+                    CORBA::Long FirstNodeIDOnSide,
+                    CORBA::Long LastNodeIDOnSide,
+                    CORBA::Boolean CreatePolygons,
+                    CORBA::Boolean CreatePolyedrs) throw (SALOME::SALOME_Exception);
   SMESH::SMESH_MeshEditor::Sew_Error
-  SewSideElements(const SMESH::long_array& IDsOfSide1Elements,
-                  const SMESH::long_array& IDsOfSide2Elements,
-                  CORBA::Long NodeID1OfSide1ToMerge,
-                  CORBA::Long NodeID1OfSide2ToMerge,
-                  CORBA::Long NodeID2OfSide1ToMerge,
-                  CORBA::Long NodeID2OfSide2ToMerge) throw (SALOME::SALOME_Exception);
+    SewSideElements(const SMESH::long_array& IDsOfSide1Elements,
+                    const SMESH::long_array& IDsOfSide2Elements,
+                    CORBA::Long NodeID1OfSide1ToMerge,
+                    CORBA::Long NodeID1OfSide2ToMerge,
+                    CORBA::Long NodeID2OfSide1ToMerge,
+                    CORBA::Long NodeID2OfSide2ToMerge) throw (SALOME::SALOME_Exception);
 
   /*!
    * Set new nodes for given element.
index e779c7a7ab8d220c2e8f2afaa8d66ae18f7f6fc9..3afd753c16561de846f9ce01a192aed4d7a9faa7 100644 (file)
@@ -960,6 +960,8 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
             functor = aFilterMgr.CreateLength()
         elif theCriterion == FT_Length2D:
             functor = aFilterMgr.CreateLength2D()
+        elif theCriterion == FT_Deflection2D:
+            functor = aFilterMgr.CreateDeflection2D()
         elif theCriterion == FT_NodeConnectivityNumber:
             functor = aFilterMgr.CreateNodeConnectivityNumber()
         elif theCriterion == FT_BallDiameter:
@@ -3072,6 +3074,16 @@ class Mesh:
     def GetPointState(self, x, y, z):
         return self.editor.GetPointState(x, y, z)
 
+    ## Check if a 2D mesh is manifold
+    #  @ingroup l1_controls
+    def IsManifold(self):
+        return self.editor.IsManifold()
+
+    ## Check if orientation of 2D elements is coherent
+    #  @ingroup l1_controls
+    def IsCoherentOrientation2D(self):
+        return self.editor.IsCoherentOrientation2D()
+
     ## Finds the node closest to a point and moves it to a point location
     #  @param x  the X coordinate of a point
     #  @param y  the Y coordinate of a point
@@ -4557,6 +4569,24 @@ class Mesh:
     def MergeEqualElements(self):
         self.editor.MergeEqualElements()
 
+    ## Returns all or only closed free borders
+    #  @return list of SMESH.FreeBorder's
+    #  @ingroup l2_modif_trsf
+    def FindFreeBorders(self, ClosedOnly=True):
+        return self.editor.FindFreeBorders( ClosedOnly )
+
+    ## Fill with 2D elements a hole defined by a SMESH.FreeBorder.
+    #  @param FreeBorder either a SMESH.FreeBorder or a list on node IDs. These nodes
+    #         must describe all sequential nodes of the hole border. The first and the last
+    #         nodes must be the same. Use FindFreeBorders() to get nodes of holes.
+    #  @ingroup l2_modif_trsf
+    def FillHole(self, holeNodes):
+        if holeNodes and isinstance( holeNodes, list ) and isinstance( holeNodes[0], int ):
+            holeNodes = SMESH.FreeBorder(nodeIDs=holeNodes)
+        if not isinstance( holeNodes, SMESH.FreeBorder ):
+            raise TypeError, "holeNodes must be either SMESH.FreeBorder or list of integer and not %s" % holeNodes
+        self.editor.FillHole( holeNodes )
+
     ## Returns groups of FreeBorder's coincident within the given tolerance.
     #  @param tolerance the tolerance. If the tolerance <= 0.0 then one tenth of an average
     #         size of elements adjacent to free borders being compared is used.
@@ -4870,7 +4900,14 @@ class Mesh:
     def CreateHoleSkin(self, radius, theShape, groupName, theNodesCoords):
         return self.editor.CreateHoleSkin( radius, theShape, groupName, theNodesCoords )
 
-    def _getFunctor(self, funcType ):
+    ## Return a cached numerical functor by its type.
+    #  @param theCriterion functor type - an item of SMESH.FunctorType enumeration.
+    #          Type SMESH.FunctorType._items in the Python Console to see all items.
+    #          Note that not all items correspond to numerical functors.
+    #  @return SMESH_NumericalFunctor. The functor is already initialized
+    #          with a mesh
+    #  @ingroup l1_measurements
+    def GetFunctor(self, funcType ):
         fn = self.functors[ funcType._v ]
         if not fn:
             fn = self.smeshpyD.GetFunctor(funcType)
@@ -4885,7 +4922,7 @@ class Mesh:
     #  @param isElem @a elemId is ID of element or node
     #  @return the functor value or zero in case of invalid arguments
     def FunctorValue(self, funcType, elemId, isElem=True):
-        fn = self._getFunctor( funcType )
+        fn = self.GetFunctor( funcType )
         if fn.GetElementType() == self.GetElementType(elemId, isElem):
             val = fn.GetValue(elemId)
         else:
@@ -4991,7 +5028,7 @@ class Mesh:
             unRegister.set( meshPart )
         if isinstance( meshPart, Mesh ):
             meshPart = meshPart.mesh
-        fun = self._getFunctor( funType )
+        fun = self.GetFunctor( funType )
         if fun:
             if meshPart:
                 if hasattr( meshPart, "SetMesh" ):
index 5b6fe40c30f13be00185adebc70f77b5b4926ca5..91a1b3ca6d26cf31de5e5e8bef6eb3956b151ea1 100644 (file)
@@ -136,7 +136,7 @@ this one for this mesh/sub-mesh.</translation>
     </message>
     <message>
         <source>SMESH_DISTR_EXPR</source>
-        <translation>Distribution with analitic density</translation>
+        <translation>Distribution with analytic density</translation>
     </message>
     <message>
         <source>SMESH_DISTR_REGULAR</source>