Salome HOME
refs #255: 7.5.6. Generation of the boundary particles for particulate boundary model
authoreap <eap@opencascade.com>
Tue, 13 Feb 2018 16:27:04 +0000 (19:27 +0300)
committereap <eap@opencascade.com>
Tue, 13 Feb 2018 16:27:04 +0000 (19:27 +0300)
56 files changed:
idl/SMESH_MeshEditor.idl
resources/CMakeLists.txt
resources/mesh_offset.png [new file with mode: 0644]
src/DriverSTL/DriverSTL_W_SMDS_Mesh.cxx
src/SMDS/SMDS_Mesh.hxx
src/SMDS/SMDS_PolygonalFaceOfNodes.hxx
src/SMDS/SMDS_StdIterator.hxx
src/SMESH/SMESH_MeshEditor.cxx
src/SMESH/SMESH_MeshEditor.hxx
src/SMESH/SMESH_MesherHelper.cxx
src/SMESHGUI/CMakeLists.txt
src/SMESHGUI/SMESHGUI.cxx
src/SMESHGUI/SMESHGUI_AddMeshElementDlg.cxx
src/SMESHGUI/SMESHGUI_AddQuadraticElementDlg.cxx
src/SMESHGUI/SMESHGUI_CopyMeshDlg.cxx
src/SMESHGUI/SMESHGUI_CreatePolyhedralVolumeDlg.cxx
src/SMESHGUI/SMESHGUI_ExtrusionDlg.cxx
src/SMESHGUI/SMESHGUI_FindElemByPointDlg.cxx
src/SMESHGUI/SMESHGUI_MeshInfo.cxx
src/SMESHGUI/SMESHGUI_MeshPatternDlg.cxx
src/SMESHGUI/SMESHGUI_MultiEditDlg.cxx
src/SMESHGUI/SMESHGUI_OffsetDlg.cxx [new file with mode: 0644]
src/SMESHGUI/SMESHGUI_OffsetDlg.h [new file with mode: 0644]
src/SMESHGUI/SMESHGUI_Operations.h
src/SMESHGUI/SMESHGUI_RemoveElementsDlg.cxx
src/SMESHGUI/SMESHGUI_RemoveNodesDlg.cxx
src/SMESHGUI/SMESHGUI_RotationDlg.cxx
src/SMESHGUI/SMESHGUI_ScaleDlg.cxx
src/SMESHGUI/SMESHGUI_SelectionOp.cxx
src/SMESHGUI/SMESHGUI_SelectionOp.h
src/SMESHGUI/SMESHGUI_SewingDlg.cxx
src/SMESHGUI/SMESHGUI_SingleEditDlg.cxx
src/SMESHGUI/SMESHGUI_SmoothingDlg.cxx
src/SMESHGUI/SMESHGUI_SymmetryDlg.cxx
src/SMESHGUI/SMESHGUI_TranslationDlg.cxx
src/SMESHGUI/SMESH_images.ts
src/SMESHGUI/SMESH_msg_en.ts
src/SMESHGUI/SMESH_msg_fr.ts
src/SMESHGUI/SMESH_msg_ja.ts
src/SMESHUtils/CMakeLists.txt
src/SMESHUtils/SMESH_MAT2d.hxx
src/SMESHUtils/SMESH_MeshAlgos.cxx
src/SMESHUtils/SMESH_MeshAlgos.hxx
src/SMESHUtils/SMESH_Offset.cxx [new file with mode: 0644]
src/SMESHUtils/SMESH_Triangulate.cxx [new file with mode: 0644]
src/SMESHUtils/SMESH_TypeDefs.hxx
src/SMESH_I/SMESH_Gen_i_1.cxx
src/SMESH_I/SMESH_MeshEditor_i.cxx
src/SMESH_I/SMESH_MeshEditor_i.hxx
src/SMESH_I/SMESH_PythonDump.hxx
src/SMESH_SWIG/smeshBuilder.py
src/StdMeshers/StdMeshers_Cartesian_3D.cxx
src/StdMeshersGUI/StdMeshersGUI_PropagationHelperWdg.cxx
src/Tools/MacMesh/MacMesh/PublishGroups.py
src/Tools/YamsPlug/doc/Mandatory_params.rst
src/Tools/padder/spadderpy/gui/plugindialog.py

index 0a157b8ad8cd58d21950010042f8736240654348..41e33ea43c62326dbed901f21e6f70f1c748582c 100644 (file)
@@ -670,6 +670,13 @@ module SMESH
                                      in string         MeshName)
       raises (SALOME::SALOME_Exception);
 
+    SMESH_Mesh Offset(in SMESH_IDSource theObject,
+                      in double         Value,
+                      in boolean        CopyGroups,
+                      in string         MeshName,
+                      out ListOfGroups  Groups)
+      raises (SALOME::SALOME_Exception);
+
     void FindCoincidentNodes (in  double              Tolerance,
                               out array_of_long_array GroupsOfNodes,
                               in  boolean             SeparateCornersAndMedium)
@@ -855,7 +862,7 @@ module SMESH
      * \param theElements - container of elements to duplicate.
      * \param theGroupName - a name of group to contain the generated elements.
      *                    If a group with such a name already exists, the new elements
-     *                    are added to the existng group, else a new group is created.
+     *                    are added to the existing group, else a new group is created.
      *                    If \a theGroupName is empty, new elements are not added 
      *                    in any group.
      * \return a group where the new elements are added. NULL if theGroupName == "".
index 6db2127ebc5281ba2d5417353c72c47b2b18e684..ab8792bc1b435e9d6769d383b8ecc91280667a6e 100755 (executable)
@@ -229,6 +229,7 @@ SET(SMESH_RESOURCES_FILES
   mesh_show.png
   mesh_hide.png
   mesh_deflection.png
+  mesh_offset.png
 )
 
 INSTALL(FILES ${SMESH_RESOURCES_FILES} DESTINATION ${SALOME_SMESH_INSTALL_RES_DATA})
diff --git a/resources/mesh_offset.png b/resources/mesh_offset.png
new file mode 100644 (file)
index 0000000..47e03cc
Binary files /dev/null and b/resources/mesh_offset.png differ
index cb42a321b81a9f1a64be47b8cb8ae0915ac269a1..a9ac8cad3818c2b988ff7424de9533328d738f85 100644 (file)
 #include "SMDS_FaceOfNodes.hxx"
 #include "SMDS_IteratorOnIterators.hxx"
 #include "SMDS_Mesh.hxx"
-#include "SMDS_MeshElement.hxx"
-#include "SMDS_MeshNode.hxx"
 #include "SMDS_PolygonalFaceOfNodes.hxx"
 #include "SMDS_SetIterator.hxx"
 #include "SMDS_VolumeTool.hxx"
 #include "SMESH_File.hxx"
+#include "SMESH_MeshAlgos.hxx"
 #include "SMESH_TypeDefs.hxx"
 
-#include <Standard_ErrorHandler.hxx>
-#include <Standard_Failure.hxx>
-#include <gp_Ax2.hxx>
-
 #include <limits>
 
 
@@ -208,270 +203,6 @@ static gp_XYZ getNormale( const SMDS_MeshNode* n1,
   return n;
 }
 
-namespace
-{
-  /*!
-   * \brief Vertex of a polygon. Together with 2 neighbor Vertices represents a triangle
-   */
-  struct PolyVertex
-  {
-    SMESH_TNodeXYZ _nxyz;
-    gp_XY          _xy;
-    PolyVertex*    _prev;
-    PolyVertex*    _next;
-
-    void SetNodeAndNext( const SMDS_MeshNode* n, PolyVertex& v )
-    {
-      _nxyz.Set( n );
-      _next = &v;
-      v._prev = this;
-    }
-    PolyVertex* Delete()
-    {
-      _prev->_next = _next;
-      _next->_prev = _prev;
-      return _next;
-    }
-    void GetTriaNodes( const SMDS_MeshNode** nodes) const
-    {
-      nodes[0] = _prev->_nxyz._node;
-      nodes[1] =  this->_nxyz._node;
-      nodes[2] = _next->_nxyz._node;
-    }
-
-    inline static double Area( const PolyVertex* v0, const PolyVertex* v1, const PolyVertex* v2 )
-    {
-      gp_XY vPrev = v0->_xy - v1->_xy;
-      gp_XY vNext = v2->_xy - v1->_xy;
-      return vNext ^ vPrev;
-    }
-    double TriaArea() const { return Area( _prev, this, _next ); }
-
-    bool IsInsideTria( const PolyVertex* v )
-    {
-      gp_XY p = _prev->_xy - v->_xy;
-      gp_XY t =  this->_xy - v->_xy;
-      gp_XY n = _next->_xy - v->_xy;
-      const double tol = -1e-12;
-      return (( p ^ t ) >= tol &&
-              ( t ^ n ) >= tol &&
-              ( n ^ p ) >= tol );
-      // return ( Area( _prev, this, v ) > 0 &&
-      //          Area( this, _next, v ) > 0 &&
-      //          Area( _next, _prev, v ) > 0 );
-    }
-  };
-
-  //================================================================================
-  /*!
-   * \brief Triangulate a polygon. Assure correct orientation for concave polygons
-   */
-  //================================================================================
-
-  bool triangulate( std::vector< const SMDS_MeshNode*>& nodes, const size_t nbNodes )
-  {
-    // connect nodes into a ring
-    std::vector< PolyVertex > pv( nbNodes );
-    for ( size_t i = 1; i < nbNodes; ++i )
-      pv[i-1].SetNodeAndNext( nodes[i-1], pv[i] );
-    pv[ nbNodes-1 ].SetNodeAndNext( nodes[ nbNodes-1 ], pv[0] );
-
-    // get a polygon normal
-    gp_XYZ normal(0,0,0), p0,v01,v02;
-    p0  = pv[0]._nxyz;
-    v01 = pv[1]._nxyz - p0;
-    for ( size_t i = 2; i < nbNodes; ++i )
-    {
-      v02 = pv[i]._nxyz - p0;
-      normal += v01 ^ v02;
-      v01 = v02;
-    }
-    // project nodes to the found plane
-    gp_Ax2 axes;
-    try {
-      axes = gp_Ax2( p0, normal, v01 );
-    }
-    catch ( Standard_Failure ) {
-      return false;
-    }
-    for ( size_t i = 0; i < nbNodes; ++i )
-    {
-      gp_XYZ p = pv[i]._nxyz - p0;
-      pv[i]._xy.SetX( axes.XDirection().XYZ() * p );
-      pv[i]._xy.SetY( axes.YDirection().XYZ() * p );
-    }
-
-    // in a loop, find triangles with positive area and having no vertices inside
-    int iN = 0, nbTria = nbNodes - 2;
-    nodes.reserve( nbTria * 3 );
-    const double minArea = 1e-6;
-    PolyVertex* v = &pv[0], *vi;
-    int nbVertices = nbNodes, nbBadTria = 0, isGoodTria;
-    while ( nbBadTria < nbVertices )
-    {
-      if (( isGoodTria = v->TriaArea() > minArea ))
-      {
-        for ( vi = v->_next->_next;
-              vi != v->_prev;
-              vi = vi->_next )
-        {
-          if ( v->IsInsideTria( vi ))
-            break;
-        }
-        isGoodTria = ( vi == v->_prev );
-      }
-      if ( isGoodTria )
-      {
-        v->GetTriaNodes( &nodes[ iN ] );
-        iN += 3;
-        v = v->Delete();
-        if ( --nbVertices == 3 )
-        {
-          // last triangle remains
-          v->GetTriaNodes( &nodes[ iN ] );
-          return true;
-        }
-        nbBadTria = 0;
-      }
-      else
-      {
-        v = v->_next;
-        ++nbBadTria;
-      }
-    }
-
-    // the polygon is invalid; add triangles with positive area
-    nbBadTria = 0;
-    while ( nbBadTria < nbVertices )
-    {
-      isGoodTria = v->TriaArea() > minArea;
-      if ( isGoodTria )
-      {
-        v->GetTriaNodes( &nodes[ iN ] );
-        iN += 3;
-        v = v->Delete();
-        if ( --nbVertices == 3 )
-        {
-          // last triangle remains
-          v->GetTriaNodes( &nodes[ iN ] );
-          return true;
-        }
-        nbBadTria = 0;
-      }
-      else
-      {
-        v = v->_next;
-        ++nbBadTria;
-      }
-    }
-
-    // add all the rest triangles
-    while ( nbVertices >= 3 )
-    {
-      v->GetTriaNodes( &nodes[ iN ] );
-      iN += 3;
-      v = v->Delete();
-      --nbVertices;
-    }
-
-    return true;
-
-  } // triangulate()
-} // namespace
-
-//================================================================================
-/*!
- * \brief Return nb triangles in a decomposed mesh face
- *  \retval int - number of triangles
- */
-//================================================================================
-
-static int getNbTriangles( const SMDS_MeshElement* face)
-{
-  // WARNING: counting triangles must be coherent with getTriangles()
-  switch ( face->GetEntityType() )
-  {
-  case SMDSEntity_BiQuad_Triangle:
-  case SMDSEntity_BiQuad_Quadrangle:
-    return face->NbNodes() - 1;
-  // case SMDSEntity_Triangle:
-  // case SMDSEntity_Quad_Triangle:
-  // case SMDSEntity_Quadrangle:
-  // case SMDSEntity_Quad_Quadrangle:
-  // case SMDSEntity_Polygon:
-  // case SMDSEntity_Quad_Polygon:
-  default:
-    return face->NbNodes() - 2;
-  }
-  return 0;
-}
-
-//================================================================================
-/*!
- * \brief Decompose a mesh face into triangles
- *  \retval int - number of triangles
- */
-//================================================================================
-
-static int getTriangles( const SMDS_MeshElement*             face,
-                         std::vector< const SMDS_MeshNode*>& nodes)
-{
-  // WARNING: decomposing into triangles must be coherent with getNbTriangles()
-  int nbTria, i = 0, nbNodes = face->NbNodes();
-  SMDS_NodeIteratorPtr nIt = face->interlacedNodesIterator();
-  nodes.resize( nbNodes * 3 );
-  nodes[ i++ ] = nIt->next();
-  nodes[ i++ ] = nIt->next();
-
-  const SMDSAbs_EntityType type = face->GetEntityType();
-  switch ( type )
-  {
-  case SMDSEntity_BiQuad_Triangle:
-  case SMDSEntity_BiQuad_Quadrangle:
-    nbTria = ( type == SMDSEntity_BiQuad_Triangle ) ? 6 : 8;
-    nodes[ i++ ] = face->GetNode( nbTria );
-    for ( i = 3; i < 3*(nbTria-1); i += 3 )
-    {
-      nodes[ i+0 ] = nodes[ i-2 ];
-      nodes[ i+1 ] = nIt->next();
-      nodes[ i+2 ] = nodes[ 2 ];
-    }
-    nodes[ i+0 ] = nodes[ i-2 ];
-    nodes[ i+1 ] = nodes[ 0 ];
-    nodes[ i+2 ] = nodes[ 2 ];
-    break;
-  case SMDSEntity_Triangle:
-    nbTria = 1;
-    nodes[ i++ ] = nIt->next();
-    break;
-  default:
-    // case SMDSEntity_Quad_Triangle:
-    // case SMDSEntity_Quadrangle:
-    // case SMDSEntity_Quad_Quadrangle:
-    // case SMDSEntity_Polygon:
-    // case SMDSEntity_Quad_Polygon:
-    nbTria = nbNodes - 2;
-    while ( nIt->more() )
-      nodes[ i++ ] = nIt->next();
-
-    if ( !triangulate( nodes, nbNodes ))
-    {
-      nIt = face->interlacedNodesIterator();
-      nodes[ 0 ] = nIt->next();
-      nodes[ 1 ] = nIt->next();
-      nodes[ 2 ] = nIt->next();
-      for ( i = 3; i < 3*nbTria; i += 3 )
-      {
-        nodes[ i+0 ] = nodes[ 0 ];
-        nodes[ i+1 ] = nodes[ i-1 ];
-        nodes[ i+2 ] = nIt->next();
-      }
-    }
-    break;
-  }
-  return nbTria;
-}
-
 // private methods
 
 Driver_Mesh::Status DriverSTL_W_SMDS_Mesh::writeAscii() const
@@ -491,11 +222,13 @@ Driver_Mesh::Status DriverSTL_W_SMDS_Mesh::writeAscii() const
   char sval[128];
   std::vector< const SMDS_MeshNode* > triaNodes;
 
+  SMESH_MeshAlgos::Triangulate triangulator;
+
   SMDS_ElemIteratorPtr itFaces = getFaces();
   while ( itFaces->more() )
   {
     const SMDS_MeshElement* aFace = itFaces->next();
-    int nbTria = getTriangles( aFace, triaNodes );
+    int nbTria = triangulator.GetTriangles( aFace, triaNodes );
 
     for ( int iT = 0, iN = 0; iT < nbTria; ++iT )
     {
@@ -544,13 +277,15 @@ Driver_Mesh::Status DriverSTL_W_SMDS_Mesh::writeBinary() const
   SMESH_File aFile( myFile );
   aFile.openForWriting();
 
+  SMESH_MeshAlgos::Triangulate triangulator;
+
   // we first count the number of triangles
   int nbTri = myNbVolumeTrias;
   {
     SMDS_FaceIteratorPtr itFaces = myMesh->facesIterator();
     while ( itFaces->more() ) {
       const SMDS_MeshElement* aFace = itFaces->next();
-      nbTri += getNbTriangles( aFace );
+      nbTri += triangulator.GetNbTriangles( aFace );
     }
   }
   std::string sval( LABEL_SIZE, ' ' );
@@ -569,7 +304,7 @@ Driver_Mesh::Status DriverSTL_W_SMDS_Mesh::writeBinary() const
   while ( itFaces->more() )
   {
     const SMDS_MeshElement* aFace = itFaces->next();
-    int nbTria = getTriangles( aFace, triaNodes );
+    int nbTria = triangulator.GetTriangles( aFace, triaNodes );
     
     for ( int iT = 0, iN = 0; iT < nbTria; ++iT )
     {
index 9e489ad658442c45ad90382d89617a894ddd1192..ef7ac73b5da4b1bf28e10c18af3796333cf0e80a 100644 (file)
@@ -641,6 +641,7 @@ public:
   virtual void Renumber (const bool isNodes, const int startID = 1, const int deltaID = 1);
   // Renumber all nodes or elements.
   virtual void compactMesh();
+  virtual void CompactMesh() { compactMesh(); }
 
   const SMDS_MeshNode *FindNode(int idnode) const;
   const SMDS_MeshNode *FindNodeVtk(int idnode) const;
index 67c6115422f0f34515ae6ec4739955fb852f07a2..4dc8bea4945415e5565180e7cebf93db6b121ada 100644 (file)
@@ -67,7 +67,6 @@ class SMDS_EXPORT SMDS_PolygonalFaceOfNodes:public SMDS_MeshFace
  protected:
   virtual SMDS_ElemIteratorPtr elementsIterator (SMDSAbs_ElementType type) const;
 
- private:
   std::vector<const SMDS_MeshNode *> myNodes;
 };
 
index 0e960cb802d723311459a4b2db4e5d539c02a995..bf535fdf81ee52d82e96de3e7dbaadedc5c3d85f 100644 (file)
@@ -45,7 +45,7 @@ public:
 
   // constructor to use as return from begin()
   SMDS_StdIterator( PtrSMDSIterator pItr )
-    : _value( pItr->more() ? (VALUE)(pItr->next()) : 0 ), _piterator(pItr)
+    : _value( pItr->more() ? VALUE(pItr->next()) : VALUE(0) ), _piterator(pItr)
   {}
   // constructor to use as return from end()
   SMDS_StdIterator(): _value( 0 )
@@ -58,12 +58,12 @@ public:
   //  Step to the next one
   _Self&
   operator++()
-  { _value = _piterator->more() ? VALUE( _piterator->next()) : 0; return *this; }
+  { _value = _piterator->more() ? VALUE( _piterator->next()) : VALUE(0); return *this; }
 
   //  Step to the next one
   _Self
   operator++(int)
-  { _Self res = *this; _value = _piterator->more() ? VALUE( _piterator->next()) : 0; return res; }
+  { _Self res = *this; _value = _piterator->more() ? VALUE( _piterator->next()) : VALUE(0); return res; }
 
   // Test of end
   bool
index 056da7050d0089695521d1503a50de99e9016ea0..5c01ab529f54d20d2a643a1cb8a4fb909fc6ac12 100644 (file)
 using namespace std;
 using namespace SMESH::Controls;
 
-namespace
-{
-  template < class ELEM_SET >
-  SMDS_ElemIteratorPtr elemSetIterator( const ELEM_SET& elements )
-  {
-    typedef SMDS_SetIterator
-      < SMDS_pElement, typename ELEM_SET::const_iterator> TSetIterator;
-    return SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
-  }
-}
-
 //=======================================================================
 //function : SMESH_MeshEditor
 //purpose  :
@@ -145,8 +134,8 @@ SMESHDS_Mesh * SMESH_MeshEditor::GetMeshDS()
 
 void SMESH_MeshEditor::ClearLastCreated()
 {
-  myLastCreatedNodes.Clear();
-  myLastCreatedElems.Clear();
+  SMESHUtils::FreeVector( myLastCreatedElems );
+  SMESHUtils::FreeVector( myLastCreatedNodes );
 }
 
 //================================================================================
@@ -378,7 +367,7 @@ SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
 
   default:;
   }
-  if ( e ) myLastCreatedElems.Append( e );
+  if ( e ) myLastCreatedElems.push_back( e );
   return e;
 }
 
@@ -412,8 +401,7 @@ SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
                               const bool         isNodes )
 {
-  myLastCreatedElems.Clear();
-  myLastCreatedNodes.Clear();
+  ClearLastCreated();
 
   SMESHDS_Mesh* aMesh = GetMeshDS();
   set< SMESH_subMesh *> smmap;
@@ -493,7 +481,7 @@ void SMESH_MeshEditor::Create0DElementsOnAllNodes( const TIDSortedElemSet& eleme
   }
   else
   {
-    elemIt = elemSetIterator( elements );
+    elemIt = SMESHUtils::elemSetIterator( elements );
   }
 
   while ( elemIt->more() )
@@ -506,8 +494,8 @@ void SMESH_MeshEditor::Create0DElementsOnAllNodes( const TIDSortedElemSet& eleme
       SMDS_ElemIteratorPtr it0D = n->GetInverseElementIterator( SMDSAbs_0DElement );
       if ( duplicateElements || !it0D->more() )
       {
-        myLastCreatedElems.Append( GetMeshDS()->Add0DElement( n ));
-        all0DElems.insert( myLastCreatedElems.Last() );
+        myLastCreatedElems.push_back( GetMeshDS()->Add0DElement( n ));
+        all0DElems.insert( myLastCreatedElems.back() );
       }
       while ( it0D->more() )
         all0DElems.insert( it0D->next() );
@@ -523,8 +511,7 @@ void SMESH_MeshEditor::Create0DElementsOnAllNodes( const TIDSortedElemSet& eleme
 
 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
 {
-  myLastCreatedElems.Clear();
-  myLastCreatedNodes.Clear();
+  ClearLastCreated();
 
   SMESHDS_Mesh * aMesh = GetMeshDS();
   if ( aMesh->ShapeToMesh().IsNull() )
@@ -691,8 +678,7 @@ static bool getNodesFromTwoTria(const SMDS_MeshElement * theTria1,
 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
                                     const SMDS_MeshElement * theTria2 )
 {
-  myLastCreatedElems.Clear();
-  myLastCreatedNodes.Clear();
+  ClearLastCreated();
 
   if (!theTria1 || !theTria2)
     return false;
@@ -892,8 +878,7 @@ static bool findTriangles(const SMDS_MeshNode *    theNode1,
 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
                                     const SMDS_MeshNode * theNode2)
 {
-  myLastCreatedElems.Clear();
-  myLastCreatedNodes.Clear();
+  ClearLastCreated();
 
   const SMDS_MeshElement *tr1, *tr2;
   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
@@ -1013,8 +998,7 @@ bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
                                    const SMDS_MeshNode * theNode2)
 {
-  myLastCreatedElems.Clear();
-  myLastCreatedNodes.Clear();
+  ClearLastCreated();
 
   const SMDS_MeshElement *tr1, *tr2;
   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
@@ -1035,13 +1019,13 @@ bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
 
     const SMDS_MeshElement* newElem = 0;
     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
-    myLastCreatedElems.Append(newElem);
+    myLastCreatedElems.push_back(newElem);
     AddToSameGroups( newElem, tr1, aMesh );
     int aShapeId = tr1->getshapeId();
     if ( aShapeId )
-      {
-        aMesh->SetMeshElementOnShape( newElem, aShapeId );
-      }
+    {
+      aMesh->SetMeshElementOnShape( newElem, aShapeId );
+    }
     aMesh->RemoveElement( tr1 );
     aMesh->RemoveElement( tr2 );
 
@@ -1085,13 +1069,13 @@ bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
   const SMDS_MeshElement* newElem = 0;
   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
-  myLastCreatedElems.Append(newElem);
+  myLastCreatedElems.push_back(newElem);
   AddToSameGroups( newElem, tr1, aMesh );
   int aShapeId = tr1->getshapeId();
   if ( aShapeId )
-    {
-      aMesh->SetMeshElementOnShape( newElem, aShapeId );
-    }
+  {
+    aMesh->SetMeshElementOnShape( newElem, aShapeId );
+  }
   aMesh->RemoveElement( tr1 );
   aMesh->RemoveElement( tr2 );
 
@@ -1108,8 +1092,7 @@ bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
 
 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
 {
-  myLastCreatedElems.Clear();
-  myLastCreatedNodes.Clear();
+  ClearLastCreated();
 
   if (!theElem)
     return false;
@@ -1314,7 +1297,7 @@ int SMESH_MeshEditor::Reorient2DBy3D (TIDSortedElemSet & theFaces,
   if ( theFaces.empty() )
     faceIt = GetMeshDS()->elementsIterator( SMDSAbs_Face );
   else
-    faceIt = elemSetIterator( theFaces );
+    faceIt = SMESHUtils::elemSetIterator( theFaces );
 
   vector< const SMDS_MeshNode* > faceNodes;
   TIDSortedElemSet checkedVolumes;
@@ -1403,17 +1386,17 @@ static double getBadRate (const SMDS_MeshElement*               theElem,
 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
                                   SMESH::Controls::NumericalFunctorPtr theCrit)
 {
-  myLastCreatedElems.Clear();
-  myLastCreatedNodes.Clear();
+  ClearLastCreated();
 
   if ( !theCrit.get() )
     return false;
 
-  SMESHDS_Mesh * aMesh = GetMeshDS();
-
+  SMESHDS_Mesh *       aMesh = GetMeshDS();
   Handle(Geom_Surface) surface;
   SMESH_MesherHelper   helper( *GetMesh() );
 
+  myLastCreatedElems.reserve( theElems.size() * 2 );
+
   TIDSortedElemSet::iterator itElem;
   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
   {
@@ -1482,8 +1465,8 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
 
     // care of a new element
 
-    myLastCreatedElems.Append(newElem1);
-    myLastCreatedElems.Append(newElem2);
+    myLastCreatedElems.push_back(newElem1);
+    myLastCreatedElems.push_back(newElem2);
     AddToSameGroups( newElem1, elem, aMesh );
     AddToSameGroups( newElem2, elem, aMesh );
 
@@ -1506,15 +1489,15 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
 
 void SMESH_MeshEditor::QuadTo4Tri (TIDSortedElemSet & theElems)
 {
-  myLastCreatedElems.Clear();
-  myLastCreatedNodes.Clear();
+  ClearLastCreated();
+  myLastCreatedElems.reserve( theElems.size() * 4 );
 
   SMESH_MesherHelper helper( *GetMesh() );
   helper.SetElementsOnShape( true );
 
   SMDS_ElemIteratorPtr faceIt;
   if ( theElems.empty() ) faceIt = GetMeshDS()->elementsIterator(SMDSAbs_Face);
-  else                    faceIt = elemSetIterator( theElems );
+  else                    faceIt = SMESHUtils::elemSetIterator( theElems );
 
   bool   checkUV;
   gp_XY  uv [9]; uv[8] = gp_XY(0,0);
@@ -1598,7 +1581,7 @@ void SMESH_MeshEditor::QuadTo4Tri (TIDSortedElemSet & theElems)
 
       nCentral = helper.AddNode( xyz[8].X(), xyz[8].Y(), xyz[8].Z(), /*id=*/0,
                                  uv[8].X(), uv[8].Y() );
-      myLastCreatedNodes.Append( nCentral );
+      myLastCreatedNodes.push_back( nCentral );
     }
 
     // create 4 triangles
@@ -1616,7 +1599,7 @@ void SMESH_MeshEditor::QuadTo4Tri (TIDSortedElemSet & theElems)
                                                nodes[(i+1)%4],
                                                nCentral );
       ReplaceElemInGroups( tria, quad, GetMeshDS() );
-      myLastCreatedElems.Append( tria );
+      myLastCreatedElems.push_back( tria );
     }
   }
 }
@@ -1629,8 +1612,7 @@ void SMESH_MeshEditor::QuadTo4Tri (TIDSortedElemSet & theElems)
 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
                                  SMESH::Controls::NumericalFunctorPtr theCrit)
 {
-  myLastCreatedElems.Clear();
-  myLastCreatedNodes.Clear();
+  ClearLastCreated();
 
   if (!theCrit.get())
     return -1;
@@ -2296,7 +2278,7 @@ void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems,
       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
       nodes.push_back( gcNode );
-      newNodes.Append( gcNode );
+      newNodes.push_back( gcNode );
     }
     if ( !splitMethod._faceBaryNode.empty() )
     {
@@ -2310,7 +2292,7 @@ void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems,
         if ( !f_n->second )
         {
           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
-          newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
+          newNodes.push_back( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
         }
         nodes.push_back( iF_n->second = f_n->second );
       }
@@ -2321,18 +2303,18 @@ void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems,
     const int* volConn = splitMethod._connectivity;
     if ( splitMethod._nbCorners == 4 ) // tetra
       for ( int i = 0; i < splitMethod._nbSplits; ++i, volConn += splitMethod._nbCorners )
-        newElems.Append( splitVols[ i ] = helper.AddVolume( nodes[ volConn[0] ],
-                                                            nodes[ volConn[1] ],
-                                                            nodes[ volConn[2] ],
-                                                            nodes[ volConn[3] ]));
+        newElems.push_back( splitVols[ i ] = helper.AddVolume( nodes[ volConn[0] ],
+                                                               nodes[ volConn[1] ],
+                                                               nodes[ volConn[2] ],
+                                                               nodes[ volConn[3] ]));
     else // prisms
       for ( int i = 0; i < splitMethod._nbSplits; ++i, volConn += splitMethod._nbCorners )
-        newElems.Append( splitVols[ i ] = helper.AddVolume( nodes[ volConn[0] ],
-                                                            nodes[ volConn[1] ],
-                                                            nodes[ volConn[2] ],
-                                                            nodes[ volConn[3] ],
-                                                            nodes[ volConn[4] ],
-                                                            nodes[ volConn[5] ]));
+        newElems.push_back( splitVols[ i ] = helper.AddVolume( nodes[ volConn[0] ],
+                                                               nodes[ volConn[1] ],
+                                                               nodes[ volConn[2] ],
+                                                               nodes[ volConn[3] ],
+                                                               nodes[ volConn[4] ],
+                                                               nodes[ volConn[5] ]));
 
     ReplaceElemInGroups( elem, splitVols, GetMeshDS() );
 
@@ -2385,7 +2367,7 @@ void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems,
               gp_XY uv( 1e100, 1e100 );
               double distXYZ[4];
               if ( !fHelper.CheckNodeUV( TopoDS::Face( s ), baryNode,
-                                        uv, /*tol=*/1e-7, /*force=*/true, distXYZ ) &&
+                                         uv, /*tol=*/1e-7, /*force=*/true, distXYZ ) &&
                    uv.X() < 1e100 )
               {
                 // node is too far from the surface
@@ -2439,7 +2421,7 @@ void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems,
           if ( !triangles[ i ]) continue;
           if ( fSubMesh )
             fSubMesh->AddElement( triangles[ i ]);
-          newElems.Append( triangles[ i ]);
+          newElems.push_back( triangles[ i ]);
         }
         ReplaceElemInGroups( face, triangles, GetMeshDS() );
         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
@@ -2476,7 +2458,7 @@ void SMESH_MeshEditor::GetHexaFacetsToSplit( TIDSortedElemSet& theHexas,
                                              const gp_Ax1&     theFacetNormal,
                                              TFacetOfElem &    theFacets)
 {
-  #define THIS_METHOD "SMESH_MeshEditor::GetHexaFacetsToSplit(): "
+#define THIS_METHOD "SMESH_MeshEditor::GetHexaFacetsToSplit(): "
 
   // Find a hexa closest to the location of theFacetNormal
 
@@ -2930,11 +2912,10 @@ void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*
 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
                                   const bool         the13Diag)
 {
-  myLastCreatedElems.Clear();
-  myLastCreatedNodes.Clear();
-
-  SMESHDS_Mesh * aMesh = GetMeshDS();
+  ClearLastCreated();
+  myLastCreatedElems.reserve( theElems.size() * 2 );
 
+  SMESHDS_Mesh *       aMesh = GetMeshDS();
   Handle(Geom_Surface) surface;
   SMESH_MesherHelper   helper( *GetMesh() );
 
@@ -2964,8 +2945,8 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
       }
-      myLastCreatedElems.Append(newElem1);
-      myLastCreatedElems.Append(newElem2);
+      myLastCreatedElems.push_back(newElem1);
+      myLastCreatedElems.push_back(newElem2);
       // put a new triangle on the same shape and add to the same groups
       if ( aShapeId )
       {
@@ -3007,7 +2988,7 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
         centrNode = helper.GetCentralNode( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
                                            aNodes[4], aNodes[5], aNodes[6], aNodes[7],
                                            surface.IsNull() );
-        myLastCreatedNodes.Append(centrNode);
+        myLastCreatedNodes.push_back(centrNode);
       }
 
       // create a new element
@@ -3025,8 +3006,8 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
                                   centrNode, aNodes[5], aNodes[6] );
       }
-      myLastCreatedElems.Append(newElem1);
-      myLastCreatedElems.Append(newElem2);
+      myLastCreatedElems.push_back(newElem1);
+      myLastCreatedElems.push_back(newElem2);
       // put a new triangle on the same shape and add to the same groups
       if ( aShapeId )
       {
@@ -3150,8 +3131,8 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
                                   SMESH::Controls::NumericalFunctorPtr theCrit,
                                   const double                         theMaxAngle)
 {
-  myLastCreatedElems.Clear();
-  myLastCreatedNodes.Clear();
+  ClearLastCreated();
+  myLastCreatedElems.reserve( theElems.size() / 2 );
 
   if ( !theCrit.get() )
     return false;
@@ -3335,7 +3316,7 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
           {
             const SMDS_MeshElement* newElem = 0;
             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
-            myLastCreatedElems.Append(newElem);
+            myLastCreatedElems.push_back(newElem);
             AddToSameGroups( newElem, tr1, aMesh );
             int aShapeId = tr1->getshapeId();
             if ( aShapeId )
@@ -3366,7 +3347,7 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
             else
               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
-            myLastCreatedElems.Append(newElem);
+            myLastCreatedElems.push_back(newElem);
             AddToSameGroups( newElem, tr1, aMesh );
             int aShapeId = tr1->getshapeId();
             if ( aShapeId )
@@ -3389,7 +3370,7 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
           if ( tr1->NbNodes() == 3 ) {
             const SMDS_MeshElement* newElem = 0;
             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
-            myLastCreatedElems.Append(newElem);
+            myLastCreatedElems.push_back(newElem);
             AddToSameGroups( newElem, tr1, aMesh );
             int aShapeId = tr1->getshapeId();
             if ( aShapeId )
@@ -3420,7 +3401,7 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
             else
               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
-            myLastCreatedElems.Append(newElem);
+            myLastCreatedElems.push_back(newElem);
             AddToSameGroups( newElem, tr1, aMesh );
             int aShapeId = tr1->getshapeId();
             if ( aShapeId )
@@ -3448,286 +3429,6 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
   return true;
 }
 
-
-/*#define DUMPSO(txt) \
-//  cout << txt << endl;
-//=============================================================================
-//
-//
-//
-//=============================================================================
-static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
-{
-if ( i1 == i2 )
-return;
-int tmp = idNodes[ i1 ];
-idNodes[ i1 ] = idNodes[ i2 ];
-idNodes[ i2 ] = tmp;
-gp_Pnt Ptmp = P[ i1 ];
-P[ i1 ] = P[ i2 ];
-P[ i2 ] = Ptmp;
-DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
-}
-
-//=======================================================================
-//function : SortQuadNodes
-//purpose  : Set 4 nodes of a quadrangle face in a good order.
-//           Swap 1<->2 or 2<->3 nodes and correspondingly return
-//           1 or 2 else 0.
-//=======================================================================
-
-int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
-int               idNodes[] )
-{
-  gp_Pnt P[4];
-  int i;
-  for ( i = 0; i < 4; i++ ) {
-    const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
-    if ( !n ) return 0;
-    P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
-  }
-
-  gp_Vec V1(P[0], P[1]);
-  gp_Vec V2(P[0], P[2]);
-  gp_Vec V3(P[0], P[3]);
-
-  gp_Vec Cross1 = V1 ^ V2;
-  gp_Vec Cross2 = V2 ^ V3;
-
-  i = 0;
-  if (Cross1.Dot(Cross2) < 0)
-  {
-    Cross1 = V2 ^ V1;
-    Cross2 = V1 ^ V3;
-
-    if (Cross1.Dot(Cross2) < 0)
-      i = 2;
-    else
-      i = 1;
-    swap ( i, i + 1, idNodes, P );
-
-    //     for ( int ii = 0; ii < 4; ii++ ) {
-    //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
-    //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
-    //     }
-  }
-  return i;
-}
-
-//=======================================================================
-//function : SortHexaNodes
-//purpose  : Set 8 nodes of a hexahedron in a good order.
-//           Return success status
-//=======================================================================
-
-bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
-                                      int               idNodes[] )
-{
-  gp_Pnt P[8];
-  int i;
-  DUMPSO( "INPUT: ========================================");
-  for ( i = 0; i < 8; i++ ) {
-    const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
-    if ( !n ) return false;
-    P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
-    DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
-  }
-  DUMPSO( "========================================");
-
-
-  set<int> faceNodes;  // ids of bottom face nodes, to be found
-  set<int> checkedId1; // ids of tried 2-nd nodes
-  Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
-  const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
-  int iMin, iLoop1 = 0;
-
-  // Loop to try the 2-nd nodes
-
-  while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
-  {
-    // Find not checked 2-nd node
-    for ( i = 1; i < 8; i++ )
-      if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
-        int id1 = idNodes[i];
-        swap ( 1, i, idNodes, P );
-        checkedId1.insert ( id1 );
-        break;
-      }
-
-    // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
-    // ie that all but meybe one (id3 which is on the same face) nodes
-    // lay on the same side from the triangle plane.
-
-    bool manyInPlane = false; // more than 4 nodes lay in plane
-    int iLoop2 = 0;
-    while ( ++iLoop2 < 6 ) {
-
-      // get 1-2-3 plane coeffs
-      Standard_Real A, B, C, D;
-      gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
-      if ( N.SquareMagnitude() > gp::Resolution() )
-      {
-        gp_Pln pln ( P[0], N );
-        pln.Coefficients( A, B, C, D );
-
-        // find the node (iMin) closest to pln
-        Standard_Real dist[ 8 ], minDist = DBL_MAX;
-        set<int> idInPln;
-        for ( i = 3; i < 8; i++ ) {
-          dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
-          if ( fabs( dist[i] ) < minDist ) {
-            minDist = fabs( dist[i] );
-            iMin = i;
-          }
-          if ( fabs( dist[i] ) <= tol )
-            idInPln.insert( idNodes[i] );
-        }
-
-        // there should not be more than 4 nodes in bottom plane
-        if ( idInPln.size() > 1 )
-        {
-          DUMPSO( "### idInPln.size() = " << idInPln.size());
-          // idInPlane does not contain the first 3 nodes
-          if ( manyInPlane || idInPln.size() == 5)
-            return false; // all nodes in one plane
-          manyInPlane = true;
-
-          // set the 1-st node to be not in plane
-          for ( i = 3; i < 8; i++ ) {
-            if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
-              DUMPSO( "### Reset 0-th node");
-              swap( 0, i, idNodes, P );
-              break;
-            }
-          }
-
-          // reset to re-check second nodes
-          leastDist = DBL_MAX;
-          faceNodes.clear();
-          checkedId1.clear();
-          iLoop1 = 0;
-          break; // from iLoop2;
-        }
-
-        // check that the other 4 nodes are on the same side
-        bool sameSide = true;
-        bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
-        for ( i = 3; sameSide && i < 8; i++ ) {
-          if ( i != iMin )
-            sameSide = ( isNeg == dist[i] <= 0.);
-        }
-
-        // keep best solution
-        if ( sameSide && minDist < leastDist ) {
-          leastDist = minDist;
-          faceNodes.clear();
-          faceNodes.insert( idNodes[ 1 ] );
-          faceNodes.insert( idNodes[ 2 ] );
-          faceNodes.insert( idNodes[ iMin ] );
-          DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
-                  << " leastDist = " << leastDist);
-          if ( leastDist <= DBL_MIN )
-            break;
-        }
-      }
-
-      // set next 3-d node to check
-      int iNext = 2 + iLoop2;
-      if ( iNext < 8 ) {
-        DUMPSO( "Try 2-nd");
-        swap ( 2, iNext, idNodes, P );
-      }
-    } // while ( iLoop2 < 6 )
-  } // iLoop1
-
-  if ( faceNodes.empty() ) return false;
-
-  // Put the faceNodes in proper places
-  for ( i = 4; i < 8; i++ ) {
-    if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
-      // find a place to put
-      int iTo = 1;
-      while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
-        iTo++;
-      DUMPSO( "Set faceNodes");
-      swap ( iTo, i, idNodes, P );
-    }
-  }
-
-
-  // Set nodes of the found bottom face in good order
-  DUMPSO( " Found bottom face: ");
-  i = SortQuadNodes( theMesh, idNodes );
-  if ( i ) {
-    gp_Pnt Ptmp = P[ i ];
-    P[ i ] = P[ i+1 ];
-    P[ i+1 ] = Ptmp;
-  }
-  //   else
-  //     for ( int ii = 0; ii < 4; ii++ ) {
-  //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
-  //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
-  //    }
-
-  // Gravity center of the top and bottom faces
-  gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
-  gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
-
-  // Get direction from the bottom to the top face
-  gp_Vec upDir ( aGCb, aGCt );
-  Standard_Real upDirSize = upDir.Magnitude();
-  if ( upDirSize <= gp::Resolution() ) return false;
-  upDir / upDirSize;
-
-  // Assure that the bottom face normal points up
-  gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
-  Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
-  if ( Nb.Dot( upDir ) < 0 ) {
-    DUMPSO( "Reverse bottom face");
-    swap( 1, 3, idNodes, P );
-  }
-
-  // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
-  Standard_Real minDist = DBL_MAX;
-  for ( i = 4; i < 8; i++ ) {
-    // projection of P[i] to the plane defined by P[0] and upDir
-    gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
-    Standard_Real sqDist = P[0].SquareDistance( Pp );
-    if ( sqDist < minDist ) {
-      minDist = sqDist;
-      iMin = i;
-    }
-  }
-  DUMPSO( "Set 4-th");
-  swap ( 4, iMin, idNodes, P );
-
-  // Set nodes of the top face in good order
-  DUMPSO( "Sort top face");
-  i = SortQuadNodes( theMesh, &idNodes[4] );
-  if ( i ) {
-    i += 4;
-    gp_Pnt Ptmp = P[ i ];
-    P[ i ] = P[ i+1 ];
-    P[ i+1 ] = Ptmp;
-  }
-
-  // Assure that direction of the top face normal is from the bottom face
-  gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
-  Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
-  if ( Nt.Dot( upDir ) < 0 ) {
-    DUMPSO( "Reverse top face");
-    swap( 5, 7, idNodes, P );
-  }
-
-  //   DUMPSO( "OUTPUT: ========================================");
-  //   for ( i = 0; i < 8; i++ ) {
-  //     float *p = ugrid->GetPoint(idNodes[i]);
-  //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
-  //   }
-
-  return true;
-}*/
-
 //================================================================================
 /*!
  * \brief Return nodes linked to the given one
@@ -3933,8 +3634,7 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
                                double                      theTgtAspectRatio,
                                const bool                  the2D)
 {
-  myLastCreatedElems.Clear();
-  myLastCreatedNodes.Clear();
+  ClearLastCreated();
 
   if ( theTgtAspectRatio < 1.0 )
     theTgtAspectRatio = 1.0;
@@ -4140,7 +3840,7 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
             // if ( posType != SMDS_TOP_3DSPACE )
             //   dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
             // if ( dist2 < dist1 )
-              uv = newUV;
+            uv = newUV;
           }
         }
         // store UV in the map
@@ -4660,55 +4360,55 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
         break;
       }
       case SMDSEntity_Triangle: // TRIANGLE --->
-        {
-          if ( nbDouble > 0 ) break;
-          if ( nbSame == 0 )       // ---> pentahedron
-            aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
-                                         nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] );
-
-          else if ( nbSame == 1 )  // ---> pyramid
-            aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
-                                         nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
-                                         nextNod[ iSameNode ]);
-
-          else // 2 same nodes:       ---> tetrahedron
-            aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
-                                         nextNod[ iNotSameNode ]);
-          break;
-        }
+      {
+        if ( nbDouble > 0 ) break;
+        if ( nbSame == 0 )       // ---> pentahedron
+          aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
+                                       nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] );
+
+        else if ( nbSame == 1 )  // ---> pyramid
+          aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
+                                       nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
+                                       nextNod[ iSameNode ]);
+
+        else // 2 same nodes:       ---> tetrahedron
+          aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
+                                       nextNod[ iNotSameNode ]);
+        break;
+      }
       case SMDSEntity_Quad_Edge: // sweep quadratic EDGE --->
+      {
+        if ( nbSame == 2 )
+          return;
+        if ( nbDouble+nbSame == 2 )
         {
-          if ( nbSame == 2 )
-            return;
-          if ( nbDouble+nbSame == 2 )
-          {
-            if(nbSame==0) {      // ---> quadratic quadrangle
-              aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
-                                        prevNod[2], midlNod[1], nextNod[2], midlNod[0]);
-            }
-            else { //(nbSame==1) // ---> quadratic triangle
-              if(sames[0]==2) {
-                return; // medium node on axis
-              }
-              else if(sames[0]==0)
-                aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1],
-                                          prevNod[2], midlNod[1], nextNod[2] );
-              else // sames[0]==1
-                aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[0],
-                                          prevNod[2], nextNod[2], midlNod[0]);
-            }
+          if(nbSame==0) {      // ---> quadratic quadrangle
+            aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
+                                      prevNod[2], midlNod[1], nextNod[2], midlNod[0]);
           }
-          else if ( nbDouble == 3 )
-          {
-            if ( nbSame == 0 ) {  // ---> bi-quadratic quadrangle
-              aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
-                                        prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]);
+          else { //(nbSame==1) // ---> quadratic triangle
+            if(sames[0]==2) {
+              return; // medium node on axis
             }
+            else if(sames[0]==0)
+              aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1],
+                                        prevNod[2], midlNod[1], nextNod[2] );
+            else // sames[0]==1
+              aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[0],
+                                        prevNod[2], nextNod[2], midlNod[0]);
           }
-          else
-            return;
-          break;
         }
+        else if ( nbDouble == 3 )
+        {
+          if ( nbSame == 0 ) {  // ---> bi-quadratic quadrangle
+            aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
+                                      prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]);
+          }
+        }
+        else
+          return;
+        break;
+      }
       case SMDSEntity_Quadrangle: { // sweep QUADRANGLE --->
         if ( nbDouble > 0 ) break;
 
@@ -4930,8 +4630,8 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
 
     if ( aNewElem ) {
       newElems.push_back( aNewElem );
-      myLastCreatedElems.Append(aNewElem);
-      srcElements.Append( elem );
+      myLastCreatedElems.push_back(aNewElem);
+      srcElements.push_back( elem );
     }
 
     // set new prev nodes
@@ -5021,19 +4721,19 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
       if ( !isQuadratic ) {
         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
                                vecNewNodes[ 1 ]->second.back())) {
-          myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
-                                                   vecNewNodes[ 1 ]->second.back()));
-          srcElements.Append( elem );
+          myLastCreatedElems.push_back(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
+                                                      vecNewNodes[ 1 ]->second.back()));
+          srcElements.push_back( elem );
         }
       }
       else {
         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
                                vecNewNodes[ 1 ]->second.back(),
                                vecNewNodes[ 2 ]->second.back())) {
-          myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
-                                                   vecNewNodes[ 1 ]->second.back(),
-                                                   vecNewNodes[ 2 ]->second.back()));
-          srcElements.Append( elem );
+          myLastCreatedElems.push_back(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
+                                                      vecNewNodes[ 1 ]->second.back(),
+                                                      vecNewNodes[ 2 ]->second.back()));
+          srcElements.push_back( elem );
         }
       }
     }
@@ -5061,14 +4761,14 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
           // make a new edge and a ceiling for a new edge
           const SMDS_MeshElement* edge;
           if ( ! ( edge = aMesh->FindEdge( n1, n2 ))) {
-            myLastCreatedElems.Append( edge = aMesh->AddEdge( n1, n2 )); // free link edge
-            srcElements.Append( myLastCreatedElems.Last() );
+            myLastCreatedElems.push_back( edge = aMesh->AddEdge( n1, n2 )); // free link edge
+            srcElements.push_back( myLastCreatedElems.back() );
           }
           n1 = vecNewNodes[ iNode ]->second.back();
           n2 = vecNewNodes[ iNext ]->second.back();
           if ( !aMesh->FindEdge( n1, n2 )) {
-            myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // new edge ceiling
-            srcElements.Append( edge );
+            myLastCreatedElems.push_back(aMesh->AddEdge( n1, n2 )); // new edge ceiling
+            srcElements.push_back( edge );
           }
         }
       }
@@ -5089,15 +4789,15 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
           // make an edge and a ceiling for a new edge
           // find medium node
           if ( !aMesh->FindEdge( n1, n2, n3 )) {
-            myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
-            srcElements.Append( elem );
+            myLastCreatedElems.push_back(aMesh->AddEdge( n1, n2, n3 )); // free link edge
+            srcElements.push_back( elem );
           }
           n1 = vecNewNodes[ iNode ]->second.back();
           n2 = vecNewNodes[ iNext ]->second.back();
           n3 = vecNewNodes[ iNode+nbn ]->second.back();
           if ( !aMesh->FindEdge( n1, n2, n3 )) {
-            myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
-            srcElements.Append( elem );
+            myLastCreatedElems.push_back(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
+            srcElements.push_back( elem );
           }
         }
       }
@@ -5190,8 +4890,8 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
                 if ( f )
                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
                 else
-                  myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
-                                                            newOrder[ 2 ] ));
+                  myLastCreatedElems.push_back(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
+                                                               newOrder[ 2 ] ));
               }
             }
             else if ( nbn == 4 )       ///// quadrangle
@@ -5205,8 +4905,8 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
                 if ( f )
                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
                 else
-                  myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
-                                                            newOrder[ 2 ], newOrder[ 3 ]));
+                  myLastCreatedElems.push_back(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
+                                                               newOrder[ 2 ], newOrder[ 3 ]));
               }
             }
             else if ( nbn == 6 && isQuadratic ) /////// quadratic triangle
@@ -5224,12 +4924,12 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
                 if ( f )
                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
                 else
-                  myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
-                                                            newOrder[ 1 ],
-                                                            newOrder[ 2 ],
-                                                            newOrder[ 3 ],
-                                                            newOrder[ 4 ],
-                                                            newOrder[ 5 ] ));
+                  myLastCreatedElems.push_back(aMesh->AddFace( newOrder[ 0 ],
+                                                               newOrder[ 1 ],
+                                                               newOrder[ 2 ],
+                                                               newOrder[ 3 ],
+                                                               newOrder[ 4 ],
+                                                               newOrder[ 5 ] ));
               }
             }
             else if ( nbn == 8 && isQuadratic ) /////// quadratic quadrangle
@@ -5250,10 +4950,10 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
                 if ( f )
                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
                 else
-                  myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
-                                                           newOrder[ 2 ], newOrder[ 3 ],
-                                                           newOrder[ 4 ], newOrder[ 5 ],
-                                                           newOrder[ 6 ], newOrder[ 7 ]));
+                  myLastCreatedElems.push_back(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
+                                                              newOrder[ 2 ], newOrder[ 3 ],
+                                                              newOrder[ 4 ], newOrder[ 5 ],
+                                                              newOrder[ 6 ], newOrder[ 7 ]));
               }
             }
             else if ( nbn == 9 && isQuadratic ) /////// bi-quadratic quadrangle
@@ -5275,11 +4975,11 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
                 if ( f )
                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
                 else
-                  myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
-                                                           newOrder[ 2 ], newOrder[ 3 ],
-                                                           newOrder[ 4 ], newOrder[ 5 ],
-                                                           newOrder[ 6 ], newOrder[ 7 ],
-                                                           newOrder[ 8 ]));
+                  myLastCreatedElems.push_back(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
+                                                              newOrder[ 2 ], newOrder[ 3 ],
+                                                              newOrder[ 4 ], newOrder[ 5 ],
+                                                              newOrder[ 6 ], newOrder[ 7 ],
+                                                              newOrder[ 8 ]));
               }
             }
             else  //////// polygon
@@ -5298,8 +4998,8 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
               }
             }
 
-            while ( srcElements.Length() < myLastCreatedElems.Length() )
-              srcElements.Append( *srcEdge );
+            while ( srcElements.size() < myLastCreatedElems.size() )
+              srcElements.push_back( *srcEdge );
 
           }  // loop on free faces
 
@@ -5336,8 +5036,8 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
 
         AddElement( nodeVec, anyFace.Init( elem ));
 
-        while ( srcElements.Length() < myLastCreatedElems.Length() )
-          srcElements.Append( elem );
+        while ( srcElements.size() < myLastCreatedElems.size() )
+          srcElements.push_back( elem );
       }
     }
   } // loop on swept elements
@@ -5357,11 +5057,16 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet   theElemSets[2],
                                 const bool         theMakeGroups,
                                 const bool         theMakeWalls)
 {
-  myLastCreatedElems.Clear();
-  myLastCreatedNodes.Clear();
+  ClearLastCreated();
+
+  setElemsFirst( theElemSets );
+  myLastCreatedElems.reserve( theElemSets[0].size() * theNbSteps );
+  myLastCreatedNodes.reserve( theElemSets[1].size() * theNbSteps );
 
   // source elements for each generated one
   SMESH_SequenceOfElemPtr srcElems, srcNodes;
+  srcElems.reserve( theElemSets[0].size() );
+  srcNodes.reserve( theElemSets[1].size() );
 
   gp_Trsf aTrsf;
   aTrsf.SetRotation( theAxis, theAngle );
@@ -5381,7 +5086,6 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet   theElemSets[2],
                                      myMesh->NbFaces(ORDER_QUADRATIC) +
                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
   // loop on theElemSets
-  setElemsFirst( theElemSets );
   TIDSortedElemSet::iterator itElem;
   for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet )
   {
@@ -5433,8 +5137,8 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet   theElemSets[2],
               {
                 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
                 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
-                myLastCreatedNodes.Append(newNode);
-                srcNodes.Append( node );
+                myLastCreatedNodes.push_back(newNode);
+                srcNodes.push_back( node );
                 listNewNodes.push_back( newNode );
                 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
               }
@@ -5443,8 +5147,8 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet   theElemSets[2],
               }
               // create a corner node
               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
-              myLastCreatedNodes.Append(newNode);
-              srcNodes.Append( node );
+              myLastCreatedNodes.push_back(newNode);
+              srcNodes.push_back( node );
               listNewNodes.push_back( newNode );
             }
             else {
@@ -5750,12 +5454,12 @@ makeNodesByDirAndSew( SMESHDS_Mesh*                     mesh,
     P1 += myDir.XYZ() * nextStep();
 
     // try to search in sequence of existing nodes
-    // if myNodes.Length()>0 we 'nave to use given sequence
+    // if myNodes.size()>0 we 'nave to use given sequence
     // else - use all nodes of mesh
     const SMDS_MeshNode * node = 0;
     if ( myNodes.Length() > 0 ) {
       int i;
-      for(i=1; i<=myNodes.Length(); i++) {
+      for ( i = 1; i <= myNodes.Length(); i++ ) {
         gp_XYZ P2 = SMESH_TNodeXYZ( myNodes.Value(i) );
         if (( P1 - P2 ).SquareModulus() < myTolerance * myTolerance )
         {
@@ -5917,13 +5621,17 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet     theElemSets[2],
                                   ExtrusParam&         theParams,
                                   TTElemOfElemListMap& newElemsMap)
 {
-  myLastCreatedElems.Clear();
-  myLastCreatedNodes.Clear();
+  ClearLastCreated();
+
+  setElemsFirst( theElemSets );
+  myLastCreatedElems.reserve( theElemSets[0].size() * theParams.NbSteps() );
+  myLastCreatedNodes.reserve( theElemSets[1].size() * theParams.NbSteps() );
 
   // source elements for each generated one
   SMESH_SequenceOfElemPtr srcElems, srcNodes;
+  srcElems.reserve( theElemSets[0].size() );
+  srcNodes.reserve( theElemSets[1].size() );
 
-  setElemsFirst( theElemSets );
   const int nbSteps = theParams.NbSteps();
   theParams.SetElementsToUse( theElemSets[0], theElemSets[1] );
 
@@ -5982,8 +5690,8 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet     theElemSets[2],
             list<const SMDS_MeshNode*>::iterator newNodesIt = listNewNodes.begin();
             for ( ; newNodesIt != listNewNodes.end(); ++newNodesIt )
             {
-              myLastCreatedNodes.Append( *newNodesIt );
-              srcNodes.Append( node );
+              myLastCreatedNodes.push_back( *newNodesIt );
+              srcNodes.push_back( node );
             }
           }
           else
@@ -6024,8 +5732,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet     theElements[2],
                                        const gp_Pnt&        theRefPoint,
                                        const bool           theMakeGroups)
 {
-  myLastCreatedElems.Clear();
-  myLastCreatedNodes.Clear();
+  ClearLastCreated();
 
   int aNbE;
   std::list<double> aPrms;
@@ -6199,8 +5906,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet     theElements[2],
                                        const gp_Pnt&        theRefPoint,
                                        const bool           theMakeGroups)
 {
-  myLastCreatedElems.Clear();
-  myLastCreatedNodes.Clear();
+  ClearLastCreated();
 
   int aNbE;
   std::list<double> aPrms;
@@ -6679,13 +6385,13 @@ SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet                  theElemSets
               // create additional node
               gp_XYZ midP = 0.5 * ( aPN1.XYZ() + aPN0.XYZ() );
               const SMDS_MeshNode* newNode = aMesh->AddNode( midP.X(), midP.Y(), midP.Z() );
-              myLastCreatedNodes.Append(newNode);
-              srcNodes.Append( node );
+              myLastCreatedNodes.push_back(newNode);
+              srcNodes.push_back( node );
               listNewNodes.push_back( newNode );
             }
             const SMDS_MeshNode* newNode = aMesh->AddNode( aPN1.X(), aPN1.Y(), aPN1.Z() );
-            myLastCreatedNodes.Append(newNode);
-            srcNodes.Append( node );
+            myLastCreatedNodes.push_back(newNode);
+            srcNodes.push_back( node );
             listNewNodes.push_back( newNode );
 
             aPN0 = aPN1;
@@ -6711,8 +6417,8 @@ SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet                  theElemSets
               double y = ( N->Y() + P.Y() )/2.;
               double z = ( N->Z() + P.Z() )/2.;
               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
-              srcNodes.Append( node );
-              myLastCreatedNodes.Append(newN);
+              srcNodes.push_back( node );
+              myLastCreatedNodes.push_back(newN);
               aNodes[2*i] = newN;
               aNodes[2*i+1] = N;
               P = gp_XYZ(N->X(),N->Y(),N->Z());
@@ -6805,8 +6511,8 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
                              const bool         theMakeGroups,
                              SMESH_Mesh*        theTargetMesh)
 {
-  myLastCreatedElems.Clear();
-  myLastCreatedNodes.Clear();
+  ClearLastCreated();
+  myLastCreatedElems.reserve( theElems.size() );
 
   bool needReverse = false;
   string groupPostfix;
@@ -6901,14 +6607,14 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
         if ( theTargetMesh ) {
           const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
           n2n_isnew.first->second = newNode;
-          myLastCreatedNodes.Append(newNode);
-          srcNodes.Append( node );
+          myLastCreatedNodes.push_back(newNode);
+          srcNodes.push_back( node );
         }
         else if ( theCopy ) {
           const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
           n2n_isnew.first->second = newNode;
-          myLastCreatedNodes.Append(newNode);
-          srcNodes.Append( node );
+          myLastCreatedNodes.push_back(newNode);
+          srcNodes.push_back( node );
         }
         else {
           aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
@@ -6998,7 +6704,7 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
     if ( editor ) {
       // copy in this or a new mesh
       if ( editor->AddElement( nodes, elemType.Init( elem, /*basicOnly=*/false )))
-        srcElems.Append( elem );
+        srcElems.push_back( elem );
     }
     else {
       // reverse element as it was reversed by transformation
@@ -7009,7 +6715,7 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
   } // loop on elements
 
   if ( editor && editor != this )
-    myLastCreatedElems = editor->myLastCreatedElems;
+    myLastCreatedElems.swap( editor->myLastCreatedElems );
 
   PGroupIDs newGroupIDs;
 
@@ -7020,14 +6726,97 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
   return newGroupIDs;
 }
 
+//================================================================================
+/*!
+ * \brief Make an offset mesh from a source 2D mesh
+ *  \param [in] theElements - source faces
+ *  \param [in] theValue - offset value
+ *  \param [out] theTgtMesh - a mesh to add offset elements to
+ *  \param [in] theMakeGroups - to generate groups
+ *  \return PGroupIDs - IDs of created groups
+ */
+//================================================================================
+
+SMESH_MeshEditor::PGroupIDs SMESH_MeshEditor::Offset( TIDSortedElemSet & theElements,
+                                                      const double       theValue,
+                                                      SMESH_Mesh*        theTgtMesh,
+                                                      const bool         theMakeGroups,
+                                                      const bool         theFixSelfIntersection)
+{
+  SMESHDS_Mesh*    meshDS = GetMeshDS();
+  SMESHDS_Mesh* tgtMeshDS = theTgtMesh->GetMeshDS();
+  SMESH_MeshEditor tgtEditor( theTgtMesh );
+
+  SMDS_ElemIteratorPtr eIt;
+  if ( theElements.empty() ) eIt = meshDS->elementsIterator( SMDSAbs_Face );
+  else                       eIt = SMESHUtils::elemSetIterator( theElements );
+
+  SMESH_MeshAlgos::TEPairVec new2OldFaces;
+  SMESH_MeshAlgos::TNPairVec new2OldNodes;
+  std::unique_ptr< SMDS_Mesh > offsetMesh
+    ( SMESH_MeshAlgos::MakeOffset( eIt, *meshDS, theValue,
+                                   theFixSelfIntersection,
+                                   new2OldFaces, new2OldNodes ));
+
+  offsetMesh->Modified();
+  offsetMesh->CompactMesh(); // make IDs start from 1
+
+  // source elements for each generated one
+  SMESH_SequenceOfElemPtr srcElems, srcNodes;
+  srcElems.reserve( new2OldFaces.size() );
+  srcNodes.reserve( new2OldNodes.size() );
+
+  ClearLastCreated();
+  myLastCreatedElems.reserve( new2OldFaces.size() );
+  myLastCreatedNodes.reserve( new2OldNodes.size() );
+
+  // copy offsetMesh to theTgtMesh
+
+  int idShift = meshDS->MaxNodeID();
+  for ( size_t i = 0; i < new2OldNodes.size(); ++i )
+    if ( const SMDS_MeshNode* n = new2OldNodes[ i ].first )
+    {
+      if ( n->NbInverseElements() > 0 )
+      {
+        const SMDS_MeshNode* n2 =
+          tgtMeshDS->AddNodeWithID( n->X(), n->Y(), n->Z(), idShift + n->GetID() );
+        myLastCreatedNodes.push_back( n2 );
+        srcNodes.push_back( new2OldNodes[ i ].second );
+      }
+    }
+
+  ElemFeatures elemType;
+  for ( size_t i = 0; i < new2OldFaces.size(); ++i )
+    if ( const SMDS_MeshElement* f = new2OldFaces[ i ].first )
+    {
+      elemType.Init( f );
+      elemType.myNodes.clear();
+      for ( SMDS_NodeIteratorPtr nIt = f->nodeIterator(); nIt->more(); )
+      {
+        const SMDS_MeshNode* n2 = nIt->next();
+        elemType.myNodes.push_back( tgtMeshDS->FindNode( idShift + n2->GetID() ));
+      }
+      tgtEditor.AddElement( elemType.myNodes, elemType );
+      srcElems.push_back( new2OldFaces[ i ].second );
+    }
+
+  myLastCreatedElems.swap( tgtEditor.myLastCreatedElems );
+
+  PGroupIDs newGroupIDs;
+  if ( theMakeGroups )
+    newGroupIDs = generateGroups( srcNodes, srcElems, "offset", theTgtMesh, false );
+
+  return newGroupIDs;
+}
+
 //=======================================================================
 /*!
  * \brief Create groups of elements made during transformation
  *  \param nodeGens - nodes making corresponding myLastCreatedNodes
  *  \param elemGens - elements making corresponding myLastCreatedElems
- *  \param postfix - to append to names of new groups
+ *  \param postfix - to push_back to names of new groups
  *  \param targetMesh - mesh to create groups in
- *  \param topPresent - is there "top" elements that are created by sweeping
+ *  \param topPresent - is there are "top" elements that are created by sweeping
  */
 //=======================================================================
 
@@ -7080,30 +6869,30 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
   {
     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
-    if ( gens.Length() != elems.Length() )
+    if ( gens.size() != elems.size() )
       throw SALOME_Exception("SMESH_MeshEditor::generateGroups(): invalid args");
 
     // loop on created elements
-    for (int iElem = 1; iElem <= elems.Length(); ++iElem )
+    for (size_t iElem = 0; iElem < elems.size(); ++iElem )
     {
-      const SMDS_MeshElement* sourceElem = gens( iElem );
+      const SMDS_MeshElement* sourceElem = gens[ iElem ];
       if ( !sourceElem ) {
         MESSAGE("generateGroups(): NULL source element");
         continue;
       }
       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
       if ( groupsOldNew.empty() ) { // no groups of this type at all
-        while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
+        while ( iElem+1 < gens.size() && gens[ iElem+1 ] == sourceElem )
           ++iElem; // skip all elements made by sourceElem
         continue;
       }
       // collect all elements made by the iElem-th sourceElem
       resultElems.clear();
-      if ( const SMDS_MeshElement* resElem = elems( iElem ))
+      if ( const SMDS_MeshElement* resElem = elems[ iElem ])
         if ( resElem != sourceElem )
           resultElems.push_back( resElem );
-      while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
-        if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
+      while ( iElem+1 < gens.size() && gens[ iElem+1 ] == sourceElem )
+        if ( const SMDS_MeshElement* resElem = elems[ ++iElem ])
           if ( resElem != sourceElem )
             resultElems.push_back( resElem );
 
@@ -7143,7 +6932,7 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
           {
             SMDS_MeshGroup & newTopGroup = gOldNew->get<2>()->SMDSGroup();
             newTopGroup.Add( topElem );
-         }
+          }
         }
       }
     } // loop on created elements
@@ -7230,8 +7019,7 @@ void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
                                             TListOfListOfNodes & theGroupsOfNodes,
                                             bool                 theSeparateCornersAndMedium)
 {
-  myLastCreatedElems.Clear();
-  myLastCreatedNodes.Clear();
+  ClearLastCreated();
 
   if ( myMesh->NbEdges  ( ORDER_QUADRATIC ) +
        myMesh->NbFaces  ( ORDER_QUADRATIC ) +
@@ -7343,8 +7131,7 @@ int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *>& faceNod
 
 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
 {
-  myLastCreatedElems.Clear();
-  myLastCreatedNodes.Clear();
+  ClearLastCreated();
 
   SMESHDS_Mesh* aMesh = GetMeshDS();
 
@@ -7530,7 +7317,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
               {
                 const SMDS_MeshElement* newElem =
                   aMesh->AddPolyhedralVolume( poly_nodes, quantities );
-                myLastCreatedElems.Append( newElem );
+                myLastCreatedElems.push_back( newElem );
                 if ( aShapeId && newElem )
                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
                 rmElemIds.push_back( elem->GetID() );
@@ -7799,7 +7586,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
           if ( quantities.size() >= 4 )
           {
             const SMDS_MeshElement* newElem = aMesh->AddPolyhedralVolume( poly_nodes, quantities );
-            myLastCreatedElems.Append( newElem );
+            myLastCreatedElems.push_back( newElem );
             if ( aShapeId && newElem )
               aMesh->SetMeshElementOnShape( newElem, aShapeId );
             rmElemIds.push_back( elem->GetID() );
@@ -7880,27 +7667,22 @@ private:
 void SMESH_MeshEditor::FindEqualElements(TIDSortedElemSet &        theElements,
                                          TListOfListOfElementsID & theGroupsOfElementsID)
 {
-  myLastCreatedElems.Clear();
-  myLastCreatedNodes.Clear();
+  ClearLastCreated();
 
   typedef map< SortableElement, int > TMapOfNodeSet;
   typedef list<int> TGroupOfElems;
 
-  if ( theElements.empty() )
-  { // get all elements in the mesh
-    SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
-    while ( eIt->more() )
-      theElements.insert( theElements.end(), eIt->next() );
-  }
+  SMDS_ElemIteratorPtr elemIt;
+  if ( theElements.empty() ) elemIt = GetMeshDS()->elementsIterator();
+  else                       elemIt = SMESHUtils::elemSetIterator( theElements );
 
   vector< TGroupOfElems > arrayOfGroups;
   TGroupOfElems groupOfElems;
   TMapOfNodeSet mapOfNodeSet;
 
-  TIDSortedElemSet::iterator elemIt = theElements.begin();
-  for ( int i = 0; elemIt != theElements.end(); ++elemIt )
+  for ( int i = 0; elemIt->more(); )
   {
-    const SMDS_MeshElement* curElem = *elemIt;
+    const SMDS_MeshElement* curElem = elemIt->next();
     SortableElement SE(curElem);
     // check uniqueness
     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
@@ -7935,8 +7717,7 @@ void SMESH_MeshEditor::FindEqualElements(TIDSortedElemSet &        theElements,
 
 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
 {
-  myLastCreatedElems.Clear();
-  myLastCreatedNodes.Clear();
+  ClearLastCreated();
 
   typedef list<int> TListOfIDs;
   TListOfIDs rmElemIds; // IDs of elems to remove
@@ -8138,7 +7919,7 @@ bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirst
       if ( contNodes[0].empty() && contNodes[1].empty() )
         return false;
 
-      // append the best free border
+      // push_back the best free border
       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
       theNodes.pop_back(); // remove nIgnore
@@ -8188,8 +7969,7 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
                                  const bool           toCreatePolygons,
                                  const bool           toCreatePolyedrs)
 {
-  myLastCreatedElems.Clear();
-  myLastCreatedNodes.Clear();
+  ClearLastCreated();
 
   Sew_Error aResult = SEW_OK;
 
@@ -8642,13 +8422,13 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
   // get new segments
   TIDSortedElemSet segments;
   SMESH_SequenceOfElemPtr newFaces;
-  for ( int i = 1; i <= myLastCreatedElems.Length(); ++i )
+  for ( size_t i = 0; i < myLastCreatedElems.size(); ++i )
   {
-    if ( !myLastCreatedElems(i) ) continue;
-    if ( myLastCreatedElems(i)->GetType() == SMDSAbs_Edge )
-      segments.insert( segments.end(), myLastCreatedElems(i) );
+    if ( !myLastCreatedElems[i] ) continue;
+    if ( myLastCreatedElems[i]->GetType() == SMDSAbs_Edge )
+      segments.insert( segments.end(), myLastCreatedElems[i] );
     else
-      newFaces.Append( myLastCreatedElems(i) );
+      newFaces.push_back( myLastCreatedElems[i] );
   }
   // get segments adjacent to merged nodes
   TListOfListOfNodes::iterator groupIt = nodeGroupsToMerge.begin();
@@ -8683,7 +8463,7 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
     myLastCreatedElems = newFaces;
     TIDSortedElemSet::iterator seg = segments.begin();
     for ( ; seg != segments.end(); ++seg )
-      myLastCreatedElems.Append( *seg );
+      myLastCreatedElems.push_back( *seg );
   }
 
   return aResult;
@@ -8753,7 +8533,7 @@ void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theElemen
       if ( newElems[i] )
       {
         aMesh->SetMeshElementOnShape( newElems[i], theElement->getshapeId() );
-        myLastCreatedElems.Append( newElems[i] );
+        myLastCreatedElems.push_back( newElems[i] );
       }
     ReplaceElemInGroups( theElement, newElems, aMesh );
     aMesh->RemoveElement( theElement );
@@ -9014,7 +8794,7 @@ void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theElemen
     if ( newElems[i] )
     {
       aMesh->SetMeshElementOnShape( newElems[i], theFace->getshapeId() );
-      myLastCreatedElems.Append( newElems[i] );
+      myLastCreatedElems.push_back( newElems[i] );
     }
   ReplaceElemInGroups( theFace, newElems, aMesh );
   aMesh->RemoveElement(theFace);
@@ -9030,8 +8810,7 @@ void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode
                                       const SMDS_MeshNode*        theBetweenNode2,
                                       list<const SMDS_MeshNode*>& theNodesToInsert)
 {
-  myLastCreatedElems.Clear();
-  myLastCreatedNodes.Clear();
+  ClearLastCreated();
 
   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
@@ -9093,7 +8872,7 @@ void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode
     if ( SMDS_MeshElement* newElem = aMesh->AddPolyhedralVolume( poly_nodes, quantities ))
     {
       aMesh->SetMeshElementOnShape( newElem, elem->getshapeId() );
-      myLastCreatedElems.Append( newElem );
+      myLastCreatedElems.push_back( newElem );
       ReplaceElemInGroups( elem, newElem, aMesh );
     }
     aMesh->RemoveElement( elem );
@@ -9208,50 +8987,50 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
     switch( aType )
     {
     case SMDSAbs_Edge :
-      {
-        NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
-        break;
-      }
+    {
+      NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
+      break;
+    }
     case SMDSAbs_Face :
+    {
+      switch(nbNodes)
       {
-        switch(nbNodes)
-        {
-        case 3:
-          NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
-          break;
-        case 4:
-          NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
-          break;
-        default:
-          NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
-        }
+      case 3:
+        NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
+        break;
+      case 4:
+        NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
         break;
+      default:
+        NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
       }
+      break;
+    }
     case SMDSAbs_Volume :
+    {
+      switch( aGeomType )
       {
-        switch( aGeomType )
-        {
-        case SMDSEntity_Tetra:
-          NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
-          break;
-        case SMDSEntity_Pyramid:
-          NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
-          break;
-        case SMDSEntity_Penta:
-          NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
-          break;
-        case SMDSEntity_Hexa:
-        case SMDSEntity_Quad_Hexa:
-        case SMDSEntity_TriQuad_Hexa:
-          NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
-                                        nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
-          break;
-        case SMDSEntity_Hexagonal_Prism:
-        default:
-          NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
-        }
+      case SMDSEntity_Tetra:
+        NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
+        break;
+      case SMDSEntity_Pyramid:
+        NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
+        break;
+      case SMDSEntity_Penta:
+        NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
         break;
+      case SMDSEntity_Hexa:
+      case SMDSEntity_Quad_Hexa:
+      case SMDSEntity_TriQuad_Hexa:
+        NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
+                                      nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
+        break;
+      case SMDSEntity_Hexagonal_Prism:
+      default:
+        NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
       }
+      break;
+    }
     default :
       continue;
     }
@@ -9621,7 +9400,7 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
     if( newElem && smDS )
       smDS->AddElement( newElem );
 
-     // remove central nodes
+    // remove central nodes
     for ( size_t i = nodes.size() - nbCentralNodes; i < nodes.size(); ++i )
       if ( nodes[i]->NbInverseElements() == 0 )
         meshDS->RemoveFreeNode( nodes[i], smDS, /*fromGroups=*/true );
@@ -9755,7 +9534,7 @@ void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
   }
 
   // replace given elements by linear ones
-  SMDS_ElemIteratorPtr elemIt = elemSetIterator( theElements );
+  SMDS_ElemIteratorPtr elemIt = SMESHUtils::elemSetIterator( theElements );
   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
 
   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
@@ -9807,7 +9586,7 @@ void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
       }
     }
   }
-  elemIt = elemSetIterator( moreElemsToConvert );
+  elemIt = SMESHUtils::elemSetIterator( moreElemsToConvert );
   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
 }
 
@@ -9824,8 +9603,7 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
                                    const SMDS_MeshNode* theSecondNode1,
                                    const SMDS_MeshNode* theSecondNode2)
 {
-  myLastCreatedElems.Clear();
-  myLastCreatedNodes.Clear();
+  ClearLastCreated();
 
   if ( theSide1.size() != theSide2.size() )
     return SEW_DIFF_NB_OF_ELEMENTS;
@@ -10101,12 +9879,12 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
 
   if ( faceSet1.size() != faceSet2.size() ) {
     // delete temporary faces: they are in reverseElements of actual nodes
-//    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
-//    while ( tmpFaceIt->more() )
-//      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
-//    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
-//    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
-//      aMesh->RemoveElement(*tmpFaceIt);
+    //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
+    //    while ( tmpFaceIt->more() )
+    //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
+    //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
+    //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
+    //      aMesh->RemoveElement(*tmpFaceIt);
     MESSAGE("Diff nb of faces");
     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
   }
@@ -10245,7 +10023,7 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
 
   if ( aResult == SEW_OK &&
        ( //linkIt[0] != linkList[0].end() ||
-         !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
+        !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
              " " << (faceSetPtr[1]->empty()));
     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
@@ -10256,9 +10034,9 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
   // ====================================================================
 
   // delete temporary faces
-//  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
-//  while ( tmpFaceIt->more() )
-//    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
+  //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
+  //  while ( tmpFaceIt->more() )
+  //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
   list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
   for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
     aMesh->RemoveElement(*tmpFaceIt);
@@ -10523,17 +10301,12 @@ void SMESH_MeshEditor::DoubleElements( const TIDSortedElemSet& theElements )
         type = types[i];
         break;
       }
-    // put all elements in the vector <allElems>
-    allElems.reserve( mesh->GetMeshInfo().NbElements( type ));
     elemIt = mesh->elementsIterator( type );
-    while ( elemIt->more() )
-      allElems.push_back( elemIt->next());
-    elemIt = elemSetIterator( allElems );
   }
   else
   {
     type = (*theElements.begin())->GetType();
-    elemIt = elemSetIterator( theElements );
+    elemIt = SMESHUtils::elemSetIterator( theElements );
   }
 
   // duplicate elements
@@ -10570,8 +10343,7 @@ bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
                                     const TIDSortedElemSet& theNodesNot,
                                     const TIDSortedElemSet& theAffectedElems )
 {
-  myLastCreatedElems.Clear();
-  myLastCreatedNodes.Clear();
+  ClearLastCreated();
 
   if ( theElems.size() == 0 )
     return false;
@@ -10639,7 +10411,7 @@ bool SMESH_MeshEditor::doubleNodes(SMESHDS_Mesh*           theMeshDS,
         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
         copyPosition( aCurrNode, aNewNode );
         theNodeNodeMap[ aCurrNode ] = aNewNode;
-        myLastCreatedNodes.Append( aNewNode );
+        myLastCreatedNodes.push_back( aNewNode );
       }
       isDuplicate |= (aCurrNode != aNewNode);
       newNodes[ ind++ ] = aNewNode;
@@ -10671,8 +10443,7 @@ bool SMESH_MeshEditor::doubleNodes(SMESHDS_Mesh*           theMeshDS,
 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
                                     const std::list< int >& theListOfModifiedElems )
 {
-  myLastCreatedElems.Clear();
-  myLastCreatedNodes.Clear();
+  ClearLastCreated();
 
   if ( theListOfNodes.size() == 0 )
     return false;
@@ -10700,7 +10471,7 @@ bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
     {
       copyPosition( aNode, aNewNode );
       anOldNodeToNewNode[ aNode ] = aNewNode;
-      myLastCreatedNodes.Append( aNewNode );
+      myLastCreatedNodes.push_back( aNewNode );
     }
   }
 
@@ -10756,8 +10527,8 @@ namespace {
 
   //================================================================================
   /*!
-  \brief Check if element located inside shape
-  \return TRUE if IN or ON shape, FALSE otherwise
+    \brief Check if element located inside shape
+    \return TRUE if IN or ON shape, FALSE otherwise
   */
   //================================================================================
 
@@ -12482,7 +12253,7 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
 
   SMDS_ElemIteratorPtr eIt;
   if (elements.empty()) eIt = aMesh->elementsIterator(elemType);
-  else                  eIt = elemSetIterator( elements );
+  else                  eIt = SMESHUtils::elemSetIterator( elements );
 
   while (eIt->more())
   {
@@ -12661,7 +12432,7 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
     else // store present elements to add them to a group
       for ( size_t i = 0 ; i < presentBndElems.size(); ++i )
       {
-        presentEditor->myLastCreatedElems.Append( presentBndElems[ i ]);
+        presentEditor->myLastCreatedElems.push_back( presentBndElems[ i ]);
       }
 
   } // loop on given elements
@@ -12672,11 +12443,11 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
   if ( group )
   {
     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
-      for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
-        g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
+      for ( size_t i = 0; i < tgtEditor.myLastCreatedElems.size(); ++i )
+        g->SMDSGroup().Add( tgtEditor.myLastCreatedElems[ i ]);
   }
-  tgtEditor.myLastCreatedElems.Clear();
-  tgtEditor2.myLastCreatedElems.Clear();
+  tgtEditor.myLastCreatedElems.clear();
+  tgtEditor2.myLastCreatedElems.clear();
 
   // -----------------------
   // 5. Copy given elements
@@ -12684,7 +12455,7 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
   if ( toCopyElements && targetMesh != myMesh )
   {
     if (elements.empty()) eIt = aMesh->elementsIterator(elemType);
-    else                  eIt = elemSetIterator( elements );
+    else                  eIt = SMESHUtils::elemSetIterator( elements );
     while (eIt->more())
     {
       const SMDS_MeshElement* elem = eIt->next();
@@ -12693,7 +12464,7 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
         tgtNodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
       tgtEditor.AddElement( tgtNodes, elemToCopy.Init( elem ));
 
-      tgtEditor.myLastCreatedElems.Clear();
+      tgtEditor.myLastCreatedElems.clear();
     }
   }
   return nbAddedBnd;
index 103e4a4172ca4b0028106ccea29044ed35d6b3bd..6dd0fae4f17046d070751cacc3aa5506244c8bf6 100644 (file)
@@ -83,11 +83,12 @@ public:
   // --------------------------------------------------------------------------------
   struct ElemFeatures //!< Features of element to create
   {
-    SMDSAbs_ElementType myType;
-    bool                myIsPoly, myIsQuad;
-    int                 myID;
-    double              myBallDiameter;
-    std::vector<int>    myPolyhedQuantities;
+    SMDSAbs_ElementType               myType;
+    bool                              myIsPoly, myIsQuad;
+    int                               myID;
+    double                            myBallDiameter;
+    std::vector<int>                  myPolyhedQuantities;
+    std::vector<const SMDS_MeshNode*> myNodes; // not managed by ElemFeatures
 
     SMESH_EXPORT ElemFeatures( SMDSAbs_ElementType type=SMDSAbs_All, bool isPoly=false, bool isQuad=false )
       :myType( type ), myIsPoly(isPoly), myIsQuad(isQuad), myID(-1), myBallDiameter(0) {}
@@ -462,6 +463,13 @@ public:
                        SMESH_Mesh*        theTargetMesh=0);
   // Move or copy theElements applying theTrsf to their nodes
 
+  PGroupIDs Offset( TIDSortedElemSet & theElements,
+                    const double       theValue,
+                    SMESH_Mesh*        theTgtMesh,
+                    const bool         theMakeGroups,
+                    const bool         theFixSelfIntersection);
+  // Make an offset mesh from a source 2D mesh
+
   typedef std::list< std::list< const SMDS_MeshNode* > > TListOfListOfNodes;
 
   void FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
index 67df8daebb388f8127ad0e94026a6bcb89fea7ec..11821a38b183ccadd0f2c9674b0d47c99e1ed88a 100644 (file)
@@ -4023,9 +4023,9 @@ namespace { // Structures used by FixQuadraticElements()
   {
     // code is valid for convex faces only
     gp_XYZ gc(0,0,0);
-    for ( TIDSortedNodeSet::const_iterator n = begin(); n!=end(); ++n)
-      gc += XYZ( *n ) / size();
-    for (unsigned i = 0; i < _sides.size(); ++i )
+    for ( TIDSortedNodeSet::const_iterator n = begin(); n != end(); ++n )
+      gc += XYZ( *n ) / double( size() );
+    for ( size_t i = 0; i < _sides.size(); ++i )
     {
       if ( _sides[i] == bentLink ) continue;
       gp_Vec linkNorm = _normal ^ gp_Vec( XYZ(_sides[i]->node1()), XYZ(_sides[i]->node2()));
@@ -4041,12 +4041,12 @@ namespace { // Structures used by FixQuadraticElements()
         return true;
     }
     return false;
-    
+
   }
 
   //================================================================================
   /*!
-   * \brief Find pairs of continues faces 
+   * \brief Find pairs of continues faces
    */
   //================================================================================
 
index b3acd18ac98e08c4d317cf1d817b222180475513..4569e5e43b0c1e02d7d21621bd8c8f5fe4342ba8 100644 (file)
@@ -111,6 +111,7 @@ SET(_moc_HEADERS
   SMESHGUI_RotationDlg.h
   SMESHGUI_TranslationDlg.h
   SMESHGUI_ScaleDlg.h
+  SMESHGUI_OffsetDlg.h
   SMESHGUI_SymmetryDlg.h
   SMESHGUI_SewingDlg.h
   SMESHGUI_DuplicateNodesDlg.h
@@ -206,6 +207,7 @@ SET(_other_SOURCES
   SMESHGUI_RotationDlg.cxx
   SMESHGUI_TranslationDlg.cxx
   SMESHGUI_ScaleDlg.cxx
+  SMESHGUI_OffsetDlg.cxx
   SMESHGUI_SymmetryDlg.cxx
   SMESHGUI_SewingDlg.cxx
   SMESHGUI_DuplicateNodesDlg.cxx
index 89262f1b5801302bd014aa9fde9811886c843304..cefb6fc1482c73b67d587e33fa932f40afe55e08 100644 (file)
@@ -74,6 +74,7 @@
 #include "SMESHGUI_RevolutionDlg.h"
 #include "SMESHGUI_RotationDlg.h"
 #include "SMESHGUI_ScaleDlg.h"
+#include "SMESHGUI_OffsetDlg.h"
 #include "SMESHGUI_Selection.h"
 #include "SMESHGUI_SewingDlg.h"
 #include "SMESHGUI_SingleEditDlg.h"
@@ -3505,6 +3506,20 @@ bool SMESHGUI::OnGUIEvent( int theCommandID )
       break;
     }
 
+  case SMESHOp::OpOffset:
+    {
+      if(checkLock(aStudy)) break;
+      if ( vtkwnd ) {
+        EmitSignalDeactivateDialog();
+        ( new SMESHGUI_OffsetDlg( this ) )->show();
+      }
+      else {
+        SUIT_MessageBox::warning(SMESHGUI::desktop(),
+                                 tr("SMESH_WRN_WARNING"), tr("SMESH_WRN_VIEWER_VTK"));
+      }
+      break;
+    }
+
   case SMESHOp::OpSewing:
     {
       if(checkLock(aStudy)) break;
@@ -3946,6 +3961,7 @@ void SMESHGUI::initialize( CAM_Application* app )
   createSMESHAction( SMESHOp::OpRotation,               "ROT",             "ICON_DLG_MESH_ROTATION" );
   createSMESHAction( SMESHOp::OpSymmetry,               "SYM",             "ICON_SMESH_SYMMETRY_PLANE" );
   createSMESHAction( SMESHOp::OpScale,                  "SCALE",           "ICON_DLG_MESH_SCALE" );
+  createSMESHAction( SMESHOp::OpOffset,                 "OFFSET",          "ICON_DLG_MESH_OFFSET" );
   createSMESHAction( SMESHOp::OpSewing,                 "SEW",             "ICON_SMESH_SEWING_FREEBORDERS" );
   createSMESHAction( SMESHOp::OpMergeNodes,             "MERGE",           "ICON_SMESH_MERGE_NODES" );
   createSMESHAction( SMESHOp::OpMergeElements,          "MERGE_ELEMENTS",  "ICON_DLG_MERGE_ELEMENTS" );
@@ -4183,31 +4199,32 @@ void SMESHGUI::initialize( CAM_Application* app )
   //createMenu( SMESHOp::OpRenumberingNodes,    renumId, -1 );
   //createMenu( SMESHOp::OpRenumberingElements, renumId, -1 );
 
+  createMenu( SMESHOp::OpMergeNodes,     transfId, -1 );
+  createMenu( SMESHOp::OpMergeElements,  transfId, -1 );
   createMenu( SMESHOp::OpTranslation,    transfId, -1 );
   createMenu( SMESHOp::OpRotation,       transfId, -1 );
   createMenu( SMESHOp::OpSymmetry,       transfId, -1 );
   createMenu( SMESHOp::OpScale,          transfId, -1 );
+  createMenu( SMESHOp::OpOffset,         transfId, -1 );
   createMenu( SMESHOp::OpSewing,         transfId, -1 );
-  createMenu( SMESHOp::OpMergeNodes,     transfId, -1 );
-  createMenu( SMESHOp::OpMergeElements,  transfId, -1 );
   createMenu( SMESHOp::OpDuplicateNodes, transfId, -1 );
 
+  createMenu( SMESHOp::OpConvertMeshToQuadratic, modifyId, -1 );
+  createMenu( SMESHOp::OpCreateBoundaryElements, modifyId, -1 );
+  createMenu( SMESHOp::OpExtrusion,              modifyId, -1 );
+  createMenu( SMESHOp::OpExtrusionAlongAPath,    modifyId, -1 );
+  createMenu( SMESHOp::OpRevolution,             modifyId, -1 );
+  createMenu( SMESHOp::OpOrientation,            modifyId, -1 );
+  createMenu( SMESHOp::OpReorientFaces,          modifyId, -1 );
   createMenu( SMESHOp::OpMoveNode,               modifyId, -1 );
   createMenu( SMESHOp::OpDiagonalInversion,      modifyId, -1 );
   createMenu( SMESHOp::OpUnionOfTwoTriangle,     modifyId, -1 );
-  createMenu( SMESHOp::OpOrientation,            modifyId, -1 );
-  createMenu( SMESHOp::OpReorientFaces,          modifyId, -1 );
   createMenu( SMESHOp::OpUnionOfTriangles,       modifyId, -1 );
   createMenu( SMESHOp::OpCuttingOfQuadrangles,   modifyId, -1 );
   createMenu( SMESHOp::OpSplitVolumes,           modifyId, -1 );
   createMenu( SMESHOp::OpSplitBiQuadratic,       modifyId, -1 );
   createMenu( SMESHOp::OpSmoothing,              modifyId, -1 );
-  createMenu( SMESHOp::OpExtrusion,              modifyId, -1 );
-  createMenu( SMESHOp::OpExtrusionAlongAPath ,   modifyId, -1 );
-  createMenu( SMESHOp::OpRevolution,             modifyId, -1 );
   createMenu( SMESHOp::OpPatternMapping,         modifyId, -1 );
-  createMenu( SMESHOp::OpConvertMeshToQuadratic, modifyId, -1 );
-  createMenu( SMESHOp::OpCreateBoundaryElements, modifyId, -1 );
 
   createMenu( SMESHOp::OpMinimumDistance,  measureId,   -1 );
   createMenu( SMESHOp::OpBoundingBox,      measureId,   -1 );
@@ -4326,31 +4343,32 @@ void SMESHGUI::initialize( CAM_Application* app )
   //createTool( SMESHOp::OpRenumberingNodes,    renumbTb );
   //createTool( SMESHOp::OpRenumberingElements, renumbTb );
 
+  createTool( SMESHOp::OpMergeNodes,     transformTb );
+  createTool( SMESHOp::OpMergeElements,  transformTb );
   createTool( SMESHOp::OpTranslation,    transformTb );
   createTool( SMESHOp::OpRotation,       transformTb );
   createTool( SMESHOp::OpSymmetry,       transformTb );
   createTool( SMESHOp::OpScale,          transformTb );
+  createTool( SMESHOp::OpOffset,         transformTb );
   createTool( SMESHOp::OpSewing,         transformTb );
-  createTool( SMESHOp::OpMergeNodes,     transformTb );
-  createTool( SMESHOp::OpMergeElements,  transformTb );
   createTool( SMESHOp::OpDuplicateNodes, transformTb );
 
+  createTool( SMESHOp::OpConvertMeshToQuadratic, modifyTb );
+  createTool( SMESHOp::OpCreateBoundaryElements, modifyTb );
+  createTool( SMESHOp::OpExtrusion,              modifyTb );
+  createTool( SMESHOp::OpExtrusionAlongAPath,    modifyTb );
+  createTool( SMESHOp::OpRevolution,             modifyTb );
+  createTool( SMESHOp::OpOrientation,            modifyTb );
+  createTool( SMESHOp::OpReorientFaces,          modifyTb );
   createTool( SMESHOp::OpMoveNode,               modifyTb );
   createTool( SMESHOp::OpDiagonalInversion,      modifyTb );
   createTool( SMESHOp::OpUnionOfTwoTriangle,     modifyTb );
-  createTool( SMESHOp::OpOrientation,            modifyTb );
-  createTool( SMESHOp::OpReorientFaces,          modifyTb );
   createTool( SMESHOp::OpUnionOfTriangles,       modifyTb );
   createTool( SMESHOp::OpCuttingOfQuadrangles,   modifyTb );
   createTool( SMESHOp::OpSplitVolumes,           modifyTb );
   createTool( SMESHOp::OpSplitBiQuadratic,       modifyTb );
   createTool( SMESHOp::OpSmoothing,              modifyTb );
-  createTool( SMESHOp::OpExtrusion,              modifyTb );
-  createTool( SMESHOp::OpExtrusionAlongAPath,    modifyTb );
-  createTool( SMESHOp::OpRevolution,             modifyTb );
   createTool( SMESHOp::OpPatternMapping,         modifyTb );
-  createTool( SMESHOp::OpConvertMeshToQuadratic, modifyTb );
-  createTool( SMESHOp::OpCreateBoundaryElements, modifyTb );
 
   createTool( SMESHOp::OpMinimumDistance, measuremTb );
 
index 25bbd46e7c12d24af2e0db2541e6bb6c3d72ffe7..a956989cfe1e6420d04586566395825efefd58e9 100644 (file)
@@ -40,7 +40,7 @@
 #include <SMESH_FaceOrientationFilter.h>
 #include <SMDS_Mesh.hxx>
 
-// SALOME GUI inclues
+// SALOME GUI includes
 #include <SUIT_Desktop.h>
 #include <SUIT_Session.h>
 #include <SUIT_ResourceMgr.h>
@@ -56,7 +56,7 @@
 #include <Qtx.h>
 
 
-// IDL incldues
+// IDL includes
 #include CORBA_SERVER_HEADER(SMESH_MeshEditor)
 
 // OCCT includes
@@ -777,7 +777,7 @@ void SMESHGUI_AddMeshElementDlg::onTextChange (const QString& theNewText)
 
   mySimulation->SetVisibility(false);
 
-  // hilight entered nodes
+  // highlight entered nodes
   SMDS_Mesh* aMesh = 0;
   if (myActor)
     aMesh = myActor->GetObject()->GetMesh();
index c24dbc4b3eac838cee465990b0267b74649f2dd1..b192f27ed188831252f8453809a5b46f7cdf6e32 100644 (file)
@@ -966,7 +966,7 @@ void SMESHGUI_AddQuadraticElementDlg::onTextChange (const QString& theNewText)
 
   mySimulation->SetVisibility(false);
 
-  // hilight entered nodes
+  // highlight entered nodes
   SMDS_Mesh* aMesh = 0;
   if (myActor)
     aMesh = myActor->GetObject()->GetMesh();
index 0fc5aef49ba59fd75f94e995ff9e4a20ef7ee09d..9f8c1f2886b1b0c0195a7dc1b41032b596f90aa9 100644 (file)
@@ -452,7 +452,7 @@ void SMESHGUI_CopyMeshDlg::onTextChange (const QString& theNewText)
   buttonOk->setEnabled(false);
   buttonApply->setEnabled(false);
 
-  // hilight entered elements
+  // highlight entered elements
   SMDS_Mesh* aMesh = 0;
   if (myActor)
     aMesh = myActor->GetObject()->GetMesh();
index e938f0667250f9a48878ba630d0ebf2b9ae07f7d..f7017dfe1046c8a7606cd1c27daa08bbb2ecfae7 100644 (file)
@@ -717,7 +717,7 @@ void SMESHGUI_CreatePolyhedralVolumeDlg::onTextChange(const QString& theNewText)
         buttonOk->setEnabled( false );
         buttonApply->setEnabled( false );
       
-        // check entered ids of faces and hilight them
+        // check entered ids of faces and highlight them
         QStringList aListId;
         if ( aMesh ) {
           TColStd_MapOfInteger newIndices;
index 205544cfa0993ba688f3dfd69a386640774a7525..66b268813104936d9b37566b969bc311e1aedfa8 100644 (file)
@@ -337,7 +337,7 @@ void SMESHGUI_3TypesSelector::onTextChange( const QString& theNewText )
 
   myBusy = true;
 
-  // hilight entered elements/nodes
+  // highlight entered elements/nodes
 
   myIDSource[ iType ]->length( 0 );
 
index 5ec69fed3974685b0e6d6e8cefec956a777e021c..b864ea4df13c191bf571f4dfaa2e9b69c4f377f1 100644 (file)
@@ -346,7 +346,7 @@ void SMESHGUI_FindElemByPointOp::onCloseView()
 }
 //================================================================================
 /*!
- * \brief hilight found selected elements
+ * \brief highlight found selected elements
  */
 //================================================================================
 
index 226f785943123572bbc5d003f3e0d01317608bc6..486a654178126a3432d2b98e6376d27865c39984 100644 (file)
@@ -2329,7 +2329,7 @@ void SMESHGUI_TreeElemInfo::saveInfo( QTextStream &out )
 */
 
 /*!
-  \brief Contructor
+  \brief Constructor
 */
 GrpComputor::GrpComputor( SMESH::SMESH_GroupBase_ptr grp,
                           QTreeWidgetItem*           item,
index e8429fd5879b3f5172702023e794bfd044a7d952..441b9769c9b118ef5fe39baa4ac2add2926f7c95 100755 (executable)
@@ -1400,7 +1400,7 @@ void SMESHGUI_MeshPatternDlg::onTextChanged (const QString& theNewText)
     activateSelection();
   }
 
-  // hilight entered elements/nodes
+  // highlight entered elements/nodes
   SMDS_Mesh* aMesh = 0;
   SMESH_Actor* anActor = SMESH::FindActorByObject(myMesh);
   if (anActor)
index f31874bb0be88e298906d82c13ece5201a2dbc36..be7fd7be20354c3812cdaf6afcc3505fd3195fff 100755 (executable)
@@ -883,7 +883,7 @@ void SMESHGUI_MultiEditDlg::onListSelectionChanged()
     if (myListBox->item(i)->isSelected())
     {
       int anId = myListBox->item(i)->text().toInt();
-      if (anObj->GetElemVTKId(anId) >= 0) // avoid exception in hilight
+      if (anObj->GetElemVTKId(anId) >= 0) // avoid exception in highlight
         anIndexes.Add(anId);
     }
   }
diff --git a/src/SMESHGUI/SMESHGUI_OffsetDlg.cxx b/src/SMESHGUI/SMESHGUI_OffsetDlg.cxx
new file mode 100644 (file)
index 0000000..b63375a
--- /dev/null
@@ -0,0 +1,937 @@
+// Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+//  File   : SMESHGUI_OffsetDlg.cxx
+
+//  SMESH includes
+
+#include "SMESHGUI_OffsetDlg.h"
+
+#include "SMESHGUI.h"
+#include "SMESHGUI_SpinBox.h"
+#include "SMESHGUI_Utils.h"
+#include "SMESHGUI_VTKUtils.h"
+#include "SMESHGUI_MeshUtils.h"
+#include "SMESHGUI_IdValidator.h"
+#include "SMESHGUI_FilterDlg.h"
+#include "SMESHGUI_MeshEditPreview.h"
+
+#include <SMESH_Actor.h>
+#include <SMESH_TypeFilter.hxx>
+#include <SMESH_LogicalFilter.hxx>
+#include <SMDS_Mesh.hxx>
+
+// SALOME GUI includes
+#include <LightApp_Application.h>
+#include <LightApp_SelectionMgr.h>
+#include <SALOME_ListIO.hxx>
+#include <SUIT_Desktop.h>
+#include <SUIT_MessageBox.h>
+#include <SUIT_OverrideCursor.h>
+#include <SUIT_ResourceMgr.h>
+#include <SUIT_Session.h>
+#include <SVTK_ViewModel.h>
+#include <SVTK_ViewWindow.h>
+#include <SalomeApp_Tools.h>
+
+// SALOME KERNEL includes
+#include <SALOMEDSClient.hxx>
+#include <SALOMEDSClient_SObject.hxx>
+
+// OCCT includes
+#include <TColStd_MapOfInteger.hxx>
+
+// Qt includes
+#include <QApplication>
+#include <QButtonGroup>
+#include <QGroupBox>
+#include <QLabel>
+#include <QLineEdit>
+#include <QPushButton>
+#include <QRadioButton>
+#include <QCheckBox>
+#include <QHBoxLayout>
+#include <QVBoxLayout>
+#include <QGridLayout>
+#include <QSpinBox>
+#include <QKeyEvent>
+
+// IDL includes
+#include <SALOMEconfig.h>
+#include CORBA_SERVER_HEADER(SMESH_Group)
+#include CORBA_SERVER_HEADER(SMESH_MeshEditor)
+
+enum { MOVE_ELEMS_BUTTON = 0, COPY_ELEMS_BUTTON, MAKE_MESH_BUTTON }; //!< action type
+
+/*!
+  \class BusyLocker
+  \brief Simple 'busy state' flag locker.
+  \internal
+*/
+class BusyLocker
+{
+public:
+  //! Constructor. Sets passed boolean flag to \c true.
+  BusyLocker( bool& busy ) : myBusy( busy ) { myBusy = true; }
+  //! Destructor. Clear external boolean flag passed as parameter to the constructor to \c false.
+  ~BusyLocker() { myBusy = false; }
+private:
+  bool& myBusy; //! External 'busy state' boolean flag
+};
+
+#define SPACING 6
+#define MARGIN  11
+
+//=================================================================================
+// class    : SMESHGUI_OffsetDlg()
+// purpose  :
+//=================================================================================
+SMESHGUI_OffsetDlg::SMESHGUI_OffsetDlg( SMESHGUI* theModule ) :
+  SMESHGUI_MultiPreviewDlg( theModule ),
+  mySelectionMgr( SMESH::GetSelectionMgr( theModule ) ),
+  myFilterDlg(0)
+{
+  QPixmap image0 (SMESH::GetResourceMgr( mySMESHGUI )->loadPixmap("SMESH", tr("ICON_DLG_MESH_OFFSET")));
+  QPixmap image1 (SMESH::GetResourceMgr( mySMESHGUI )->loadPixmap("SMESH", tr("ICON_SELECT")));
+
+  setModal(false);
+  setAttribute(Qt::WA_DeleteOnClose, true);
+  setWindowTitle(tr("SMESH_OFFSET_TITLE"));
+  setSizeGripEnabled(true);
+
+  QVBoxLayout* dlgLayout = new QVBoxLayout(this);
+  dlgLayout->setSpacing(SPACING);
+  dlgLayout->setMargin(MARGIN);
+
+  /***************************************************************/
+  ConstructorsBox = new QGroupBox(tr("SMESH_OFFSET"), this);
+  QHBoxLayout* ConstructorsBoxLayout = new QHBoxLayout(ConstructorsBox);
+  ConstructorsBoxLayout->setSpacing(SPACING);
+  ConstructorsBoxLayout->setMargin(MARGIN);
+
+  QRadioButton* RadioButton1= new QRadioButton(ConstructorsBox);
+  RadioButton1->setIcon(image0);
+
+  ConstructorsBoxLayout->addWidget(RadioButton1);
+
+  /***************************************************************/
+  GroupArguments = new QGroupBox(tr("SMESH_ARGUMENTS"), this);
+  QGridLayout* GroupArgumentsLayout = new QGridLayout(GroupArguments);
+  GroupArgumentsLayout->setSpacing(SPACING);
+  GroupArgumentsLayout->setMargin(MARGIN);
+
+  myIdValidator = new SMESHGUI_IdValidator(this);
+
+  // Controls for elements selection
+  TextLabelElements = new QLabel(tr("SMESH_ID_ELEMENTS"), GroupArguments);
+  // SelectElementsButton = new QPushButton(GroupArguments);
+  // SelectElementsButton->setIcon(image1);
+  LineEditElements = new QLineEdit(GroupArguments);
+  LineEditElements->setValidator(myIdValidator);
+  LineEditElements->setMaxLength(-1);
+  myFilterBtn = new QPushButton( tr( "SMESH_BUT_FILTER" ), GroupArguments );
+  connect(myFilterBtn,   SIGNAL(clicked()), this, SLOT(setFilters()));
+
+  // Control for the whole mesh selection
+  CheckBoxMesh = new QCheckBox(tr("SMESH_SELECT_WHOLE_MESH"), GroupArguments);
+
+  // offset
+  QLabel* TextLabel1 = new QLabel(tr("OFFSET_VALUE"), GroupArguments);
+  SpinBox = new SMESHGUI_SpinBox(GroupArguments);
+
+
+  // switch of action type
+  ActionBox = new QGroupBox(GroupArguments);
+  ActionGroup = new QButtonGroup(GroupArguments);
+  QVBoxLayout* ActionBoxLayout = new QVBoxLayout(ActionBox);
+  ActionBoxLayout->addSpacing(SPACING);
+  ActionBoxLayout->setMargin(MARGIN);
+
+  QRadioButton* aMoveElements = new QRadioButton(tr("SMESH_MOVE_ELEMENTS"), ActionBox);
+  QRadioButton* aCopyElements = new QRadioButton(tr("SMESH_COPY_ELEMENTS"), ActionBox);
+  QRadioButton* aCreateMesh   = new QRadioButton(tr("SMESH_CREATE_MESH"),   ActionBox);
+
+  ActionBoxLayout->addWidget(aMoveElements);
+  ActionBoxLayout->addWidget(aCopyElements);
+  ActionBoxLayout->addWidget(aCreateMesh);
+  ActionGroup->addButton(aMoveElements, MOVE_ELEMS_BUTTON);
+  ActionGroup->addButton(aCopyElements, COPY_ELEMS_BUTTON);
+  ActionGroup->addButton(aCreateMesh,   MAKE_MESH_BUTTON);
+
+  // CheckBox for groups generation
+  MakeGroupsCheck = new QCheckBox(tr("SMESH_MAKE_GROUPS"), GroupArguments);
+  MakeGroupsCheck->setChecked(false);
+
+  // Name of a mesh to create
+  LineEditNewMesh = new QLineEdit(GroupArguments);
+
+  //Preview check box
+  myPreviewCheckBox = new QCheckBox(tr("PREVIEW"), GroupArguments);
+
+  // layout
+  GroupArgumentsLayout->addWidget(TextLabelElements,    0, 0);
+  //GroupArgumentsLayout->addWidget(SelectElementsButton, 0, 1);
+  GroupArgumentsLayout->addWidget(LineEditElements,     0, 2, 1, 5);
+  GroupArgumentsLayout->addWidget(myFilterBtn,          0, 7);
+  GroupArgumentsLayout->addWidget(CheckBoxMesh,         1, 0, 1, 8);
+  GroupArgumentsLayout->addWidget(TextLabel1,           2, 0);
+  GroupArgumentsLayout->addWidget(SpinBox,              2, 3);
+  GroupArgumentsLayout->addWidget(ActionBox,            3, 0, 3, 4);
+  GroupArgumentsLayout->addWidget(MakeGroupsCheck,      4, 5, 1, 4);
+  GroupArgumentsLayout->addWidget(LineEditNewMesh,      5, 5, 1, 4);
+  GroupArgumentsLayout->addWidget(myPreviewCheckBox,    6, 0);
+
+  /***************************************************************/
+  GroupButtons = new QGroupBox(this);
+  QHBoxLayout* GroupButtonsLayout = new QHBoxLayout(GroupButtons);
+  GroupButtonsLayout->setSpacing(SPACING);
+  GroupButtonsLayout->setMargin(MARGIN);
+
+  buttonOk = new QPushButton(tr("SMESH_BUT_APPLY_AND_CLOSE"), GroupButtons);
+  buttonOk->setAutoDefault(true);
+  buttonOk->setDefault(true);
+  buttonApply = new QPushButton(tr("SMESH_BUT_APPLY"), GroupButtons);
+  buttonApply->setAutoDefault(true);
+  buttonCancel = new QPushButton(tr("SMESH_BUT_CLOSE"), GroupButtons);
+  buttonCancel->setAutoDefault(true);
+  buttonHelp = new QPushButton(tr("SMESH_BUT_HELP"), GroupButtons);
+  buttonHelp->setAutoDefault(true);
+
+  GroupButtonsLayout->addWidget(buttonOk);
+  GroupButtonsLayout->addSpacing(10);
+  GroupButtonsLayout->addWidget(buttonApply);
+  GroupButtonsLayout->addSpacing(10);
+  GroupButtonsLayout->addStretch();
+  GroupButtonsLayout->addWidget(buttonCancel);
+  GroupButtonsLayout->addWidget(buttonHelp);
+
+  /***************************************************************/
+  dlgLayout->addWidget(ConstructorsBox);
+  dlgLayout->addWidget(GroupArguments);
+  dlgLayout->addWidget(GroupButtons);
+
+  /* Initialisations */
+  SpinBox->RangeStepAndValidator(COORD_MIN, COORD_MAX, 1.0, "length_precision");
+
+  RadioButton1->setChecked(true);
+
+  mySelector = (SMESH::GetViewWindow( mySMESHGUI ))->GetSelector();
+
+  mySMESHGUI->SetActiveDialogBox((QDialog*)this);
+
+  // Costruction of the logical filter
+  SMESH_TypeFilter* aMeshOrSubMeshFilter = new SMESH_TypeFilter (SMESH::MESHorSUBMESH);
+  SMESH_TypeFilter* aSmeshGroupFilter    = new SMESH_TypeFilter (SMESH::GROUP);
+
+  QList<SUIT_SelectionFilter*> aListOfFilters;
+  if (aMeshOrSubMeshFilter) aListOfFilters.append(aMeshOrSubMeshFilter);
+  if (aSmeshGroupFilter)    aListOfFilters.append(aSmeshGroupFilter);
+
+  myMeshOrSubMeshOrGroupFilter =
+    new SMESH_LogicalFilter(aListOfFilters, SMESH_LogicalFilter::LO_OR);
+
+  myHelpFileName = "Offset_page.html";
+
+  Init();
+
+  /* signals and slots connections */
+  connect(buttonOk,     SIGNAL(clicked()), this, SLOT(ClickOnOk()));
+  connect(buttonCancel, SIGNAL(clicked()), this, SLOT(reject()));
+  connect(buttonApply,  SIGNAL(clicked()), this, SLOT(ClickOnApply()));
+  connect(buttonHelp,   SIGNAL(clicked()), this, SLOT(ClickOnHelp()));
+
+  //connect(SelectElementsButton, SIGNAL (clicked()), this, SLOT(SetEditCurrentArgument()));
+
+  connect(mySMESHGUI, SIGNAL (SignalDeactivateActiveDialog()), this, SLOT(DeactivateActiveDialog()));
+  connect(mySelectionMgr, SIGNAL(currentSelectionChanged()),   this, SLOT(SelectionIntoArgument()));
+  /* to close dialog if study change */
+  connect(mySMESHGUI, SIGNAL(SignalCloseAllDialogs()),      this, SLOT(reject()));
+  connect(mySMESHGUI, SIGNAL(SignalActivatedViewManager()), this, SLOT(onOpenView()));
+  connect(mySMESHGUI, SIGNAL(SignalCloseView()),            this, SLOT(onCloseView()));
+
+  connect(LineEditElements, SIGNAL(textChanged(const QString&)),    SLOT(onTextChange(const QString&)));
+  connect(CheckBoxMesh,     SIGNAL(toggled(bool)),                  SLOT(onSelectMesh(bool)));
+  connect(ActionGroup,      SIGNAL(buttonClicked(int)),             SLOT(onActionClicked(int)));
+
+  connect(SpinBox,  SIGNAL(valueChanged(double)), this, SLOT(toDisplaySimulation()));
+
+  //To Connect preview check box
+  connectPreviewControl();
+
+  SelectionIntoArgument();
+  onActionClicked(MOVE_ELEMS_BUTTON);
+}
+
+//=================================================================================
+// function : ~SMESHGUI_OffsetDlg()
+// purpose  : Destroys the object and frees any allocated resources
+//=================================================================================
+SMESHGUI_OffsetDlg::~SMESHGUI_OffsetDlg()
+{
+  if ( myFilterDlg ) {
+    myFilterDlg->setParent( 0 );
+    delete myFilterDlg;
+    myFilterDlg = 0;
+  }
+}
+
+//=================================================================================
+// function : Init()
+// purpose  :
+//=================================================================================
+void SMESHGUI_OffsetDlg::Init (bool ResetControls)
+{
+  myBusy = false;
+  myObjects.clear();
+  myObjectsNames.clear();
+  myMeshes.clear();
+
+  LineEditElements->clear();
+  myElementsId = "";
+  myNbOkElements = 0;
+
+  buttonOk->setEnabled(false);
+  buttonApply->setEnabled(false);
+
+  myActor = 0;
+
+  if (ResetControls)
+  {
+    SpinBox->SetValue(1.0);
+    myPreviewCheckBox->setChecked(false);
+    onDisplaySimulation(false);
+
+    ActionGroup->button( MOVE_ELEMS_BUTTON )->setChecked(true);
+    CheckBoxMesh->setChecked(true);
+    onSelectMesh(true);
+  }
+}
+
+//=================================================================================
+// function : ClickOnApply()
+// purpose  :
+//=================================================================================
+bool SMESHGUI_OffsetDlg::ClickOnApply()
+{
+  if (mySMESHGUI->isActiveStudyLocked())
+    return false;
+
+  if( !isValid() )
+    return false;
+
+  SUIT_OverrideCursor aWaitCursor;
+
+  if (myNbOkElements)
+  {
+    QStringList aListElementsId = myElementsId.split(" ", QString::SkipEmptyParts);
+
+    SMESH::long_array_var anElementsId = new SMESH::long_array;
+    anElementsId->length(aListElementsId.count());
+    for (int i = 0; i < aListElementsId.count(); i++)
+      anElementsId[i] = aListElementsId[i].toInt();
+
+    double offsetValue = SpinBox->value();
+
+    QStringList aParameters;
+    aParameters << SpinBox->text();
+
+    int actionButton = ActionGroup->checkedId();
+    bool makeGroups = ( MakeGroupsCheck->isEnabled() && MakeGroupsCheck->isChecked() );
+    SMESH::ListOfGroups_var groups;
+    SMESH::SMESH_Mesh_var mesh;
+    QStringList anEntryList;
+    try
+    {
+      switch ( actionButton ) {
+
+      case MOVE_ELEMS_BUTTON:
+        if ( CheckBoxMesh->isChecked() )
+          for ( int i = 0; i < myObjects.count(); i++ ) {
+            SMESH::SMESH_MeshEditor_var aMeshEditor = myMeshes[i]->GetMeshEditor();
+            myMeshes[i]->SetParameters( aParameters.join( ":" ).toLatin1().constData() );
+            mesh = aMeshEditor->Offset( myObjects[i], offsetValue, true, "", groups.out() );
+          }
+        else {
+          SMESH::SMESH_MeshEditor_var aMeshEditor = myMeshes[0]->GetMeshEditor();
+          SMESH::IDSource_wrap src = aMeshEditor->MakeIDSource(anElementsId, SMESH::FACE);
+          myMeshes[0]->SetParameters( aParameters.join( ":" ).toLatin1().constData() );
+          mesh = aMeshEditor->Offset( src, offsetValue, true, "", groups.out() );
+        }
+        break;
+
+      case COPY_ELEMS_BUTTON:
+        if ( CheckBoxMesh->isChecked() )
+          for ( int i = 0; i < myObjects.count(); i++ ) {
+            SMESH::SMESH_MeshEditor_var aMeshEditor = myMeshes[i]->GetMeshEditor();
+            myMeshes[i]->SetParameters(aParameters.join( ":" ).toLatin1().constData());
+            mesh = aMeshEditor->Offset( myObjects[i], offsetValue, makeGroups, "", groups.out() );
+          }
+        else {
+          SMESH::SMESH_MeshEditor_var aMeshEditor = myMeshes[0]->GetMeshEditor();
+          SMESH::IDSource_wrap src = aMeshEditor->MakeIDSource(anElementsId, SMESH::FACE );
+          myMeshes[0]->SetParameters(aParameters.join( ":" ).toLatin1().constData());
+          mesh = aMeshEditor->Offset( src, offsetValue, makeGroups, "", groups.out() );
+        }
+        break;
+
+      case MAKE_MESH_BUTTON: {
+        SMESH::SMESH_Mesh_var mesh;
+        if ( CheckBoxMesh->isChecked() ) {
+          for ( int i = 0; i < myObjects.count(); i++ ) {
+            QString aName =
+              SMESH::UniqueMeshName( LineEditNewMesh->text().replace( "*", myObjectsNames[i] ));
+            SMESH::SMESH_MeshEditor_var aMeshEditor = myMeshes[i]->GetMeshEditor();
+            myMeshes[i]->SetParameters(aParameters.join( ":" ).toLatin1().constData());
+            mesh = aMeshEditor->Offset( myObjects[i], offsetValue, makeGroups,
+                                        aName.toLatin1().data(), groups.out() );
+            if( _PTR(SObject) aSObject = SMESH::ObjectToSObject( mesh ))
+              anEntryList.append( aSObject->GetID().c_str() );
+          }
+        }
+        else {
+          SMESH::SMESH_MeshEditor_var aMeshEditor = myMeshes[0]->GetMeshEditor();
+          myMeshes[0]->SetParameters(aParameters.join( ":" ).toLatin1().constData());
+          SMESH::IDSource_wrap src = aMeshEditor->MakeIDSource(anElementsId, SMESH::FACE );
+          mesh = aMeshEditor->Offset( src, offsetValue, makeGroups,
+                                      LineEditNewMesh->text().toLatin1().data(), groups.out() );
+          if( _PTR(SObject) aSObject = SMESH::ObjectToSObject( mesh ) )
+            anEntryList.append( aSObject->GetID().c_str() );
+        }
+        break;
+      }
+      }
+    }
+    catch ( const SALOME::SALOME_Exception& S_ex ) {
+      SalomeApp_Tools::QtCatchCorbaException( S_ex );
+    }
+    catch (...) {
+    }
+
+    for ( int i = 0; i < myObjects.count(); i++ ) {
+      SMESH_Actor* actor = SMESH::FindActorByObject( myObjects[i] );
+      if ( actor ) SMESH::Update( actor->getIO(), true );
+    }
+
+    if ( makeGroups || actionButton == MAKE_MESH_BUTTON )
+    {
+      mySMESHGUI->updateObjBrowser(true); // new groups may appear
+      if( LightApp_Application* anApp =
+          dynamic_cast<LightApp_Application*>( SUIT_Session::session()->activeApplication() ) )
+        anApp->browseObjects( anEntryList, isApplyAndClose() );
+    }
+    if ( !isApplyAndClose() )
+    {
+      Init(false);
+      SelectionIntoArgument();
+    }
+    SMESHGUI::Modified();
+  }
+
+  return true;
+}
+
+//=================================================================================
+// function : ClickOnOk()
+// purpose  :
+//=================================================================================
+void SMESHGUI_OffsetDlg::ClickOnOk()
+{
+  setIsApplyAndClose( true );
+  if( ClickOnApply() )
+    reject();
+}
+
+//=================================================================================
+// function : reject()
+// purpose  :
+//=================================================================================
+void SMESHGUI_OffsetDlg::reject()
+{
+  disconnect(mySelectionMgr, 0, this, 0);
+  mySelectionMgr->clearFilters();
+  if (SMESH::GetCurrentVtkView()) {
+    SMESH::RemoveFilters(); // PAL6938 -- clean all mesh entity filters
+    SMESH::SetPointRepresentation(false);
+  }
+  if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
+    aViewWindow->SetSelectionMode( ActorSelection );
+  mySMESHGUI->ResetState();
+  QDialog::reject();
+}
+
+//=================================================================================
+// function : onOpenView()
+// purpose  :
+//=================================================================================
+void SMESHGUI_OffsetDlg::onOpenView()
+{
+  if ( mySelector ) {
+    SMESH::SetPointRepresentation(false);
+  }
+  else {
+    mySelector = SMESH::GetViewWindow( mySMESHGUI )->GetSelector();
+    ActivateThisDialog();
+  }
+}
+
+//=================================================================================
+// function : onCloseView()
+// purpose  :
+//=================================================================================
+void SMESHGUI_OffsetDlg::onCloseView()
+{
+  DeactivateActiveDialog();
+  mySelector = 0;
+}
+
+//=================================================================================
+// function : ClickOnHelp()
+// purpose  :
+//=================================================================================
+void SMESHGUI_OffsetDlg::ClickOnHelp()
+{
+  LightApp_Application* app = (LightApp_Application*)(SUIT_Session::session()->activeApplication());
+  if (app)
+    app->onHelpContextModule(mySMESHGUI ? app->moduleName(mySMESHGUI->moduleName()) : QString(""), myHelpFileName);
+  else {
+    QString platform;
+#ifdef WIN32
+    platform = "winapplication";
+#else
+    platform = "application";
+#endif
+    SUIT_MessageBox::warning(this, tr("WRN_WARNING"),
+                             tr("EXTERNAL_BROWSER_CANNOT_SHOW_PAGE").
+                             arg(app->resourceMgr()->stringValue("ExternalBrowser",
+                                                                 platform)).
+                             arg(myHelpFileName));
+  }
+}
+
+//=======================================================================
+// function : onTextChange()
+// purpose  :
+//=======================================================================
+
+void SMESHGUI_OffsetDlg::onTextChange (const QString& theNewText)
+{
+  if (myBusy) return;
+  BusyLocker lock( myBusy );
+
+  myNbOkElements = 0;
+
+  buttonOk->setEnabled(false);
+  buttonApply->setEnabled(false);
+
+  // hilight entered elements
+  SMDS_Mesh* aMesh = 0;
+  if (myActor)
+    aMesh = myActor->GetObject()->GetMesh();
+
+  if (aMesh) {
+    Handle(SALOME_InteractiveObject) anIO = myActor->getIO();
+
+    TColStd_MapOfInteger newIndices;
+
+    QStringList aListId = theNewText.split(" ", QString::SkipEmptyParts);
+    for (int i = 0; i < aListId.count(); i++)
+    {
+      if ( const SMDS_MeshElement * e = aMesh->FindElement(aListId[ i ].toInt()))
+        newIndices.Add( e->GetID() );
+      myNbOkElements++;
+    }
+
+    mySelector->AddOrRemoveIndex( anIO, newIndices, false );
+    if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
+      aViewWindow->highlight( anIO, true, true );
+
+    myElementsId = theNewText;
+  }
+
+  if (myNbOkElements) {
+    buttonOk->setEnabled(true);
+    buttonApply->setEnabled(true);
+  }
+}
+
+//=================================================================================
+// function : SelectionIntoArgument()
+// purpose  : Called when selection as changed or other case
+//=================================================================================
+void SMESHGUI_OffsetDlg::SelectionIntoArgument()
+{
+  if (myBusy) return;
+  if (myFilterDlg && myFilterDlg->isVisible()) return; // filter dlg active
+
+  BusyLocker lock( myBusy );
+
+  // clear
+  myActor = 0;
+  QString aString = "";
+  onDisplaySimulation(false);
+
+  LineEditElements->setText(aString);
+  myNbOkElements = 0;
+  buttonOk->setEnabled(false);
+  buttonApply->setEnabled(false);
+
+  if (!GroupButtons->isEnabled()) // inactive
+    return;
+
+  // get selected mesh
+  SALOME_ListIO aList;
+  mySelectionMgr->selectedObjects(aList);
+
+  int nbSel = aList.Extent();
+  if (nbSel < 1)
+    return;
+
+  myElementsId = "";
+  myObjects.clear();
+  myObjectsNames.clear();
+  myMeshes.clear();
+
+  for ( SALOME_ListIteratorOfListIO it( aList ); it.More(); it.Next() )
+  {
+    Handle(SALOME_InteractiveObject) IO = it.Value();
+    SMESH::SMESH_Mesh_var aMesh = SMESH::GetMeshByIO( IO );
+    if ( aMesh->_is_nil() || aMesh->NbFaces() == 0 )
+      return;
+
+    myActor = SMESH::FindActorByObject( aMesh );
+    if ( !myActor )
+      myActor = SMESH::FindActorByEntry( IO->getEntry() );
+
+    SMESH::SMESH_IDSource_var idSrc = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
+    if ( _PTR(SObject) obj = SMESH::FindSObject( idSrc ))
+    {
+      std::string name = obj->GetName();
+      if ( !name.empty() )
+      {
+        myObjects << idSrc;
+        myObjectsNames << name.c_str();
+        myMeshes << aMesh;
+      }
+    }
+  }
+
+  // MakeGroups is available if there are groups and "Copy"
+  int aNbGroups = 0;
+  for ( int i = 0; i < myMeshes.count(); i++ )
+    aNbGroups += myMeshes[i]->NbGroups();
+
+  if ( aNbGroups == 0 ) {
+    MakeGroupsCheck->setChecked(false);
+    MakeGroupsCheck->setEnabled(false);
+  }
+  else if ( ActionGroup->checkedId() != MOVE_ELEMS_BUTTON ) {
+    MakeGroupsCheck->setEnabled(true);
+  }
+
+  if (CheckBoxMesh->isChecked()) {
+    if (myMeshes.isEmpty())
+      return;
+    SMESH::GetNameOfSelectedIObjects( mySelectionMgr, aString );
+  }
+  else {
+    int aNbUnits = SMESH::GetNameOfSelectedElements(mySelector, aList.First(), aString);
+    myElementsId = aString;
+    if (aNbUnits < 1)
+      return;
+  }
+
+  myNbOkElements = true;
+  
+  LineEditElements->setText(aString);
+  LineEditElements->repaint();
+  LineEditElements->setEnabled(false); // to fully update lineedit IPAL 19809
+  LineEditElements->setEnabled(true);
+  setNewMeshName();
+
+  buttonOk->setEnabled(true);
+  buttonApply->setEnabled(true);
+
+  onDisplaySimulation(true);
+}
+
+//=================================================================================
+// function : DeactivateActiveDialog()
+// purpose  :
+//=================================================================================
+
+void SMESHGUI_OffsetDlg::DeactivateActiveDialog()
+{
+  if (ConstructorsBox->isEnabled())
+  {
+    ConstructorsBox->setEnabled(false);
+    GroupArguments->setEnabled(false);
+    GroupButtons->setEnabled(false);
+    mySMESHGUI->ResetState();
+    mySMESHGUI->SetActiveDialogBox(0);
+  }
+}
+
+//=================================================================================
+// function : ActivateThisDialog()
+// purpose  :
+//=================================================================================
+
+void SMESHGUI_OffsetDlg::ActivateThisDialog()
+{
+  /* Emit a signal to deactivate the active dialog */
+  mySMESHGUI->EmitSignalDeactivateDialog();
+  ConstructorsBox->setEnabled(true);
+  GroupArguments->setEnabled(true);
+  GroupButtons->setEnabled(true);
+
+  mySMESHGUI->SetActiveDialogBox((QDialog*)this);
+
+  if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
+    aViewWindow->SetSelectionMode( CellSelection );
+
+  SelectionIntoArgument();
+}
+
+//=================================================================================
+// function : enterEvent()
+// purpose  :
+//=================================================================================
+
+void SMESHGUI_OffsetDlg::enterEvent (QEvent*)
+{
+  if (!ConstructorsBox->isEnabled()) {
+    SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI );
+    if ( aViewWindow && !mySelector) {
+      mySelector = aViewWindow->GetSelector();
+    }
+    ActivateThisDialog();
+  }
+}
+
+//=======================================================================
+//function : onSelectMesh
+//purpose  :
+//=======================================================================
+
+void SMESHGUI_OffsetDlg::onSelectMesh (bool toSelectMesh)
+{
+  if (toSelectMesh)
+    TextLabelElements->setText(tr("SMESH_NAME"));
+  else
+    TextLabelElements->setText(tr("SMESH_ID_ELEMENTS"));
+  myFilterBtn->setEnabled(!toSelectMesh);
+
+  mySelectionMgr->clearFilters();
+  SMESH::SetPointRepresentation(false);
+
+  if (toSelectMesh)
+  {
+    if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
+      aViewWindow->SetSelectionMode( ActorSelection );
+    mySelectionMgr->installFilter( myMeshOrSubMeshOrGroupFilter );
+    LineEditElements->setReadOnly( true );
+    LineEditElements->setValidator( 0 );
+  }
+  else
+  {
+    if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
+      aViewWindow->SetSelectionMode( FaceSelection );
+    LineEditElements->setReadOnly( false );
+    LineEditElements->setValidator( myIdValidator );
+    onTextChange(LineEditElements->text());
+    hidePreview();
+  }
+
+  SelectionIntoArgument();
+}
+
+//=======================================================================
+//function : onActionClicked
+//purpose  : slot called when an action type changed
+//=======================================================================
+
+void SMESHGUI_OffsetDlg::onActionClicked(int button)
+{
+  int aNbGroups = 0;
+  for ( int i = 0; i < myMeshes.count(); i++ )
+    aNbGroups += myMeshes[i]->NbGroups();
+
+  switch ( button ) {
+  case MOVE_ELEMS_BUTTON:
+    MakeGroupsCheck->setEnabled(false);
+    LineEditNewMesh->setEnabled(false);
+    break;
+  case COPY_ELEMS_BUTTON:
+    LineEditNewMesh->setEnabled(false);
+    MakeGroupsCheck->setText( tr("SMESH_MAKE_GROUPS"));
+    MakeGroupsCheck->setEnabled( myMeshes.isEmpty() || aNbGroups > 0 );
+    break;
+  case MAKE_MESH_BUTTON:
+    LineEditNewMesh->setEnabled(true);
+    MakeGroupsCheck->setText( tr("SMESH_COPY_GROUPS"));
+    MakeGroupsCheck->setEnabled( myMeshes.isEmpty() || aNbGroups > 0 );
+    break;
+  }
+  setNewMeshName();
+  //toDisplaySimulation();
+}
+
+//=======================================================================
+//function : setNewMeshName
+//purpose  : update contents of LineEditNewMesh
+//=======================================================================
+
+void SMESHGUI_OffsetDlg::setNewMeshName()
+{
+  LineEditNewMesh->setText("");
+  if ( LineEditNewMesh->isEnabled() && !myMeshes.isEmpty() ) {
+    QString name;
+    if ( CheckBoxMesh->isChecked() ) {
+      name = myObjects.count() > 1 ? "*" : LineEditElements->text();
+    }
+    else {
+      _PTR(SObject) meshSO = SMESH::FindSObject( myMeshes[0] );
+      name = meshSO->GetName().c_str();
+    }
+    if ( !name.isEmpty() )
+      LineEditNewMesh->setText( SMESH::UniqueMeshName( name, "Offset"));
+  }
+}
+
+//=================================================================================
+// function : keyPressEvent()
+// purpose  :
+//=================================================================================
+
+void SMESHGUI_OffsetDlg::keyPressEvent( QKeyEvent* e )
+{
+  QDialog::keyPressEvent( e );
+  if ( e->isAccepted() )
+    return;
+
+  if ( e->key() == Qt::Key_F1 ) {
+    e->accept();
+    ClickOnHelp();
+  }
+}
+
+//=================================================================================
+// function : setFilters()
+// purpose  : SLOT. Called when "Filter" button pressed.
+//=================================================================================
+
+void SMESHGUI_OffsetDlg::setFilters()
+{
+  if ( myMeshes.isEmpty() ) {
+    SUIT_MessageBox::critical(this, tr("SMESH_ERROR"), tr("NO_MESH_SELECTED"));
+    return;
+  }
+  if ( !myFilterDlg ) {
+    myFilterDlg = new SMESHGUI_FilterDlg( mySMESHGUI, SMESH::ALL );
+    connect(myFilterDlg, SIGNAL(Accepted()), SLOT(onFilterAccepted()));
+  }
+
+  myFilterDlg->Init( SMESH::FACE );
+  myFilterDlg->SetSelection();
+  myFilterDlg->SetMesh( myMeshes[0] );
+  myFilterDlg->SetSourceWg( LineEditElements );
+
+  myFilterDlg->show();
+}
+
+//=======================================================================
+// name    : onFilterAccepted()
+// Purpose : SLOT. Called when Filter dlg closed with OK button.
+//           Activate [Apply] if no Actor is available
+//=======================================================================
+
+void SMESHGUI_OffsetDlg::onFilterAccepted()
+{
+  if ( myMeshes.length() > 0 && !buttonOk->isEnabled() )
+  {
+    myElementsId = LineEditElements->text();
+    QStringList aListElementsId = myElementsId.split(" ", QString::SkipEmptyParts);
+    myNbOkElements = aListElementsId.count();
+    buttonOk->setEnabled   ( myNbOkElements );
+    buttonApply->setEnabled( myNbOkElements );
+  }
+}
+
+//=================================================================================
+// function : isValid
+// purpose  :
+//=================================================================================
+
+bool SMESHGUI_OffsetDlg::isValid()
+{
+  return true;
+}
+
+//=================================================================================
+// function : onDisplaySimulation
+// purpose  : Show/Hide preview
+//=================================================================================
+void SMESHGUI_OffsetDlg::onDisplaySimulation( bool toDisplayPreview )
+{
+  SUIT_OverrideCursor aWaitCursor;
+
+  if (myPreviewCheckBox->isChecked() && toDisplayPreview)
+  {
+    if ( myNbOkElements && isValid() )
+    {
+      double offsetValue = SpinBox->value();
+
+      SMESH::ListOfGroups_var groups;
+      SMESH::SMESH_Mesh_var mesh;
+
+      try
+      {
+        QList<SMESH::MeshPreviewStruct_var> aMeshPreviewStruct;
+
+        if ( CheckBoxMesh->isChecked())
+          for ( int i = 0; i < myObjects.count(); i++ )
+          {
+            SMESH::SMESH_MeshEditor_var aMeshEditor = myMeshes[i]->GetMeshEditPreviewer();
+            mesh = aMeshEditor->Offset( myObjects[i], offsetValue, false, "", groups.out() );
+            aMeshPreviewStruct << aMeshEditor->GetPreviewData();
+          }
+        else
+        {
+          SMESH::long_array_var anElementsId = new SMESH::long_array;
+          QStringList aListElementsId = myElementsId.split(" ", QString::SkipEmptyParts);
+          anElementsId->length(aListElementsId.count());
+          for (int i = 0; i < aListElementsId.count(); i++)
+            anElementsId[i] = aListElementsId[i].toInt();
+
+          SMESH::SMESH_MeshEditor_var aMeshEditor = myMeshes[0]->GetMeshEditPreviewer();
+          SMESH::IDSource_wrap src = aMeshEditor->MakeIDSource(anElementsId, SMESH::FACE);
+          mesh = aMeshEditor->Offset( src, offsetValue, false, "", groups.out() );
+          aMeshPreviewStruct << aMeshEditor->GetPreviewData();
+        }
+        setSimulationPreview(aMeshPreviewStruct);
+
+      } catch (...) {
+        hidePreview();
+      }
+    } else {
+      hidePreview();
+    }
+  } else {
+    hidePreview();
+  }
+}
diff --git a/src/SMESHGUI/SMESHGUI_OffsetDlg.h b/src/SMESHGUI/SMESHGUI_OffsetDlg.h
new file mode 100644 (file)
index 0000000..e8f4b9c
--- /dev/null
@@ -0,0 +1,134 @@
+// Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+// SMESH SMESHGUI : GUI for SMESH component
+// File   : SMESHGUI_OffsetDlg.h
+//
+#ifndef SMESHGUI_OffsetDLG_H
+#define SMESHGUI_OffsetDLG_H
+
+// SMESH includes
+#include "SMESH_SMESHGUI.hxx"
+#include "SMESHGUI_PreviewDlg.h"
+
+// IDL includes
+#include <SALOMEconfig.h>
+#include CORBA_SERVER_HEADER(SMESH_Mesh)
+
+class QButtonGroup;
+class QGroupBox;
+class QLabel;
+class QLineEdit;
+class QPushButton;
+class QRadioButton;
+class QCheckBox;
+class SMESHGUI;
+class SMESHGUI_IdValidator;
+class SMESHGUI_SpinBox;
+class SMESHGUI_FilterDlg;
+class SMESH_Actor;
+class SVTK_Selector;
+class LightApp_SelectionMgr;
+class SMESH_LogicalFilter;
+
+//=================================================================================
+// class    : SMESHGUI_OffsetDlg
+// purpose  :
+//=================================================================================
+class SMESHGUI_EXPORT SMESHGUI_OffsetDlg : public SMESHGUI_MultiPreviewDlg
+{
+  Q_OBJECT
+
+ public:
+  SMESHGUI_OffsetDlg( SMESHGUI* );
+  ~SMESHGUI_OffsetDlg();
+
+ private:
+  void                   Init( bool = true );
+  void                   enterEvent( QEvent* );           /* mouse enter the QWidget */
+  void                   keyPressEvent( QKeyEvent* );
+  int                    GetConstructorId();
+  void                   setNewMeshName();
+
+  bool                   isValid();
+  void                   getOffset( SMESH::PointStruct& thePoint,
+                                    SMESH::double_array_var& theOffsetFact);
+
+  SMESHGUI_IdValidator*  myIdValidator;
+  LightApp_SelectionMgr* mySelectionMgr;          /* User shape selection */
+  QString                myElementsId;
+  int                    myNbOkElements;          /* to check when elements are defined */
+
+  SVTK_Selector*         mySelector;
+
+  QWidget*               myEditCurrentArgument;
+
+  bool                   myBusy;
+  SMESH_Actor*           myActor;
+  SMESH_LogicalFilter*   myMeshOrSubMeshOrGroupFilter;
+
+  QList<SMESH::SMESH_IDSource_var> myObjects;
+  QList<QString>                   myObjectsNames;
+  QList<SMESH::SMESH_Mesh_var>     myMeshes;
+
+
+  QGroupBox*             ConstructorsBox;
+  QGroupBox*             GroupButtons;
+  QPushButton*           buttonOk;
+  QPushButton*           buttonCancel;
+  QPushButton*           buttonApply;
+  QPushButton*           buttonHelp;
+  QGroupBox*             GroupArguments;
+  QLabel*                TextLabelElements;
+  //QPushButton*           SelectElementsButton;
+  QLineEdit*             LineEditElements;
+  QCheckBox*             CheckBoxMesh;
+  SMESHGUI_SpinBox*      SpinBox;
+  QGroupBox*             ActionBox;
+  QButtonGroup*          ActionGroup;
+  QCheckBox*             MakeGroupsCheck;
+  QLineEdit*             LineEditNewMesh;
+
+  QString                myHelpFileName;
+
+  QPushButton*           myFilterBtn;
+  SMESHGUI_FilterDlg*    myFilterDlg;
+
+
+protected slots:
+  virtual void           onDisplaySimulation( bool );
+  virtual void           reject();
+  void                   onFilterAccepted();
+   
+private slots:
+  void                   ClickOnOk();
+  bool                   ClickOnApply();
+  void                   ClickOnHelp();
+  void                   SelectionIntoArgument();
+  void                   DeactivateActiveDialog();
+  void                   ActivateThisDialog();
+  void                   onTextChange( const QString& );
+  void                   onSelectMesh( bool );
+  void                   onActionClicked( int );
+  void                   onOpenView();
+  void                   onCloseView();
+  void                   setFilters();
+};
+
+#endif // SMESHGUI_OffsetDLG_H
index b32aff54bc0320ba50c5d8c94343cc53e38a824a..9f89cf77cc3bf475fcf82f5d8522eab3c0ee69da 100644 (file)
@@ -166,6 +166,7 @@ namespace SMESHOp {
     OpMergeNodes             = 4405,   // MENU MODIFICATION - TRANSFORMATION - MERGE NODES
     OpMergeElements          = 4406,   // MENU MODIFICATION - TRANSFORMATION - MERGE ELEMENTS
     OpDuplicateNodes         = 4407,   // MENU MODIFICATION - TRANSFORMATION - DUPLICATE NODES OR/AND ELEMENTS
+    OpOffset                 = 4408,   // MENU MODIFICATION - TRANSFORMATION - OFFSET
     OpMoveNode               = 4500,   // MENU MODIFICATION - MOVE NODE
     OpDiagonalInversion      = 4501,   // MENU MODIFICATION - DIAGONAL INVERSION
     OpUnionOfTwoTriangle     = 4502,   // MENU MODIFICATION - UNION OF TWO TRIANGLE
index 067eb5f49e734f6c2d48e900f21e4fcb784dbbd3..1e458d8caed1e1101763d1838767d25c7bdcddee 100644 (file)
@@ -345,7 +345,7 @@ void SMESHGUI_RemoveElementsDlg::onTextChange(const QString& theNewText)
 
   myNbOkElements = 0;
 
-  // hilight entered elements
+  // highlight entered elements
   if(myActor){
     if(SMDS_Mesh* aMesh = myActor->GetObject()->GetMesh()){
       Handle(SALOME_InteractiveObject) anIO = myActor->getIO();
index 805b37c85a1eccabe0371eb783e6abea10295d11..1eb516aa0f28521c98dd4562249285a297dd0710 100644 (file)
@@ -351,7 +351,7 @@ void SMESHGUI_RemoveNodesDlg::onTextChange(const QString& theNewText)
 
   myNbOkNodes = 0;
 
-  // hilight entered nodes
+  // highlight entered nodes
   if(myActor){
     if(SMDS_Mesh* aMesh = myActor->GetObject()->GetMesh()){
       Handle(SALOME_InteractiveObject) anIO = myActor->getIO();
index 48e7204cbac16bc01bc660abbe394a2435bd8198..abeb2ccaa23f14bc6917f62bcb222770b1728e12 100644 (file)
@@ -635,7 +635,7 @@ void SMESHGUI_RotationDlg::onTextChange (const QString& theNewText)
   buttonOk->setEnabled(false);
   buttonApply->setEnabled(false);
 
-  // hilight entered elements
+  // highlight entered elements
   SMDS_Mesh* aMesh = 0;
   if (myActor)
     aMesh = myActor->GetObject()->GetMesh();
index 85e9dd46c84125ccf57c95c3cb9ebdf19c6ce611..034a7126088b727bcbdf06c1bc4975e2dc14133b 100644 (file)
@@ -674,7 +674,7 @@ void SMESHGUI_ScaleDlg::onTextChange (const QString& theNewText)
   buttonOk->setEnabled(false);
   buttonApply->setEnabled(false);
 
-  // hilight entered elements
+  // highlight entered elements
   SMDS_Mesh* aMesh = 0;
   if (myActor)
     aMesh = myActor->GetObject()->GetMesh();
index ca551105a5db5d68f9f9ababf00ecf2a9c66abb0..2d69e85974dfa74cb1f82f4c27f535ddfe94e100 100644 (file)
@@ -250,11 +250,11 @@ void SMESHGUI_SelectionOp::setSelectionMode( const Selection_Mode mode )
 // Purpose : Highlight object in 3d viewer
 //=======================================================================
 void SMESHGUI_SelectionOp::highlight( const Handle( SALOME_InteractiveObject )& obj,
-                                      const bool hilight, const bool immediately )
+                                      const bool highlight, const bool immediately )
 {
   SVTK_ViewWindow* wnd = viewWindow();
   if( wnd )
-    wnd->highlight( obj, hilight, immediately );
+    wnd->highlight( obj, highlight, immediately );
 }
 
 //=======================================================================
index b60a88c07502dfec364f311296777b307cbe0ff0..69a5c016c0a5f8bcf46468dcf9b8e6ac4de2e643 100644 (file)
@@ -104,7 +104,7 @@ protected:
   //! Set selection mode in VTK viewer
   void                          setSelectionMode( const Selection_Mode );
 
-  //! Hilight object in VTK viewer
+  //! Highlight object in VTK viewer
   void                          highlight( const Handle( SALOME_InteractiveObject )&,
                                            const bool, const bool = true );
                                
index 22253c4d69caec10655af62a565c787b09d98365..d2562b348d09fceb3512dddad26af8cf3917ecb9 100644 (file)
@@ -1532,7 +1532,7 @@ void SMESHGUI_SewingDlg::onTextChange (const QString& theNewText)
   else if (send == LineEdit6)
     myOk6 = false;
 
-  // hilight entered elements/nodes
+  // highlight entered elements/nodes
   SMDS_Mesh* aMesh = 0;
 
   if (myActor)
index 08424f6d49a6d91fe65eae2ac847c5092df9ecf9..69256692c9c4e99f91c7ffa69a8432088e98f9e7 100755 (executable)
@@ -339,7 +339,7 @@ void SMESHGUI_SingleEditDlg::onTextChange (const QString& theNewText)
   myOkBtn->setEnabled(false);
   myApplyBtn->setEnabled(false);
 
-  // hilight entered edge
+  // highlight entered edge
   if(myActor){
     if(SMDS_Mesh* aMesh = myActor->GetObject()->GetMesh()){
       Handle(SALOME_InteractiveObject) anIO = myActor->getIO();
index caa4c51194fd1f1de33e69da4e28144d19cace2c..51335cb9f0b8294ebeef294fddbede7a1fda2f3c 100644 (file)
@@ -518,7 +518,7 @@ void SMESHGUI_SmoothingDlg::onTextChange (const QString& theNewText)
   buttonOk->setEnabled(false);
   buttonApply->setEnabled(false);
 
-  // hilight entered elements/nodes
+  // highlight entered elements/nodes
   SMDS_Mesh* aMesh = myActor ? myActor->GetObject()->GetMesh() : 0;
   QStringList aListId = theNewText.split(" ", QString::SkipEmptyParts);
 
index e6886021ad769e40218d413116f1c0ffd04f4254..649565996a63e941ed6bbbfa3b3f17e2027759e9 100644 (file)
@@ -693,7 +693,7 @@ void SMESHGUI_SymmetryDlg::onTextChange (const QString& theNewText)
   buttonOk->setEnabled(false);
   buttonApply->setEnabled(false);
 
-  // hilight entered elements
+  // highlight entered elements
   SMDS_Mesh* aMesh = 0;
   if (myActor)
     aMesh = myActor->GetObject()->GetMesh();
index 75e5635bfa59a153b34e9938ac52e9e4a1259423..cf878e9eeb19813682d485b382ee17875e342ce4 100644 (file)
@@ -705,7 +705,7 @@ void SMESHGUI_TranslationDlg::onTextChange (const QString& theNewText)
   buttonOk->setEnabled(false);
   buttonApply->setEnabled(false);
 
-  // hilight entered elements
+  // highlight entered elements
   SMDS_Mesh* aMesh = 0;
   if (myActor)
     aMesh = myActor->GetObject()->GetMesh();
index 509dd4e303fb16f89f7b93e9c321183d7c3dec52..99e6d218320c05147550006750e8fd7867294aa5 100644 (file)
             <source>ICON_DLG_MESH_SCALE</source>
             <translation>scale.png</translation>
         </message>
+        <message>
+            <source>ICON_DLG_MESH_OFFSET</source>
+            <translation>mesh_offset.png</translation>
+        </message>
         <message>
             <source>ICON_DLG_SCALE_ALONG_AXES</source>
             <translation>scale_along_axes.png</translation>
index afe29f3affb55a40f24a8c4bf54656649faee7f4..0bdc83bc75560b1e3e7923a6b7b69b8971d00228 100644 (file)
         <source>MEN_SCALE</source>
         <translation>Scale Transform</translation>
     </message>
+    <message>
+        <source>MEN_OFFSET</source>
+        <translation>Offset</translation>
+    </message>
     <message>
         <source>MEN_DUPLICATE_NODES</source>
         <translation>Duplicate Nodes or/and Elements</translation>
@@ -1898,7 +1902,7 @@ add the exported data to its contents?</translation>
         <translation>Hexahedrons</translation>
     </message>
     <message>
-        <source>SMESH_HILIGHT_COLOR</source>
+        <source>SMESH_HIGHLIGHT_COLOR</source>
         <translation>Highlight Color</translation>
     </message>
     <message>
@@ -3514,6 +3518,10 @@ Use Display Entity menu command to show them.
         <source>STB_SCALE</source>
         <translation>Scale Transform</translation>
     </message>
+    <message>
+        <source>STB_OFFSET</source>
+        <translation>Offset</translation>
+    </message>
     <message>
         <source>STB_DUPLICATE_NODES</source>
         <translation>Duplicate Nodes or/and Elements</translation>
@@ -4190,6 +4198,10 @@ Use Display Entity menu command to show them.
         <source>TOP_SCALE</source>
         <translation>Scale Transform</translation>
     </message>
+    <message>
+        <source>TOP_OFFSET</source>
+        <translation>Offset</translation>
+    </message>
     <message>
         <source>TOP_DUPLICATE_NODES</source>
         <translation>Duplicate Nodes or/and Elements</translation>
@@ -4465,6 +4477,21 @@ It can&apos;t be deleted </translation>
         <translation>Export Fields</translation>
     </message>
 </context>
+<context>
+    <name>SMESHGUI_OffsetDlg</name>
+    <message>
+        <source>SMESH_OFFSET_TITLE</source>
+        <translation>Offset</translation>
+    </message>
+    <message>
+        <source>SMESH_OFFSET</source>
+        <translation>Offset</translation>
+    </message>
+    <message>
+        <source>OFFSET_VALUE</source>
+        <translation>Offset Value</translation>
+    </message>
+</context>
 <context>
     <name>SMESHGUI_AddMeshElementDlg</name>
     <message>
index 506912cfea99033ad886eac27861dd85d3c3fc44..9e4d3d8f63afbfac8d4005457745c2740a7973fb 100755 (executable)
@@ -1882,7 +1882,7 @@ les données exportées ?</translation>
         <translation>Hexaèdres</translation>
     </message>
     <message>
-        <source>SMESH_HILIGHT_COLOR</source>
+        <source>SMESH_HIGHLIGHT_COLOR</source>
         <translation>Couleur de sélection</translation>
     </message>
     <message>
index d18673c16e21e2e48cc904f721b3e72710fbe496..f8d821db320682e1c8bf20e66bc817306b62ff40 100644 (file)
       <translation>六面体</translation>
     </message>
     <message>
-      <source>SMESH_HILIGHT_COLOR</source>
+      <source>SMESH_HIGHLIGHT_COLOR</source>
       <translation>選択色</translation>
     </message>
     <message>
index 032194e633cd3c318c39eb9acda42ef2b139b41f..2d36c3c824eca3bcd19453a9ae094c6370307a51 100644 (file)
@@ -67,7 +67,7 @@ SET(SMESHUtils_HEADERS
   SMESH_MeshAlgos.hxx
   SMESH_MAT2d.hxx
   SMESH_ControlPnt.hxx
-)
+  )
 
 # --- sources ---
 
@@ -84,7 +84,9 @@ SET(SMESHUtils_SOURCES
   SMESH_FreeBorders.cxx
   SMESH_ControlPnt.cxx
   SMESH_FillHole.cxx
-)
+  SMESH_Triangulate.cxx
+  SMESH_Offset.cxx
+  )
 
 # --- rules ---
 
index fbaac9eaee7b76bda3479c100fca9c8fd4d52e83..257ef5e75bb9847fe6b5c6486d05f1eec282321d 100644 (file)
@@ -56,7 +56,7 @@ namespace SMESH_MAT2d
   //-------------------------------------------------------------------------------------
   // type of Branch end point
   enum BranchEndType { BE_UNDEF,
-                       BE_ON_VERTEX, // branch ends at a convex VRTEX
+                       BE_ON_VERTEX, // branch ends at a convex VERTEX
                        BE_BRANCH_POINT, // branch meats 2 or more other branches
                        BE_END // branch end equidistant from several adjacent segments
   };
index eea7912c7e3303c67e6f4eaf77742fe248f81a39..9f6b3391cdaaf1a22d6c140b6e7f2af84a22d808 100644 (file)
@@ -48,7 +48,7 @@
 #include <limits>
 #include <numeric>
 
-using namespace std;
+#include <boost/container/flat_set.hpp>
 
 //=======================================================================
 /*!
@@ -110,21 +110,21 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
    */
   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
   {
-    map<double, const SMDS_MeshNode*> dist2Nodes;
+    std::map<double, const SMDS_MeshNode*> dist2Nodes;
     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
     if ( !dist2Nodes.empty() )
       return dist2Nodes.begin()->second;
-    list<const SMDS_MeshNode*> nodes;
+    std::list<const SMDS_MeshNode*> nodes;
     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
 
     double minSqDist = DBL_MAX;
     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
     {
       // sort leafs by their distance from thePnt
-      typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
+      typedef std::map< double, SMESH_OctreeNode* > TDistTreeMap;
       TDistTreeMap treeMap;
-      list< SMESH_OctreeNode* > treeList;
-      list< SMESH_OctreeNode* >::iterator trIt;
+      std::list< SMESH_OctreeNode* > treeList;
+      std::list< SMESH_OctreeNode* >::iterator trIt;
       treeList.push_back( myOctreeNode );
 
       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
@@ -143,9 +143,10 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
         {
           const Bnd_B3d& box = *tree->getBox();
           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
-          pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
+          std::pair<TDistTreeMap::iterator,bool> it_in =
+            treeMap.insert( std::make_pair( sqDist, tree ));
           if ( !it_in.second ) // not unique distance to box center
-            treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
+            treeMap.insert( it_in.first, std::make_pair( sqDist + 1e-13*treeMap.size(), tree ));
         }
       }
       // find distance after which there is no sense to check tree's
@@ -168,7 +169,7 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
     // find closest among nodes
     minSqDist = DBL_MAX;
     const SMDS_MeshNode* closestNode = 0;
-    list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
+    std::list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
     for ( ; nIt != nodes.end(); ++nIt ) {
       double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
       if ( minSqDist > sqDist ) {
@@ -226,15 +227,16 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
   {
   public:
 
+    typedef boost::container::flat_set< const SMDS_MeshElement* > TElemSeq;
+
     ElementBndBoxTree(const SMDS_Mesh&     mesh,
                       SMDSAbs_ElementType  elemType,
                       SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(),
                       double               tolerance = NodeRadius );
-    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);
+    void getElementsNearPoint( const gp_Pnt& point, TElemSeq& foundElems );
+    void getElementsNearLine ( const gp_Ax1& line,  TElemSeq& foundElems );
+    void getElementsInBox    ( const Bnd_B3d& box,  TElemSeq& foundElems );
+    void getElementsInSphere ( const gp_XYZ& center, const double radius, TElemSeq& foundElems );
     ElementBndBoxTree* getLeafAtPoint( const gp_XYZ& point );
 
   protected:
@@ -247,10 +249,9 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
     struct ElementBox : public Bnd_B3d
     {
       const SMDS_MeshElement* _element;
-      bool                    _isMarked;
       void init(const SMDS_MeshElement* elem, double tolerance);
     };
-    vector< ElementBox* > _elements;
+    std::vector< ElementBox* > _elements;
 
     typedef ObjectPool< ElementBox > TElementBoxPool;
 
@@ -258,7 +259,6 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
     struct LimitAndPool : public SMESH_TreeLimit
     {
       TElementBoxPool            _elBoPool;
-      std::vector< ElementBox* > _markedElems;
       LimitAndPool():SMESH_TreeLimit( MaxLevel, /*minSize=*/0. ), _elBoPool(1024) {}
     };
     LimitAndPool* getLimitAndPool() const
@@ -345,37 +345,21 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
    */
   //================================================================================
 
-  void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&                    point,
-                                                vector<const SMDS_MeshElement*>& foundElems)
+  void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point, TElemSeq& 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() ) &&
-             !_elements[i]->_isMarked )
-        {
-          foundElems.push_back( _elements[i]->_element );
-          _elements[i]->_isMarked = true;
-          pool->_markedElems.push_back( _elements[i] );
-        }
+        if ( !_elements[i]->IsOut( point.XYZ() ))
+          foundElems.insert( _elements[i]->_element );
     }
     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();
-      }
     }
   }
 
@@ -385,37 +369,21 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
    */
   //================================================================================
 
-  void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&                    line,
-                                               vector<const SMDS_MeshElement*>& foundElems)
+  void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line, TElemSeq& 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 ) &&
-             !_elements[i]->_isMarked )
-        {
-          foundElems.push_back( _elements[i]->_element );
-          _elements[i]->_isMarked = true;
-          pool->_markedElems.push_back( _elements[i] );
-        }
+        if ( !_elements[i]->IsOut( line ) )
+          foundElems.insert( _elements[i]->_element );
     }
     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();
-      }
     }
   }
 
@@ -425,38 +393,47 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
    */
   //================================================================================
 
-  void ElementBndBoxTree::getElementsInSphere ( const gp_XYZ&                    center,
-                                                const double                     radius,
-                                                vector<const SMDS_MeshElement*>& foundElems)
+  void ElementBndBoxTree::getElementsInSphere ( const gp_XYZ& center,
+                                                const double  radius,
+                                                TElemSeq&     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 ) &&
-             !_elements[i]->_isMarked )
-        {
-          foundElems.push_back( _elements[i]->_element );
-          _elements[i]->_isMarked = true;
-          pool->_markedElems.push_back( _elements[i] );
-        }
+        if ( !_elements[i]->IsOut( center, radius ))
+          foundElems.insert( _elements[i]->_element );
     }
     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 elements from leaves intersecting the box
+   */
+  //================================================================================
+
+  void ElementBndBoxTree::getElementsInBox( const Bnd_B3d& box,  TElemSeq& foundElems )
+  {
+    if ( getBox()->IsOut( box ))
+      return;
+
+    if ( isLeaf() )
+    {
+      for ( size_t i = 0; i < _elements.size(); ++i )
+        if ( !_elements[i]->IsOut( box ))
+          foundElems.insert( _elements[i]->_element );
+    }
+    else
+    {
+      for (int i = 0; i < 8; i++)
+        ((ElementBndBoxTree*) myChildren[i])->getElementsInBox( box, foundElems );
     }
   }
 
@@ -493,7 +470,6 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
   void ElementBndBoxTree::ElementBox::init(const SMDS_MeshElement* elem, double tolerance)
   {
     _element  = elem;
-    _isMarked = false;
     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
     while ( nIt->more() )
       Add( SMESH_NodeXYZ( nIt->next() ));
@@ -515,15 +491,15 @@ SMESH_ElementSearcher::~SMESH_ElementSearcher()
 
 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
 {
-  SMDS_Mesh*                   _mesh;
-  SMDS_ElemIteratorPtr         _meshPartIt;
-  ElementBndBoxTree*           _ebbTree      [SMDSAbs_NbElementTypes];
-  int                          _ebbTreeHeight[SMDSAbs_NbElementTypes];
-  SMESH_NodeSearcherImpl*      _nodeSearcher;
-  SMDSAbs_ElementType          _elementType;
-  double                       _tolerance;
-  bool                         _outerFacesFound;
-  set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
+  SMDS_Mesh*                        _mesh;
+  SMDS_ElemIteratorPtr              _meshPartIt;
+  ElementBndBoxTree*                _ebbTree      [SMDSAbs_NbElementTypes];
+  int                               _ebbTreeHeight[SMDSAbs_NbElementTypes];
+  SMESH_NodeSearcherImpl*           _nodeSearcher;
+  SMDSAbs_ElementType               _elementType;
+  double                            _tolerance;
+  bool                              _outerFacesFound;
+  std::set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
 
   SMESH_ElementSearcherImpl( SMDS_Mesh&           mesh,
                              double               tol=-1,
@@ -545,20 +521,23 @@ struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
     }
     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
   }
-  virtual int FindElementsByPoint(const gp_Pnt&                      point,
-                                  SMDSAbs_ElementType                type,
-                                  vector< const SMDS_MeshElement* >& foundElements);
+  virtual int FindElementsByPoint(const gp_Pnt&                           point,
+                                  SMDSAbs_ElementType                     type,
+                                  std::vector< const SMDS_MeshElement* >& foundElements);
   virtual TopAbs_State GetPointState(const gp_Pnt& point);
   virtual const SMDS_MeshElement* FindClosestTo( const gp_Pnt&       point,
                                                  SMDSAbs_ElementType type );
 
-  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 void GetElementsNearLine( const gp_Ax1&                           line,
+                                    SMDSAbs_ElementType                     type,
+                                    std::vector< const SMDS_MeshElement* >& foundElems);
+  virtual void GetElementsInSphere( const gp_XYZ&                           center,
+                                    const double                            radius,
+                                    SMDSAbs_ElementType                     type,
+                                    std::vector< const SMDS_MeshElement* >& foundElems);
+  virtual void GetElementsInBox( const Bnd_B3d&                          box,
+                                 SMDSAbs_ElementType                     type,
+                                 std::vector< const SMDS_MeshElement* >& foundElems);
   virtual gp_XYZ Project(const gp_Pnt&            point,
                          SMDSAbs_ElementType      type,
                          const SMDS_MeshElement** closestElem);
@@ -649,7 +628,7 @@ double SMESH_ElementSearcherImpl::getTolerance()
         while ( nodeIt->more() )
         {
           double dist = n1.Distance( static_cast<const SMDS_MeshNode*>( nodeIt->next() ));
-          elemSize = max( dist, elemSize );
+          elemSize = std::max( dist, elemSize );
         }
       }
       _tolerance = 1e-4 * elemSize;
@@ -707,10 +686,10 @@ void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerF
   // and BTW find out if there are internal faces at all.
 
   // checked links and links where outer boundary meets internal one
-  set< SMESH_TLink > visitedLinks, seamLinks;
+  std::set< SMESH_TLink > visitedLinks, seamLinks;
 
   // links to treat with already visited faces sharing them
-  list < TFaceLink > startLinks;
+  std::list < TFaceLink > startLinks;
 
   // load startLinks with the first outerFace
   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
@@ -752,8 +731,8 @@ void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerF
         // direction from the link inside outerFace
         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
         // sort all other faces by angle with the dirInOF
-        map< double, const SMDS_MeshElement* > angle2Face;
-        set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
+        std::map< double, const SMDS_MeshElement* > angle2Face;
+        std::set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
         for ( ; face != faces.end(); ++face )
         {
           if ( *face == outerFace ) continue;
@@ -762,7 +741,7 @@ void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerF
           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
           if ( angle < 0 ) angle += 2. * M_PI;
-          angle2Face.insert( make_pair( angle, *face ));
+          angle2Face.insert( std::make_pair( angle, *face ));
         }
         if ( !angle2Face.empty() )
           outerFace2 = angle2Face.begin()->second;
@@ -807,9 +786,9 @@ void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerF
 //=======================================================================
 
 int SMESH_ElementSearcherImpl::
-FindElementsByPoint(const gp_Pnt&                      point,
-                    SMDSAbs_ElementType                type,
-                    vector< const SMDS_MeshElement* >& foundElements)
+FindElementsByPoint(const gp_Pnt&                           point,
+                    SMDSAbs_ElementType                     type,
+                    std::vector< const SMDS_MeshElement* >& foundElements)
 {
   foundElements.clear();
   _elementType = type;
@@ -850,9 +829,9 @@ FindElementsByPoint(const gp_Pnt&                      point,
     {
       _ebbTree[_elementType] = new ElementBndBoxTree( *_mesh, type, _meshPartIt, tolerance );
     }
-    vector< const SMDS_MeshElement* > suspectElems;
+    ElementBndBoxTree::TElemSeq suspectElems;
     _ebbTree[ type ]->getElementsNearPoint( point, suspectElems );
-    vector< const SMDS_MeshElement* >::iterator elem = suspectElems.begin();
+    ElementBndBoxTree::TElemSeq::iterator elem = suspectElems.begin();
     for ( ; elem != suspectElems.end(); ++elem )
       if ( !SMESH_MeshAlgos::IsOut( *elem, point, tolerance ))
         foundElements.push_back( *elem );
@@ -883,7 +862,7 @@ SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt&       point,
     if ( !ebbTree )
       ebbTree = new ElementBndBoxTree( *_mesh, type, _meshPartIt );
 
-    vector<const SMDS_MeshElement*> suspectElems;
+    ElementBndBoxTree::TElemSeq suspectElems;
     ebbTree->getElementsNearPoint( point, suspectElems );
 
     if ( suspectElems.empty() && ebbTree->maxSize() > 0 )
@@ -902,20 +881,20 @@ SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt&       point,
       }
     }
     double minDist = std::numeric_limits<double>::max();
-    multimap< double, const SMDS_MeshElement* > dist2face;
-    vector<const SMDS_MeshElement*>::iterator elem = suspectElems.begin();
+    std::multimap< double, const SMDS_MeshElement* > dist2face;
+    ElementBndBoxTree::TElemSeq::iterator elem = suspectElems.begin();
     for ( ; elem != suspectElems.end(); ++elem )
     {
       double dist = SMESH_MeshAlgos::GetDistance( *elem, point );
       if ( dist < minDist + 1e-10)
       {
         minDist = dist;
-        dist2face.insert( dist2face.begin(), make_pair( dist, *elem ));
+        dist2face.insert( dist2face.begin(), std::make_pair( dist, *elem ));
       }
     }
     if ( !dist2face.empty() )
     {
-      multimap< double, const SMDS_MeshElement* >::iterator d2f = dist2face.begin();
+      std::multimap< double, const SMDS_MeshElement* >::iterator d2f = dist2face.begin();
       closestElem = d2f->second;
       // if there are several elements at the same distance, select one
       // with GC closest to the point
@@ -974,21 +953,21 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
 
   const int nbAxes = 3;
   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
-  map< double, TInters >   paramOnLine2TInters[ nbAxes ];
-  list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
-  multimap< int, int > nbInt2Axis; // to find the simplest case
+  std::map< double, TInters >   paramOnLine2TInters[ nbAxes ];
+  std::list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
+  std::multimap< int, int > nbInt2Axis; // to find the simplest case
   for ( int axis = 0; axis < nbAxes; ++axis )
   {
     gp_Ax1 lineAxis( point, axisDir[axis]);
     gp_Lin line    ( lineAxis );
 
-    vector<const SMDS_MeshElement*> suspectFaces; // faces possibly intersecting the line
+    ElementBndBoxTree::TElemSeq suspectFaces; // faces possibly intersecting the line
     ebbTree->getElementsNearLine( lineAxis, suspectFaces );
 
     // Intersect faces with the line
 
-    map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
-    vector<const SMDS_MeshElement*>::iterator face = suspectFaces.begin();
+    std::map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
+    ElementBndBoxTree::TElemSeq::iterator face = suspectFaces.begin();
     for ( ; face != suspectFaces.end(); ++face )
     {
       // get face plane
@@ -1009,7 +988,7 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
         double tol = 1e-4 * Sqrt( fNorm.Modulus() );
         gp_Pnt intersectionPoint = intersection.Point(1);
         if ( !SMESH_MeshAlgos::IsOut( *face, intersectionPoint, tol ))
-          u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
+          u2inters.insert( std::make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
       }
     }
     // Analyse intersections roughly
@@ -1033,7 +1012,7 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
       return TopAbs_IN;
 
-    nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
+    nbInt2Axis.insert( std::make_pair( std::min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
 
     if ( _outerFacesFound ) break; // pass to thorough analysis
 
@@ -1047,29 +1026,29 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
 
   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
   {
-    multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
+    std::multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
     {
       int axis = nb_axis->second;
-      map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
+      std::map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
 
       gp_Ax1 lineAxis( point, axisDir[axis]);
       gp_Lin line    ( lineAxis );
 
       // add tangent intersections to u2inters
       double param;
-      list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
+      std::list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
-          u2inters.insert(make_pair( param, *tgtInt ));
+          u2inters.insert( std::make_pair( param, *tgtInt ));
       tangentInters[ axis ].clear();
 
       // Count intersections before and after the point excluding touching ones.
       // If hasPositionInfo we count intersections of outer boundary only
 
       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
-      double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
-      map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
+      double f = std::numeric_limits<double>::max(), l = -std::numeric_limits<double>::max();
+      std::map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
       bool ok = ! u_int1->second._coincides;
       while ( ok && u_int1 != u2inters.end() )
       {
@@ -1118,8 +1097,8 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
           // decide if we skipped a touching intersection
           if ( nbSamePnt + nbTgt > 0 )
           {
-            double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
-            map< double, TInters >::iterator u_int = u_int1;
+            double minDot = std::numeric_limits<double>::max(), maxDot = -minDot;
+            std::map< double, TInters >::iterator u_int = u_int1;
             for ( ; u_int != u_int2; ++u_int )
             {
               if ( u_int->second._coincides ) continue;
@@ -1172,7 +1151,7 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
     if ( !hasPositionInfo )
     {
       // gather info on faces position - is face in the outer boundary or not
-      map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
+      std::map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
       findOuterBoundary( u2inters.begin()->second._face );
     }
 
@@ -1187,16 +1166,20 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
  */
 //=======================================================================
 
-void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
-                                                     SMDSAbs_ElementType                type,
-                                                     vector< const SMDS_MeshElement* >& foundElems)
+void SMESH_ElementSearcherImpl::
+GetElementsNearLine( const gp_Ax1&                           line,
+                     SMDSAbs_ElementType                     type,
+                     std::vector< const SMDS_MeshElement* >& foundElems)
 {
   _elementType = type;
   ElementBndBoxTree*& ebbTree = _ebbTree[ type ];
   if ( !ebbTree )
     ebbTree = new ElementBndBoxTree( *_mesh, _elementType, _meshPartIt );
 
-  ebbTree->getElementsNearLine( line, foundElems );
+  ElementBndBoxTree::TElemSeq elems;
+  ebbTree->getElementsNearLine( line, elems );
+
+  foundElems.insert( foundElems.end(), elems.begin(), elems.end() );
 }
 
 //=======================================================================
@@ -1205,17 +1188,43 @@ void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&
  */
 //=======================================================================
 
-void SMESH_ElementSearcherImpl::GetElementsInSphere( const gp_XYZ&                      center,
-                                                     const double                       radius,
-                                                     SMDSAbs_ElementType                type,
-                                                     vector< const SMDS_MeshElement* >& foundElems)
+void SMESH_ElementSearcherImpl::
+GetElementsInSphere( const gp_XYZ&                           center,
+                     const double                            radius,
+                     SMDSAbs_ElementType                     type,
+                     std::vector< const SMDS_MeshElement* >& foundElems)
 {
   _elementType = type;
   ElementBndBoxTree*& ebbTree = _ebbTree[ type ];
   if ( !ebbTree )
     ebbTree = new ElementBndBoxTree( *_mesh, _elementType, _meshPartIt );
 
-  ebbTree->getElementsInSphere( center, radius, foundElems );
+  ElementBndBoxTree::TElemSeq elems;
+  ebbTree->getElementsInSphere( center, radius, elems );
+
+  foundElems.insert( foundElems.end(), elems.begin(), elems.end() );
+}
+
+//=======================================================================
+/*
+ * Return elements whose bounding box intersects a given bounding box
+ */
+//=======================================================================
+
+void SMESH_ElementSearcherImpl::
+GetElementsInBox( const Bnd_B3d&                          box,
+                  SMDSAbs_ElementType                     type,
+                  std::vector< const SMDS_MeshElement* >& foundElems)
+{
+  _elementType = type;
+  ElementBndBoxTree*& ebbTree = _ebbTree[ type ];
+  if ( !ebbTree )
+    ebbTree = new ElementBndBoxTree( *_mesh, _elementType, _meshPartIt, getTolerance() );
+
+  ElementBndBoxTree::TElemSeq elems;
+  ebbTree->getElementsInBox( box, elems );
+
+  foundElems.insert( foundElems.end(), elems.begin(), elems.end() );
 }
 
 //=======================================================================
@@ -1242,7 +1251,7 @@ gp_XYZ SMESH_ElementSearcherImpl::Project(const gp_Pnt&            point,
   const Bnd_B3d* box = ebbLeaf->getBox();
   double radius = ( box->CornerMax() - box->CornerMin() ).Modulus();
 
-  vector< const SMDS_MeshElement* > elems;
+  ElementBndBoxTree::TElemSeq elems;
   ebbTree->getElementsInSphere( p, radius, elems );
   while ( elems.empty() )
   {
@@ -1252,13 +1261,14 @@ gp_XYZ SMESH_ElementSearcherImpl::Project(const gp_Pnt&            point,
   gp_XYZ proj, bestProj;
   const SMDS_MeshElement* elem = 0;
   double minDist = 2 * radius;
-  for ( size_t i = 0; i < elems.size(); ++i )
+  ElementBndBoxTree::TElemSeq::iterator e = elems.begin();
+  for ( ; e != elems.end(); ++e )
   {
-    double d = SMESH_MeshAlgos::GetDistance( elems[i], p, &proj );
+    double d = SMESH_MeshAlgos::GetDistance( *e, p, &proj );
     if ( d < minDist )
     {
       bestProj = proj;
-      elem = elems[i];
+      elem = *e;
       minDist = d;
     }
   }
@@ -1282,7 +1292,7 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin
 
   // get ordered nodes
 
-  vector< SMESH_TNodeXYZ > xyz; xyz.reserve( element->NbNodes()+1 );
+  std::vector< SMESH_TNodeXYZ > xyz; xyz.reserve( element->NbNodes()+1 );
 
   SMDS_ElemIteratorPtr nodeIt = element->interlacedNodesElemIterator();
   for ( int i = 0; nodeIt->more(); ++i )
@@ -1347,7 +1357,7 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin
     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);
+    std::vector<double> dist( nbNodes + 1);
     for ( i = 0; i < nbNodes; ++i )
     {
       gp_Vec n2p( xyz[i], point );
@@ -1550,7 +1560,7 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face,
 
   // coordinates of nodes (medium nodes, if any, ignored)
   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator;
-  vector<gp_XYZ> xyz( TXyzIterator( face->nodesIterator()), TXyzIterator() );
+  std::vector<gp_XYZ> xyz( TXyzIterator( face->nodesIterator()), TXyzIterator() );
   xyz.resize( face->NbCornerNodes()+1 );
 
   // transformation to get xyz[0] lies on the origin, xyz[1] lies on the Z axis,
@@ -1574,7 +1584,7 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face,
   trsf.SetTransformation( tgtCS );
 
   // move all the nodes to 2D
-  vector<gp_XY> xy( xyz.size() );
+  std::vector<gp_XY> xy( xyz.size() );
   for ( size_t i = 0;i < xyz.size()-1; ++i )
   {
     gp_XYZ p3d = xyz[i];
@@ -1590,7 +1600,7 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face,
   gp_XY point2D( tmpPnt.X(), tmpPnt.Z() );
 
   // loop on edges of the face to analyze point position ralative to the face
-  set< PointPos > pntPosSet;
+  std::set< PointPos > pntPosSet;
   for ( size_t i = 1; i < xy.size(); ++i )
   {
     PointPos pos = getPointPosition( point2D, &xy[0], i-1 );
@@ -1608,7 +1618,7 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face,
     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 ];
+    gp_XYZ proj = xyz[ pos._index ] + u * edge.XYZ();
     if ( closestPnt ) *closestPnt = proj;
     return point.Distance( proj );
   }
@@ -1655,7 +1665,7 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshEdge* seg,
 
   int i = 0, nbNodes = seg->NbNodes();
 
-  vector< SMESH_TNodeXYZ > xyz( nbNodes );
+  std::vector< SMESH_TNodeXYZ > xyz( nbNodes );
   SMDS_ElemIteratorPtr nodeIt = seg->interlacedNodesElemIterator();
   while ( nodeIt->more() )
     xyz[ i++ ].Set( nodeIt->next() );
@@ -1734,7 +1744,7 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshVolume* volume,
       break;
     }
     default:
-      vector<const SMDS_MeshNode *> nvec( nodes, nodes + vTool.NbFaceNodes( iF ));
+      std::vector<const SMDS_MeshNode *> nvec( nodes, nodes + vTool.NbFaceNodes( iF ));
       SMDS_PolygonalFaceOfNodes tmpFace( nvec );
       dist = GetDistance( &tmpFace, point, closestPnt );
     }
@@ -1839,7 +1849,7 @@ SMESH_MeshAlgos::FindFaceInSet(const SMDS_MeshNode*    n1,
         }
         else if ( n2 == prevN && n1 == n )
         {
-          face = elem; swap( i1, i2 );
+          face = elem; std::swap( i1, i2 );
         }
         prevN = n;
       }
@@ -1874,7 +1884,7 @@ bool SMESH_MeshAlgos::FaceNormal(const SMDS_MeshElement* F, gp_XYZ& normal, bool
     normal += ( p[2] - p[1] ) ^ ( p[0] - p[1] );
   }
   double size2 = normal.SquareModulus();
-  bool ok = ( size2 > numeric_limits<double>::min() * numeric_limits<double>::min());
+  bool ok = ( size2 > std::numeric_limits<double>::min() * std::numeric_limits<double>::min());
   if ( normalized && ok )
     normal /= sqrt( size2 );
 
@@ -1886,10 +1896,10 @@ bool SMESH_MeshAlgos::FaceNormal(const SMDS_MeshElement* F, gp_XYZ& normal, bool
 //purpose  : Return nodes common to two elements
 //=======================================================================
 
-vector< const SMDS_MeshNode*> SMESH_MeshAlgos::GetCommonNodes(const SMDS_MeshElement* e1,
-                                                              const SMDS_MeshElement* e2)
+std::vector< const SMDS_MeshNode*> SMESH_MeshAlgos::GetCommonNodes(const SMDS_MeshElement* e1,
+                                                                   const SMDS_MeshElement* e2)
 {
-  vector< const SMDS_MeshNode*> common;
+  std::vector< const SMDS_MeshNode*> common;
   for ( int i = 0 ; i < e1->NbNodes(); ++i )
     if ( e2->GetNodeIndex( e1->GetNode( i )) >= 0 )
       common.push_back( e1->GetNode( i ));
index 66b3aa45c1243a30deb6e2795b9f80899514fc1e..624cf1d9ee9a74a5ef2ddfd418ba1ad38cb7ca4c 100644 (file)
@@ -24,7 +24,7 @@
 // Author    : Edward AGAPOV (eap)
 
 // This file holds some low level algorithms extracted from SMESH_MeshEditor
-// to make them accessible from Controls package
+// to make them accessible from Controls package, and more
 
 
 #ifndef __SMESH_MeshAlgos_HXX__
@@ -41,6 +41,7 @@
 
 class gp_Pnt;
 class gp_Ax1;
+class Bnd_B3d;
 class SMDS_MeshNode;
 class SMDS_MeshElement;
 class SMDS_Mesh;
@@ -96,6 +97,12 @@ struct SMESHUtils_EXPORT SMESH_ElementSearcher
                                     const double                            radius,
                                     SMDSAbs_ElementType                     type,
                                     std::vector< const SMDS_MeshElement* >& foundElems) = 0;
+  /*!
+   * \brief Return elements whose bounding box intersects a given bounding box
+   */
+  virtual void GetElementsInBox( const Bnd_B3d&                          box,
+                                 SMDSAbs_ElementType                     type,
+                                 std::vector< const SMDS_MeshElement* >& foundElems) = 0;
   /*!
    * \brief Find out if the given point is out of closed 2D mesh.
    */
@@ -114,6 +121,27 @@ struct SMESHUtils_EXPORT SMESH_ElementSearcher
 
 namespace SMESH_MeshAlgos
 {
+  /*!
+   * \brief Return SMESH_NodeSearcher. The caller is responsible for deleting it
+   */
+  SMESHUtils_EXPORT
+  SMESH_NodeSearcher* GetNodeSearcher( SMDS_Mesh& mesh );
+
+  SMESHUtils_EXPORT
+  SMESH_NodeSearcher* GetNodeSearcher( SMDS_ElemIteratorPtr elemIt );
+
+  /*!
+   * \brief Return SMESH_ElementSearcher. The caller is responsible for deleting it
+   */
+  SMESHUtils_EXPORT
+  SMESH_ElementSearcher* GetElementSearcher( SMDS_Mesh& mesh,
+                                             double     tolerance=-1.);
+  SMESHUtils_EXPORT
+  SMESH_ElementSearcher* GetElementSearcher( SMDS_Mesh& mesh,
+                                             SMDS_ElemIteratorPtr elemIt,
+                                             double     tolerance=-1. );
+
+
   /*!
    * \brief Return true if the point is IN or ON of the element
    */
@@ -172,24 +200,52 @@ namespace SMESH_MeshAlgos
                      const SMDS_MeshNode*    node1 );
 
   /*!
-   * \brief Return SMESH_NodeSearcher. The caller is responsible for deleteing it
+   * \brief Mark elements given by SMDS_Iterator
    */
-  SMESHUtils_EXPORT
-  SMESH_NodeSearcher* GetNodeSearcher( SMDS_Mesh& mesh );
-
-  SMESHUtils_EXPORT
-  SMESH_NodeSearcher* GetNodeSearcher( SMDS_ElemIteratorPtr elemIt );
-
+  template< class ElemIter >
+  void MarkElems( ElemIter it, const bool isMarked )
+  {
+    while ( it->more() ) it->next()->setIsMarked( isMarked );
+  }
   /*!
-   * \brief Return SMESH_ElementSearcher. The caller is responsible for deleting it
+   * \brief Mark elements given by std iterators
    */
-  SMESHUtils_EXPORT
-  SMESH_ElementSearcher* GetElementSearcher( SMDS_Mesh& mesh,
-                                             double     tolerance=-1.);
-  SMESHUtils_EXPORT
-  SMESH_ElementSearcher* GetElementSearcher( SMDS_Mesh& mesh,
-                                             SMDS_ElemIteratorPtr elemIt,
-                                             double     tolerance=-1. );
+  template< class ElemIter >
+  void MarkElems( ElemIter it, ElemIter end, const bool isMarked )
+  {
+    for ( ; it != end; ++it ) (*it)->setIsMarked( isMarked );
+  }
+  /*!
+   * \brief Mark nodes of elements given by SMDS_Iterator
+   */
+  template< class ElemIter >
+  void MarkElemNodes( ElemIter it, const bool isMarked, const bool markElem = false )
+  {
+    if ( markElem )
+      while ( it->more() ) {
+        const SMDS_MeshElement* e = it->next();
+        e->setIsMarked( isMarked );
+        MarkElems( e->nodesIterator(), isMarked );
+      }
+    else
+      while ( it->more() )
+        MarkElems( it->next()->nodesIterator(), isMarked );
+  }
+  /*!
+   * \brief Mark elements given by std iterators
+   */
+  template< class ElemIter >
+  void MarkElemNodes( ElemIter it, ElemIter end, const bool isMarked, const bool markElem = false )
+  {
+    if ( markElem )
+      for ( ; it != end; ++it ) {
+        (*it)->setIsMarked( isMarked );
+        MarkElems( (*it)->nodesIterator(), isMarked );
+      }
+    else
+      for ( ; it != end; ++it )
+        MarkElems( (*it)->nodesIterator(), isMarked );
+  }
 
 
 
@@ -214,18 +270,16 @@ namespace SMESH_MeshAlgos
    * Returns TFreeBorder's coincident within the given tolerance.
    * If the tolerance <= 0.0 then one tenth of an average size of elements adjacent
    * to free borders being compared is used.
-   *
-   * (Implemented in ./SMESH_FreeBorders.cxx)
    */
   SMESHUtils_EXPORT
   void FindCoincidentFreeBorders(SMDS_Mesh&              mesh,
                                  double                  tolerance,
                                  CoincidentFreeBorders & foundFreeBordes);
+  // Implemented in ./SMESH_FreeBorders.cxx
+
   /*!
    * 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,
@@ -244,6 +298,62 @@ namespace SMESH_MeshAlgos
                 std::vector<const SMDS_MeshElement*>& newFaces);
 
 
+  typedef std::vector< std::pair< const SMDS_MeshElement*, const SMDS_MeshElement* > > TEPairVec;
+  typedef std::vector< std::pair< const SMDS_MeshNode*, const SMDS_MeshNode* > >       TNPairVec;
+  /*!
+   * \brief Create an offset mesh of given faces
+   *  \param [in] faceIt - the input faces
+   *  \param [in] theFixIntersections - to fix self intersections of the offset mesh or not
+   *  \param [out] new2OldFaces - history of faces
+   *  \param [out] new2OldNodes - history of nodes
+   *  \return SMDS_Mesh* - the new offset mesh, a caller should delete
+   */
+  SMESHUtils_EXPORT
+  SMDS_Mesh* MakeOffset( SMDS_ElemIteratorPtr faceIt,
+                         SMDS_Mesh&           mesh,
+                         const double         offset,
+                         const bool           theFixIntersections,
+                         TEPairVec&           new2OldFaces,
+                         TNPairVec&           new2OldNodes );
+  // Implemented in ./SMESH_Offset.cxx
+
+
+  /*!
+   * \brief Divide a mesh face into triangles
+   */
+  // Implemented in ./SMESH_Triangulate.cxx
+
+  class SMESHUtils_EXPORT Triangulate
+  {
+  public:
+
+    static int GetNbTriangles( const SMDS_MeshElement* face );
+
+    int GetTriangles( const SMDS_MeshElement*             face,
+                      std::vector< const SMDS_MeshNode*>& nodes);
+  private:
+
+    bool triangulate( std::vector< const SMDS_MeshNode*>& nodes, const size_t nbNodes );
+
+    /*!
+     * \brief Vertex of a polygon. Together with 2 neighbor Vertices represents a triangle
+     */
+    struct PolyVertex
+    {
+      SMESH_NodeXYZ _nxyz;
+      gp_XY         _xy;
+      PolyVertex*   _prev;
+      PolyVertex*   _next;
+
+      void   SetNodeAndNext( const SMDS_MeshNode* n, PolyVertex& v );
+      void   GetTriaNodes( const SMDS_MeshNode** nodes) const;
+      double TriaArea() const;
+      bool   IsInsideTria( const PolyVertex* v );
+      PolyVertex* Delete();
+    };
+    std::vector< PolyVertex > _pv;
+  };
+
 } // SMESH_MeshAlgos
 
 #endif
diff --git a/src/SMESHUtils/SMESH_Offset.cxx b/src/SMESHUtils/SMESH_Offset.cxx
new file mode 100644 (file)
index 0000000..f571535
--- /dev/null
@@ -0,0 +1,2912 @@
+// 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_Offset.cxx
+// Created   : Mon Dec 25 15:52:38 2017
+// Author    : Edward AGAPOV (eap)
+
+#include "SMESH_MeshAlgos.hxx"
+
+#include <SMDS_PolygonalFaceOfNodes.hxx>
+#include "SMDS_Mesh.hxx"
+
+#include <Utils_SALOME_Exception.hxx>
+
+#include <Bnd_B3d.hxx>
+#include <NCollection_Map.hxx>
+#include <gp_Lin.hxx>
+#include <gp_Pln.hxx>
+
+#include <boost/container/flat_set.hpp>
+#include <boost/dynamic_bitset.hpp>
+
+namespace
+{
+  const size_t theMaxNbFaces = 256; // max number of faces sharing a node
+
+  typedef NCollection_DataMap< Standard_Address, const SMDS_MeshNode* > TNNMap;
+  typedef NCollection_Map< SMESH_Link, SMESH_Link >                     TLinkMap;
+
+  //--------------------------------------------------------------------------------
+  /*!
+   * \brief Intersected face side storing a node created at this intersection
+   *        and a intersected face
+   */
+  struct CutLink
+  {
+    bool                     myReverse;
+    const SMDS_MeshNode*     myNode[2]; // side nodes
+    mutable SMESH_NodeXYZ    myIntNode; // intersection node
+    const SMDS_MeshElement*  myFace;    // cutter face
+    int                      myIndex;   // index of a node on the same link
+
+    CutLink(const SMDS_MeshNode*    node1=0,
+            const SMDS_MeshNode*    node2=0,
+            const SMDS_MeshElement* face=0,
+            const int               index=0) { Set ( node1, node2, face, index ); }
+
+    void Set( const SMDS_MeshNode*    node1,
+              const SMDS_MeshNode*    node2,
+              const SMDS_MeshElement* face,
+              const int               index=0)
+    {
+      myNode[0] = node1; myNode[1] = node2; myFace = face; myIndex = index; myReverse = false;
+      if ( myNode[0] && ( myReverse = ( myNode[0]->GetID() > myNode[1]->GetID() )))
+        std::swap( myNode[0], myNode[1] );
+    }
+    const SMDS_MeshNode* IntNode() const { return myIntNode.Node(); }
+    const SMDS_MeshNode* Node1() const { return myNode[ myReverse ]; }
+    const SMDS_MeshNode* Node2() const { return myNode[ !myReverse ]; }
+
+    static Standard_Integer HashCode(const CutLink&         link,
+                                     const Standard_Integer upper)
+    {
+      Standard_Integer n = ( link.myNode[0]->GetID() +
+                             link.myNode[1]->GetID() +
+                             link.myIndex );
+      return ::HashCode( n, upper );
+    }
+    static Standard_Boolean IsEqual(const CutLink& link1, const CutLink& link2 )
+    {
+      return ( link1.myNode[0] == link2.myNode[0] &&
+               link1.myNode[1] == link2.myNode[1] &&
+               link1.myIndex == link2.myIndex );
+    }
+  };
+
+  typedef NCollection_Map< CutLink, CutLink > TCutLinkMap;
+
+  //--------------------------------------------------------------------------------
+  /*!
+   * \brief Part of a divided face edge
+   */
+  struct EdgePart
+  {
+    const SMDS_MeshNode*    myNode1;
+    const SMDS_MeshNode*    myNode2;
+    int                     myIndex; // positive -> side index, negative -> State
+    const SMDS_MeshElement* myFace;
+
+    enum State { _INTERNAL = -1, _COPLANAR = -2 };
+
+    void Set( const SMDS_MeshNode*    Node1,
+              const SMDS_MeshNode*    Node2,
+              const SMDS_MeshElement* Face = 0,
+              int                     EdgeIndex = _INTERNAL )
+    { myNode1 = Node1; myNode2 = Node2; myIndex = EdgeIndex; myFace = Face; }
+
+    // bool HasSameNode( const EdgePart& other ) { return ( myNode1 == other.myNode1 ||
+    //                                                      myNode1 == other.myNode2 ||
+    //                                                      myNode2 == other.myNode1 ||
+    //                                                      myNode2 == other.myNode2 );
+    // }
+    bool IsInternal() const { return myIndex < 0; }
+    bool IsTwin( const EdgePart& e ) const { return myNode1 == e.myNode2 && myNode2 == e.myNode1; }
+    bool IsSame( const EdgePart& e ) const {
+      return (( myNode1 == e.myNode2 && myNode2 == e.myNode1 ) ||
+              ( myNode1 == e.myNode1 && myNode2 == e.myNode2 )); }
+    bool ReplaceCoplanar( const EdgePart& e );
+    operator SMESH_Link() const { return SMESH_Link( myNode1, myNode2 ); }
+    operator gp_Vec() const { return SMESH_NodeXYZ( myNode2 ) - SMESH_NodeXYZ( myNode1 ); }
+  };
+
+  //--------------------------------------------------------------------------------
+  /*!
+   * \brief Loop of EdgePart's forming a new face which is a part of CutFace
+   */
+  struct EdgeLoop : public SMDS_PolygonalFaceOfNodes
+  {
+    std::vector< const EdgePart* > myLinks;
+    bool                           myIsBndConnected; //!< is there a path to CutFace side edges
+    bool                           myHasPending;     //!< an edge encounters twice
+
+    EdgeLoop() : SMDS_PolygonalFaceOfNodes( std::vector<const SMDS_MeshNode *>() ) {}
+    void Clear() { myLinks.clear(); myIsBndConnected = false; myHasPending = false; }
+    bool SetConnected() { bool was = myIsBndConnected; myIsBndConnected = true; return !was; }
+    bool Contains( const SMDS_MeshNode* n ) const
+    {
+      for ( size_t i = 0; i < myLinks.size(); ++i )
+        if ( myLinks[i]->myNode1 == n ) return true;
+      return false;
+    }
+    virtual int NbNodes() const { return myLinks.size(); }
+    virtual SMDS_ElemIteratorPtr nodesIterator() const
+    {
+      return setNodes(), SMDS_PolygonalFaceOfNodes::nodesIterator();
+    }
+    virtual SMDS_NodeIteratorPtr nodeIterator() const
+    {
+      return setNodes(), SMDS_PolygonalFaceOfNodes::nodeIterator();
+    }
+    void setNodes() const //!< set nodes to SMDS_PolygonalFaceOfNodes
+    {
+      EdgeLoop* me = const_cast<EdgeLoop*>( this );
+      me->myNodes.resize( NbNodes() );
+      size_t iMin = 0;
+      for ( size_t i = 1; i < myNodes.size(); ++i ) {
+        if ( myLinks[ i ]->myNode1->GetID() < myLinks[ iMin ]->myNode1->GetID() )
+          iMin = i;
+      }
+      for ( size_t i = 0; i < myNodes.size(); ++i )
+        me->myNodes[ i ] = myLinks[ ( iMin + i ) % myNodes.size() ]->myNode1;
+    }
+  };
+
+  //--------------------------------------------------------------------------------
+  /*!
+   * \brief Set of EdgeLoop's constructed from a CutFace
+   */
+  struct EdgeLoopSet
+  {
+    std::vector< EdgeLoop >  myLoops;       //!< buffer of EdgeLoop's
+    size_t                   myNbLoops;     //!< number of constructed loops
+
+    const EdgePart*          myEdge0;       //!< & CutFace.myLinks[0]
+    size_t                   myNbUsedEdges; //!< nb of EdgePart's added to myLoops
+    boost::dynamic_bitset<>  myIsUsedEdge;  //!< is i-th EdgePart of CutFace is in any EdgeLoop
+    std::vector< EdgeLoop* > myLoopOfEdge;  //!< EdgeLoop of CutFace.myLinks[i]
+    std::vector< EdgePart* > myCandidates;  //!< EdgePart's starting at the same node
+
+    EdgeLoopSet(): myLoops(100) {}
+
+    void Init( const std::vector< EdgePart >& edges )
+    {
+      size_t nb = edges.size();
+      myEdge0 = & edges[0];
+      myNbLoops = 0;
+      myNbUsedEdges = 0;
+      myIsUsedEdge.reset();
+      myIsUsedEdge.resize( nb, false );
+      myLoopOfEdge.clear();
+      myLoopOfEdge.resize( nb, (EdgeLoop*) 0 );
+    }
+    EdgeLoop& AddNewLoop()
+    {
+      if ( ++myNbLoops >= myLoops.size() )
+        myLoops.resize( myNbLoops + 10 );
+      myLoops[ myNbLoops-1 ].Clear();
+      return myLoops[ myNbLoops-1 ];
+    }
+    bool AllEdgesUsed() const { return myNbUsedEdges == myLoopOfEdge.size(); }
+
+    bool AddEdge( EdgePart& edge )
+    {
+      size_t i = Index( edge );
+      if ( myIsUsedEdge[ i ])
+        return false;
+      myLoops[ myNbLoops-1 ].myLinks.push_back( &edge );
+      myLoopOfEdge[ i ] = & myLoops[ myNbLoops-1 ];
+      myIsUsedEdge[ i ] = true;
+      ++myNbUsedEdges;
+      return true;
+    }
+    void Erase( EdgeLoop* loop )
+    {
+      for ( size_t iE = 0; iE < loop->myLinks.size(); ++iE )
+        myLoopOfEdge[ Index( *loop->myLinks[ iE ] )] = 0;
+      loop->Clear();
+    }
+    size_t    Index( const EdgePart& edge ) const { return &edge - myEdge0; }
+    EdgeLoop* GetLoopOf( const EdgePart* edge ) { return myLoopOfEdge[ Index( *edge )]; }
+  };
+
+  //--------------------------------------------------------------------------------
+  /*!
+   * \brief Intersections of a face
+   */
+  struct CutFace
+  {
+    mutable std::vector< EdgePart > myLinks;
+    const SMDS_MeshElement*         myInitFace;
+
+    CutFace( const SMDS_MeshElement* face ): myInitFace( face ) {}
+    void AddEdge( const CutLink&          p1,
+                  const CutLink&          p2,
+                  const SMDS_MeshElement* cutter,
+                  const int               nbOnPlane,
+                  const int               iNotOnPlane = -1) const;
+    void AddPoint( const CutLink& p1, const CutLink& p2, double tol ) const;
+    bool ReplaceNodes( const TNNMap& theRm2KeepMap ) const;
+    bool IsCut() const;
+    int  NbInternalEdges() const;
+    void MakeLoops( EdgeLoopSet& loops, const gp_XYZ& theFaceNorm ) const;
+    bool RemoveInternalLoops( EdgeLoopSet& theLoops ) const;
+    void CutOffLoops( EdgeLoopSet&                 theLoops,
+                      const double                 theSign,
+                      const std::vector< gp_XYZ >& theNormals,
+                      std::vector< EdgePart >&     theCutOffLinks,
+                      TLinkMap&                    theCutOffCoplanarLinks) const;
+    void InitLinks() const;
+    bool IsCoplanar( const EdgePart* edge ) const;
+
+    static Standard_Integer HashCode(const CutFace& f, const Standard_Integer upper)
+    {
+      return ::HashCode( f.myInitFace->GetID(), upper );
+    }
+    static Standard_Boolean IsEqual(const CutFace& f1, const CutFace& f2 )
+    {
+      return f1.myInitFace == f2.myInitFace;
+    }
+    void Dump() const;
+
+  private:
+
+    EdgePart* getTwin( const EdgePart* edge ) const;
+  };
+
+  typedef NCollection_Map< CutFace, CutFace > TCutFaceMap;
+
+  //--------------------------------------------------------------------------------
+  /*!
+   * \brief Intersection point of two edges of co-planar triangles
+   */
+  struct IntPoint2D
+  {
+    size_t        myEdgeInd[2]; //!< edge indices of triangles
+    double        myU      [2]; //!< parameter [0,1] on edges of triangles
+    SMESH_NodeXYZ myNode;       //!< intersection node
+    bool          myIsCollinear;//!< edges are collinear
+
+    IntPoint2D() : myIsCollinear( false ) {}
+
+    void InitLink( CutLink& link, int iFace, const std::vector< SMESH_NodeXYZ >& nodes ) const
+    {
+      link.Set( nodes[  myEdgeInd[ iFace ]                      ].Node(),
+                nodes[( myEdgeInd[ iFace ] + 1 ) % nodes.size() ].Node(),
+                link.myFace );
+      link.myIntNode = myNode;
+    }
+    const SMDS_MeshNode* Node() const { return myNode.Node(); }
+  };
+  struct IntPoint2DCompare
+  {
+    int myI;
+    IntPoint2DCompare( int iFace=0 ): myI( iFace ) {}
+    bool operator() ( const IntPoint2D* ip1, const IntPoint2D* ip2 ) const
+    {
+      return ip1->myU[ myI ] < ip2->myU[ myI ];
+    }
+    bool operator() ( const IntPoint2D& ip1, const IntPoint2D& ip2 ) const
+    {
+      return ip1.myU[ myI ] < ip2.myU[ myI ];
+    }
+  };
+  typedef boost::container::flat_set< IntPoint2D, IntPoint2DCompare >  TIntPointSet;
+  typedef boost::container::flat_set< IntPoint2D*, IntPoint2DCompare > TIntPointPtrSet;
+
+  //--------------------------------------------------------------------------------
+  /*!
+   * \brief Face used to find translated position of the node
+   */
+  struct Face
+  {
+    const SMDS_MeshElement* myFace;
+    SMESH_TNodeXYZ          myNode1; //!< nodes neighboring another node of myFace
+    SMESH_TNodeXYZ          myNode2;
+    const gp_XYZ*           myNorm;
+    bool                    myNodeRightOrder;
+    void operator=(const SMDS_MeshElement* f) { myFace = f; }
+    const SMDS_MeshElement* operator->() { return myFace; }
+    void SetNodes( int i0, int i1 ) //!< set myNode's
+    {
+      myNode1.Set( myFace->GetNode( i1 ));
+      int i2 = ( i0 - 1 + myFace->NbCornerNodes() ) % myFace->NbCornerNodes();
+      if ( i2 == i1 )
+        i2 = ( i0 + 1 ) % myFace->NbCornerNodes();
+      myNode2.Set( myFace->GetNode( i2 ));
+      myNodeRightOrder = ( Abs( i2-i1 ) == 1 ) ?  i2 > i1  :  i2 < i1;
+    }
+    void SetOldNodes( const SMDS_Mesh& theSrcMesh )
+    {
+      myNode1.Set( theSrcMesh.FindNode( myNode1->GetID() ));
+      myNode2.Set( theSrcMesh.FindNode( myNode2->GetID() ));
+    }
+    bool SetNormal( const std::vector< gp_XYZ >& faceNormals )
+    {
+      myNorm = & faceNormals[ myFace->GetID() ];
+      return ( myNorm->SquareModulus() > gp::Resolution() * gp::Resolution() );
+    }
+    const gp_XYZ& Norm() const { return *myNorm; }
+  };
+
+  //--------------------------------------------------------------------------------
+  /*!
+   * \brief Offset plane used to find translated position of the node
+   */
+  struct OffsetPlane
+  {
+    gp_XYZ myNode;
+    Face*  myFace;
+    gp_Pln myPln;
+    gp_Lin myLines[2]; //!< line of intersection with neighbor OffsetPlane's
+    bool   myIsLineOk[2];
+    double myWeight[2];
+
+    void   Init( const gp_XYZ& node, Face& tria, double offset )
+    {
+      myNode = node;
+      myFace = & tria;
+      myPln  = gp_Pln( node + tria.Norm() * offset, tria.Norm() );
+      myIsLineOk[0] = myIsLineOk[1] = false;
+      myWeight[0] = myWeight[1] = 0;
+    }
+    bool   ComputeIntersectionLine( OffsetPlane& pln );
+    void   SetSkewLine( const gp_Lin& line );
+    gp_XYZ GetCommonPoint( int & nbOkPoints, double& sumWeight );
+    gp_XYZ ProjectNodeOnLine( int & nbOkPoints );
+    double Weight() const { return myWeight[0] + myWeight[1]; }
+  };
+
+  //================================================================================
+  /*!
+   * \brief Set the second line
+   */
+  //================================================================================
+
+  void OffsetPlane::SetSkewLine( const gp_Lin& line )
+  {
+    myLines[1] = line;
+    gp_XYZ n = myLines[0].Direction().XYZ() ^ myLines[1].Direction().XYZ();
+    if (( myIsLineOk[1] = n.SquareModulus() > gp::Resolution() ))
+      myPln = gp_Pln( myPln.Location(), n );
+  }
+
+  //================================================================================
+  /*!
+   * \brief Project myNode on myLine[0]
+   */
+  //================================================================================
+
+  gp_XYZ OffsetPlane::ProjectNodeOnLine( int & nbOkPoints )
+  {
+    gp_XYZ p = gp::Origin().XYZ();
+    if ( myIsLineOk[0] )
+    {
+      gp_Vec l2n( myLines[0].Location(), myNode );
+      double u = l2n * myLines[0].Direction();
+      p = myLines[0].Location().XYZ() + u * myLines[0].Direction().XYZ();
+      ++nbOkPoints;
+    }
+    return p;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Computes intersection point of myLines
+   */
+  //================================================================================
+
+  gp_XYZ OffsetPlane::GetCommonPoint( int & nbOkPoints, double& sumWeight )
+  {
+    if ( !myIsLineOk[0] || !myIsLineOk[1] )
+    {
+      // sumWeight += myWeight[0];
+      // return ProjectNodeOnLine( nbOkPoints ) * myWeight[0];
+      return gp::Origin().XYZ();
+    }
+
+    gp_XYZ p;
+
+    gp_Vec lPerp0 = myLines[0].Direction().XYZ() ^ myPln.Axis().Direction().XYZ();
+    double  dot01 = lPerp0 * myLines[1].Direction().XYZ();
+    if ( Abs( dot01 ) > 0.05 )
+    {
+      gp_Vec l0l1 = myLines[1].Location().XYZ() - myLines[0].Location().XYZ();
+      double   u1 = - ( lPerp0 * l0l1 ) / dot01;
+      p = ( myLines[1].Location().XYZ() + myLines[1].Direction().XYZ() * u1 );
+    }
+    else
+    {
+      gp_Vec  lv0( myLines[0].Location(), myNode),  lv1(myLines[1].Location(), myNode );
+      double dot0( lv0 * myLines[0].Direction() ), dot1( lv1 * myLines[1].Direction() );
+      p  = 0.5 * ( myLines[0].Location().XYZ() + myLines[0].Direction().XYZ() * dot0 );
+      p += 0.5 * ( myLines[1].Location().XYZ() + myLines[1].Direction().XYZ() * dot1 );
+    }
+
+    sumWeight += Weight();
+    ++nbOkPoints;
+
+    return p * Weight();
+  }
+
+  //================================================================================
+  /*!
+   * \brief Compute line of intersection of 2 planes
+   */
+  //================================================================================
+
+  bool OffsetPlane::ComputeIntersectionLine( OffsetPlane& theNextPln )
+  {
+    const gp_XYZ& n1 = myFace->Norm();
+    const gp_XYZ& n2 = theNextPln.myFace->Norm();
+
+    gp_XYZ lineDir = n1 ^ n2;
+    gp_Pnt linePos;
+
+    double x = Abs( lineDir.X() );
+    double y = Abs( lineDir.Y() );
+    double z = Abs( lineDir.Z() );
+
+    int cooMax; // max coordinate
+    if (x > y) {
+      if (x > z) cooMax = 1;
+      else       cooMax = 3;
+    }
+    else {
+      if (y > z) cooMax = 2;
+      else       cooMax = 3;
+    }
+
+    bool ok = true;
+    if ( Abs( lineDir.Coord( cooMax )) < 0.05 )
+    {
+      // parallel planes - intersection is an offset of the common edge
+      linePos  = 0.5 * ( myPln.Location().XYZ() + theNextPln.myPln.Location().XYZ() );
+      lineDir  = myNode - myFace->myNode2;
+      ok       = false;
+      myWeight[0] = 0;
+    }
+    else
+    {
+      // the constants in the 2 plane equations
+      double d1 = - ( n1 * myPln.Location().XYZ() );
+      double d2 = - ( n2 * theNextPln.myPln.Location().XYZ() );
+
+      switch ( cooMax ) {
+      case 1:
+        linePos.SetX(  0 );
+        linePos.SetY(( d2*n1.Z() - d1*n2.Z()) / lineDir.X() );
+        linePos.SetZ(( d1*n2.Y() - d2*n1.Y()) / lineDir.X() );
+        break;
+      case 2:
+        linePos.SetX(( d1*n2.Z() - d2*n1.Z()) / lineDir.Y() );
+        linePos.SetY(  0 );
+        linePos.SetZ(( d2*n1.X() - d1*n2.X()) / lineDir.Y() );
+        break;
+      case 3:
+        linePos.SetX(( d2*n1.Y() - d1*n2.Y()) / lineDir.Z() );
+        linePos.SetY(( d1*n2.X() - d2*n1.X()) / lineDir.Z() );
+        linePos.SetZ(  0 );
+      }
+      myWeight[0] = lineDir.SquareModulus();
+      if ( n1 * n2 < 0 )
+        myWeight[0] = 2. - myWeight[0];
+    }
+    myLines   [ 0 ].SetDirection( lineDir );
+    myLines   [ 0 ].SetLocation ( linePos );
+    myIsLineOk[ 0 ] = ok;
+
+    theNextPln.myLines   [ 1 ] = myLines[ 0 ];
+    theNextPln.myIsLineOk[ 1 ] = ok;
+    theNextPln.myWeight  [ 1 ] = myWeight[ 0 ];
+
+    return ok;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Return a translated position of a node
+   *  \param [in] new2OldNodes - new and old nodes
+   *  \param [in] faceNormals - normals to input faces
+   *  \param [in] theSrcMesh - initial mesh
+   *  \param [in] theNewPos - a computed normal
+   *  \return bool - true if theNewPos is computed
+   */
+  //================================================================================
+
+  bool getTranslatedPosition( const SMDS_MeshNode*         theNewNode,
+                              const double                 theOffset,
+                              const double                 theTol,
+                              const double                 theSign,
+                              const std::vector< gp_XYZ >& theFaceNormals,
+                              SMDS_Mesh&                   theSrcMesh,
+                              gp_XYZ&                      theNewPos)
+  {
+    bool useOneNormal = true;
+
+    // check if theNewNode needs an average position, i.e. theNewNode is convex
+    // SMDS_ElemIteratorPtr faceIt = theNewNode->GetInverseElementIterator();
+    // const SMDS_MeshElement*  f0 = faceIt->next();
+    // const gp_XYZ&         norm0 = theFaceNormals[ f0->GetID() ];
+    // const SMESH_NodeXYZ nodePos = theNewNode;
+    // while ( faceIt->more() )
+    // {
+    //   const SMDS_MeshElement* f = faceIt->next();
+    //   const int         nodeInd = f->GetNodeIndex( theNewNode );
+    //   SMESH_NodeXYZ    nodePos2 = f->GetWrapNode( nodeInd + 1 );
+    //   try {
+    //     const gp_XYZ      nnDir = ( nodePos2 - nodePos ).Normalized();
+    //   }
+    //   catch {
+    //     continue;
+    //   }
+    //   const double dot = norm0 * nnDir;
+    //   bool isConvex = 
+
+
+
+    // get faces surrounding theNewNode and sort them
+    Face faces[ theMaxNbFaces ];
+    SMDS_ElemIteratorPtr faceIt = theNewNode->GetInverseElementIterator();
+    faces[0] = faceIt->next();
+    while ( !faces[0].SetNormal( theFaceNormals ) && faceIt->more() )
+      faces[0] = faceIt->next();
+    int i0 = faces[0]->GetNodeIndex( theNewNode );
+    int i1 = ( i0 + 1 ) % faces[0]->NbCornerNodes();
+    faces[0].SetNodes( i0, i1 );
+    TIDSortedElemSet elemSet, avoidSet;
+    int iFace = 0;
+    const SMDS_MeshElement* f;
+    for ( ; faceIt->more(); faceIt->next() )
+    {
+      avoidSet.insert( faces[ iFace ].myFace );
+      f = SMESH_MeshAlgos::FindFaceInSet( theNewNode, faces[ iFace ].myNode2.Node(),
+                                          elemSet, avoidSet, &i0, &i1 );
+      if ( !f )
+      {
+        std::reverse( &faces[0], &faces[0] + iFace + 1 );
+        for ( int i = 0; i <= iFace; ++i )
+        {
+          std::swap( faces[i].myNode1, faces[i].myNode2 );
+          faces[i].myNodeRightOrder = !faces[i].myNodeRightOrder;
+        }
+        f = SMESH_MeshAlgos::FindFaceInSet( theNewNode, faces[ iFace ].myNode2.Node(),
+                                            elemSet, avoidSet, &i0, &i1 );
+        if ( !f )
+          break;
+      }
+      faces[ ++iFace ] = f;
+      faces[ iFace ].SetNodes( i0, i1 );
+      faces[ iFace ].SetNormal( theFaceNormals );
+    }
+    int nbFaces = Min( iFace + 1, (int)theMaxNbFaces );
+
+    theNewPos.SetCoord( 0, 0, 0 );
+    gp_XYZ oldXYZ = SMESH_NodeXYZ( theNewNode );
+
+    // check if all faces are co-planar
+    bool isPlanar = true;
+    const double tol = 1e-2;
+    for ( int i = 1; i < nbFaces &&  isPlanar;  ++i )
+      isPlanar = ( faces[i].Norm() - faces[i-1].Norm() ).SquareModulus() < tol*tol;
+
+    if ( isPlanar )
+    {
+      theNewPos = oldXYZ + faces[0].Norm() * theOffset;
+      return useOneNormal;
+    }
+
+    // prepare OffsetPlane's
+    OffsetPlane pln[ theMaxNbFaces ];
+    for ( int i = 0; i < nbFaces; ++i )
+    {
+      faces[i].SetOldNodes( theSrcMesh );
+      pln[i].Init( oldXYZ, faces[i], theOffset );
+    }
+    // intersect neighboring OffsetPlane's
+    int nbOkPoints = 0;
+    for ( int i = 1; i < nbFaces; ++i )
+      nbOkPoints += pln[ i-1 ].ComputeIntersectionLine( pln[ i ]);
+    nbOkPoints += pln[ nbFaces-1 ].ComputeIntersectionLine( pln[ 0 ]);
+
+    // move intersection lines to over parallel planes
+    if ( nbOkPoints > 1 )
+      for ( int i = 0; i < nbFaces; ++i )
+        if ( pln[i].myIsLineOk[0] && !pln[i].myIsLineOk[1] )
+          for ( int j = 1; j < nbFaces &&  !pln[i].myIsLineOk[1]; ++j )
+          {
+            int i2 = ( i + j ) % nbFaces;
+            if ( pln[i2].myIsLineOk[0] )
+              pln[i].SetSkewLine( pln[i2].myLines[0] );
+          }
+
+    // get the translated position
+    nbOkPoints = 0;
+    double sumWegith = 0;
+    const double minWeight = Sin( 30 * M_PI / 180. ) * Sin( 30 * M_PI / 180. );
+    for ( int i = 0; i < nbFaces; ++i )
+      if ( pln[ i ].Weight() > minWeight )
+        theNewPos += pln[ i ].GetCommonPoint( nbOkPoints, sumWegith );
+
+    if ( nbOkPoints == 0 )
+    {
+      // there is only one feature edge;
+      // find the theNewPos by projecting oldXYZ to any intersection line
+      for ( int i = 0; i < nbFaces; ++i )
+        theNewPos += pln[ i ].ProjectNodeOnLine( nbOkPoints );
+
+      if ( nbOkPoints == 0 )
+      {
+        theNewPos = oldXYZ + faces[0].Norm() * theOffset;
+        return useOneNormal;
+      }
+      sumWegith = nbOkPoints;
+    }
+    theNewPos /= sumWegith;
+
+
+    // mark theNewNode if it is concave
+    useOneNormal = false;
+    gp_Vec moveVec( oldXYZ, theNewPos );
+    for ( int i = 0, iPrev = nbFaces-1; i < nbFaces; iPrev = i++ )
+    {
+      gp_Vec nodeVec( oldXYZ, faces[ i ].myNode1 );
+      double u = ( moveVec * nodeVec ) / nodeVec.SquareMagnitude();
+      if ( u > 0.5 ) // param [0,1] on nodeVec
+      {
+        theNewNode->setIsMarked( true );
+      }
+      if ( !useOneNormal )
+      {
+        gp_XYZ inFaceVec = faces[ i ].Norm() ^ nodeVec.XYZ();
+        double       dot = inFaceVec * faces[ iPrev ].Norm();
+        if ( !faces[ i ].myNodeRightOrder )
+          dot *= -1;
+        if ( dot * theSign < 0 )
+        {
+          gp_XYZ p1 = oldXYZ + faces[ i ].Norm()     * theOffset;
+          gp_XYZ p2 = oldXYZ + faces[ iPrev ].Norm() * theOffset;
+          useOneNormal = ( p1 - p2 ).SquareModulus() > theTol * theTol;
+        }
+      }
+      if ( useOneNormal && theNewNode->isMarked() )
+        break;
+    }
+
+    return useOneNormal;
+  }
+
+  //--------------------------------------------------------------------------------
+  /*!
+   * \brief Intersect faces of a mesh
+   */
+  struct Intersector
+  {
+    SMDS_Mesh*                   myMesh;
+    double                       myTol, myEps;
+    const std::vector< gp_XYZ >& myNormals;
+    TCutLinkMap                  myCutLinks; //!< assure sharing of new nodes
+    TCutFaceMap                  myCutFaces;
+    TNNMap                       myRemove2KeepNodes; //!< node merge map
+
+    // data to intersect 2 faces
+    const SMDS_MeshElement*      myFace1;
+    const SMDS_MeshElement*      myFace2;
+    std::vector< SMESH_NodeXYZ > myNodes1, myNodes2;
+    std::vector< double >        myDist1,  myDist2;
+    int                          myInd1, myInd2; // coordinate indices on an axis-aligned plane
+    int                          myNbOnPlane1, myNbOnPlane2;
+    TIntPointSet                 myIntPointSet;
+
+    Intersector( SMDS_Mesh* mesh, double tol, const std::vector< gp_XYZ >& normals )
+      : myMesh( mesh ),
+        myTol( tol ),
+        myEps( 1e-100 ),
+        //myEps( Sqrt( std::numeric_limits<double>::min() )),
+        //myEps( gp::Resolution() ),
+        myNormals( normals )
+    {}
+    void Cut( const SMDS_MeshElement* face1,
+              const SMDS_MeshElement* face2,
+              const int               nbCommonNodes );
+    void MakeNewFaces( SMESH_MeshAlgos::TEPairVec& theNew2OldFaces,
+                       SMESH_MeshAlgos::TNPairVec& theNew2OldNodes,
+                       const double                theSign );
+
+  private:
+
+    bool isPlaneIntersected( const gp_XYZ&                       n2,
+                             const double                        d2,
+                             const std::vector< SMESH_NodeXYZ >& nodes1,
+                             std::vector< double > &             dist1,
+                             int &                               nbOnPlane1,
+                             int &                               iNotOnPlane1);
+    void computeIntervals( const std::vector< SMESH_NodeXYZ >& nodes,
+                           const std::vector< double >&        dist,
+                           const int                           nbOnPln,
+                           const int                           iMaxCoo,
+                           double *                            u,
+                           int*                                iE);
+    void cutCoplanar();
+    void addLink ( CutLink& link );
+    bool findLink( CutLink& link );
+    bool coincide( const gp_XYZ& p1, const gp_XYZ& p2, const double tol ) const
+    {
+      return ( p1 - p2 ).SquareModulus() < tol * tol;
+    }
+    gp_XY p2D( const gp_XYZ& p ) const { return gp_XY( p.Coord( myInd1 ), p.Coord( myInd2 )); }
+
+    void intersectLink( const std::vector< SMESH_NodeXYZ >& nodes1,
+                        const std::vector< double > &       dist1,
+                        const int                           iEdge1,
+                        const SMDS_MeshElement*             face2,
+                        CutLink&                            link1);
+    void findIntPointOnPlane( const std::vector< SMESH_NodeXYZ >& nodes,
+                              const std::vector< double > &       dist,
+                              CutLink&                            link );
+    void replaceIntNode( const SMDS_MeshNode* nToKeep, const SMDS_MeshNode* nToRemove );
+    void computeIntPoint( const double           u1,
+                          const double           u2,
+                          const int              iE1,
+                          const int              iE2,
+                          CutLink &              link,
+                          const SMDS_MeshNode* & node1,
+                          const SMDS_MeshNode* & node2);
+    void cutCollinearLink( const int                           iNotOnPlane1,
+                           const std::vector< SMESH_NodeXYZ >& nodes1,
+                           const SMDS_MeshElement*             face2,
+                           const CutLink&                      link1,
+                           const CutLink&                      link2);
+    void setPlaneIndices( const gp_XYZ& planeNorm );
+    bool intersectEdgeEdge( const gp_XY s1p0, const gp_XY s1p1,
+                            const gp_XY s2p0, const gp_XY s2p1,
+                            double &    t1,   double &    t2,
+                            bool &      isCollinear  );
+    bool intersectEdgeEdge( int iE1, int iE2, IntPoint2D& intPoint );
+    bool isPointInTriangle( const gp_XYZ& p, const std::vector< SMESH_NodeXYZ >& nodes );
+    void intersectNewEdges( const CutFace& theCFace );
+    const SMDS_MeshNode* createNode( const gp_XYZ& p );
+  };
+
+  //================================================================================
+  /*!
+   * \brief Return coordinate index with maximal abs value
+   */
+  //================================================================================
+
+  int MaxIndex( const gp_XYZ& x )
+  {
+    int iMaxCoo = ( Abs( x.X()) < Abs( x.Y() )) + 1;
+    if ( Abs( x.Coord( iMaxCoo )) < Abs( x.Z() ))
+      iMaxCoo = 3;
+    return iMaxCoo;
+  }
+  //================================================================================
+  /*!
+   * \brief Store a CutLink
+   */
+  //================================================================================
+
+  const SMDS_MeshNode* Intersector::createNode( const gp_XYZ& p )
+  {
+    const SMDS_MeshNode* n = myMesh->AddNode( p.X(), p.Y(), p.Z() );
+    n->setIsMarked( true ); // cut nodes are marked
+    return n;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Store a CutLink
+   */
+  //================================================================================
+
+  void Intersector::addLink( CutLink& link )
+  {
+    link.myIndex = 0;
+    const CutLink* added = & myCutLinks.Added( link );
+    while ( added->myIntNode.Node() != link.myIntNode.Node() )
+    {
+      if ( !added->myIntNode )
+      {
+        added->myIntNode = link.myIntNode;
+        break;
+      }
+      else
+      {
+        link.myIndex++;
+        added = & myCutLinks.Added( link );
+      }
+    }
+    link.myIndex = 0;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Find a CutLink with an intersection point coincident with that of a given link
+   */
+  //================================================================================
+
+  bool Intersector::findLink( CutLink& link )
+  {
+    link.myIndex = 0;
+    while ( myCutLinks.Contains( link ))
+    {
+      const CutLink* added = & myCutLinks.Added( link );
+      if ( !!added->myIntNode && coincide( added->myIntNode, link.myIntNode, myTol ))
+      {
+        link.myIntNode = added->myIntNode;
+        return true;
+      }
+      link.myIndex++;
+    }
+    return false;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Check if a triangle intersects the plane of another triangle
+   *  \param [in] nodes1 - nodes of triangle 1
+   *  \param [in] n2 - normal of triangle 2
+   *  \param [in] d2 - a constant of the plane equation 2
+   *  \param [out] dist1 - distance of nodes1 from the plane 2
+   *  \param [out] nbOnPlane - number of nodes1 lying on the plane 2
+   *  \return bool - true if the triangle intersects the plane 2
+   */
+  //================================================================================
+
+  bool Intersector::isPlaneIntersected( const gp_XYZ&                       n2,
+                                        const double                        d2,
+                                        const std::vector< SMESH_NodeXYZ >& nodes1,
+                                        std::vector< double > &             dist1,
+                                        int &                               nbOnPlane1,
+                                        int &                               iNotOnPlane1)
+  {
+    iNotOnPlane1 = nbOnPlane1 = 0;
+    dist1.resize( nodes1.size() );
+    for ( size_t i = 0; i < nodes1.size(); ++i )
+    {
+      dist1[i] = n2 * nodes1[i] + d2;
+      if ( Abs( dist1[i] ) < myTol )
+      {
+        ++nbOnPlane1;
+        dist1[i] = 0.;
+      }
+      else
+      {
+        iNotOnPlane1 = i;
+      }
+    }
+    if ( nbOnPlane1 == 0 )
+      for ( size_t i = 0; i < nodes1.size(); ++i )
+        if ( dist1[iNotOnPlane1] * dist1[i] < 0 )
+          return true;
+
+    return nbOnPlane1;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Compute parameters on the plane intersection line of intersections
+   *        of edges of a triangle
+   *  \param [in] nodes - triangle nodes
+   *  \param [in] dist - distance of triangle nodes from the plane of another triangle
+   *  \param [in] nbOnPln - number of nodes lying on the plane of another triangle
+   *  \param [in] iMaxCoo - index of coordinate of max component of the plane intersection line
+   *  \param [out] u - two computed parameters on the plane intersection line
+   *  \param [out] iE - indices of intersected edges
+   */
+  //================================================================================
+
+  void Intersector::computeIntervals( const std::vector< SMESH_NodeXYZ >& nodes,
+                                      const std::vector< double >&        dist,
+                                      const int                           nbOnPln, 
+                                      const int                           iMaxCoo,
+                                      double *                            u,
+                                      int*                                iE)
+  {
+    if ( nbOnPln == 3 )
+    {
+      u[0] = u[1] = 1e+100;
+      return;
+    }
+    int nb = 0;
+    int i1 = 2, i2 = 0;
+    if ( nbOnPln == 1 && ( dist[i1] == 0. || dist[i2] == 0 ))
+    {
+      int i = dist[i1] == 0 ? i1 : i2;
+      u [ 1 ] = nodes[ i ].Coord( iMaxCoo );
+      iE[ 1 ] = i;
+      i1 = i2++;
+    }
+    for ( ; i2 < 3 && nb < 2;  i1 = i2++ )
+    {
+      double dd = dist[i1] - dist[i2];
+      if ( dd != 0. && dist[i2] * dist[i1] <= 0. )
+      {
+        double x1 = nodes[i1].Coord( iMaxCoo );
+        double x2 = nodes[i2].Coord( iMaxCoo );
+        u [ nb ] = x1 + ( x2 - x1 ) * dist[i1] / dd;
+        iE[ nb ] = i1;
+        ++nb;
+      }
+    }
+    if ( u[0] > u[1] )
+    {
+      std::swap( u [0], u [1] );
+      std::swap( iE[0], iE[1] );
+    }
+  }
+
+  //================================================================================
+  /*!
+   * \brief Try to find an intersection node on a link collinear with the plane intersection line
+   */
+  //================================================================================
+
+  void Intersector::findIntPointOnPlane( const std::vector< SMESH_NodeXYZ >& nodes,
+                                         const std::vector< double > &       dist,
+                                         CutLink&                            link )
+  {
+    int i1 = ( dist[0] == 0 ? 0 : 1 ), i2 = ( dist[2] == 0 ? 2 : 1 );
+    CutLink link2 = link;
+    link2.Set( nodes[i1].Node(), nodes[i2].Node(), 0 );
+    if ( findLink( link2 ))
+      link.myIntNode = link2.myIntNode;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Compute intersection point of a link1 with a face2
+   */
+  //================================================================================
+
+  void Intersector::intersectLink( const std::vector< SMESH_NodeXYZ >& nodes1,
+                                   const std::vector< double > &       dist1,
+                                   const int                           iEdge1,
+                                   const SMDS_MeshElement*             face2,
+                                   CutLink&                            link1)
+  {
+    const int iEdge2 = ( iEdge1 + 1 ) % nodes1.size();
+    const SMESH_NodeXYZ& p1 = nodes1[ iEdge1 ];
+    const SMESH_NodeXYZ& p2 = nodes1[ iEdge2 ];
+
+    link1.Set( p1.Node(), p2.Node(), face2 );
+    const CutLink* link = & myCutLinks.Added( link1 );
+    if ( !link->IntNode() )
+    {
+      if      ( dist1[ iEdge1 ] == 0. ) link1.myIntNode = p1;
+      else if ( dist1[ iEdge2 ] == 0. ) link1.myIntNode = p2;
+      else
+      {
+        gp_XYZ p = p1 + ( p2 - p1 ) * dist1[ iEdge1 ] / ( dist1[ iEdge1 ] - dist1[ iEdge2 ]);
+        (gp_XYZ&)link1.myIntNode = p;
+      }
+    }
+    else
+    {
+      gp_XYZ p = p1 + ( p2 - p1 ) * dist1[ iEdge1 ] / ( dist1[ iEdge1 ] - dist1[ iEdge2 ]);
+      while ( link->IntNode() )
+      {
+        if ( coincide( p, link->myIntNode, myTol ))
+        {
+          link1.myIntNode = link->myIntNode;
+          break;
+        }
+        link1.myIndex++;
+        link = & myCutLinks.Added( link1 );
+      }
+      if ( !link1.IntNode() )
+      {
+        if      ( dist1[ iEdge1 ] == 0. ) link1.myIntNode = p1;
+        else if ( dist1[ iEdge2 ] == 0. ) link1.myIntNode = p2;
+        else                     (gp_XYZ&)link1.myIntNode = p;
+      }
+    }
+  }
+
+  //================================================================================
+  /*!
+   * \brief Store node replacement in myCutFaces
+   */
+  //================================================================================
+
+  void Intersector::replaceIntNode( const SMDS_MeshNode* nToKeep,
+                                    const SMDS_MeshNode* nToRemove )
+  {
+    if ( nToKeep == nToRemove )
+      return;
+    if ( nToRemove->GetID() < nToKeep->GetID() ) // keep node with lower ID
+      myRemove2KeepNodes.Bind((void*) nToKeep, nToRemove );
+    else
+      myRemove2KeepNodes.Bind((void*) nToRemove, nToKeep );
+  }
+
+  //================================================================================
+  /*!
+   * \brief Compute intersection point on a link of either of faces by choosing
+   *        a link whose parameter on the intersection line in maximal
+   *  \param [in] u1 - parameter on the intersection line of link iE1 of myFace1
+   *  \param [in] u2 - parameter on the intersection line of link iE2 of myFace2
+   *  \param [in] iE1 - index of a link myFace1
+   *  \param [in] iE2 - index of a link myFace2
+   *  \param [out] link - CutLink storing the intersection point
+   *  \param [out] node1 - a node of the 2nd link if two links intersect
+   *  \param [out] node2 - a node of the 2nd link if two links intersect
+   */
+  //================================================================================
+
+  void Intersector::computeIntPoint( const double           u1,
+                                     const double           u2,
+                                     const int              iE1,
+                                     const int              iE2,
+                                     CutLink &              link,
+                                     const SMDS_MeshNode* & node1,
+                                     const SMDS_MeshNode* & node2)
+  {
+    if      ( u1 > u2 + myTol )
+    {
+      intersectLink( myNodes1, myDist1, iE1, myFace2, link );
+      node1 = node2 = 0;
+      if ( myNbOnPlane2 == 2 )
+        findIntPointOnPlane( myNodes2, myDist2, link );
+    }
+    else if ( u2 > u1 + myTol )
+    {
+      intersectLink( myNodes2, myDist2, iE2, myFace1, link );
+      node1 = node2 = 0;
+      if ( myNbOnPlane1 == 2 )
+        findIntPointOnPlane( myNodes1, myDist1, link );
+    }
+    else // edges of two faces intersect the line at the same point
+    {
+      CutLink link2;
+      intersectLink( myNodes1, myDist1, iE1, myFace2, link );
+      intersectLink( myNodes2, myDist2, iE2, myFace1, link2 );
+      node1 = link2.Node1();
+      node2 = link2.Node2();
+
+      if      ( !link.IntNode() && link2.IntNode() )
+        link.myIntNode = link2.myIntNode;
+
+      else if ( !link.IntNode() && !link2.IntNode() )
+        (gp_XYZ&)link.myIntNode = 0.5 * ( link.myIntNode + link2.myIntNode );
+
+      else if ( link.IntNode() && link2.IntNode() )
+        replaceIntNode( link.IntNode(), link2.IntNode() );
+    }
+  }
+
+  //================================================================================
+  /*!
+   * \brief Add intersections to a link collinear with the intersection line
+   */
+  //================================================================================
+
+  void Intersector::cutCollinearLink( const int                           iNotOnPlane1,
+                                      const std::vector< SMESH_NodeXYZ >& nodes1,
+                                      const SMDS_MeshElement*             face2,
+                                      const CutLink&                      link1,
+                                      const CutLink&                      link2)
+
+  {
+    int iN1 = ( iNotOnPlane1 + 1 ) % 3;
+    int iN2 = ( iNotOnPlane1 + 2 ) % 3;
+    CutLink link( nodes1[ iN1 ].Node(), nodes1[ iN2 ].Node(), face2 );
+    if ( link1.myFace != face2 )
+    {
+      link.myIntNode = link1.myIntNode;
+      addLink( link );
+    }
+    if ( link2.myFace != face2 )
+    {
+      link.myIntNode = link2.myIntNode;
+      addLink( link );
+    }
+  }
+
+  //================================================================================
+  /*!
+   * \brief Choose indices on an axis-aligned plane
+   */
+  //================================================================================
+
+  void Intersector::setPlaneIndices( const gp_XYZ& planeNorm )
+  {
+    switch ( MaxIndex( planeNorm )) {
+    case 1: myInd1 = 2; myInd2 = 3; break;
+    case 2: myInd1 = 3; myInd2 = 1; break;
+    case 3: myInd1 = 1; myInd2 = 2; break;
+    }
+  }
+
+  //================================================================================
+  /*!
+   * \brief Intersect two faces
+   */
+  //================================================================================
+
+  void Intersector::Cut( const SMDS_MeshElement* face1,
+                         const SMDS_MeshElement* face2,
+                         const int               nbCommonNodes)
+  {
+    myFace1 = face1;
+    myFace2 = face2;
+    myNodes1.assign( face1->begin_nodes(), face1->end_nodes() );
+    myNodes2.assign( face2->begin_nodes(), face2->end_nodes() );
+
+    const gp_XYZ& n1 = myNormals[ face1->GetID() ];
+    const gp_XYZ& n2 = myNormals[ face2->GetID() ];
+
+    // check if triangles intersect
+    int iNotOnPlane1, iNotOnPlane2;
+    const double d2 = -( n2 * myNodes2[0]);
+    if ( !isPlaneIntersected( n2, d2, myNodes1, myDist1, myNbOnPlane1, iNotOnPlane1 ))
+      return;
+    const double d1 = -( n1 * myNodes1[0]);
+    if ( !isPlaneIntersected( n1, d1, myNodes2, myDist2, myNbOnPlane2, iNotOnPlane2 ))
+      return;
+
+    if ( myNbOnPlane1 == 3 || myNbOnPlane2 == 3 )// triangles are co-planar
+    {
+      setPlaneIndices( myNbOnPlane1 == 3 ? n2 : n1 ); // choose indices on an axis-aligned plane
+      cutCoplanar();
+    }
+    else if ( nbCommonNodes < 2 ) // triangle planes intersect
+    {
+      gp_XYZ lineDir = n1 ^ n2; // intersection line
+
+      // check if intervals of intersections of triangles with lineDir overlap
+
+      double u1[2], u2 [2]; // parameters on lineDir of edge intersection points { minU, maxU }
+      int   iE1[2], iE2[2]; // indices of edges
+      int iMaxCoo = MaxIndex( lineDir );
+      computeIntervals( myNodes1, myDist1, myNbOnPlane1, iMaxCoo, u1, iE1 );
+      computeIntervals( myNodes2, myDist2, myNbOnPlane2, iMaxCoo, u2, iE2 );
+      if ( u1[1] < u2[0] - myTol || u2[1] < u1[0] - myTol )
+        return; // intervals do not overlap
+
+      // make intersection nodes
+
+      const SMDS_MeshNode *l1n1, *l1n2, *l2n1, *l2n2;
+      CutLink link1; // intersection with smaller u on lineDir
+      computeIntPoint( u1[0], u2[0], iE1[0], iE2[0], link1, l1n1, l1n2 );
+      CutLink link2; // intersection with larger u on lineDir
+      computeIntPoint( -u1[1], -u2[1], iE1[1], iE2[1], link2, l2n1, l2n2 );
+
+      const CutFace& cf1 = myCutFaces.Added( CutFace( face1 ));
+      const CutFace& cf2 = myCutFaces.Added( CutFace( face2 ));
+
+      if ( coincide( link1.myIntNode, link2.myIntNode, myTol ))
+      {
+        // intersection is a point
+        if ( link1.IntNode() && link2.IntNode() )
+          replaceIntNode( link1.IntNode(), link2.IntNode() );
+
+        CutLink* link = link2.IntNode() ? &link2 : &link1;
+        if ( !link->IntNode() )
+        {
+          gp_XYZ p = 0.5 * ( link1.myIntNode + link2.myIntNode );
+          link->myIntNode.Set( createNode( p ));
+        }
+        if ( !link1.IntNode() ) link1.myIntNode = link2.myIntNode;
+        if ( !link2.IntNode() ) link2.myIntNode = link1.myIntNode;
+
+        cf1.AddPoint( link1, link2, myTol );
+        cf2.AddPoint( link1, link2, myTol );
+      }
+      else
+      {
+        // intersection is a line segment
+        if ( !link1.IntNode() )
+          link1.myIntNode.Set( createNode( link1.myIntNode ));
+        if ( !link2.IntNode() )
+          link2.myIntNode.Set( createNode( link2.myIntNode ));
+
+        cf1.AddEdge( link1, link2, face2, myNbOnPlane1, iNotOnPlane1 );
+        if ( l1n1 ) link1.Set( l1n1, l1n2, face2 );
+        if ( l2n1 ) link2.Set( l2n1, l2n2, face2 );
+        cf2.AddEdge( link1, link2, face1, myNbOnPlane2, iNotOnPlane2 );
+
+        // add intersections to a link collinear with the intersection line
+        if ( myNbOnPlane1 == 2 && ( link1.myFace != face2 || link2.myFace != face2 ))
+          cutCollinearLink( iNotOnPlane1, myNodes1, face2, link1, link2 );
+
+        if ( myNbOnPlane2 == 2 && ( link1.myFace != face1 || link2.myFace != face1 ))
+          cutCollinearLink( iNotOnPlane2, myNodes2, face1, link1, link2 );
+      }
+
+      addLink( link1 );
+      addLink( link2 );
+
+    } // non co-planar case
+
+    return;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Intersect two 2D line segments
+   */
+  //================================================================================
+
+  bool Intersector::intersectEdgeEdge( const gp_XY s1p0, const gp_XY s1p1,
+                                       const gp_XY s2p0, const gp_XY s2p1,
+                                       double &    t1,   double &    t2,
+                                       bool &      isCollinear )
+  {
+    gp_XY u = s1p1 - s1p0;
+    gp_XY v = s2p1 - s2p0;
+    gp_XY w = s1p0 - s2p0;
+    double perpDotUV = u * gp_XY( -v.Y(), v.X() );
+    double perpDotVW = v * gp_XY( -w.Y(), w.X() );
+    double perpDotUW = u * gp_XY( -w.Y(), w.X() );
+    double        u2 = u.SquareModulus();
+    double        v2 = v.SquareModulus();
+    if ( u2 < myEps * myEps || v2 < myEps * myEps )
+      return false;
+    if ( perpDotUV * perpDotUV / u2 / v2 < 1e-6 ) // cos ^ 2
+    {
+      if ( !isCollinear )
+        return false; // no need in collinear solution
+      if ( perpDotUW * perpDotUW / u2 > myTol * myTol )
+        return false; // parallel
+
+      // collinear
+      gp_XY w2 = s1p1 - s2p0;
+      if ( Abs( v.X()) + Abs( u.X()) > Abs( v.Y()) + Abs( u.Y())) {
+        t1 = w.X() / v.X();  // params on segment 2
+        t2 = w2.X() / v.X();
+      }
+      else {
+        t1 = w.Y() / v.Y();
+        t2 = w2.Y() / v.Y();
+      }
+      if ( Max( t1,t2 ) <= 0 || Min( t1,t2 ) >= 1 )
+        return false; // no overlap
+      return true;
+    }
+    isCollinear = false;
+
+    t1 = perpDotVW / perpDotUV; // param on segment 1
+    if ( t1 < 0. || t1 > 1. )
+      return false; // intersection not within the segment
+
+    t2 = perpDotUW / perpDotUV; // param on segment 2
+    if ( t2 < 0. || t2 > 1. )
+      return false; // intersection not within the segment
+
+    return true;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Intersect two edges of co-planar triangles
+   *  \param [inout] iE1 - edge index of triangle 1
+   *  \param [inout] iE2 - edge index of triangle 2
+   *  \param [inout] intPoints - intersection points
+   *  \param [inout] nbIntPoints - nb of found intersection points
+   */
+  //================================================================================
+
+  bool Intersector::intersectEdgeEdge( int iE1, int iE2, IntPoint2D& intPoint )
+  {
+    int i01 = iE1, i11 = ( iE1 + 1 ) % 3;
+    int i02 = iE2, i12 = ( iE2 + 1 ) % 3;
+    if (( !intPoint.myIsCollinear ) &&
+        ( myNodes1[ i01 ] == myNodes2[ i02 ] ||
+          myNodes1[ i01 ] == myNodes2[ i12 ] ||
+          myNodes1[ i11 ] == myNodes2[ i02 ] ||
+          myNodes1[ i11 ] == myNodes2[ i12 ] ))
+      return false;
+
+    // segment 1
+    gp_XY s1p0 = p2D( myNodes1[ i01 ]);
+    gp_XY s1p1 = p2D( myNodes1[ i11 ]);
+
+    // segment 2
+    gp_XY s2p0 = p2D( myNodes2[ i02 ]);
+    gp_XY s2p1 = p2D( myNodes2[ i12 ]);
+
+    double t1, t2;
+    if ( !intersectEdgeEdge( s1p0,s1p1, s2p0,s2p1, t1, t2, intPoint.myIsCollinear ))
+      return false;
+
+    intPoint.myEdgeInd[0] = iE1;
+    intPoint.myEdgeInd[1] = iE2;
+    intPoint.myU[0] = t1;
+    intPoint.myU[1] = t2;
+    (gp_XYZ&)intPoint.myNode = myNodes1[i01] * ( 1 - t1 ) + myNodes1[i11] * t1;
+
+    if ( intPoint.myIsCollinear )
+      return true;
+
+    // try to find existing node at intPoint.myNode
+
+    if ( myNodes1[ i01 ] == myNodes2[ i02 ] ||
+         myNodes1[ i01 ] == myNodes2[ i12 ] ||
+         myNodes1[ i11 ] == myNodes2[ i02 ] ||
+         myNodes1[ i11 ] == myNodes2[ i12 ] )
+      return false;
+
+    const double coincTol = myTol * 1e-3;
+
+    CutLink link1( myNodes1[i01].Node(), myNodes1[i11].Node(), myFace2 );
+    CutLink link2( myNodes2[i02].Node(), myNodes2[i12].Node(), myFace1 );
+
+    SMESH_NodeXYZ& n1 = myNodes1[ t1 < 0.5 ? i01 : i11 ];
+    bool same1 = coincide( n1, intPoint.myNode, coincTol );
+    if ( same1 )
+    {
+      link2.myIntNode = intPoint.myNode = n1;
+      addLink( link2 );
+    }
+    SMESH_NodeXYZ& n2 = myNodes2[ t2 < 0.5 ? i02 : i12 ];
+    bool same2 = coincide( n2, intPoint.myNode, coincTol );
+    if ( same2 )
+    {
+      link1.myIntNode = intPoint.myNode = n2;
+      addLink( link1 );
+      if ( same1 )
+      {
+        replaceIntNode( n1.Node(), n2.Node() );
+        return false;
+      }
+      return true;
+    }
+    if ( same1 )
+      return true;
+
+    link1.myIntNode = intPoint.myNode;
+    if ( findLink( link1 ))
+    {
+      intPoint.myNode = link2.myIntNode = link1.myIntNode;
+      addLink( link2 );
+      return true;
+    }
+
+    link2.myIntNode = intPoint.myNode;
+    if ( findLink( link2 ))
+    {
+      intPoint.myNode = link1.myIntNode = link2.myIntNode;
+      addLink( link1 );
+      return true;
+    }
+
+    for ( int is2nd = 0; is2nd < 2; ++is2nd )
+    {
+      const SMDS_MeshElement* f = is2nd ? myFace1 : myFace2;
+      const CutFace&         cf = myCutFaces.Added( CutFace( is2nd ? myFace2 : myFace1 ));
+      for ( size_t i = 0; i < cf.myLinks.size(); ++i )
+        if ( cf.myLinks[i].myFace == f &&
+             //cf.myLinks[i].myIndex != EdgePart::_COPLANAR &&
+             coincide( intPoint.myNode, SMESH_NodeXYZ( cf.myLinks[i].myNode1 ), coincTol ))
+        {
+          intPoint.myNode.Set( cf.myLinks[i].myNode1 );
+          return true;
+        }
+    }
+
+    // make a new node
+
+    intPoint.myNode._node = createNode( intPoint.myNode );
+    link1.myIntNode = link2.myIntNode = intPoint.myNode;
+    addLink( link1 );
+    addLink( link2 );
+
+    return true;
+  }
+
+
+  //================================================================================
+  /*!
+   * \brief Check if a point is contained in a triangle
+   */
+  //================================================================================
+
+  bool Intersector::isPointInTriangle( const gp_XYZ& p, const std::vector< SMESH_NodeXYZ >& nodes )
+  {
+    double bc1, bc2;
+    SMESH_MeshAlgos::GetBarycentricCoords( p2D( p ),
+                                           p2D( nodes[0] ), p2D( nodes[1] ), p2D( nodes[2] ),
+                                           bc1, bc2 );
+    return ( 0. < bc1 && 0. < bc2 && bc1 + bc2 < 1. );
+  }
+
+  //================================================================================
+  /*!
+   * \brief Intersect two co-planar faces
+   */
+  //================================================================================
+
+  void Intersector::cutCoplanar()
+  {
+    // find intersections of edges
+
+    IntPoint2D intPoints[ 6 ];
+    int      nbIntPoints = 0;
+    for ( int iE1 = 0; iE1 < 3; ++iE1 )
+    {
+      int maxNbIntPoints = nbIntPoints + 2;
+      for ( int iE2 = 0; iE2 < 3 &&  nbIntPoints < maxNbIntPoints; ++iE2 )
+        nbIntPoints += intersectEdgeEdge( iE1, iE2, intPoints[ nbIntPoints ]);
+    }
+    const int minNbOnPlane = Min( myNbOnPlane1, myNbOnPlane2 );
+
+    if ( nbIntPoints == 0 ) // no intersections of edges
+    {
+      bool is1in2;
+      if      ( isPointInTriangle( myNodes1[0], myNodes2 )) // face2 includes face1
+        is1in2 = true;
+      else if ( isPointInTriangle( myNodes2[0], myNodes1 )) // face1 includes face2
+        is1in2 = false;
+      else
+        return;
+
+      // add edges of an inner triangle to an outer one
+
+      const std::vector< SMESH_NodeXYZ >& nodesIn = is1in2 ? myNodes1 : myNodes2;
+      const SMDS_MeshElement*             faceOut = is1in2 ? myFace2  : myFace1;
+      const SMDS_MeshElement*              faceIn = is1in2 ? myFace1  : myFace2;
+
+      const CutFace& outFace = myCutFaces.Added( CutFace( faceOut ));
+      CutLink link1( nodesIn.back().Node(), nodesIn.back().Node(), faceOut );
+      CutLink link2( nodesIn.back().Node(), nodesIn.back().Node(), faceOut );
+
+      link1.myIntNode = nodesIn.back();
+      for ( size_t i = 0; i < nodesIn.size(); ++i )
+      {
+        link2.myIntNode = nodesIn[ i ];
+        outFace.AddEdge( link1, link2, faceIn, minNbOnPlane );
+        link1.myIntNode = link2.myIntNode;
+      }
+    }
+    else
+    {
+      // add parts of edges to a triangle including them
+
+      CutLink link1, link2;
+      IntPoint2D ip0, ip1;
+      ip0.myU[0] = ip0.myU[1] = 0.;
+      ip1.myU[0] = ip1.myU[1] = 1.;
+      ip0.myEdgeInd[0] = ip0.myEdgeInd[1] = ip1.myEdgeInd[0] = ip1.myEdgeInd[1] = 0;
+
+      for ( int isFromFace1 = 0; isFromFace1 < 2; ++isFromFace1 )
+      {
+        const SMDS_MeshElement*                faceTo = isFromFace1 ? myFace2  : myFace1;
+        const SMDS_MeshElement*              faceFrom = isFromFace1 ? myFace1  : myFace2;
+        const std::vector< SMESH_NodeXYZ >&   nodesTo = isFromFace1 ? myNodes2 : myNodes1;
+        const std::vector< SMESH_NodeXYZ >& nodesFrom = isFromFace1 ? myNodes1 : myNodes2;
+        const int                                 iTo = isFromFace1 ? 1 : 0;
+        const int                               iFrom = isFromFace1 ? 0 : 1;
+        //const int                       nbOnPlaneFrom = isFromFace1 ? myNbOnPlane1 : myNbOnPlane2;
+
+        const CutFace* cutFaceTo   = & myCutFaces.Added( CutFace( faceTo ));
+        // const CutFace* cutFaceFrom = 0;
+        // if ( nbOnPlaneFrom > minNbOnPlane )
+        //   cutFaceFrom = & myCutFaces.Added( CutFace( faceTo ));
+
+        link1.myFace = link2.myFace = faceTo;
+
+        IntPoint2DCompare ipCompare( iFrom );
+        TIntPointPtrSet pointsOnEdge( ipCompare ); // IntPoint2D sorted by parameter on edge
+
+        for ( size_t iE = 0; iE < nodesFrom.size(); ++iE )
+        {
+          // get parts of an edge iE
+
+          ip0.myEdgeInd[ iTo ] = iE;
+          ip1.myEdgeInd[ iTo ] = ( iE + 1 ) % nodesFrom.size();
+          ip0.myNode = nodesFrom[ ip0.myEdgeInd[ iTo ]];
+          ip1.myNode = nodesFrom[ ip1.myEdgeInd[ iTo ]];
+
+          pointsOnEdge.clear();
+
+          for ( int iP = 0; iP < nbIntPoints; ++iP )
+            if ( intPoints[ iP ].myEdgeInd[ iFrom ] == iE )
+              pointsOnEdge.insert( & intPoints[ iP ] );
+
+          pointsOnEdge.insert( pointsOnEdge.begin(), & ip0 );
+          pointsOnEdge.insert( pointsOnEdge.end(),   & ip1 );
+
+          // add edge parts to faceTo
+
+          TIntPointPtrSet::iterator ipIt = pointsOnEdge.begin() + 1;
+          for ( ; ipIt != pointsOnEdge.end(); ++ipIt )
+          {
+            const IntPoint2D* p1 = *(ipIt-1);
+            const IntPoint2D* p2 = *ipIt;
+            gp_XYZ middle = 0.5 * ( p1->myNode + p2->myNode );
+            if ( isPointInTriangle( middle, nodesTo ))
+            {
+              p1->InitLink( link1, iTo, ( p1 != & ip0 ) ? nodesTo : nodesFrom );
+              p2->InitLink( link2, iTo, ( p2 != & ip1 ) ? nodesTo : nodesFrom );
+              cutFaceTo->AddEdge( link1, link2, faceFrom, minNbOnPlane );
+
+              // if ( cutFaceFrom )
+              // {
+              //   p1->InitLink( link1, iFrom, nodesFrom );
+              //   p2->InitLink( link2, iFrom, nodesFrom );
+              //   cutFaceTo->AddEdge( link1, link2, faceTo, minNbOnPlane );
+              // }
+            }
+          }
+        }
+      }
+    }
+    return;
+
+  } // Intersector::cutCoplanar()
+
+  //================================================================================
+  /*!
+   * \brief Intersect edges added to myCutFaces
+   */
+  //================================================================================
+
+  void Intersector::intersectNewEdges( const CutFace& cf )
+  {
+    IntPoint2D intPoint;
+
+    if ( cf.NbInternalEdges() < 2 )
+      return;
+
+    const gp_XYZ& faceNorm = myNormals[ cf.myInitFace->GetID() ];
+    setPlaneIndices( faceNorm ); // choose indices on an axis-aligned plane
+
+    size_t limit = cf.myLinks.size() * cf.myLinks.size() * 2;
+
+    for ( size_t i1 = 3; i1 < cf.myLinks.size(); ++i1 )
+    {
+      if ( !cf.myLinks[i1].IsInternal() )
+        continue;
+
+      myIntPointSet.clear();
+      for ( size_t i2 = i1 + 2; i2 < cf.myLinks.size(); ++i2 )
+      {
+        if ( !cf.myLinks[i2].IsInternal() )
+          continue;
+
+        // prepare to intersection
+        myFace1     = cf.myLinks[i1].myFace;
+        myNodes1[0] = cf.myLinks[i1].myNode1;
+        myNodes1[1] = cf.myLinks[i1].myNode2;
+        myFace2     = cf.myLinks[i2].myFace;
+        myNodes2[0] = cf.myLinks[i2].myNode1;
+        myNodes2[1] = cf.myLinks[i2].myNode2;
+
+        // intersect
+        intPoint.myIsCollinear = true; // to find collinear solutions
+        if ( intersectEdgeEdge( 0, 0, intPoint ))
+        {
+          if ( cf.myLinks[i1].IsSame( cf.myLinks[i2] )) // remove i2
+          {
+            cf.myLinks[i1].ReplaceCoplanar( cf.myLinks[i2] );
+            cf.myLinks.erase( cf.myLinks.begin() + i2, cf.myLinks.begin() + i2 + 2 );
+            --i2;
+            continue;
+          }
+          if ( !intPoint.myIsCollinear )
+          {
+            intPoint.myEdgeInd[1] = i2;
+            myIntPointSet.insert( intPoint );
+          }
+          else // if ( intPoint.myIsCollinear ) // overlapping edges
+          {
+            myIntPointSet.clear(); // to recompute
+
+            if ( intPoint.myU[0] > intPoint.myU[1] ) // orient in same direction
+            {
+              std::swap( intPoint.myU[0], intPoint.myU[1] );
+              std::swap( myNodes1[0], myNodes1[1] );
+            }
+            // replace _COPLANAR by _INTERNAL
+            cf.myLinks[i1].ReplaceCoplanar( cf.myLinks[i1+1] );
+            cf.myLinks[i2].ReplaceCoplanar( cf.myLinks[i2+1] );
+
+            if ( coincide( myNodes1[0], myNodes2[0], myTol ) &&
+                 coincide( myNodes1[1], myNodes2[1], myTol ))
+            {
+              cf.myLinks.erase( cf.myLinks.begin() + i2, cf.myLinks.begin() + i2 + 2 );
+              --i2;
+              continue;
+            }
+
+            EdgePart common = cf.myLinks[i1];
+            common.ReplaceCoplanar( cf.myLinks[i2] );
+
+            const SMDS_MeshNode* n1 = myNodes1[0].Node(); // end nodes of an overlapping part
+            const SMDS_MeshNode* n2 = myNodes1[1].Node();
+            size_t i3 = cf.myLinks.size();
+
+            if ( myNodes1[0] != myNodes2[0] ) // a part before the overlapping one
+            {
+              if ( intPoint.myU[0] < 0 )
+                cf.myLinks[i1].Set( myNodes1[0].Node(), myNodes2[0].Node(),
+                                    cf.myLinks[i1].myFace, cf.myLinks[i1].myIndex );
+              else
+                cf.myLinks[i1].Set( myNodes2[0].Node(), myNodes1[0].Node(),
+                                    cf.myLinks[i2].myFace, cf.myLinks[i2].myIndex );
+
+              cf.myLinks[i1+1].Set( cf.myLinks[i1].myNode2,
+                                    cf.myLinks[i1].myNode1,
+                                    cf.myLinks[i1].myFace,
+                                    cf.myLinks[i1].myIndex);
+              n1 = cf.myLinks[i1].myNode2;
+            }
+            else
+              i3 = i1;
+
+            if ( myNodes1[1] != myNodes2[1] ) // a part after the overlapping one
+            {
+              if ( intPoint.myU[1] < 1 )
+                cf.myLinks[i2].Set( myNodes1[1].Node(), myNodes2[1].Node(),
+                                    cf.myLinks[i2].myFace, cf.myLinks[i2].myIndex );
+              else
+                cf.myLinks[i2].Set( myNodes2[1].Node(), myNodes1[1].Node(),
+                                    cf.myLinks[i1].myFace, cf.myLinks[i1].myIndex );
+
+              cf.myLinks[i2+1].Set( cf.myLinks[i2].myNode2,
+                                    cf.myLinks[i2].myNode1,
+                                    cf.myLinks[i2].myFace,
+                                    cf.myLinks[i2].myIndex);
+              n2 = cf.myLinks[i2].myNode1;
+            }
+            else
+              i3 = i2;
+
+            if ( i3 == cf.myLinks.size() )
+              cf.myLinks.resize( i3 + 2 );
+
+            cf.myLinks[i3].Set  ( n1, n2, common.myFace, common.myIndex );
+            cf.myLinks[i3+1].Set( n2, n1, common.myFace, common.myIndex );
+
+            i2 = i1 + 1; // recheck modified i1
+            continue;
+          }
+          //else
+          // {
+          //   // remember a new node
+          //   CutLink link1( myNodes1[0].Node(), myNodes1[1].Node(), cf.myInitFace );
+          //   CutLink link2( myNodes2[0].Node(), myNodes2[1].Node(), cf.myInitFace );
+          //   link2.myIntNode = link1.myIntNode = intPoint.myNode;
+          //   addLink( link1 );
+          //   addLink( link2 );
+
+          //   // split edges
+          //   size_t i = cf.myLinks.size();
+          //   if ( intPoint.myNode != cf.myLinks[ i1 ].myNode1 &&
+          //        intPoint.myNode != cf.myLinks[ i1 ].myNode2 )
+          //   {
+          //     cf.myLinks.push_back( cf.myLinks[ i1 ]);
+          //     cf.myLinks.push_back( cf.myLinks[ i1 + 1 ]);
+          //     cf.myLinks[ i1 ].myNode2 = cf.myLinks[ i1 + 1 ].myNode1 = intPoint.Node();
+          //     cf.myLinks[ i  ].myNode1 = cf.myLinks[ i  + 1 ].myNode2 = intPoint.Node();
+          //   }
+          //   if ( intPoint.myNode != cf.myLinks[ i2 ].myNode1 &&
+          //        intPoint.myNode != cf.myLinks[ i2 ].myNode2 )
+          //   {
+          //     i = cf.myLinks.size();
+          //     cf.myLinks.push_back( cf.myLinks[ i2 ]);
+          //     cf.myLinks.push_back( cf.myLinks[ i2 + 1 ]);
+          //     cf.myLinks[ i2 ].myNode2 = cf.myLinks[ i2 + 1 ].myNode1 = intPoint.Node();
+          //     cf.myLinks[ i  ].myNode1 = cf.myLinks[ i  + 1 ].myNode2 = intPoint.Node();
+          //   }
+          // }
+
+        } // if ( intersectEdgeEdge( 0, 0, intPoint ))
+
+        ++i2;
+        --limit;
+      }
+
+      // split i1 edge and all edges it intersects
+      // don't do it inside intersection loop in order not to loose direction of i1 edge
+      if ( !myIntPointSet.empty() )
+      {
+        cf.myLinks.reserve( cf.myLinks.size() + myIntPointSet.size() * 2 + 2 );
+
+        EdgePart* edge1 = &cf.myLinks[ i1 ];
+        EdgePart* twin1 = &cf.myLinks[ i1 + 1 ];
+
+        TIntPointSet::iterator ipIt = myIntPointSet.begin();
+        for ( ; ipIt != myIntPointSet.end(); ++ipIt ) // int points sorted on i1 edge
+        {
+          size_t i = cf.myLinks.size();
+          if ( ipIt->myNode != edge1->myNode1 &&
+               ipIt->myNode != edge1->myNode2 )
+          {
+            cf.myLinks.push_back( *edge1 );
+            cf.myLinks.push_back( *twin1 );
+            edge1->myNode2          = twin1->myNode1              = ipIt->Node();
+            cf.myLinks[ i ].myNode1 = cf.myLinks[ i + 1 ].myNode2 = ipIt->Node();
+            edge1 = & cf.myLinks[ i ];
+            twin1 = & cf.myLinks[ i + 1 ];
+          }
+          size_t i2 = ipIt->myEdgeInd[1];
+          if ( ipIt->myNode != cf.myLinks[ i2 ].myNode1 &&
+               ipIt->myNode != cf.myLinks[ i2 ].myNode2 )
+          {
+            i = cf.myLinks.size();
+            cf.myLinks.push_back( cf.myLinks[ i2 ]);
+            cf.myLinks.push_back( cf.myLinks[ i2 + 1 ]);
+            cf.myLinks[ i2 ].myNode2 = cf.myLinks[ i2 + 1 ].myNode1 = ipIt->Node();
+            cf.myLinks[ i  ].myNode1 = cf.myLinks[ i  + 1 ].myNode2 = ipIt->Node();
+          }
+        }
+        if ( cf.myLinks.size() >= limit )
+          throw SALOME_Exception( "Infinite loop in Intersector::intersectNewEdges()" );
+      }
+      ++i1; // each internal edge encounters twice
+    }
+    return;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Split intersected faces
+   */
+  //================================================================================
+
+  void Intersector::MakeNewFaces( SMESH_MeshAlgos::TEPairVec& theNew2OldFaces,
+                                  SMESH_MeshAlgos::TNPairVec& theNew2OldNodes,
+                                  const double                theSign)
+  {
+    // unmark all nodes except intersection ones
+
+    for ( SMDS_NodeIteratorPtr nIt = myMesh->nodesIterator(); nIt->more(); )
+    {
+      const SMDS_MeshNode* n = nIt->next();
+      if ( n->isMarked() && n->GetID()-1 < (int) theNew2OldNodes.size() )
+        n->setIsMarked( false );
+    }
+    // SMESH_MeshAlgos::MarkElems( myMesh->nodesIterator(), false );
+
+    TCutLinkMap::const_iterator cutLinksIt = myCutLinks.cbegin();
+    // for ( ; cutLinksIt != myCutLinks.cend(); ++cutLinksIt )
+    // {
+    //   const CutLink& link = *cutLinksIt;
+    //   if ( link.IntNode() && link.IntNode()->GetID()-1 < (int) theNew2OldNodes.size() )
+    //     link.IntNode()->setIsMarked( true );
+    // }
+
+    // intersect edges added to myCutFaces
+
+    TCutFaceMap::const_iterator cutFacesIt = myCutFaces.cbegin();
+    for ( ; cutFacesIt != myCutFaces.cend(); ++cutFacesIt )
+    {
+      const CutFace& cf = *cutFacesIt;
+      cf.ReplaceNodes( myRemove2KeepNodes );
+      intersectNewEdges( cf );
+    }
+
+    // make new faces
+
+    EdgeLoopSet                            loopSet;
+    SMESH_MeshAlgos::Triangulate           triangulator;
+    std::vector< EdgePart >                cutOffLinks;
+    TLinkMap                               cutOffCoplanarLinks;
+    std::vector< const CutFace* >          touchedFaces;
+    SMESH_MeshAlgos::TEPairVec::value_type new2OldTria;
+    CutFace                                cutFace(0);
+    std::vector< const SMDS_MeshNode* >    nodes;
+    std::vector<const SMDS_MeshElement *>  faces;
+
+    cutOffLinks.reserve( myCutFaces.Extent() * 2 );
+
+    for ( cutFacesIt = myCutFaces.cbegin(); cutFacesIt != myCutFaces.cend(); ++cutFacesIt )
+    {
+      const CutFace& cf = *cutFacesIt;
+      if ( !cf.IsCut() )
+      {
+        touchedFaces.push_back( & cf );
+        continue;
+      }
+
+      const gp_XYZ& normal = myNormals[ cf.myInitFace->GetID() ];
+
+      // form loops of new faces
+      cf.ReplaceNodes( myRemove2KeepNodes );
+      cf.MakeLoops( loopSet, normal );
+
+      // avoid loops that are not connected to boundary edges of cf.myInitFace
+      if ( cf.RemoveInternalLoops( loopSet ))
+      {
+        intersectNewEdges( cf );
+        cf.MakeLoops( loopSet, normal );
+      }
+      // erase loops that are cut off by face intersections
+      cf.CutOffLoops( loopSet, theSign, myNormals, cutOffLinks, cutOffCoplanarLinks );
+
+      int index = cf.myInitFace->GetID(); // index in theNew2OldFaces
+
+      const SMDS_MeshElement* tria;
+      for ( size_t iL = 0; iL < loopSet.myNbLoops; ++iL )
+      {
+        EdgeLoop& loop = loopSet.myLoops[ iL ];
+        if ( loop.myLinks.size() == 0 )
+          continue;
+
+        int nbTria  = triangulator.GetTriangles( &loop, nodes );
+        int nbNodes = 3 * nbTria;
+        for ( int i = 0; i < nbNodes; i += 3 )
+        {
+          if ( nodes[i] == nodes[i+1] || nodes[i] == nodes[i+2] || nodes[i+1] == nodes[i+2] )
+          {
+#ifdef _DEBUG_
+            std::cerr << "BAD tria" << std::endl;
+            cf.Dump();
+#endif
+            continue;
+          }
+          if (!( tria = myMesh->FindFace( nodes[i], nodes[i+1], nodes[i+2] )))
+            tria = myMesh->AddFace( nodes[i], nodes[i+1], nodes[i+2] );
+          tria->setIsMarked( true ); // not to remove it
+
+          new2OldTria = std::make_pair( tria, theNew2OldFaces[ index ].second );
+          if ( tria->GetID() < (int)theNew2OldFaces.size() )
+            theNew2OldFaces[ tria->GetID() ] = new2OldTria;
+          else
+            theNew2OldFaces.push_back( new2OldTria );
+
+          if ( index == tria->GetID() )
+            index = 0; // do not remove tria
+        }
+      }
+      theNew2OldFaces[ index ].first = 0;
+    }
+
+    // remove split faces
+    for ( size_t id = 1; id < theNew2OldFaces.size(); ++id )
+    {
+      if ( theNew2OldFaces[id].first )
+        continue;
+      if ( const SMDS_MeshElement* f = myMesh->FindElement( id ))
+        myMesh->RemoveFreeElement( f );
+    }
+
+    // remove face connected to cut off parts of cf.myInitFace
+
+    nodes.resize(2);
+    for ( size_t i = 0; i < cutOffLinks.size(); ++i )
+    {
+      //break;
+      nodes[0] = cutOffLinks[i].myNode1;
+      nodes[1] = cutOffLinks[i].myNode2;
+
+      if ( nodes[0] != nodes[1] &&
+           myMesh->GetElementsByNodes( nodes, faces ))
+      {
+        if ( cutOffLinks[i].myFace &&
+             cutOffLinks[i].myIndex != EdgePart::_COPLANAR &&
+             faces.size() == 2 )
+          continue;
+        for ( size_t iF = 0; iF < faces.size(); ++iF )
+        {
+          int index = faces[iF]->GetID();
+          // if ( //faces[iF]->isMarked()         ||  // kept part of cutFace
+          //      !theNew2OldFaces[ index ].first ) // already removed
+          //   continue;
+          cutFace.myInitFace = faces[iF];
+          // if ( myCutFaces.Contains( cutFace )) // keep cutting faces needed in CutOffLoops()
+          // {
+          //   if ( !myCutFaces.Added( cutFace ).IsCut() )
+          //     theNew2OldFaces[ index ].first = 0;
+          //   continue;
+          // }
+          cutFace.myLinks.clear();
+          cutFace.InitLinks();
+          for ( size_t iL = 0; iL < cutFace.myLinks.size(); ++iL )
+            if ( !cutOffLinks[i].IsSame( cutFace.myLinks[ iL ]))
+              cutOffLinks.push_back( cutFace.myLinks[ iL ]);
+
+          theNew2OldFaces[ index ].first = 0;
+          myMesh->RemoveFreeElement( faces[iF] );
+        }
+      }
+    }
+
+    // replace nodes in touched faces
+
+    // treat touched faces
+    for ( size_t i = 0; i < touchedFaces.size(); ++i )
+    {
+      const CutFace& cf = *touchedFaces[i];
+
+      int index = cf.myInitFace->GetID(); // index in theNew2OldFaces
+      if ( !theNew2OldFaces[ index ].first )
+        continue; // already cut off
+
+      if ( !cf.ReplaceNodes( myRemove2KeepNodes ))
+        continue; // just keep as is
+
+      if ( cf.myLinks.size() == 3 )
+      {
+        const SMDS_MeshElement* tria = myMesh->AddFace( cf.myLinks[0].myNode1,
+                                                        cf.myLinks[1].myNode1,
+                                                        cf.myLinks[2].myNode1 );
+        new2OldTria = std::make_pair( tria, theNew2OldFaces[ index ].second );
+        if ( tria->GetID() < (int)theNew2OldFaces.size() )
+          theNew2OldFaces[ tria->GetID() ] = new2OldTria;
+        else
+          theNew2OldFaces.push_back( new2OldTria );
+      }
+      theNew2OldFaces[ index ].first = 0;
+    }
+
+
+    // add used new nodes to theNew2OldNodes
+    SMESH_MeshAlgos::TNPairVec::value_type new2OldNode;
+    new2OldNode.second = NULL;
+    for ( cutLinksIt = myCutLinks.cbegin(); cutLinksIt != myCutLinks.cend(); ++cutLinksIt )
+    {
+      const CutLink& link = *cutLinksIt;
+      if ( link.IntNode() ) // && link.IntNode()->NbInverseElements() > 0 )
+      {
+        new2OldNode.first = link.IntNode();
+        theNew2OldNodes.push_back( new2OldNode );
+      }
+    }
+
+    return;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Debug
+   */
+  //================================================================================
+
+  void CutFace::Dump() const
+  {
+    std::cout << std::endl << "INI F " << myInitFace->GetID() << std::endl;
+    for ( size_t i = 0; i < myLinks.size(); ++i )
+      std::cout << "[" << i << "] ("
+                << char(( myLinks[i].IsInternal() ? 'j' : '0' ) + myLinks[i].myIndex ) << ") "
+                << myLinks[i].myNode1->GetID() << " - " << myLinks[i].myNode2->GetID()
+                << " " << ( myLinks[i].myFace ? 'F' : 'C' )
+                << ( myLinks[i].myFace ? myLinks[i].myFace->GetID() : 0 ) << " " << std::endl;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Add an edge cutting this face
+   *  \param [in] p1 - start point of the edge
+   *  \param [in] p2 - end point of the edge
+   *  \param [in] cutter - a face producing the added cut edge.
+   *  \param [in] nbOnPlane - nb of triangle nodes lying on the plane of the cutter face
+   */
+  //================================================================================
+
+  void CutFace::AddEdge( const CutLink&          p1,
+                         const CutLink&          p2,
+                         const SMDS_MeshElement* cutterFace,
+                         const int               nbOnPlane,
+                         const int               iNotOnPlane) const
+  {
+    int iN[2] = { myInitFace->GetNodeIndex( p1.IntNode() ),
+                  myInitFace->GetNodeIndex( p2.IntNode() ) };
+    if ( iN[0] >= 0 && iN[1] >= 0 )
+    {
+      // the cutting edge is a whole side
+      if ((  cutterFace && nbOnPlane < 3 ) &&
+          !( cutterFace->GetNodeIndex( p1.IntNode() ) >= 0 &&
+             cutterFace->GetNodeIndex( p2.IntNode() ) >= 0 ))
+      {
+        InitLinks();
+        myLinks[ Abs( iN[0] - iN[1] ) == 1 ? Min( iN[0], iN[1] ) : 2 ].myFace = cutterFace;
+      }
+      return;
+    }
+
+    if ( p1.IntNode() == p2.IntNode() )
+    {
+      AddPoint( p1, p2, 1e-10 );
+      return;
+    }
+
+    InitLinks();
+
+    // cut side edges by a new one
+
+    int iEOnPlane = ( nbOnPlane == 2 ) ? ( iNotOnPlane + 1 ) % 3  :  -1;
+
+    double dist[2];
+    for ( int is2nd = 0; is2nd < 2; ++is2nd )
+    {
+      const CutLink& p = is2nd ? p2 : p1;
+      dist[ is2nd ] = 0;
+      if ( iN[ is2nd ] >= 0 )
+        continue;
+
+      int iE = Max( iEOnPlane, myInitFace->GetNodeIndex( p.Node1() ));
+      if ( iE < 0 )
+        continue; // link of other face
+
+      SMESH_NodeXYZ n0 = myLinks[iE].myNode1;
+      dist[ is2nd ]    = ( n0 - p.myIntNode ).SquareModulus();
+
+      for ( size_t i = 0; i < myLinks.size(); ++i )
+        if ( myLinks[i].myIndex == iE )
+        {
+          double d1 = n0.SquareDistance( myLinks[i].myNode1 );
+          if ( d1 < dist[ is2nd ] )
+          {
+            double d2 = n0.SquareDistance( myLinks[i].myNode2 );
+            if ( dist[ is2nd ] < d2 )
+            {
+              myLinks.push_back( myLinks[i] );
+              myLinks.back().myNode1 = myLinks[i].myNode2 = p.IntNode();
+              break;
+            }
+          }
+        }
+    }
+
+    int state = nbOnPlane == 3 ? EdgePart::_COPLANAR : EdgePart::_INTERNAL;
+
+    // look for an existing equal edge
+    if ( nbOnPlane == 2 )
+    {
+      SMESH_NodeXYZ n0 = myLinks[ iEOnPlane ].myNode1;
+      if ( iN[0] >= 0 ) dist[0] = ( n0 - p1.myIntNode ).SquareModulus();
+      if ( iN[1] >= 0 ) dist[1] = ( n0 - p2.myIntNode ).SquareModulus();
+      if ( dist[0] > dist[1] )
+        std::swap( dist[0], dist[1] );
+      for ( size_t i = 0; i < myLinks.size(); ++i )
+      {
+        if ( myLinks[i].myIndex != iEOnPlane )
+          continue;
+        gp_XYZ mid = 0.5 * ( SMESH_NodeXYZ( myLinks[i].myNode1 ) +
+                             SMESH_NodeXYZ( myLinks[i].myNode2 ));
+        double d = ( n0 - mid ).SquareModulus();
+        if ( dist[0] < d && d < dist[1] )
+          myLinks[i].myFace = cutterFace;
+      }
+      return;
+    }
+    else
+    {
+      EdgePart newEdge; newEdge.Set( p1.IntNode(), p2.IntNode(), cutterFace, state );
+      for ( size_t i = 0; i < myLinks.size(); ++i )
+      {
+        if ( myLinks[i].IsSame( newEdge ))
+        {
+          // if ( !myLinks[i].IsInternal() )
+          //   myLinks[ i ].myFace = cutterFace;
+          // else
+          myLinks[ i   ].ReplaceCoplanar( newEdge );
+          myLinks[ i+1 ].ReplaceCoplanar( newEdge );
+          return;
+        }
+        i += myLinks[i].IsInternal();
+      }
+    }
+
+    size_t  i = myLinks.size();
+    myLinks.resize( i + 2 );
+    myLinks[ i   ].Set( p1.IntNode(), p2.IntNode(), cutterFace, state );
+    myLinks[ i+1 ].Set( p2.IntNode(), p1.IntNode(), cutterFace, state );
+  }
+
+  //================================================================================
+  /*!
+   * \brief Add a point cutting this face
+   */
+  //================================================================================
+
+  void CutFace::AddPoint( const CutLink& p1, const CutLink& p2, double tol ) const
+  {
+    if ( myInitFace->GetNodeIndex( p1.IntNode() ) >= 0 ||
+         myInitFace->GetNodeIndex( p2.IntNode() ) >= 0 )
+      return;
+
+    InitLinks();
+
+    const CutLink* link = &p1;
+    int iE = myInitFace->GetNodeIndex( link->Node1() );
+    if ( iE < 0 )
+    {
+      link = &p2;
+      iE = myInitFace->GetNodeIndex( link->Node1() );
+    }
+    if ( iE >= 0 )
+    {
+      // cut an existing edge by the point
+      SMESH_NodeXYZ n0 = link->Node1();
+      double         d = ( n0 - link->myIntNode ).SquareModulus();
+
+      for ( size_t i = 0; i < myLinks.size(); ++i )
+        if ( myLinks[i].myIndex == iE )
+        {
+          double d1 = n0.SquareDistance( myLinks[i].myNode1 );
+          if ( d1 < d )
+          {
+            double d2 = n0.SquareDistance( myLinks[i].myNode2 );
+            if ( d < d2 )
+            {
+              myLinks.push_back( myLinks[i] );
+              myLinks.back().myNode1 = myLinks[i].myNode2 = link->IntNode();
+              return;
+            }
+          }
+        }
+    }
+    else // point is inside the triangle
+    {
+      // // check if a point already added
+      // for ( size_t i = 3; i < myLinks.size(); ++i )
+      //   if ( myLinks[i].myNode1 == p1.IntNode() )
+      //     return;
+
+      // // create a link between the point and the closest corner node
+      // const SMDS_MeshNode* closeNode = myLinks[0].myNode1;
+      // double minDist = p1.myIntNode.SquareDistance( closeNode );
+      // for ( int i = 1; i < 3; ++i )
+      // {
+      //   double dist = p1.myIntNode.SquareDistance( myLinks[i].myNode1 );
+      //   if ( dist < minDist )
+      //   {
+      //     minDist = dist;
+      //     closeNode = myLinks[i].myNode1;
+      //   }
+      // }
+      // if ( minDist > tol * tol )
+      // {
+      //   size_t i = myLinks.size();
+      //   myLinks.resize( i + 2 );
+      //   myLinks[ i   ].Set( p1.IntNode(), closeNode );
+      //   myLinks[ i+1 ].Set( closeNode, p1.IntNode() );
+      // }
+    }
+  }
+
+  //================================================================================
+  /*!
+   * \brief Perform node replacement
+   */
+  //================================================================================
+
+  bool CutFace::ReplaceNodes( const TNNMap& theRm2KeepMap ) const
+  {
+    bool replaced = false;
+    for ( size_t i = 0; i < myLinks.size(); ++i )
+    {
+      while ( theRm2KeepMap.IsBound((Standard_Address) myLinks[i].myNode1 ))
+        replaced = ( myLinks[i].myNode1 = theRm2KeepMap((Standard_Address) myLinks[i].myNode1 ));
+
+      while ( theRm2KeepMap.IsBound((Standard_Address) myLinks[i].myNode2 ))
+        replaced = ( myLinks[i].myNode2 = theRm2KeepMap((Standard_Address) myLinks[i].myNode2 ));
+    }
+
+    //if ( replaced ) // remove equal links
+    {
+      for ( size_t i1 = 0; i1 < myLinks.size(); ++i1 )
+      {
+        if ( myLinks[i1].myNode1 == myLinks[i1].myNode2 )
+        {
+          myLinks.erase( myLinks.begin() + i1,
+                         myLinks.begin() + i1 + 1 + myLinks[i1].IsInternal() );
+          --i1;
+          continue;
+        }
+        size_t i2 = i1 + 1 + myLinks[i1].IsInternal();
+        for ( ; i2 < myLinks.size(); ++i2 )
+        {
+          if ( !myLinks[i2].IsInternal() )
+            continue;
+          if ( myLinks[i1].IsSame( myLinks[i2] ))
+          {
+            myLinks[i1].  ReplaceCoplanar( myLinks[i2] );
+            if ( myLinks[i1].IsInternal() )
+              myLinks[i1+1].ReplaceCoplanar( myLinks[i2+1] );
+            if ( !myLinks[i1].myFace && myLinks[i2].myFace )
+            {
+              myLinks[i1].  myFace = myLinks[i2].myFace;
+              if ( myLinks[i1].IsInternal() )
+                myLinks[i1+1].myFace = myLinks[i2+1].myFace;
+            }
+            myLinks.erase( myLinks.begin() + i2,
+                           myLinks.begin() + i2 + 2 );
+            --i2;
+            continue;
+          }
+          ++i2;
+        }
+        i1 += myLinks[i1].IsInternal();
+      }
+    }
+
+    return replaced;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Initialize myLinks with edges of myInitFace
+   */
+  //================================================================================
+
+  void CutFace::InitLinks() const
+  {
+    if ( !myLinks.empty() ) return;
+
+    int nbNodes = myInitFace->NbNodes();
+    myLinks.reserve( nbNodes * 2 );
+    myLinks.resize( nbNodes );
+
+    for ( int i = 0; i < nbNodes; ++i )
+    {
+      const SMDS_MeshNode* n1 = myInitFace->GetNode( i );
+      const SMDS_MeshNode* n2 = myInitFace->GetNodeWrap( i + 1);
+      myLinks[i].Set( n1, n2, 0, i );
+    }
+  }
+  
+  //================================================================================
+  /*!
+   * \brief Return number of internal edges
+   */
+  //================================================================================
+
+  int CutFace::NbInternalEdges() const
+  {
+    int nb = 0;
+    for ( size_t i = 3; i < myLinks.size(); ++i )
+      nb += myLinks[i].IsInternal();
+
+    return nb / 2; // each internal edge encounters twice
+  }
+
+  //================================================================================
+  /*!
+   * \brief Remove loops that are not connected to boundary edges of myFace by
+   *        adding edges connecting these loops to the boundary
+   */
+  //================================================================================
+
+  bool CutFace::RemoveInternalLoops( EdgeLoopSet& theLoops ) const
+  {
+    size_t nbReachedLoops = 0;
+
+    // count loops including boundary EdgeParts
+    for ( size_t iL = 0; iL < theLoops.myNbLoops; ++iL )
+    {
+      EdgeLoop& loop = theLoops.myLoops[ iL ];
+
+      for ( size_t iE = 0; iE < loop.myLinks.size(); ++iE )
+        if ( !loop.myLinks[ iE ]->IsInternal() )
+        {
+          nbReachedLoops += loop.SetConnected();
+          break;
+        }
+    }
+    if ( nbReachedLoops == theLoops.myNbLoops )
+      return false; // no unreachable loops
+
+
+    // try to reach all loops by propagating via internal edges shared by loops
+    size_t prevNbReached;
+    do
+    {
+      prevNbReached = nbReachedLoops;
+
+      for ( size_t iL = 0; iL < theLoops.myNbLoops; ++iL )
+      {
+        EdgeLoop& loop = theLoops.myLoops[ iL ];
+        if ( !loop.myIsBndConnected )
+          continue;
+
+        for ( size_t iE = 0; iE < loop.myLinks.size(); ++iE )
+          if ( loop.myLinks[ iE ]->IsInternal() )
+          {
+            const EdgePart* twinEdge = getTwin( loop.myLinks[ iE ]);
+            EdgeLoop*          loop2 = theLoops.GetLoopOf( twinEdge );
+            if ( loop2->SetConnected() && ++nbReachedLoops == theLoops.myNbLoops )
+              return false; // no unreachable loops
+          }
+      }
+    }
+    while ( prevNbReached < nbReachedLoops );
+
+
+    // add links connecting internal loops with the boundary ones
+
+    for ( size_t iL = 0; iL < theLoops.myNbLoops; ++iL )
+    {
+      EdgeLoop& loop = theLoops.myLoops[ iL ];
+      if ( loop.myIsBndConnected )
+        continue;
+
+      // find a pair of closest nodes
+      const SMDS_MeshNode *closestNode1, *closestNode2;
+      double minDist = 1e100;
+      for ( size_t iE = 0; iE < loop.myLinks.size(); ++iE )
+      {
+        SMESH_NodeXYZ n1 = loop.myLinks[ iE ]->myNode1;
+
+        for ( size_t i = 0; i < myLinks.size(); ++i )
+        {
+          if ( !loop.Contains( myLinks[i].myNode1 ))
+          {
+            double dist = n1.SquareDistance( myLinks[i].myNode1 );
+            if ( dist < minDist )
+            {
+              minDist = dist;
+              closestNode1 = loop.myLinks[ iE ]->myNode1;
+              closestNode2 = myLinks[i].myNode1;
+            }
+          }
+          if ( myLinks[i].IsInternal() )
+            ++i;
+        }
+      }
+
+      size_t i = myLinks.size();
+      myLinks.resize( i + 2 );
+      myLinks[ i   ].Set( closestNode1, closestNode2 );
+      myLinks[ i+1 ].Set( closestNode2, closestNode1 );
+    }
+
+    return true;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Return equal reversed edge
+   */
+  //================================================================================
+
+  EdgePart* CutFace::getTwin( const EdgePart* edge ) const
+  {
+    size_t i = edge - & myLinks[0];
+
+    if ( i > 2 && myLinks[ i-1 ].IsTwin( *edge ))
+      return & myLinks[ i-1 ];
+
+    if ( i+1 < myLinks.size() &&
+         myLinks[ i+1 ].IsTwin( *edge ))
+      return & myLinks[ i+1 ];
+
+    return 0;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Fill loops of edges
+   */
+  //================================================================================
+
+  void CutFace::MakeLoops( EdgeLoopSet& theLoops, const gp_XYZ& theFaceNorm ) const
+  {
+    theLoops.Init( myLinks );
+
+    if ( myLinks.size() == 3 )
+    {
+      theLoops.AddNewLoop();
+      theLoops.AddEdge( myLinks[0] );
+      theLoops.AddEdge( myLinks[1] );
+      theLoops.AddEdge( myLinks[2] );
+      return;
+    }
+
+    while ( !theLoops.AllEdgesUsed() )
+    {
+      theLoops.AddNewLoop();
+
+      // add 1st edge to a new loop
+      size_t i1;
+      for ( i1 = theLoops.myNbLoops - 1; i1 < myLinks.size(); ++i1 )
+        if ( theLoops.AddEdge( myLinks[i1] ))
+          break;
+
+      EdgePart*             lastEdge = & myLinks[ i1 ];
+      EdgePart*             twinEdge = getTwin( lastEdge );
+      const SMDS_MeshNode* firstNode = lastEdge->myNode1;
+      const SMDS_MeshNode*  lastNode = lastEdge->myNode2;
+
+      do // add the rest edges
+      {
+        theLoops.myCandidates.clear(); // edges starting at lastNode
+        int nbInternal = 0;
+
+        // find candidate edges
+        for ( size_t i = i1 + 1; i < myLinks.size(); ++i )
+          if ( myLinks[ i ].myNode1 == lastNode &&
+               &myLinks[ i ] != twinEdge &&
+               !theLoops.myIsUsedEdge[ i ])
+          {
+            theLoops.myCandidates.push_back( & myLinks[ i ]);
+            nbInternal += myLinks[ i ].IsInternal();
+          }
+
+        // choose among candidates
+        if ( theLoops.myCandidates.size() == 0 )
+        {
+          theLoops.GetLoopOf( lastEdge )->myHasPending = true;
+          lastEdge = twinEdge;
+        }
+        else if ( theLoops.myCandidates.size() == 1 )
+        {
+          lastEdge = theLoops.myCandidates[0];
+        }
+        else if ( nbInternal == 1 && !lastEdge->IsInternal() )
+        {
+          lastEdge = theLoops.myCandidates[ !theLoops.myCandidates[0]->IsInternal() ];
+        }
+        else
+        {
+          gp_Vec  lastVec = *lastEdge;
+          double maxAngle = -2 * M_PI;
+          for ( size_t i = 0; i < theLoops.myCandidates.size(); ++i )
+          {
+            double angle = lastVec.AngleWithRef( *theLoops.myCandidates[i], theFaceNorm );
+            if ( angle > maxAngle )
+            {
+              maxAngle = angle;
+              lastEdge = theLoops.myCandidates[i];
+            }
+          }
+        }
+        theLoops.AddEdge( *lastEdge );
+        lastNode = lastEdge->myNode2;
+        twinEdge = getTwin( lastEdge );
+      }
+      while ( lastNode != firstNode );
+
+    } // while ( !theLoops.AllEdgesUsed() )
+
+    return;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Erase loops that are cut off by face intersections
+   */
+  //================================================================================
+
+  void CutFace::CutOffLoops( EdgeLoopSet&                 theLoops,
+                             const double                 theSign,
+                             const std::vector< gp_XYZ >& theNormals,
+                             std::vector< EdgePart >&     theCutOffLinks,
+                             TLinkMap&                    theCutOffCoplanarLinks) const
+  {
+    EdgePart sideEdge;
+    for ( size_t i = 0; i < myLinks.size(); ++i )
+    {
+      if ( !myLinks[i].myFace )
+        continue;
+
+      EdgeLoop* loop = theLoops.GetLoopOf( & myLinks[i] );
+      if ( !loop || loop->myLinks.empty() || loop->myHasPending )
+        continue;
+
+      bool toErase, isCoplanar = ( myLinks[i].myIndex == EdgePart::_COPLANAR );
+
+      gp_Vec iniNorm = theNormals[ myInitFace->GetID() ];
+      if ( isCoplanar )
+      {
+        toErase = ( myLinks[i].myFace->GetID() > myInitFace->GetID() );
+
+        const EdgePart* twin = getTwin( & myLinks[i] );
+        if ( !twin || twin->myFace == myLinks[i].myFace )
+        {
+          // only one co-planar face includes myLinks[i]
+          gp_Vec inFaceDir = iniNorm ^ myLinks[i];
+          gp_XYZ   edgePnt = SMESH_NodeXYZ( myLinks[i].myNode1 );
+          for ( int iN = 0; iN < 3; ++iN )
+          {
+            gp_Vec inCutFaceDir = ( SMESH_NodeXYZ( myLinks[i].myFace->GetNode( iN )) - edgePnt );
+            if ( inCutFaceDir * inFaceDir < 0 )
+            {
+              toErase = false;
+              break;
+            }
+          }
+        }
+      }
+      else
+      {
+        gp_Vec   cutNorm = theNormals[ myLinks[i].myFace->GetID() ];
+        gp_Vec inFaceDir = iniNorm ^ myLinks[i];
+
+        toErase = inFaceDir * cutNorm * theSign < 0;
+        if ( !toErase )
+        {
+          // erase a neighboring loop
+          loop = 0;
+          if ( const EdgePart* twin = getTwin( & myLinks[i] ))
+            loop = theLoops.GetLoopOf( twin );
+          toErase = ( loop && !loop->myLinks.empty() );
+        }
+      }
+
+      if ( toErase )
+      {
+        if ( !isCoplanar )
+        {
+          // remember whole sides of myInitFace that are cut off
+          for ( size_t iE = 0; iE < loop->myLinks.size(); ++iE )
+          {
+            if ( !loop->myLinks[ iE ]->myFace              &&
+                 !loop->myLinks[ iE ]->IsInternal()     )//   &&
+                 // !loop->myLinks[ iE ]->myNode1->isMarked() && // cut nodes are marked
+                 // !loop->myLinks[ iE ]->myNode2->isMarked() )
+            {
+              int i = loop->myLinks[ iE ]->myIndex;
+              sideEdge.Set( myInitFace->GetNode    ( i   ),
+                            myInitFace->GetNodeWrap( i+1 ));
+              theCutOffLinks.push_back( sideEdge );
+
+              if ( !sideEdge.IsSame( *loop->myLinks[ iE ] )) // nodes replaced
+              {
+                theCutOffLinks.push_back( *loop->myLinks[ iE ] );
+              }
+            }
+            else if ( IsCoplanar( loop->myLinks[ iE ]))
+            {
+              // propagate erasure to a co-planar face
+              theCutOffLinks.push_back( *loop->myLinks[ iE ]);
+            }
+            else if ( loop->myLinks[ iE ]->myFace &&
+                      loop->myLinks[ iE ]->IsInternal() )
+              theCutOffLinks.push_back( *loop->myLinks[ iE ]);
+          }
+
+          // clear the loop
+          theLoops.Erase( loop );
+        }
+      }
+    }
+    return;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Check if the face has cut edges
+   */
+  //================================================================================
+
+  bool CutFace::IsCut() const
+  {
+    if ( myLinks.size() > 3 )
+      return true;
+
+    if ( myLinks.size() == 3 )
+      for ( size_t i = 0; i < 3; ++i )
+        if ( myLinks[i].myFace )
+          return true;
+
+    return false;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Check if an edge is produced by a co-planar cut
+   */
+  //================================================================================
+
+  bool CutFace::IsCoplanar( const EdgePart* edge ) const
+  {
+    if ( edge->myIndex == EdgePart::_COPLANAR )
+    {
+      const EdgePart* twin = getTwin( edge );
+      return ( !twin || twin->myIndex == EdgePart::_COPLANAR );
+    }
+    return false;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Replace _COPLANAR cut edge by _INTERNAL oe vice versa
+   */
+  //================================================================================
+
+  bool EdgePart::ReplaceCoplanar( const EdgePart& e )
+  {
+    if ( myIndex + e.myIndex == _COPLANAR + _INTERNAL )
+    {
+      //check if the faces are connected
+      int nbCommonNodes = SMESH_MeshAlgos::GetCommonNodes( e.myFace, myFace ).size();
+      bool toReplace = (( myIndex == _INTERNAL && nbCommonNodes > 1 ) ||
+                        ( myIndex == _COPLANAR && nbCommonNodes < 2 ));
+      if ( toReplace )
+      {
+        myIndex = e.myIndex;
+        myFace  = e.myFace;
+        return true;
+      }
+    }
+    return false;
+  }
+
+} // namespace
+
+//================================================================================
+/*!
+ * \brief Create an offsetMesh of given faces
+ *  \param [in] faceIt - the input faces
+ *  \param [out] new2OldFaces - history of faces
+ *  \param [out] new2OldNodes - history of nodes
+ *  \return SMDS_Mesh* - the new offset mesh, a caller should delete
+ */
+//================================================================================
+
+SMDS_Mesh* SMESH_MeshAlgos::MakeOffset( SMDS_ElemIteratorPtr theFaceIt,
+                                        SMDS_Mesh&           theSrcMesh,
+                                        const double         theOffset,
+                                        const bool           theFixIntersections,
+                                        TEPairVec&           theNew2OldFaces,
+                                        TNPairVec&           theNew2OldNodes)
+{
+  SMDS_Mesh* newMesh = new SMDS_Mesh;
+  theNew2OldFaces.clear();
+  theNew2OldNodes.clear();
+  theNew2OldFaces.push_back
+    ( std::make_pair(( const SMDS_MeshElement*) 0,
+                     ( const SMDS_MeshElement*) 0)); // to have index == face->GetID()
+
+  if ( theSrcMesh.GetMeshInfo().NbFaces( ORDER_QUADRATIC ) > 0 )
+    throw SALOME_Exception( "Offset of quadratic mesh not supported" );
+  if ( theSrcMesh.GetMeshInfo().NbFaces() > theSrcMesh.GetMeshInfo().NbTriangles() )
+    throw SALOME_Exception( "Offset of non-triangular mesh not supported" );
+
+  // copy input faces to the newMesh keeping IDs of nodes
+
+  double minNodeDist = 1e100;
+
+  std::vector< const SMDS_MeshNode* > nodes;
+  while ( theFaceIt->more() )
+  {
+    const SMDS_MeshElement* face = theFaceIt->next();
+    if ( face->GetType() != SMDSAbs_Face ) continue;
+
+    // copy nodes
+    nodes.assign( face->begin_nodes(), face->end_nodes() );
+    for ( size_t i = 0; i < nodes.size(); ++i )
+    {
+      const SMDS_MeshNode* newNode = newMesh->FindNode( nodes[i]->GetID() );
+      if ( !newNode )
+      {
+        SMESH_NodeXYZ xyz( nodes[i] );
+        newNode = newMesh->AddNodeWithID( xyz.X(), xyz.Y(), xyz.Z(), nodes[i]->GetID() );
+        theNew2OldNodes.push_back( std::make_pair( newNode, nodes[i] ));
+        nodes[i] = newNode;
+      }
+    }
+    const SMDS_MeshElement* newFace = 0;
+    switch ( face->GetEntityType() )
+    {
+    case SMDSEntity_Triangle:
+      newFace = newMesh->AddFace( nodes[0],nodes[1],nodes[2] );
+      break;
+    case SMDSEntity_Quad_Triangle:
+      newFace = newMesh->AddFace( nodes[0],nodes[1],nodes[2],
+                                  nodes[3],nodes[4],nodes[5] );
+      break;
+    case SMDSEntity_BiQuad_Triangle:
+      newFace = newMesh->AddFace( nodes[0],nodes[1],nodes[2],
+                                  nodes[3],nodes[4],nodes[5],nodes[6] );
+      break;
+    case SMDSEntity_Quadrangle:
+      newFace = newMesh->AddFace( nodes[0],nodes[1],nodes[2],nodes[3] );
+      break;
+    case SMDSEntity_Quad_Quadrangle:
+      newFace = newMesh->AddFace( nodes[0],nodes[1],nodes[2],nodes[3],
+                                  nodes[4],nodes[5],nodes[6],nodes[7] );
+      break;
+    case SMDSEntity_BiQuad_Quadrangle:
+      newFace = newMesh->AddFace( nodes[0],nodes[1],nodes[2],nodes[3],nodes[4],
+                                  nodes[5],nodes[6],nodes[7],nodes[8] );
+      break;
+    case SMDSEntity_Polygon:
+      newFace = newMesh->AddPolygonalFace( nodes );
+      break;
+    case SMDSEntity_Quad_Polygon:
+      newFace = newMesh->AddQuadPolygonalFace( nodes );
+      break;
+    default:
+      continue;
+    }
+    theNew2OldFaces.push_back( std::make_pair( newFace, face ));
+
+    SMESH_NodeXYZ pPrev = nodes.back(), p;
+    for ( size_t i = 0; i < nodes.size(); ++i )
+    {
+      p.Set( nodes[i] );
+      double dist = ( pPrev - p ).SquareModulus();
+      if ( dist > std::numeric_limits<double>::min() )
+        minNodeDist = dist;
+      pPrev = p;
+    }
+  } // while ( faceIt->more() )
+
+
+  // compute normals to faces
+  std::vector< gp_XYZ > normals( theNew2OldFaces.size() );
+  for ( size_t i = 1; i < normals.size(); ++i )
+  {
+    if ( !SMESH_MeshAlgos::FaceNormal( theNew2OldFaces[i].second, normals[i] ))
+      normals[i].SetCoord( 0,0,0 ); // TODO find norm by neighbors
+  }
+
+  const double  tol = 1e-3 * Sqrt( minNodeDist );
+  const double sign = ( theOffset < 0 ? -1 : +1 );
+
+  // translate new nodes by normal to input faces
+  gp_XYZ newXYZ;
+  std::vector< const SMDS_MeshNode* > multiNormalNodes;
+  for ( size_t i = 0; i < theNew2OldNodes.size(); ++i )
+  {
+    const SMDS_MeshNode* newNode = theNew2OldNodes[i].first;
+
+    if ( getTranslatedPosition( newNode, theOffset, tol*10., sign, normals, theSrcMesh, newXYZ ))
+      newMesh->MoveNode( newNode, newXYZ.X(), newXYZ.Y(), newXYZ.Z() );
+    else
+      multiNormalNodes.push_back( newNode );
+  }
+  // make multi-normal translation
+  std::vector< SMESH_NodeXYZ > multiPos(10);
+  for ( size_t i = 0; i < multiNormalNodes.size(); ++i )
+  {
+    const SMDS_MeshNode* newNode = multiNormalNodes[i];
+    newNode->setIsMarked( true );
+    SMESH_NodeXYZ oldXYZ = newNode;
+    multiPos.clear();
+    for ( SMDS_ElemIteratorPtr fIt = newNode->GetInverseElementIterator(); fIt->more(); )
+    {
+      const SMDS_MeshElement* newFace = fIt->next();
+      const int             faceIndex = newFace->GetID();
+      const gp_XYZ&           oldNorm = normals[ faceIndex ];
+      const gp_XYZ             newXYZ = oldXYZ + oldNorm * theOffset;
+      if ( multiPos.empty() )
+      {
+        newMesh->MoveNode( newNode, newXYZ.X(), newXYZ.Y(), newXYZ.Z() );
+        multiPos.emplace_back( newNode );
+      }
+      else
+      {
+        newNode = 0;
+        for ( size_t iP = 0; iP < multiPos.size() &&  !newNode; ++iP )
+          if (( multiPos[iP] - newXYZ ).SquareModulus() < tol * tol )
+            newNode = multiPos[iP].Node();
+        if ( !newNode )
+        {
+          newNode = newMesh->AddNode( newXYZ.X(), newXYZ.Y(), newXYZ.Z() );
+          newNode->setIsMarked( true );
+          theNew2OldNodes.push_back( std::make_pair( newNode, theNew2OldNodes[i].second ));
+          multiPos.emplace_back( newNode );
+        }
+      }
+      if ( newNode != oldXYZ.Node() )
+      {
+        nodes.assign( newFace->begin_nodes(), newFace->end_nodes() );
+        nodes[ newFace->GetNodeIndex( oldXYZ.Node() )] = newNode;
+        newMesh->ChangeElementNodes( newFace, & nodes[0], nodes.size() );
+      }
+    }
+  }
+
+  if ( !theFixIntersections )
+    return newMesh;
+
+
+  // remove new faces around concave nodes (they are marked) if the faces are inverted
+  gp_XYZ faceNorm;
+  for ( size_t i = 0; i < theNew2OldNodes.size(); ++i )
+  {
+    const SMDS_MeshNode* newNode = theNew2OldNodes[i].first;
+    //const SMDS_MeshNode* oldNode = theNew2OldNodes[i].second;
+    if ( newNode->isMarked() )
+    {
+      //gp_XYZ moveVec = sign * ( SMESH_NodeXYZ( newNode ) - SMESH_NodeXYZ( oldNode ));
+
+      //bool haveInverseFace = false;
+      for ( SMDS_ElemIteratorPtr fIt = newNode->GetInverseElementIterator(); fIt->more(); )
+      {
+        const SMDS_MeshElement* newFace = fIt->next();
+        const int             faceIndex = newFace->GetID();
+        const gp_XYZ&           oldNorm = normals[ faceIndex ];
+        if ( !SMESH_MeshAlgos::FaceNormal( newFace, faceNorm, /*normalize=*/false ) ||
+             //faceNorm * moveVec < 0 )
+             faceNorm * oldNorm < 0 )
+        {
+          //haveInverseFace = true;
+          theNew2OldFaces[ faceIndex ].first = 0;
+          newMesh->RemoveFreeElement( newFace );
+          //break;
+        }
+      }
+      // if ( haveInverseFace )
+      // {
+      //   newMesh->MoveNode( newNode, oldNode->X(), oldNode->Y(), oldNode->Z() );
+
+      //   for ( SMDS_ElemIteratorPtr fIt = newNode->GetInverseElementIterator(); fIt->more(); )
+      //   {
+      //     const SMDS_MeshElement* newFace = fIt->next();
+      //     if ( !SMESH_MeshAlgos::FaceNormal( newFace, normals[ newFace->GetID() ] ))
+      //       normals[i].SetCoord( 0,0,0 ); // TODO find norm by neighbors
+      //   }
+      // }
+    }
+    // mark all new nodes located closer than theOffset from theSrcMesh
+  }
+
+  // ==================================================
+  // find self-intersections of new faces and fix them
+  // ==================================================
+
+  std::unique_ptr< SMESH_ElementSearcher > fSearcher
+    ( SMESH_MeshAlgos::GetElementSearcher( *newMesh, tol ));
+
+  Intersector intersector( newMesh, tol, normals );
+
+  std::vector< const SMDS_MeshElement* > closeFaces;
+  std::vector< const SMDS_MeshNode* >    faceNodes;
+  Bnd_B3d faceBox;
+  for ( size_t iF = 1; iF < theNew2OldFaces.size(); ++iF )
+  {
+    const SMDS_MeshElement* newFace = theNew2OldFaces[iF].first;
+    if ( !newFace ) continue;
+    faceNodes.assign( newFace->begin_nodes(), newFace->end_nodes() );
+
+    bool isConcaveNode1 = false;
+    for ( size_t iN = 0; iN < faceNodes.size() && !isConcaveNode1; ++iN )
+      isConcaveNode1 = faceNodes[iN]->isMarked();
+
+    // get faces close to a newFace
+    closeFaces.clear();
+    faceBox.Clear();
+    for ( size_t i = 0; i < faceNodes.size(); ++i )
+      faceBox.Add( SMESH_NodeXYZ( faceNodes[i] ));
+    faceBox.Enlarge( tol );
+
+    fSearcher->GetElementsInBox( faceBox, SMDSAbs_Face, closeFaces );
+
+    // intersect the newFace with closeFaces
+
+    for ( size_t i = 0; i < closeFaces.size(); ++i )
+    {
+      const SMDS_MeshElement* closeFace = closeFaces[i];
+      if ( closeFace->GetID() <= newFace->GetID() )
+        continue; // this pair already treated
+
+      // do not intersect connected faces if they have no concave nodes
+      int nbCommonNodes = 0;
+      for ( size_t iN = 0; iN < faceNodes.size(); ++iN )
+        nbCommonNodes += ( closeFace->GetNodeIndex( faceNodes[iN] ) >= 0 );
+
+      if ( !isConcaveNode1 )
+      {
+        bool isConcaveNode2 = false;
+        for ( SMDS_ElemIteratorPtr nIt = closeFace->nodesIterator(); nIt->more(); )
+          if (( isConcaveNode2 = nIt->next()->isMarked() ))
+            break;
+
+        if ( !isConcaveNode2 && nbCommonNodes > 0 )
+          continue;
+      }
+
+      intersector.Cut( newFace, closeFace, nbCommonNodes );
+    }
+  }
+  intersector.MakeNewFaces( theNew2OldFaces, theNew2OldNodes, sign );
+
+  return newMesh;
+}
diff --git a/src/SMESHUtils/SMESH_Triangulate.cxx b/src/SMESHUtils/SMESH_Triangulate.cxx
new file mode 100644 (file)
index 0000000..6652aea
--- /dev/null
@@ -0,0 +1,341 @@
+// 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_Triangulate.cxx
+// Created   : Thu Jan 18 18:00:13 2018
+// Author    : Edward AGAPOV (eap)
+
+// Extracted from ../DriverSTL/DriverSTL_W_SMDS_Mesh.cxx
+
+#include "SMESH_MeshAlgos.hxx"
+
+#include <Standard_ErrorHandler.hxx>
+#include <Standard_Failure.hxx>
+#include <gp_Ax2.hxx>
+
+using namespace SMESH_MeshAlgos;
+
+//================================================================================
+/*!
+ * \brief Initialization
+ */
+//================================================================================
+
+void Triangulate::PolyVertex::SetNodeAndNext( const SMDS_MeshNode* n,
+                                              PolyVertex&          v )
+{
+  _nxyz.Set( n );
+  _next = &v;
+  v._prev = this;
+}
+//================================================================================
+/*!
+ * \brief Remove self from a polygon
+ */
+//================================================================================
+
+Triangulate::PolyVertex* Triangulate::PolyVertex::Delete()
+{
+  _prev->_next = _next;
+  _next->_prev = _prev;
+  return _next;
+}
+
+//================================================================================
+/*!
+ * \brief Return nodes of a triangle
+ */
+//================================================================================
+
+void Triangulate::PolyVertex::GetTriaNodes( const SMDS_MeshNode** nodes) const
+{
+  nodes[0] = _prev->_nxyz._node;
+  nodes[1] =  this->_nxyz._node;
+  nodes[2] = _next->_nxyz._node;
+}
+
+//================================================================================
+/*!
+ * \brief Compute triangle area
+ */
+//================================================================================
+
+inline static double Area( const gp_XY& xy0, const gp_XY& xy1, const gp_XY& xy2 )
+{
+  gp_XY vPrev = xy0 - xy1;
+  gp_XY vNext = xy2 - xy1;
+  return vNext ^ vPrev;
+}
+
+//================================================================================
+/*!
+ * \brief Compute triangle area
+ */
+//================================================================================
+
+double Triangulate::PolyVertex::TriaArea() const
+{
+  return Area( _prev->_xy, this->_xy, _next->_xy );
+}
+
+//================================================================================
+/*!
+ * \brief Check if a vertex is inside a triangle
+ */
+//================================================================================
+
+bool Triangulate::PolyVertex::IsInsideTria( const PolyVertex* v )
+{
+  if ( this ->_nxyz == v->_nxyz ||
+       _prev->_nxyz == v->_nxyz ||
+       _next->_nxyz == v->_nxyz )
+    return false;
+
+  gp_XY p = _prev->_xy - v->_xy;
+  gp_XY t =  this->_xy - v->_xy;
+  gp_XY n = _next->_xy - v->_xy;
+  const double tol = -1e-12;
+  return (( p ^ t ) >= tol &&
+          ( t ^ n ) >= tol &&
+          ( n ^ p ) >= tol );
+  // return ( Area( _prev, this, v ) > 0 &&
+  //          Area( this, _next, v ) > 0 &&
+  //          Area( _next, _prev, v ) > 0 );
+}
+
+//================================================================================
+/*!
+ * \brief Triangulate a polygon. Assure correct orientation for concave polygons
+ */
+//================================================================================
+
+bool Triangulate::triangulate( std::vector< const SMDS_MeshNode*>& nodes,
+                               const size_t                        nbNodes )
+{
+  // connect nodes into a ring
+  _pv.resize( nbNodes );
+  for ( size_t i = 1; i < nbNodes; ++i )
+    _pv[i-1].SetNodeAndNext( nodes[i-1], _pv[i] );
+  _pv[ nbNodes-1 ].SetNodeAndNext( nodes[ nbNodes-1 ], _pv[0] );
+
+  // get a polygon normal
+  gp_XYZ normal(0,0,0), p0,v01,v02;
+  p0  = _pv[0]._nxyz;
+  v01 = _pv[1]._nxyz - p0;
+  for ( size_t i = 2; i < nbNodes; ++i )
+  {
+    v02 = _pv[i]._nxyz - p0;
+    normal += v01 ^ v02;
+    v01 = v02;
+  }
+  // project nodes to the found plane
+  gp_Ax2 axes;
+  try {
+    axes = gp_Ax2( p0, normal, v01 );
+  }
+  catch ( Standard_Failure ) {
+    return false;
+  }
+  for ( size_t i = 0; i < nbNodes; ++i )
+  {
+    gp_XYZ p = _pv[i]._nxyz - p0;
+    _pv[i]._xy.SetX( axes.XDirection().XYZ() * p );
+    _pv[i]._xy.SetY( axes.YDirection().XYZ() * p );
+  }
+
+  // in a loop, find triangles with positive area and having no vertices inside
+  int iN = 0, nbTria = nbNodes - 2;
+  nodes.reserve( nbTria * 3 );
+  const double minArea = 1e-6;
+  PolyVertex* v = &_pv[0], *vi;
+  int nbVertices = nbNodes, nbBadTria = 0, isGoodTria;
+  while ( nbBadTria < nbVertices )
+  {
+    if (( isGoodTria = v->TriaArea() > minArea ))
+    {
+      for ( vi = v->_next->_next;
+            vi != v->_prev;
+            vi = vi->_next )
+      {
+        if ( v->IsInsideTria( vi ))
+          break;
+      }
+      isGoodTria = ( vi == v->_prev );
+    }
+    if ( isGoodTria )
+    {
+      v->GetTriaNodes( &nodes[ iN ] );
+      iN += 3;
+      v = v->Delete();
+      if ( --nbVertices == 3 )
+      {
+        // last triangle remains
+        v->GetTriaNodes( &nodes[ iN ] );
+        return true;
+      }
+      nbBadTria = 0;
+    }
+    else
+    {
+      v = v->_next;
+      ++nbBadTria;
+    }
+  }
+
+  // the polygon is invalid; add triangles with positive area
+  nbBadTria = 0;
+  while ( nbBadTria < nbVertices )
+  {
+    isGoodTria = v->TriaArea() > minArea;
+    if ( isGoodTria )
+    {
+      v->GetTriaNodes( &nodes[ iN ] );
+      iN += 3;
+      v = v->Delete();
+      if ( --nbVertices == 3 )
+      {
+        // last triangle remains
+        v->GetTriaNodes( &nodes[ iN ] );
+        return true;
+      }
+      nbBadTria = 0;
+    }
+    else
+    {
+      v = v->_next;
+      ++nbBadTria;
+    }
+  }
+
+  // add all the rest triangles
+  while ( nbVertices >= 3 )
+  {
+    v->GetTriaNodes( &nodes[ iN ] );
+    iN += 3;
+    v = v->Delete();
+    --nbVertices;
+  }
+
+  return true;
+
+} // triangulate()
+
+//================================================================================
+/*!
+ * \brief Return nb triangles in a decomposed mesh face
+ *  \retval int - number of triangles
+ */
+//================================================================================
+
+int Triangulate::GetNbTriangles( const SMDS_MeshElement* face )
+{
+  // WARNING: counting triangles must be coherent with GetTriangles()
+  switch ( face->GetEntityType() )
+  {
+  case SMDSEntity_BiQuad_Triangle:
+  case SMDSEntity_BiQuad_Quadrangle:
+    return face->NbNodes() - 1;
+    // case SMDSEntity_Triangle:
+    // case SMDSEntity_Quad_Triangle:
+    // case SMDSEntity_Quadrangle:
+    // case SMDSEntity_Quad_Quadrangle:
+    // case SMDSEntity_Polygon:
+    // case SMDSEntity_Quad_Polygon:
+  default:
+    return face->NbNodes() - 2;
+  }
+  return 0;
+}
+
+//================================================================================
+/*!
+ * \brief Decompose a mesh face into triangles
+ *  \retval int - number of triangles
+ */
+//================================================================================
+
+int Triangulate::GetTriangles( const SMDS_MeshElement*             face,
+                               std::vector< const SMDS_MeshNode*>& nodes)
+{
+  if ( face->GetType() != SMDSAbs_Face )
+    return 0;
+
+  // WARNING: decomposing into triangles must be coherent with getNbTriangles()
+  int nbTria, i = 0, nbNodes = face->NbNodes();
+  SMDS_NodeIteratorPtr nIt = face->interlacedNodesIterator();
+  nodes.resize( nbNodes * 3 );
+  nodes[ i++ ] = nIt->next();
+  nodes[ i++ ] = nIt->next();
+
+  const SMDSAbs_EntityType type = face->GetEntityType();
+  switch ( type )
+  {
+  case SMDSEntity_BiQuad_Triangle:
+  case SMDSEntity_BiQuad_Quadrangle:
+
+    nbTria = ( type == SMDSEntity_BiQuad_Triangle ) ? 6 : 8;
+    nodes[ i++ ] = face->GetNode( nbTria );
+    for ( i = 3; i < 3*(nbTria-1); i += 3 )
+    {
+      nodes[ i+0 ] = nodes[ i-2 ];
+      nodes[ i+1 ] = nIt->next();
+      nodes[ i+2 ] = nodes[ 2 ];
+    }
+    nodes[ i+0 ] = nodes[ i-2 ];
+    nodes[ i+1 ] = nodes[ 0 ];
+    nodes[ i+2 ] = nodes[ 2 ];
+    break;
+
+  case SMDSEntity_Triangle:
+
+    nbTria = 1;
+    nodes[ i++ ] = nIt->next();
+    break;
+
+  default:
+
+    // case SMDSEntity_Quad_Triangle:
+    // case SMDSEntity_Quadrangle:
+    // case SMDSEntity_Quad_Quadrangle:
+    // case SMDSEntity_Polygon:
+    // case SMDSEntity_Quad_Polygon:
+
+    nbTria = nbNodes - 2;
+    while ( nIt->more() )
+      nodes[ i++ ] = nIt->next();
+
+    if ( nbTria > 1 && !triangulate( nodes, nbNodes ))
+    {
+      nIt = face->interlacedNodesIterator();
+      nodes[ 0 ] = nIt->next();
+      nodes[ 1 ] = nIt->next();
+      nodes[ 2 ] = nIt->next();
+      for ( i = 3; i < 3*nbTria; i += 3 )
+      {
+        nodes[ i+0 ] = nodes[ 0 ];
+        nodes[ i+1 ] = nodes[ i-1 ];
+        nodes[ i+2 ] = nIt->next();
+      }
+    }
+  }
+
+  return nbTria;
+}
index c9be990f65b274515dd082b134ac98494fa3619a..ebf51e50eeffa4ab25a045ba2a85de58771ae355 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "SMESH_Utils.hxx"
 
+#include "SMDS_SetIterator.hxx"
 #include "SMDS_MeshNode.hxx"
 
 #include <gp_XYZ.hxx>
@@ -39,6 +40,8 @@
 #include <set>
 #include <cassert>
 
+#include <boost/make_shared.hpp>
+
 typedef std::map<const SMDS_MeshElement*,
                  std::list<const SMDS_MeshElement*>, TIDCompare > TElemOfElemListMap;
 typedef std::map<const SMDS_MeshElement*,
@@ -100,6 +103,14 @@ namespace SMESHUtils
   private:
     ArrayDeleter( const ArrayDeleter& );
   };
+
+  template < class ELEM_SET >
+  SMDS_ElemIteratorPtr elemSetIterator( const ELEM_SET& elements )
+  {
+    typedef SMDS_SetIterator
+      < SMDS_pElement, typename ELEM_SET::const_iterator> TSetIterator;
+    return boost::make_shared< TSetIterator >( elements.begin(), elements.end() );
+  }
 }
 
 //=======================================================================
@@ -127,6 +138,7 @@ struct SMESH_TLink: public NLink
     return ( l1.node1() == l2.node1() && l1.node2() == l2.node2() );
   }
 };
+typedef SMESH_TLink SMESH_Link;
 
 //=======================================================================
 /*!
@@ -165,9 +177,13 @@ struct SMESH_TNodeXYZ : public gp_XYZ
     }
     return false;
   }
+  const SMDS_MeshNode* Node() const { return _node; }
   double Distance(const SMDS_MeshNode* n)       const { return (SMESH_TNodeXYZ( n )-*this).Modulus(); }
   double SquareDistance(const SMDS_MeshNode* n) const { return (SMESH_TNodeXYZ( n )-*this).SquareModulus(); }
   bool operator==(const SMESH_TNodeXYZ& other) const { return _node == other._node; }
+  bool operator!=(const SMESH_TNodeXYZ& other)  const { return _node != other._node; }
+  bool operator!() const { return !_node; }
+  const SMDS_MeshNode* operator->() const { return _node; }
 };
 typedef SMESH_TNodeXYZ SMESH_NodeXYZ;
 
@@ -200,17 +216,12 @@ typedef std::vector< UVPtStruct > UVPtStructVec;
 
 // --------------------------------------------------------------------------------
 // class SMESH_SequenceOfElemPtr
-#include <NCollection_DefineSequence.hxx>
-
-class SMDS_MeshElement;
-
-typedef const SMDS_MeshElement* SMDS_MeshElementPtr;
-
-DEFINE_SEQUENCE (SMESH_SequenceOfElemPtr, SMESH_BaseCollectionElemPtr, SMDS_MeshElementPtr)
 
+typedef std::vector< const SMDS_MeshElement* > SMESH_SequenceOfElemPtr;
 
 // --------------------------------------------------------------------------------
 // class SMESH_SequenceOfNode
+#include <NCollection_DefineSequence.hxx>
 typedef const SMDS_MeshNode* SMDS_MeshNodePtr;
 
 DEFINE_SEQUENCE(SMESH_SequenceOfNode,
index b08b7e3e6d35d8b09a536a17ca8b5b5e75a68af5..a5b9fdfda98b78f04d1210ff1306adc0db505003 100644 (file)
@@ -1021,7 +1021,7 @@ void SMESH_Gen_i::UpdateParameters(CORBA::Object_ptr theObject, const char* theP
   myLastObj.clear();
   myLastParameters.clear();
   myLastParamIndex.clear(); /* vector holding indices of virables within the string
-                               of all varibles used for theObject */ 
+                               of all variables used for theObject */ 
   int nbVars = 0;
   int pos = 0, prevPos = 0, len = strlen( theParameters );
   if ( len == 0 ) return;
@@ -1050,7 +1050,7 @@ void SMESH_Gen_i::UpdateParameters(CORBA::Object_ptr theObject, const char* theP
     return;
 
   // store
-  // (1) variable names in the string of all varibles used for theObject and
+  // (1) variable names in the string of all variables used for theObject and
   // (2) indices of found variables in myLastParamIndex.
 
   // remember theObject
index 48ec9f667594c928800e21860f75af76db92b13d..5231e38b1585d52ecaef6ebd1677b885cf27c4f3 100644 (file)
@@ -173,7 +173,10 @@ namespace MeshEditor_I {
     }
     void Remove( SMDSAbs_ElementType type )
     {
-      SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator( type );
+      Remove( GetMeshDS()->elementsIterator( type ));
+    }
+    void Remove( SMDS_ElemIteratorPtr eIt )
+    {
       while ( eIt->more() )
         GetMeshDS()->RemoveFreeElement( eIt->next(), /*sm=*/0, /*fromGroups=*/false );
     }
@@ -530,14 +533,14 @@ SMESH::MeshPreviewStruct* SMESH_MeshEditor_i::GetPreviewData()
   SMESH_TRY;
   const bool hasBadElems = ( getEditor().GetError() && getEditor().GetError()->HasBadElems() );
 
-  if ( myIsPreviewMode || hasBadElems ) { // --- MeshPreviewStruct filling ---
-
+  if ( myIsPreviewMode || hasBadElems )
+  {
     list<int> aNodesConnectivity;
     typedef map<int, int> TNodesMap;
     TNodesMap nodesMap;
 
     SMESHDS_Mesh* aMeshDS;
-    std::auto_ptr< SMESH_MeshPartDS > aMeshPartDS;
+    std::unique_ptr< SMESH_MeshPartDS > aMeshPartDS;
     if ( hasBadElems ) {
       aMeshPartDS.reset( new SMESH_MeshPartDS( getEditor().GetError()->myBadElements ));
       aMeshDS = aMeshPartDS.get();
@@ -623,9 +626,9 @@ SMESH::long_array* SMESH_MeshEditor_i::GetLastCreatedNodes()
   SMESH::long_array_var myLastCreatedNodes = new SMESH::long_array();
 
   const SMESH_SequenceOfElemPtr& aSeq = getEditor().GetLastCreatedNodes();
-  myLastCreatedNodes->length( aSeq.Length() );
-  for (int i = 1; i <= aSeq.Length(); i++)
-    myLastCreatedNodes[i-1] = aSeq.Value(i)->GetID();
+  myLastCreatedNodes->length( aSeq.size() );
+  for ( size_t i = 0; i < aSeq.size(); i++)
+    myLastCreatedNodes[i] = aSeq[i]->GetID();
 
   return myLastCreatedNodes._retn();
   SMESH_CATCH( SMESH::throwCorbaException );
@@ -646,9 +649,9 @@ SMESH::long_array* SMESH_MeshEditor_i::GetLastCreatedElems()
   SMESH::long_array_var myLastCreatedElems = new SMESH::long_array();
 
   const SMESH_SequenceOfElemPtr& aSeq = getEditor().GetLastCreatedElems();
-  myLastCreatedElems->length( aSeq.Length() );
-  for ( int i = 1; i <= aSeq.Length(); i++ )
-    myLastCreatedElems[i-1] = aSeq.Value(i)->GetID();
+  myLastCreatedElems->length( aSeq.size() );
+  for ( size_t i = 0; i < aSeq.size(); i++ )
+    myLastCreatedElems[i] = aSeq[i]->GetID();
 
   return myLastCreatedElems._retn();
   SMESH_CATCH( SMESH::throwCorbaException );
@@ -4033,6 +4036,84 @@ SMESH_MeshEditor_i::ScaleMakeMesh(SMESH::SMESH_IDSource_ptr  theObject,
   return mesh._retn();
 }
 
+//================================================================================
+/*!
+ * \brief Make an offset mesh from a source 2D mesh
+ *  \param [inout] theObject - source mesh. New elements are added to this mesh
+ *         if \a theMeshName is empty.
+ *  \param [in] theValue - offset value
+ *  \param [in] theCopyGroups - to generate groups
+ *  \param [in] theMeshName - optional name of a new mesh
+ *  \param [out] theGroups - new groups
+ *  \return SMESH::SMESH_Mesh_ptr - the modified mesh
+ */
+//================================================================================
+
+SMESH::SMESH_Mesh_ptr SMESH_MeshEditor_i::Offset( SMESH::SMESH_IDSource_ptr theObject,
+                                                  CORBA::Double             theValue,
+                                                  CORBA::Boolean            theCopyGroups,
+                                                  const char*               theMeshName,
+                                                  SMESH::ListOfGroups_out   theGroups)
+  throw (SALOME::SALOME_Exception)
+{
+  SMESH_TRY;
+  initData();
+
+  SMESHDS_Mesh* aMeshDS = getMeshDS();
+
+  SMESH::SMESH_Mesh_var         mesh_var;
+  ::SMESH_MeshEditor::PGroupIDs groupIds;
+
+  TPythonDump pyDump;
+
+  TIDSortedElemSet elements, copyElements;
+  if ( idSourceToSet( theObject, aMeshDS, elements, SMDSAbs_Face,
+                      /*emptyIfIsMesh=*/ !myIsPreviewMode ))
+  {
+    // mesh to modify
+    SMESH_Mesh* tgtMesh = 0;
+    if ( myIsPreviewMode )
+    {
+      TPreviewMesh * tmpMesh = getPreviewMesh();
+      tgtMesh = tmpMesh;
+      tmpMesh->Copy( elements, copyElements );
+      theCopyGroups = false;
+    }
+    else
+    {
+      mesh_var =
+        *theMeshName ? makeMesh( theMeshName ) : SMESH::SMESH_Mesh::_duplicate( myMesh_i->_this() );
+      SMESH_Mesh_i* mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh_var );
+      tgtMesh = & mesh_i->GetImpl();
+    }
+    groupIds = getEditor().Offset( elements, theValue, tgtMesh, theCopyGroups, !myIsPreviewMode );
+
+    tgtMesh->GetMeshDS()->Modified();
+  }
+
+  if ( myIsPreviewMode )
+  {
+    getPreviewMesh()->Remove( SMESHUtils::elemSetIterator( copyElements ));
+  }
+  else
+  {
+    theGroups = theCopyGroups ? getGroups( groupIds.get() ) : new SMESH::ListOfGroups;
+
+    // result of Offset() is a tuple (mesh, groups)
+    if ( mesh_var->_is_nil() ) pyDump << myMesh_i->_this() << ", ";
+    else                       pyDump << mesh_var          << ", ";
+    pyDump << theGroups << " = "
+           << this << ".Offset( "
+           << theValue << ", "
+           << theCopyGroups << ", "
+           << "'" << theMeshName<< "')";
+  }
+
+  return mesh_var._retn();
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+  return SMESH::SMESH_Mesh::_nil();
+}
 
 //=======================================================================
 //function : findCoincidentNodes
@@ -4731,8 +4812,7 @@ void SMESH_MeshEditor_i::FillHole(const SMESH::FreeBorder& theHole)
     getEditor().ClearLastCreated();
     SMESH_SequenceOfElemPtr& aSeq =
       const_cast<SMESH_SequenceOfElemPtr&>( getEditor().GetLastCreatedElems() );
-    for ( size_t i = 0; i < newFaces.size(); ++i )
-      aSeq.Append( newFaces[i] );
+    aSeq.swap( newFaces );
 
     TPythonDump() << this << ".FillHole( SMESH.FreeBorder(" << theHole.nodeIDs << " ))";
   }
@@ -5548,7 +5628,7 @@ bool SMESH_MeshEditor_i::idSourceToSet(SMESH::SMESH_IDSource_ptr  theIDSource,
  * \param theElements - container of elements to duplicate.
  * \param theGroupName - a name of group to contain the generated elements.
  *                    If a group with such a name already exists, the new elements
- *                    are added to the existng group, else a new group is created.
+ *                    are added to the existing group, else a new group is created.
  *                    If \a theGroupName is empty, new elements are not added 
  *                    in any group.
  * \return a group where the new elements are added. NULL if theGroupName == "".
@@ -5573,11 +5653,11 @@ SMESH_MeshEditor_i::DoubleElements(SMESH::SMESH_IDSource_ptr theElements,
   {
     getEditor().DoubleElements( elems );
 
-    if ( strlen( theGroupName ) && !getEditor().GetLastCreatedElems().IsEmpty() )
+    if ( strlen( theGroupName ) && !getEditor().GetLastCreatedElems().empty() )
     {
       // group type
       SMESH::ElementType type =
-        SMESH::ElementType( getEditor().GetLastCreatedElems().Value(1)->GetType() );
+        SMESH::ElementType( getEditor().GetLastCreatedElems()[0]->GetType() );
       // find existing group
       SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
       for ( size_t i = 0; i < groups->length(); ++i )
@@ -5597,8 +5677,8 @@ SMESH_MeshEditor_i::DoubleElements(SMESH::SMESH_IDSource_ptr theElements,
       {
         SMESHDS_Group* groupDS = static_cast< SMESHDS_Group* >( group_i->GetGroupDS() );
         const SMESH_SequenceOfElemPtr& aSeq = getEditor().GetLastCreatedElems();
-        for ( int i = 1; i <= aSeq.Length(); i++ )
-          groupDS->SMDSGroup().Add( aSeq(i) );
+        for ( size_t i = 0; i <= aSeq.size(); i++ )
+          groupDS->SMDSGroup().Add( aSeq[i] );
       }
     }
   }
@@ -6092,14 +6172,14 @@ SMESH_MeshEditor_i::DoubleNodeElemGroup2New(SMESH::SMESH_GroupBase_ptr theElems,
     // Create group with newly created elements
     CORBA::String_var elemGroupName = theElems->GetName();
     std::string aNewName = generateGroupName( std::string(elemGroupName.in()) + "_double");
-    if ( !getEditor().GetLastCreatedElems().IsEmpty() && theElemGroupNeeded )
+    if ( !getEditor().GetLastCreatedElems().empty() && theElemGroupNeeded )
     {
       SMESH::long_array_var anIds = GetLastCreatedElems();
       SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true);
       aNewElemGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str());
       aNewElemGroup->Add(anIds);
     }
-    if ( !getEditor().GetLastCreatedNodes().IsEmpty() && theNodeGroupNeeded )
+    if ( !getEditor().GetLastCreatedNodes().empty() && theNodeGroupNeeded )
     {
       SMESH::long_array_var anIds = GetLastCreatedNodes();
       aNewNodeGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
@@ -6324,14 +6404,14 @@ SMESH_MeshEditor_i::DoubleNodeElemGroups2New(const SMESH::ListOfGroups& theElems
     // Create group with newly created elements
     CORBA::String_var elemGroupName = theElems[0]->GetName();
     std::string aNewName = generateGroupName( std::string(elemGroupName.in()) + "_double");
-    if ( !getEditor().GetLastCreatedElems().IsEmpty() && theElemGroupNeeded )
+    if ( !getEditor().GetLastCreatedElems().empty() && theElemGroupNeeded )
     {
       SMESH::long_array_var anIds = GetLastCreatedElems();
       SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true);
       aNewElemGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str());
       aNewElemGroup->Add(anIds);
     }
-    if ( !getEditor().GetLastCreatedNodes().IsEmpty() && theNodeGroupNeeded )
+    if ( !getEditor().GetLastCreatedNodes().empty() && theNodeGroupNeeded )
     {
       SMESH::long_array_var anIds = GetLastCreatedNodes();
       aNewNodeGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
index 292c2e8526d52ec0a821d6811c857b461853a9e6..d45b9e4ac0d5c19349daa8c5c786fc0395cc82c7 100644 (file)
@@ -472,11 +472,18 @@ public:
                                        const SMESH::double_array& theScaleFact)
     throw (SALOME::SALOME_Exception);
 
-  SMESH::SMESH_Mesh_ptr ScaleMakeMesh(SMESH::SMESH_IDSource_ptr Object,
-                                      const SMESH::PointStruct& Point,
+  SMESH::SMESH_Mesh_ptr ScaleMakeMesh(SMESH::SMESH_IDSource_ptr  Object,
+                                      const SMESH::PointStruct&  Point,
                                       const SMESH::double_array& theScaleFact,
-                                      CORBA::Boolean            CopyGroups,
-                                      const char*               MeshName)
+                                      CORBA::Boolean             CopyGroups,
+                                      const char*                MeshName)
+    throw (SALOME::SALOME_Exception);
+
+  SMESH::SMESH_Mesh_ptr Offset( SMESH::SMESH_IDSource_ptr theObject,
+                                CORBA::Double             Value,
+                                CORBA::Boolean            CopyGroups,
+                                const char*               MeshName,
+                                SMESH::ListOfGroups_out   Groups)
     throw (SALOME::SALOME_Exception);
 
   void FindCoincidentNodes (CORBA::Double                  Tolerance,
@@ -961,8 +968,6 @@ private: //!< private methods
 
   // temporary IDSources
   struct _IDSource;
-  // std::list< _IDSource* >      myAuxIDSources;
-  // void                         deleteAuxIDSources();
 };
 
 #endif
index 7fb82c5644a8a33a55c2c248af32ad69f739ec29..51fa745487cfb0e002d60aa481cb3d4d17f4832c 100644 (file)
@@ -90,7 +90,7 @@ namespace SMESH
 
   // ===========================================================================================
   /*!
-   * \brief Object used to make TPythonDump know that its held value can be a varible
+   * \brief Object used to make TPythonDump know that its held value can be a variable
    *
    * TPythonDump substitute TVar with names of notebook variables if any.
    */
index 3afd753c16561de846f9ce01a192aed4d7a9faa7..82666a7723d9e8fe9f259a18321f6c5127c56ba3 100644 (file)
@@ -4501,6 +4501,24 @@ class Mesh:
         self.mesh.SetParameters(Parameters)
         return Mesh( self.smeshpyD, self.geompyD, mesh )
 
+    ## Create an offset mesh from the given 2D object
+    #  @param theObject the source object (mesh, submesh, group or filter)
+    #  @param theValue signed offset size
+    #  @param MakeGroups forces the generation of new groups from existing ones
+    #  @param NewMeshName the name of a mesh to create. If empty, offset elements are added
+    #         to this mesh
+    #  @return a tuple (mesh, list_of_groups)
+    #  @ingroup l2_modif_trsf
+    def Offset(self, theObject, theValue, MakeGroups=False, NewMeshName=''):
+        if isinstance( theObject, Mesh ):
+            theObject = theObject.GetMesh()
+        theValue,Parameters,hasVars = ParseParameters(theValue)
+        mesh_groups = self.editor.Offset(theObject, theValue, MakeGroups, NewMeshName )
+        self.mesh.SetParameters(Parameters)
+        # if mesh_groups[0]:
+        #     return Mesh( self.smeshpyD, self.geompyD, mesh_groups[0] ), mesh_groups[1]
+        return mesh_groups
+
     ## Finds groups of adjacent nodes within Tolerance.
     #  @param Tolerance the value of tolerance
     #  @param SeparateCornerAndMediumNodes if @c True, in quadratic mesh puts
@@ -4710,7 +4728,7 @@ class Mesh:
     #         a Mesh, elements of highest dimension are duplicated
     #  @param theGroupName - a name of group to contain the generated elements.
     #                    If a group with such a name already exists, the new elements
-    #                    are added to the existng group, else a new group is created.
+    #                    are added to the existing group, else a new group is created.
     #                    If \a theGroupName is empty, new elements are not added 
     #                    in any group.
     # @return a group where the new elements are added. None if theGroupName == "".
index 70fe2368d063191ccee137a29eb00ae13086bdc2..100718ffc647760abd63578f4b6684b7013c4572 100644 (file)
@@ -2622,34 +2622,34 @@ namespace
   {
     enum { X = 1, Y = 2, Z = 4 }; // == 001, 010, 100
     int nbFacets = 0;
-    int vertex = 0, egdeMask = 0;
+    int vertex = 0, edgeMask = 0;
 
     if ( Abs( _grid->_coords[0][ _i   ] - ip->_uvw[0] ) < _grid->_tol ) {
       facets[ nbFacets++ ] = SMESH_Block::ID_F0yz;
-      egdeMask |= X;
+      edgeMask |= X;
     }
     else if ( Abs( _grid->_coords[0][ _i+1 ] - ip->_uvw[0] ) < _grid->_tol ) {
       facets[ nbFacets++ ] = SMESH_Block::ID_F1yz;
       vertex   |= X;
-      egdeMask |= X;
+      edgeMask |= X;
     }
     if ( Abs( _grid->_coords[1][ _j   ] - ip->_uvw[1] ) < _grid->_tol ) {
       facets[ nbFacets++ ] = SMESH_Block::ID_Fx0z;
-      egdeMask |= Y;
+      edgeMask |= Y;
     }
     else if ( Abs( _grid->_coords[1][ _j+1 ] - ip->_uvw[1] ) < _grid->_tol ) {
       facets[ nbFacets++ ] = SMESH_Block::ID_Fx1z;
       vertex   |= Y;
-      egdeMask |= Y;
+      edgeMask |= Y;
     }
     if ( Abs( _grid->_coords[2][ _k   ] - ip->_uvw[2] ) < _grid->_tol ) {
       facets[ nbFacets++ ] = SMESH_Block::ID_Fxy0;
-      egdeMask |= Z;
+      edgeMask |= Z;
     }
     else if ( Abs( _grid->_coords[2][ _k+1 ] - ip->_uvw[2] ) < _grid->_tol ) {
       facets[ nbFacets++ ] = SMESH_Block::ID_Fxy1;
       vertex   |= Z;
-      egdeMask |= Z;
+      edgeMask |= Z;
     }
 
     switch ( nbFacets )
@@ -2665,7 +2665,7 @@ namespace
         { SMESH_Block::ID_Ex00, 0, SMESH_Block::ID_Ex10, 0,
           SMESH_Block::ID_Ex01, 0, SMESH_Block::ID_Ex11 }
       };
-      switch ( egdeMask ) {
+      switch ( edgeMask ) {
       case X | Y: sub = edge[ 0 ][ vertex ]; break;
       case X | Z: sub = edge[ 1 ][ vertex ]; break;
       default:    sub = edge[ 2 ][ vertex ];
index 9f872342df0cd85deee91f18e8a0ef8b6dff727f..f7698b5b46ba177a368adb51d4d71d27fc6ab042 100644 (file)
@@ -219,7 +219,7 @@ bool StdMeshersGUI_PropagationHelperWdg::buildChains()
   // aPreviewActor holds a map od all sub-shapes of mainShape
   SMESH_PreviewActorsCollection* previewActor = mySubSelectWdg->GetActorCollection();
   if ( !previewActor ) return false;
-  const QList<int>& egdeIDs = previewActor->GetIndices();
+  const QList<int>& edgeIDs = previewActor->GetIndices();
 
   // Make a 'map' of WIREs of EDGE with quadrilateral WIREs only
 
@@ -277,11 +277,11 @@ bool StdMeshersGUI_PropagationHelperWdg::buildChains()
 
   TColStd_MapOfInteger shapeEdges;
   if ( !shape.IsSame( mainShape ))
-    for ( QList<TGeomID>::const_iterator ieIt = egdeIDs.begin(); ieIt != egdeIDs.end(); ++ieIt )
+    for ( QList<TGeomID>::const_iterator ieIt = edgeIDs.begin(); ieIt != edgeIDs.end(); ++ieIt )
       shapeEdges.Add( *ieIt );
 
   // loop on all EDGEs in mainShape
-  for ( QList<TGeomID>::const_iterator ieIt = egdeIDs.begin(); ieIt != egdeIDs.end(); ++ieIt )
+  for ( QList<TGeomID>::const_iterator ieIt = edgeIDs.begin(); ieIt != edgeIDs.end(); ++ieIt )
   {
     if ( chainedEdges.Contains( *ieIt ))
       continue;
@@ -329,7 +329,7 @@ bool StdMeshersGUI_PropagationHelperWdg::buildChains()
       if ( ch.size() < 2 )
         myChains.pop_back();
     }
-  } // loop on egdeIDs
+  } // loop on edgeIDs
 
   return !myChains.empty();
 }
index 31f2b73297f9a7b19eb895ec2ed3db91382fcd63..b5ba1c1b7ba094feed2b5e6f4120b9c1499379f1 100644 (file)
@@ -56,8 +56,8 @@ def PublishGroups ():
                 TempNames = []
                 for MacroObj in Config.ListObj :
                         if group in MacroObj.GroupNames :
-                                Occurences = IndexMultiOcc(MacroObj.GroupNames, group)
-                                for Occ in Occurences :
+                                Occurrences = IndexMultiOcc(MacroObj.GroupNames, group)
+                                for Occ in Occurrences :
                                         TempGEOList += MacroObj.GetBorder(Occ)
                 GroupGEO.append(geompy.MakeCompound(TempGEOList))
                 geompy.addToStudyInFather(FinalCompound,GroupGEO[-1],'GR_'+group)
index d4aff8f19a97041ca639dfd438391254b7dd19fe..0bd1ad69de7e5964ae2af8c61bc3ba39565f084b 100644 (file)
@@ -22,7 +22,7 @@ Simple case
 Optimisation
 ------------
     
-This is the main remeshing Option.  SurfOpt always does quality improvement. It is done by point smooting and edge swapping.  It can produce a regular mesh for finite element computation (initial mesh is a a geometrical mesh). In this case, the given surface trianglation is modified in accordance to a size map : an intrinsic size map is computed automatically. it is based on the surface proporties.  SurfOpt is also able to  produce a geometrical mesh (initial mesh is a a mesh for finite element computation). In both case, It can coarsen or enrich the mesh.     
+This is the main remeshing Option.  SurfOpt always does quality improvement. It is done by point smoothing and edge swapping.  It can produce a regular mesh for finite element computation (initial mesh is a a geometrical mesh). In this case, the given surface trianglation is modified in accordance to a size map : an intrinsic size map is computed automatically. it is based on the surface proporties.  SurfOpt is also able to  produce a geometrical mesh (initial mesh is a mesh for finite element computation). In both case, It can coarsen or enrich the mesh.     
 
    - **Quality improvement** 
 
index 8bd4294a43f227956052d68eae8a7f671ad29dcd..b17d031ed8d8e5f36c650b4088c712d9b2ddcb6a 100644 (file)
@@ -99,10 +99,10 @@ class PluginDialog(QDialog):
 
     def setupJobManager(self):
         '''
-        This function configures the jobmanager by transmiting the
+        This function configures the jobmanager by transmitting the
         parameters required for a local execution and a remote
         execution. The choice between "local" and "remote" is done at
-        the initialize step, by specifing the name of the resource to
+        the initialize step, by specifying the name of the resource to
         be used.
         '''
         # We first