Salome HOME
23627: [IMACS] ASERIS: project point to the mesh and create a slot
authoreap <eap@opencascade.com>
Thu, 17 Jan 2019 12:53:49 +0000 (15:53 +0300)
committereap <eap@opencascade.com>
Thu, 17 Jan 2019 12:53:49 +0000 (15:53 +0300)
1) Enable appending to an existing mesh via smesh.Concatenate() (compound mesh)
2) Enable filtering a mesh part: Filter::GetElementsIdFromParts( ListOfIDSources )
3) Add ElementType arg to SMESH_Mesh::GetNodeInverseElements()
4) Add Mesh.Get1DBranches( edgeIDs )
5) Define a default Z med tolerance
6) Update ElementsOnSurface upon SetTolerance()
7) Change group management to have group ID persistent
8) Extract SMESH_PolyLine.cxx from SMESH_MeshEditor.cxx
9) Enable Min Distance measure for node-element and node-object
10) Fix SMESH_MeshAlgos::GetDistance( XYZ, face )
11) Extract SMESH_MeshAlgos::Intersector from SMESH_Offset.cxx
12) Enable optimization in SMESH_MeshAlgos::Triangulate
13) Add mestods Mesh.GetEngine() and Mesh.GetGeomEngine()

41 files changed:
doc/salome/examples/creating_meshes_ex07.py
doc/salome/gui/SMESH/images/buildcompound.png
doc/salome/gui/SMESH/input/building_compounds.rst
idl/SMESH_Filter.idl
idl/SMESH_Gen.idl
idl/SMESH_Mesh.idl
idl/SMESH_MeshEditor.idl
resources/SalomeApp.xml.in
src/Controls/SMESH_Controls.cxx
src/Controls/SMESH_ControlsDef.hxx
src/SMDS/SMDS_MeshCell.cxx
src/SMESH/SMESH_Group.cxx
src/SMESH/SMESH_Group.hxx
src/SMESH/SMESH_Mesh.cxx
src/SMESH/SMESH_Mesh.hxx
src/SMESH/SMESH_MeshEditor.cxx
src/SMESH/SMESH_MeshEditor.hxx
src/SMESHGUI/SMESHGUI_BuildCompoundDlg.cxx
src/SMESHGUI/SMESHGUI_BuildCompoundDlg.h
src/SMESHGUI/SMESHGUI_Measurements.cxx
src/SMESHGUI/SMESH_msg_en.ts
src/SMESHUtils/CMakeLists.txt
src/SMESHUtils/SMESH_MeshAlgos.cxx
src/SMESHUtils/SMESH_MeshAlgos.hxx
src/SMESHUtils/SMESH_Offset.cxx
src/SMESHUtils/SMESH_PolyLine.cxx [new file with mode: 0644]
src/SMESHUtils/SMESH_Slot.cxx [new file with mode: 0644]
src/SMESHUtils/SMESH_Triangulate.cxx
src/SMESHUtils/SMESH_Triangulate.hxx [deleted file]
src/SMESHUtils/SMESH_TypeDefs.hxx
src/SMESH_I/SMESH_Filter_i.cxx
src/SMESH_I/SMESH_Filter_i.hxx
src/SMESH_I/SMESH_Gen_i.cxx
src/SMESH_I/SMESH_Gen_i.hxx
src/SMESH_I/SMESH_Measurements_i.cxx
src/SMESH_I/SMESH_MeshEditor_i.cxx
src/SMESH_I/SMESH_MeshEditor_i.hxx
src/SMESH_I/SMESH_Mesh_i.cxx
src/SMESH_I/SMESH_Mesh_i.hxx
src/SMESH_SWIG/smeshBuilder.py
src/StdMeshers/StdMeshers_Import_1D.cxx

index db82550..669c9b0 100644 (file)
@@ -2,11 +2,8 @@
 
 import salome
 salome.salome_init()
-import GEOM
 from salome.geom import geomBuilder
 geompy = geomBuilder.New()
-
-import SMESH, SALOMEDS
 from salome.smesh import smeshBuilder
 smesh =  smeshBuilder.New()
 
@@ -77,5 +74,12 @@ Compound1 = smesh.Concatenate([Mesh_inf, Mesh_sup], 0, 1, 1e-05,
 Compound2 = smesh.Concatenate([Mesh_inf, Mesh_sup], 1, 0, 1e-05, True,
                               name='Compound with UniteGrps and GrpsOfAllElems')
 
+# copy Gsup1 into a separate mesh and translate it
+groupMesh = Mesh_inf.TranslateObjectMakeMesh( Gsup1, [300,0,0] )
+
+# add Ginf2 to groupMesh
+smesh.Concatenate([Ginf2], False, meshToAppendTo = groupMesh )
+
+
 if salome.sg.hasDesktop():
     salome.sg.updateObjBrowser()
index d3534fe..d1f4801 100644 (file)
Binary files a/doc/salome/gui/SMESH/images/buildcompound.png and b/doc/salome/gui/SMESH/images/buildcompound.png differ
index 8501ab7..f7d41d1 100644 (file)
@@ -4,9 +4,14 @@
 Building Compound Meshes
 ************************
 
-Compound Mesh is a combination of several meshes. All elements and groups present in input meshes are present in the compound mesh. However, it does not use geometry or hypotheses of the initial meshes. 
+Compound Mesh is a combination of several mesh objects (meshes, groups, submeshes). All elements and groups present in input meshes are present in the compound mesh. However, it does not use geometry or hypotheses of the initial mesh objects.
 The links between the input meshes and the compound mesh are not supported, consequently the modification of an input mesh does not lead to the update of the compound mesh.
 
+There are two modes of building a compound:
+
+* joining selected mesh objects into a new mesh.
+* appending selected mesh objects to an existing mesh.
+
 *To Build a compound mesh:*
 
 .. |img| image:: ../images/image161.png
@@ -16,9 +21,13 @@ From the **Mesh** menu select **Build Compound** or click *"Build Compound Mesh"
        .. image:: ../images/buildcompound.png
                :align: center
 
-* **Name** - allows selecting the name of the resulting **Compound** mesh.
-* **Meshes, sub-meshes, groups** - allows selecting the meshes, sub-meshes and groups to be concatenated. They can be chosen in the Object Browser while holding **Ctrl** button.
-* **Processing identical groups** - allows selecting the method of processing the namesake groups existing in the input meshes. They can be either 
+* **Result** group allows selecting a mode of operation
+
+  * Activating **Create new mesh named** enables typing the name of the resulting compound mesh.
+  * Activating **Append to mesh** enables selection of a mesh to append other selected objects to.
+   
+* **Meshes, sub-meshes, groups** allows selecting the meshes, sub-meshes and groups to be concatenated. They can be chosen in the Object Browser while holding *Ctrl* button.
+* **Processing identical groups** allows selecting the method of processing the namesake groups existing in the input meshes. They can be either 
 
   * **United** - all elements of *Group1* of *Mesh_1* and *Group1* of *Mesh_2* become the elements of *Group1* of the *Compound_Mesh*, or
   * **Renamed** - *Group1* of *Mesh_1* becomes *Group1_1* and *Group1* of *Mesh_2* becomes *Group1_2*.
index 2784e45..85ae6dc 100644 (file)
@@ -523,6 +523,7 @@ module SMESH
     void          SetMesh( in SMESH_Mesh theMesh );
 
     long_array    GetElementsId( in SMESH_Mesh theMesh );
+    long_array    GetElementsIdFromParts( in ListOfIDSources theParts );
     ElementType   GetElementType();
     Predicate     GetPredicate();
 
index 29158a8..e7254a8 100644 (file)
@@ -312,7 +312,8 @@ module SMESH
       raises ( SALOME::SALOME_Exception );
 
     /*!
-     * Concatenate the given meshes or groups into one mesh.
+     * Concatenate the given meshes or groups into one mesh,
+     * optionally to theMeshToAppendTo.
      * Union groups with the same name and type if
      * theUniteIdenticalGroups flag is true.
      * Merge coincident nodes and elements if
@@ -321,11 +322,13 @@ module SMESH
     SMESH_Mesh Concatenate(in ListOfIDSources theMeshesArray,
                            in boolean         theUniteIdenticalGroups,
                            in boolean         theMergeNodesAndElements,
-                           in double          theMergeTolerance)
+                           in double          theMergeTolerance,
+                           in SMESH_Mesh      theMeshToAppendTo)
       raises ( SALOME::SALOME_Exception );
 
     /*!
-     * Concatenate the given meshes into one mesh.
+     * Concatenate the given meshes into one mesh,
+     * optionally to theMeshToAppendTo.
      * Union groups with the same name and type if
      * theUniteIdenticalGroups flag is true.
      * Merge coincident nodes and elements if
@@ -335,7 +338,8 @@ module SMESH
     SMESH_Mesh ConcatenateWithGroups(in ListOfIDSources theMeshesArray,
                                      in boolean         theUniteIdenticalGroups,
                                      in boolean         theMergeNodesAndElements,
-                                     in double          theMergeTolerance)
+                                     in double          theMergeTolerance,
+                                     in SMESH_Mesh      theMeshToAppendTo)
       raises ( SALOME::SALOME_Exception );
 
     /*!
index c8c7bd7..8d21b5f 100644 (file)
@@ -902,7 +902,7 @@ module SMESH
      * For given node returns list of IDs of inverse elements
      * If there is not node for given ID - returns empty list
      */
-    long_array GetNodeInverseElements(in long id);
+    long_array GetNodeInverseElements(in long id, in ElementType elemType);
 
     /*!
      * \brief Return position of a node on shape
index 85ba8b7..9491b92 100644 (file)
@@ -798,8 +798,8 @@ module SMESH
     long ProjectPoint(in double         x,
                       in double         y,
                       in double         z,
-                      in SMESH_IDSource meshObject,
                       in ElementType    type,
+                      in SMESH_IDSource meshObject,
                       out double_array  projecton)
       raises (SALOME::SALOME_Exception);
 
@@ -823,6 +823,18 @@ module SMESH
       raises (SALOME::SALOME_Exception);
 
     /*!
+     * Partition given 1D elements into groups of contiguous edges.
+     * A node where number of meeting edges != 2 is a group end.
+     * An optional startNode is used to orient groups it belongs to.
+     * \return a list of edge groups and a list of corresponding node groups.
+     *         If a group is closed, the first and last nodes of the group are same.
+     */
+    array_of_long_array Get1DBranches( in SMESH_IDSource       edges,
+                                       in long                 startNode,
+                                       out array_of_long_array nodeGroups)
+      raises (SALOME::SALOME_Exception);
+
+    /*!
      * Return sharp edges of faces and non-manifold ones. 
      * Optionally add existing edges. Angle is in degrees.
      */
@@ -1295,6 +1307,17 @@ module SMESH
     void MakePolyLine(inout ListOfPolySegments segments,
                       in    string             groupName)
       raises (SALOME::SALOME_Exception);
+
+    /*!
+     * \brief Create a slot of given width around given 1D elements lying on a triangle mesh.
+     *        The slot is consrtucted by cutting faces by cylindrical surfaces made
+     *        around each segment. Segments are expected to be created by MakePolyLine().
+     * \return Edges located at the slot boundary
+     */
+    ListOfEdges MakeSlot( in SMESH_GroupBase segments,
+                          in double          width )
+      raises (SALOME::SALOME_Exception);
+
   };
 };
 
index efbe065..85ad3de 100644 (file)
@@ -86,6 +86,7 @@
     <parameter name="display_mode"                 value="1"    />
     <parameter name="fitall_on_displayonly"        value="1"    />
     <parameter name="auto_groups"                  value="false"/>
+    <parameter name="med_ztolerance"               value="0.0"/>
     <parameter name="show_warning"                 value="true"/>
     <parameter name="show_result_notification"     value="2"/>
     <parameter name="mesh_elem_info"               value="1"/>
index f715650..719cd64 100644 (file)
@@ -1888,7 +1888,7 @@ void Length2D::GetValues(TValues& theValues)
 //================================================================================
 /*
   Class       : Deflection2D
-  Description : Functor for calculating number of faces conneted to the edge
+  Description : computes distance between a face center and an underlying surface
 */
 //================================================================================
 
@@ -3589,9 +3589,10 @@ void Filter::SetPredicate( PredicatePtr thePredicate )
   myPredicate = thePredicate;
 }
 
-void Filter::GetElementsId( const SMDS_Mesh* theMesh,
-                            PredicatePtr     thePredicate,
-                            TIdSequence&     theSequence )
+void Filter::GetElementsId( const SMDS_Mesh*     theMesh,
+                            PredicatePtr         thePredicate,
+                            TIdSequence&         theSequence,
+                            SMDS_ElemIteratorPtr theElements )
 {
   theSequence.clear();
 
@@ -3600,21 +3601,28 @@ void Filter::GetElementsId( const SMDS_Mesh* theMesh,
 
   thePredicate->SetMesh( theMesh );
 
-  SMDS_ElemIteratorPtr elemIt = theMesh->elementsIterator( thePredicate->GetType() );
-  if ( elemIt ) {
-    while ( elemIt->more() ) {
-      const SMDS_MeshElement* anElem = elemIt->next();
-      long anId = anElem->GetID();
-      if ( thePredicate->IsSatisfy( anId ) )
-        theSequence.push_back( anId );
+  if ( !theElements )
+    theElements = theMesh->elementsIterator( thePredicate->GetType() );
+
+  if ( theElements ) {
+    while ( theElements->more() ) {
+      const SMDS_MeshElement* anElem = theElements->next();
+      if ( thePredicate->GetType() == SMDSAbs_All ||
+           thePredicate->GetType() == anElem->GetType() )
+      {
+        long anId = anElem->GetID();
+        if ( thePredicate->IsSatisfy( anId ) )
+          theSequence.push_back( anId );
+      }
     }
   }
 }
 
 void Filter::GetElementsId( const SMDS_Mesh*     theMesh,
-                            Filter::TIdSequence& theSequence )
+                            Filter::TIdSequence& theSequence,
+                            SMDS_ElemIteratorPtr theElements )
 {
-  GetElementsId(theMesh,myPredicate,theSequence);
+  GetElementsId(theMesh,myPredicate,theSequence,theElements);
 }
 
 /*
@@ -4042,8 +4050,10 @@ SMDSAbs_ElementType ElementsOnSurface::GetType() const
 void ElementsOnSurface::SetTolerance( const double theToler )
 {
   if ( myToler != theToler )
-    myIds.Clear();
-  myToler = theToler;
+  {
+    myToler = theToler;
+    process();
+  }
 }
 
 double ElementsOnSurface::GetTolerance() const
index 34c3453..4f717d3 100644 (file)
@@ -1178,14 +1178,16 @@ namespace SMESH{
 
       virtual
       void
-      GetElementsId( const SMDS_Mesh* theMesh,
-                     TIdSequence& theSequence );
+      GetElementsId( const SMDS_Mesh*     theMesh,
+                     TIdSequence&         theSequence,
+                     SMDS_ElemIteratorPtr theElements=0);
 
       static
       void
-      GetElementsId( const SMDS_Mesh* theMesh,
-                     PredicatePtr thePredicate,
-                     TIdSequence& theSequence );
+      GetElementsId( const SMDS_Mesh*     theMesh,
+                     PredicatePtr         thePredicate,
+                     TIdSequence&         theSequence,
+                     SMDS_ElemIteratorPtr theElements=0 );
       
     protected:
       PredicatePtr myPredicate;
index 25c2f36..9b3635f 100644 (file)
@@ -639,6 +639,9 @@ const SMDS_MeshNode* SMDS_MeshCell::GetNode(const int ind) const
 
 int SMDS_MeshCell::GetNodeIndex( const SMDS_MeshNode* node ) const
 {
+  if ( !node || node->IsNull() )
+    return -1;
+
   if ( GetVtkType() == VTK_POLYHEDRON )
     return static_cast< const SMDS_MeshVolume* >( this )->SMDS_MeshVolume::GetNodeIndex( node );
 
index 23a4955..35c7192 100644 (file)
@@ -96,3 +96,14 @@ void SMESH_Group::SetName (const char* theName)
   myName = theName;
   myGroupDS->SetStoreName( theName );
 }
+
+//================================================================================
+/*!
+ * \brief Return group ID. It is negative if no SMESHDS_GroupBase exist
+ */
+//================================================================================
+
+int SMESH_Group::GetID() const
+{
+  return myGroupDS ? myGroupDS->GetID() : -1;
+}
index 2842b9a..efb6cf9 100644 (file)
@@ -58,6 +58,8 @@ class SMESH_EXPORT  SMESH_Group
 
   SMESHDS_GroupBase * GetGroupDS () { return myGroupDS; }
 
+  int GetID() const;
+
  private:
   SMESH_Group (const SMESH_Group& theOther);
   // prohibited copy constructor
index c03eaa6..c4b6c65 100644 (file)
@@ -521,11 +521,10 @@ int SMESH_Mesh::MEDToMesh(const char* theFileName, const char* theMeshName)
 
   // Reading groups (sub-meshes are out of scope of MED import functionality)
   std::list<TNameAndType> aGroupNames = myReader.GetGroupNamesAndTypes();
-  int anId;
   std::list<TNameAndType>::iterator name_type = aGroupNames.begin();
   for ( ; name_type != aGroupNames.end(); name_type++ )
   {
-    SMESH_Group* aGroup = AddGroup( name_type->second, name_type->first.c_str(), anId );
+    SMESH_Group* aGroup = AddGroup( name_type->second, name_type->first.c_str() );
     if ( aGroup ) {
       SMESHDS_Group* aGroupDS = dynamic_cast<SMESHDS_Group*>( aGroup->GetGroupDS() );
       if ( aGroupDS ) {
@@ -2029,16 +2028,18 @@ bool SMESH_Mesh::IsMainShape(const TopoDS_Shape& theShape) const
 
 SMESH_Group* SMESH_Mesh::AddGroup (const SMDSAbs_ElementType theType,
                                    const char*               theName,
-                                   int&                      theId,
+                                   const int                 theId,
                                    const TopoDS_Shape&       theShape,
                                    const SMESH_PredicatePtr& thePredicate)
 {
-  if (_mapGroup.count(_groupId))
+  if ( _mapGroup.count( theId ))
     return NULL;
-  theId = _groupId;
-  SMESH_Group* aGroup = new SMESH_Group (theId, this, theType, theName, theShape, thePredicate);
+  int id = ( theId < 0 ) ? _groupId : theId;
+  SMESH_Group* aGroup = new SMESH_Group ( id, this, theType, theName, theShape, thePredicate );
   GetMeshDS()->AddGroup( aGroup->GetGroupDS() );
-  _mapGroup[_groupId++] = aGroup;
+  _mapGroup[ id ] = aGroup;
+  while ( _mapGroup.count( _groupId ))
+    ++_groupId;
   return aGroup;
 }
 
@@ -2065,7 +2066,8 @@ SMESH_Group* SMESH_Mesh::AddGroup (SMESHDS_GroupBase* groupDS) throw(SALOME_Exce
   _mapGroup[ groupDS->GetID() ] = aGroup;
   GetMeshDS()->AddGroup( aGroup->GetGroupDS() );
 
-  _groupId = 1 + _mapGroup.rbegin()->first;
+  while ( _mapGroup.count( _groupId ))
+    ++_groupId;
 
   return aGroup;
 }
@@ -2091,8 +2093,8 @@ bool SMESH_Mesh::SynchronizeGroups()
     if ( !_mapGroup.count( _groupId ))
       _mapGroup[_groupId] = new SMESH_Group( groupDS );
   }
-  if ( !_mapGroup.empty() )
-    _groupId = _mapGroup.rbegin()->first + 1;
+  while ( _mapGroup.count( _groupId ))
+    ++_groupId;
 
   return nbGroups < _mapGroup.size();
 }
@@ -2115,11 +2117,12 @@ SMESH_Mesh::GroupIteratorPtr SMESH_Mesh::GetGroups() const
  */
 //=============================================================================
 
-SMESH_Group* SMESH_Mesh::GetGroup (const int theGroupID)
+SMESH_Group* SMESH_Mesh::GetGroup (const int theGroupID) const
 {
-  if (_mapGroup.find(theGroupID) == _mapGroup.end())
+  std::map <int, SMESH_Group*>::const_iterator id_grp = _mapGroup.find( theGroupID );
+  if ( id_grp == _mapGroup.end() )
     return NULL;
-  return _mapGroup[theGroupID];
+  return id_grp->second;
 }
 
 
index 54889de..11d435e 100644 (file)
@@ -315,9 +315,9 @@ class SMESH_EXPORT SMESH_Mesh
 
   SMESH_Group* AddGroup (const SMDSAbs_ElementType theType,
                          const char*               theName,
-                         int&                      theId,
-                         const TopoDS_Shape&       theShape=TopoDS_Shape(),
-                         const SMESH_PredicatePtr& thePredicate=SMESH_PredicatePtr());
+                         const int                 theId = -1,
+                         const TopoDS_Shape&       theShape = TopoDS_Shape(),
+                         const SMESH_PredicatePtr& thePredicate = SMESH_PredicatePtr());
 
   SMESH_Group* AddGroup (SMESHDS_GroupBase* groupDS) throw(SALOME_Exception);
 
@@ -326,7 +326,7 @@ class SMESH_EXPORT SMESH_Mesh
   
   std::list<int> GetGroupIds() const;
   
-  SMESH_Group* GetGroup (const int theGroupID);
+  SMESH_Group* GetGroup (const int theGroupID) const;
 
   bool RemoveGroup (const int theGroupID);
 
index 4953701..6ec5305 100644 (file)
@@ -97,7 +97,6 @@
 
 #include <Standard_Failure.hxx>
 #include <Standard_ErrorHandler.hxx>
-#include <OSD_Parallel.hxx>
 
 #include "SMESH_TryCatch.hxx" // include after OCCT headers!
 
@@ -6752,8 +6751,8 @@ SMESH_MeshEditor::PGroupIDs SMESH_MeshEditor::Offset( TIDSortedElemSet & theElem
   if ( theElements.empty() ) eIt = meshDS->elementsIterator( SMDSAbs_Face );
   else                       eIt = SMESHUtils::elemSetIterator( theElements );
 
-  SMESH_MeshAlgos::TEPairVec new2OldFaces;
-  SMESH_MeshAlgos::TNPairVec new2OldNodes;
+  SMESH_MeshAlgos::TElemIntPairVec new2OldFaces;
+  SMESH_MeshAlgos::TNodeIntPairVec new2OldNodes;
   std::unique_ptr< SMDS_Mesh > offsetMesh
     ( SMESH_MeshAlgos::MakeOffset( eIt, *meshDS, theValue,
                                    theFixSelfIntersection,
@@ -6796,7 +6795,7 @@ SMESH_MeshEditor::PGroupIDs SMESH_MeshEditor::Offset( TIDSortedElemSet & theElem
         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 );
+        srcNodes.push_back( meshDS->FindNode( new2OldNodes[ i ].second ));
       }
     }
 
@@ -6812,7 +6811,7 @@ SMESH_MeshEditor::PGroupIDs SMESH_MeshEditor::Offset( TIDSortedElemSet & theElem
         elemType.myNodes.push_back( tgtMeshDS->FindNode( idShift + n2->GetID() ));
       }
       tgtEditor.AddElement( elemType.myNodes, elemType );
-      srcElems.push_back( new2OldFaces[ i ].second );
+      srcElems.push_back( meshDS->FindElement( new2OldFaces[ i ].second ));
     }
 
   myLastCreatedElems.swap( tgtEditor.myLastCreatedElems );
@@ -8501,6 +8500,7 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
     {
       const SMDS_MeshElement* elem = (*insertMapIt).first;
       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
+      if ( nodeList.size() < 3 ) continue;
       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
 
@@ -11750,12 +11750,11 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
   //MESSAGE(".. Creation of elements: simple junction");
   if (createJointElems)
   {
-    int idg;
     string joints2DName = "joints2D";
-    mapOfJunctionGroups[joints2DName] = this->myMesh->AddGroup(SMDSAbs_Face, joints2DName.c_str(), idg);
+    mapOfJunctionGroups[joints2DName] = this->myMesh->AddGroup(SMDSAbs_Face, joints2DName.c_str());
     SMESHDS_Group *joints2DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints2DName]->GetGroupDS());
     string joints3DName = "joints3D";
-    mapOfJunctionGroups[joints3DName] = this->myMesh->AddGroup(SMDSAbs_Volume, joints3DName.c_str(), idg);
+    mapOfJunctionGroups[joints3DName] = this->myMesh->AddGroup(SMDSAbs_Volume, joints3DName.c_str());
     SMESHDS_Group *joints3DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints3DName]->GetGroupDS());
 
     itface = faceDomains.begin();
@@ -11783,7 +11782,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
         grpname << dom2 << "_" << dom1;
       string namegrp = grpname.str();
       if (!mapOfJunctionGroups.count(namegrp))
-        mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str(), idg);
+        mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str());
       SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
       if (sgrp)
         sgrp->Add(vol->GetID());
@@ -11816,10 +11815,9 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
       stringstream grpname;
       grpname << "m2j_";
       grpname << 0 << "_" << 0;
-      int idg;
       string namegrp = grpname.str();
       if (!mapOfJunctionGroups.count(namegrp))
-        mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str(), idg);
+        mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str());
       SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
       if (sgrp)
         sgrp->Add(face->GetID());
@@ -11845,10 +11843,9 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
               orderedNodes.push_back( nodeDomains[ nodes[ ino ]][ orderDom[ idom ]]);
         SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
 
-        int idg;
         string namegrp = "jointsMultiples";
         if (!mapOfJunctionGroups.count(namegrp))
-          mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
+          mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str());
         SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
         if (sgrp)
           sgrp->Add(vol->GetID());
@@ -12106,10 +12103,9 @@ bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSort
         stringstream grpname;
         grpname << "jf_";
         grpname << idom;
-        int idg;
         string namegrp = grpname.str();
         if (!mapOfJunctionGroups.count(namegrp))
-          mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
+          mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str());
         SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
         if (sgrp)
           sgrp->Add(vol->GetID());
@@ -12180,10 +12176,10 @@ void SMESH_MeshEditor::CreateHoleSkin(double                          radius,
 
   // --- define groups to build
 
-  int idg; // --- group of SMDS volumes
+  // --- group of SMDS volumes
   string grpvName = groupName;
   grpvName += "_vol";
-  SMESH_Group *grp = this->myMesh->AddGroup(SMDSAbs_Volume, grpvName.c_str(), idg);
+  SMESH_Group *grp = this->myMesh->AddGroup(SMDSAbs_Volume, grpvName.c_str());
   if (!grp)
   {
     MESSAGE("group not created " << grpvName);
@@ -12191,10 +12187,10 @@ void SMESH_MeshEditor::CreateHoleSkin(double                          radius,
   }
   SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(grp->GetGroupDS());
 
-  int idgs; // --- group of SMDS faces on the skin
+  // --- group of SMDS faces on the skin
   string grpsName = groupName;
   grpsName += "_skin";
-  SMESH_Group *grps = this->myMesh->AddGroup(SMDSAbs_Face, grpsName.c_str(), idgs);
+  SMESH_Group *grps = this->myMesh->AddGroup(SMDSAbs_Face, grpsName.c_str());
   if (!grps)
   {
     MESSAGE("group not created " << grpsName);
@@ -12202,10 +12198,10 @@ void SMESH_MeshEditor::CreateHoleSkin(double                          radius,
   }
   SMESHDS_Group *sgrps = dynamic_cast<SMESHDS_Group*>(grps->GetGroupDS());
 
-  int idgi; // --- group of SMDS faces internal (several shapes)
+  // --- group of SMDS faces internal (several shapes)
   string grpiName = groupName;
   grpiName += "_internalFaces";
-  SMESH_Group *grpi = this->myMesh->AddGroup(SMDSAbs_Face, grpiName.c_str(), idgi);
+  SMESH_Group *grpi = this->myMesh->AddGroup(SMDSAbs_Face, grpiName.c_str());
   if (!grpi)
   {
     MESSAGE("group not created " << grpiName);
@@ -12213,10 +12209,10 @@ void SMESH_MeshEditor::CreateHoleSkin(double                          radius,
   }
   SMESHDS_Group *sgrpi = dynamic_cast<SMESHDS_Group*>(grpi->GetGroupDS());
 
-  int idgei; // --- group of SMDS faces internal (several shapes)
+  // --- group of SMDS faces internal (several shapes)
   string grpeiName = groupName;
   grpeiName += "_internalEdges";
-  SMESH_Group *grpei = this->myMesh->AddGroup(SMDSAbs_Edge, grpeiName.c_str(), idgei);
+  SMESH_Group *grpei = this->myMesh->AddGroup(SMDSAbs_Edge, grpeiName.c_str());
   if (!grpei)
   {
     MESSAGE("group not created " << grpeiName);
@@ -13040,565 +13036,3 @@ void SMESH_MeshEditor::copyPosition( const SMDS_MeshNode* from,
   default:;
   }
 }
-
-namespace // utils for MakePolyLine
-{
-  //================================================================================
-  /*!
-   * \brief Sequence of found points and a current point data
-   */
-  struct Path
-  {
-    std::vector< gp_XYZ >   myPoints;
-    double                  myLength;
-
-    const SMDS_MeshElement* myFace;
-    SMESH_NodeXYZ           myNode1; // nodes of the edge the path entered myFace
-    SMESH_NodeXYZ           myNode2;
-    int                     myNodeInd1;
-    int                     myNodeInd2;
-    double                  myDot1;
-    double                  myDot2;
-
-    int                     mySrcPntInd; //!< start point index
-    TIDSortedElemSet        myElemSet, myAvoidSet;
-
-    Path(): myLength(0.0), myFace(0) {}
-
-    bool SetCutAtCorner( const SMESH_NodeXYZ&    cornerNode,
-                         const SMDS_MeshElement* face,
-                         const gp_XYZ&           plnNorm,
-                         const gp_XYZ&           plnOrig );
-
-    void AddPoint( const gp_XYZ& p );
-
-    bool Extend( const gp_XYZ& plnNorm, const gp_XYZ& plnOrig );
-
-    bool ReachSamePoint( const Path& other );
-
-    static void Remove( std::vector< Path > & paths, size_t& i );
-  };
-
-  //================================================================================
-  /*!
-   * \brief Return true if this Path meats another
-   */
-  //================================================================================
-
-  bool Path::ReachSamePoint( const Path& other )
-  {
-    return ( mySrcPntInd != other.mySrcPntInd &&
-             myFace == other.myFace );
-  }
-
-  //================================================================================
-  /*!
-   * \brief Remove a path from a vector
-   */
-  //================================================================================
-
-  void Path::Remove( std::vector< Path > & paths, size_t& i )
-  {
-    if ( paths.size() > 1 )
-    {
-      size_t j = paths.size() - 1; // last item to be removed
-      if ( i < j )
-      {
-        paths[ i ].myPoints.swap( paths[ j ].myPoints );
-        paths[ i ].myLength    = paths[ j ].myLength;
-        paths[ i ].mySrcPntInd = paths[ j ].mySrcPntInd;
-        paths[ i ].myFace      = paths[ j ].myFace;
-        paths[ i ].myNode1     = paths[ j ].myNode1;
-        paths[ i ].myNode2     = paths[ j ].myNode2;
-        paths[ i ].myNodeInd1  = paths[ j ].myNodeInd1;
-        paths[ i ].myNodeInd2  = paths[ j ].myNodeInd2;
-        paths[ i ].myDot1      = paths[ j ].myDot1;
-        paths[ i ].myDot2      = paths[ j ].myDot2;
-      }
-    }
-    paths.pop_back();
-    if ( i > 0 )
-      --i;
-  }
-
-  //================================================================================
-  /*!
-   * \brief Store a point that is at a node of a face if the face is intersected by plane.
-   *        Return false if the node is a sole intersection point of the face and the plane
-   */
-  //================================================================================
-
-  bool Path::SetCutAtCorner( const SMESH_NodeXYZ&    cornerNode,
-                             const SMDS_MeshElement* face,
-                             const gp_XYZ&           plnNorm,
-                             const gp_XYZ&           plnOrig )
-  {
-    if ( face == myFace )
-      return false;
-    myNodeInd1 = face->GetNodeIndex( cornerNode._node );
-    myNodeInd2 = ( myNodeInd1 + 1 ) % face->NbCornerNodes();
-    int   ind3 = ( myNodeInd1 + 2 ) % face->NbCornerNodes();
-    myNode1.Set( face->GetNode( ind3 ));
-    myNode2.Set( face->GetNode( myNodeInd2 ));
-
-    myDot1 = plnNorm * ( myNode1 - plnOrig );
-    myDot2 = plnNorm * ( myNode2 - plnOrig );
-
-    bool ok = ( myDot1 * myDot2 < 0 );
-    if ( !ok && myDot1 * myDot2 == 0 )
-    {
-      ok = ( myDot1 != myDot2 );
-      if ( ok && myFace )
-        ok = ( myFace->GetNodeIndex(( myDot1 == 0 ? myNode1 : myNode2 )._node ) < 0 );
-    }
-    if ( ok )
-    {
-      myFace = face;
-      myDot1 = 0;
-      AddPoint( cornerNode );
-    }
-    return ok;
-  }
-
-  //================================================================================
-  /*!
-   * \brief Store a point and update myLength
-   */
-  //================================================================================
-
-  void Path::AddPoint( const gp_XYZ& p )
-  {
-    if ( !myPoints.empty() )
-      myLength += ( p - myPoints.back() ).Modulus();
-    else
-      myLength = 0;
-    myPoints.push_back( p );
-  }
-
-  //================================================================================
-  /*!
-   * \brief Try to find the next point
-   *  \param [in] plnNorm - cutting plane normal
-   *  \param [in] plnOrig - cutting plane origin
-   */
-  //================================================================================
-
-  bool Path::Extend( const gp_XYZ& plnNorm, const gp_XYZ& plnOrig )
-  {
-    int nodeInd3 = ( myNodeInd1 + 1 ) % myFace->NbCornerNodes();
-    if ( myNodeInd2 == nodeInd3 )
-      nodeInd3 = ( myNodeInd1 + 2 ) % myFace->NbCornerNodes();
-
-    SMESH_NodeXYZ node3 = myFace->GetNode( nodeInd3 );
-    double         dot3 = plnNorm * ( node3 - plnOrig );
-
-    if ( dot3 * myDot1 < 0. )
-    {
-      myNode2    = node3;
-      myNodeInd2 = nodeInd3;
-      myDot2     = dot3;
-    }
-    else if ( dot3 * myDot2 < 0. )
-    {
-      myNode1    = node3;
-      myNodeInd1 = nodeInd3;
-      myDot1     = dot3;
-    }
-    else if ( dot3 == 0. )
-    {
-      SMDS_ElemIteratorPtr fIt = node3._node->GetInverseElementIterator(SMDSAbs_Face);
-      while ( fIt->more() )
-        if ( SetCutAtCorner( node3, fIt->next(), plnNorm, plnOrig ))
-          return true;
-      return false;
-    }
-    else if ( myDot2 == 0. )
-    {
-      SMESH_NodeXYZ node2 = myNode2; // copy as myNode2 changes in SetCutAtCorner()
-      SMDS_ElemIteratorPtr fIt = node2._node->GetInverseElementIterator(SMDSAbs_Face);
-      while ( fIt->more() )
-        if ( SetCutAtCorner( node2, fIt->next(), plnNorm, plnOrig ))
-          return true;
-      return false;
-    }
-
-    double r = Abs( myDot1 / ( myDot2 - myDot1 ));
-    AddPoint( myNode1 * ( 1 - r ) + myNode2 * r );
-
-    myAvoidSet.clear();
-    myAvoidSet.insert( myFace );
-    myFace = SMESH_MeshAlgos::FindFaceInSet( myNode1._node, myNode2._node,
-                                             myElemSet,   myAvoidSet,
-                                             &myNodeInd1, &myNodeInd2 );
-    return myFace;
-  }
-
-  //================================================================================
-  /*!
-   * \brief Compute a path between two points of PolySegment
-   */
-  struct PolyPathCompute
-  {
-    SMESH_MeshEditor::TListOfPolySegments& mySegments; //!< inout PolySegment's
-    std::vector< Path >&                   myPaths;    //!< path of each of segments to compute
-    SMESH_Mesh*                            myMesh;
-    mutable std::vector< std::string >     myErrors;
-
-    PolyPathCompute( SMESH_MeshEditor::TListOfPolySegments& theSegments,
-                     std::vector< Path >&                   thePaths,
-                     SMESH_Mesh*                            theMesh):
-      mySegments( theSegments ),
-      myPaths( thePaths ),
-      myMesh( theMesh ),
-      myErrors( theSegments.size() )
-    {
-    }
-
-#undef SMESH_CAUGHT
-#define SMESH_CAUGHT myErrors[i] =
-    void operator() ( const int i ) const
-    {
-      SMESH_TRY;
-      const_cast< PolyPathCompute* >( this )->Compute( i );
-      SMESH_CATCH( SMESH::returnError );
-    }
-#undef SMESH_CAUGHT
-
-    //================================================================================
-    /*!
-     * \brief Compute a path of a given segment
-     */
-    //================================================================================
-
-    void Compute( const int iSeg )
-    {
-      SMESH_MeshEditor::PolySegment& polySeg = mySegments[ iSeg ];
-
-      // the cutting plane
-      gp_XYZ plnNorm = ( polySeg.myXYZ[0] - polySeg.myXYZ[1] ) ^ polySeg.myVector.XYZ();
-      gp_XYZ plnOrig = polySeg.myXYZ[1];
-
-      // Find paths connecting the 2 end points of polySeg
-
-      std::vector< Path > paths; paths.reserve(10);
-
-      // 1) initialize paths; two paths starts at each end point
-
-      for ( int iP = 0; iP < 2; ++iP ) // loop on the polySeg end points
-      {
-        Path path;
-        path.mySrcPntInd = iP;
-        size_t nbPaths = paths.size();
-
-        if ( polySeg.myFace[ iP ]) // the end point lies on polySeg.myFace[ iP ]
-        {
-          // check coincidence of polySeg.myXYZ[ iP ] with nodes
-          const double tol = 1e-20;
-          SMESH_NodeXYZ nodes[4];
-          for ( int i = 0; i < 3 &&  !polySeg.myNode1[ iP ]; ++i )
-          {
-            nodes[ i ] = polySeg.myFace[ iP ]->GetNode( i );
-            if (( nodes[ i ] - polySeg.myXYZ[ iP ]).SquareModulus() < tol*tol )
-              polySeg.myNode1[ iP ] = nodes[ i ].Node();
-          }
-          nodes[ 3 ] = nodes[ 0 ];
-
-          // check coincidence of polySeg.myXYZ[ iP ] with edges
-          for ( int i = 0; i < 3 &&  !polySeg.myNode1[ iP ]; ++i )
-          {
-            SMDS_LinearEdge edge( nodes[i].Node(), nodes[i+1].Node() );
-            if ( SMESH_MeshAlgos::GetDistance( &edge, polySeg.myXYZ[ iP ]) < tol )
-            {
-              polySeg.myNode1[ iP ] = nodes[ i     ].Node();
-              polySeg.myNode2[ iP ] = nodes[ i + 1 ].Node();
-            }
-          }
-
-          if ( !polySeg.myNode1[ iP ] ) // polySeg.myXYZ[ iP ] is within polySeg.myFace[ iP ]
-          {
-            double dot[ 4 ];
-            for ( int i = 0; i < 3; ++i )
-              dot[ i ] = plnNorm * ( nodes[ i ] - plnOrig );
-            dot[ 3 ] = dot[ 0 ];
-
-            int iCut = 0; // index of a cut edge
-            if      ( dot[ 1 ] * dot[ 2 ] < 0. ) iCut = 1;
-            else if ( dot[ 2 ] * dot[ 3 ] < 0. ) iCut = 2;
-
-            // initialize path so as if it entered the face via iCut-th edge
-            path.myFace = polySeg.myFace[ iP ];
-            path.myNodeInd1 = iCut;
-            path.myNodeInd2 = iCut + 1;
-            path.myNode1.Set( nodes[ iCut     ].Node() );
-            path.myNode2.Set( nodes[ iCut + 1 ].Node() );
-            path.myDot1 = dot[ iCut ];
-            path.myDot2 = dot[ iCut + 1 ];
-            path.myPoints.clear();
-            path.AddPoint( polySeg.myXYZ[ iP ]);
-            paths.push_back( path );
-
-            path.Extend( plnNorm, plnOrig ); // to get another edge cut
-            path.myFace = polySeg.myFace[ iP ];
-            if ( path.myDot1 == 0. ) // cut at a node
-            {
-              path.myNodeInd1 = ( iCut + 2 ) % 3;
-              path.myNodeInd2 = ( iCut + 3 ) % 3;
-              path.myNode2.Set( path.myFace->GetNode( path.myNodeInd2 ));
-              path.myDot2 = dot[ path.myNodeInd2 ];
-            }
-            else
-            {
-              path.myNodeInd1 = path.myFace->GetNodeIndex( path.myNode1.Node() );
-              path.myNodeInd2 = path.myFace->GetNodeIndex( path.myNode2.Node() );
-            }
-            path.myPoints.clear();
-            path.AddPoint( polySeg.myXYZ[ iP ]);
-            paths.push_back( path );
-          }
-        }
-
-        if ( polySeg.myNode2[ iP ] && polySeg.myNode2[ iP ] != polySeg.myNode1[ iP ] )
-        {
-          // the end point is on an edge
-          while (( path.myFace = SMESH_MeshAlgos::FindFaceInSet( polySeg.myNode1[ iP ],
-                                                                 polySeg.myNode2[ iP ],
-                                                                 path.myElemSet,
-                                                                 path.myAvoidSet,
-                                                                 &path.myNodeInd1,
-                                                                 &path.myNodeInd2 )))
-          {
-            path.myNode1.Set( polySeg.myNode1[ iP ]);
-            path.myNode2.Set( polySeg.myNode2[ iP ]);
-            path.myDot1 = plnNorm * ( path.myNode1 - plnOrig );
-            path.myDot2 = plnNorm * ( path.myNode2 - plnOrig );
-            path.myPoints.clear();
-            path.AddPoint( polySeg.myXYZ[ iP ]);
-            path.myAvoidSet.insert( path.myFace );
-            paths.push_back( path );
-          }
-          if ( nbPaths == paths.size() )
-            throw SALOME_Exception ( SMESH_Comment("No face edge found by point ") << iP+1
-                                     << " in a PolySegment " << iSeg );
-        }
-        else if ( polySeg.myNode1[ iP ] ) // the end point is at a node
-        {
-          std::set<const SMDS_MeshNode* > nodes;
-          SMDS_ElemIteratorPtr fIt = polySeg.myNode1[ iP ]->GetInverseElementIterator(SMDSAbs_Face);
-          while ( fIt->more() )
-          {
-            path.myPoints.clear();
-            if ( path.SetCutAtCorner( polySeg.myNode1[ iP ], fIt->next(), plnNorm, plnOrig ))
-            {
-              if (( path.myDot1 * path.myDot2 != 0 ) ||
-                  ( nodes.insert( path.myDot1 == 0 ? path.myNode1._node : path.myNode2._node ).second ))
-                paths.push_back( path );
-            }
-          }
-        }
-
-        // look for a one-segment path
-        for ( size_t i = 0; i < nbPaths; ++i )
-          for ( size_t j = nbPaths; j < paths.size(); ++j )
-            if ( paths[i].myFace == paths[j].myFace )
-            {
-              myPaths[ iSeg ].myPoints.push_back( paths[i].myPoints[0] );
-              myPaths[ iSeg ].myPoints.push_back( paths[j].myPoints[0] );
-              paths.clear();
-            }
-      }
-
-      // 2) extend paths and compose the shortest one connecting the two points
-
-      myPaths[ iSeg ].myLength = 1e100;
-
-      while ( paths.size() >= 2 )
-      {
-        for ( size_t i = 0; i < paths.size(); ++i )
-        {
-          Path& path = paths[ i ];
-          if ( !path.Extend( plnNorm, plnOrig ) ||        // path reached a mesh boundary
-               path.myLength > myPaths[ iSeg ].myLength ) // path is longer than others
-          {
-            Path::Remove( paths, i );
-            continue;
-          }
-
-          // join paths that reach same point
-          for ( size_t j = 0; j < paths.size(); ++j )
-          {
-            if ( i != j && paths[i].ReachSamePoint( paths[j] ))
-            {
-              double   distLast = ( paths[i].myPoints.back() - paths[j].myPoints.back() ).Modulus();
-              double fullLength = ( paths[i].myLength + paths[j].myLength + distLast );
-              if ( fullLength < myPaths[ iSeg ].myLength )
-              {
-                myPaths[ iSeg ].myLength = fullLength;
-                std::vector< gp_XYZ > & allPoints = myPaths[ iSeg ].myPoints;
-                allPoints.swap( paths[i].myPoints );
-                allPoints.insert( allPoints.end(),
-                                  paths[j].myPoints.rbegin(),
-                                  paths[j].myPoints.rend() );
-              }
-              Path::Remove( paths, i );
-              Path::Remove( paths, j );
-            }
-          }
-        }
-        if ( !paths.empty() && (int) paths[0].myPoints.size() > myMesh->NbFaces() )
-          throw SALOME_Exception(LOCALIZED( "Infinite loop in MakePolyLine()"));
-      }
-
-      if ( myPaths[ iSeg ].myPoints.empty() )
-        throw SALOME_Exception( SMESH_Comment("Can't find a full path for PolySegment #") << iSeg );
-
-      // reverse the path
-      double d00 = ( polySeg.myXYZ[0] - myPaths[ iSeg ].myPoints.front() ).SquareModulus();
-      double d01 = ( polySeg.myXYZ[0] - myPaths[ iSeg ].myPoints.back()  ).SquareModulus();
-      if ( d00 > d01 )
-        std::reverse( myPaths[ iSeg ].myPoints.begin(), myPaths[ iSeg ].myPoints.end() );
-
-    } // PolyPathCompute::Compute()
-
-  }; // struct PolyPathCompute
-
-} // namespace
-
-//=======================================================================
-//function : MakePolyLine
-//purpose  : Create a polyline consisting of 1D mesh elements each lying on a 2D element of
-//           the initial mesh
-//=======================================================================
-
-void SMESH_MeshEditor::MakePolyLine( TListOfPolySegments&   theSegments,
-                                     SMESHDS_Group*         theGroup,
-                                     SMESH_ElementSearcher* theSearcher)
-{
-  std::vector< Path > segPaths( theSegments.size() ); // path of each of segments
-
-  SMESH_ElementSearcher* searcher = theSearcher;
-  SMESHUtils::Deleter<SMESH_ElementSearcher> delSearcher;
-  if ( !searcher )
-  {
-    searcher = SMESH_MeshAlgos::GetElementSearcher( *GetMeshDS() );
-    delSearcher._obj = searcher;
-  }
-
-  // get cutting planes
-
-  std::vector< bool > isVectorOK( theSegments.size(), true );
-  const double planarCoef = 0.333; // plane height in planar case
-
-  for ( size_t iSeg = 0; iSeg < theSegments.size(); ++iSeg )
-  {
-    PolySegment& polySeg = theSegments[ iSeg ];
-
-    gp_XYZ p1 = SMESH_NodeXYZ( polySeg.myNode1[0] );
-    gp_XYZ p2 = SMESH_NodeXYZ( polySeg.myNode1[1] );
-    if ( polySeg.myNode2[0] ) p1 = 0.5 * ( p1 + SMESH_NodeXYZ( polySeg.myNode2[0] ));
-    if ( polySeg.myNode2[1] ) p2 = 0.5 * ( p2 + SMESH_NodeXYZ( polySeg.myNode2[1] ));
-
-    polySeg.myFace[0] = polySeg.myFace[1] = 0;
-    if ( !polySeg.myNode1[0] && !polySeg.myNode2[0] )
-    {
-      p1 = searcher->Project( polySeg.myXYZ[0], SMDSAbs_Face, &polySeg.myFace[0] );
-    }
-    if ( !polySeg.myNode1[1] && !polySeg.myNode2[1] )
-    {
-      p2 = searcher->Project( polySeg.myXYZ[1], SMDSAbs_Face, &polySeg.myFace[1] );
-    }
-    polySeg.myXYZ[0] = p1;
-    polySeg.myXYZ[1] = p2;
-
-    gp_XYZ plnNorm = ( p1 - p2 ) ^ polySeg.myVector.XYZ();
-
-    isVectorOK[ iSeg ] = ( plnNorm.Modulus() > std::numeric_limits<double>::min() );
-    if ( !isVectorOK[ iSeg ])
-    {
-      gp_XYZ pMid = 0.5 * ( p1 + p2 );
-      const SMDS_MeshElement* face;
-      polySeg.myMidProjPoint = searcher->Project( pMid, SMDSAbs_Face, &face );
-      polySeg.myVector       = polySeg.myMidProjPoint.XYZ() - pMid;
-
-      gp_XYZ faceNorm;
-      SMESH_MeshAlgos::FaceNormal( face, faceNorm );
-
-      if ( polySeg.myVector.Magnitude() < Precision::Confusion() ||
-           polySeg.myVector * faceNorm  < Precision::Confusion() )
-      {
-        polySeg.myVector = faceNorm;
-        polySeg.myMidProjPoint = pMid + faceNorm * ( p1 - p2 ).Modulus() * planarCoef;
-      }
-    }
-    else
-    {
-      polySeg.myVector = plnNorm ^ ( p1 - p2 );
-    }
-  }
-
-  // assure that inverse elements are constructed, avoid their concurrent building in threads
-  GetMeshDS()->nodesIterator()->next()->NbInverseElements();
-
-  // find paths
-
-  PolyPathCompute algo( theSegments, segPaths, myMesh );
-  OSD_Parallel::For( 0, theSegments.size(), algo, theSegments.size() == 1 );
-
-  for ( size_t iSeg = 0; iSeg < theSegments.size(); ++iSeg )
-    if ( !algo.myErrors[ iSeg ].empty() )
-      throw SALOME_Exception( algo.myErrors[ iSeg ].c_str() );
-
-  // create an 1D mesh
-
-  const SMDS_MeshNode *n, *nPrev = 0;
-  SMESHDS_Mesh* mesh = GetMeshDS();
-
-  for ( size_t iSeg = 0; iSeg < theSegments.size(); ++iSeg )
-  {
-    const Path& path = segPaths[iSeg];
-    if ( path.myPoints.size() < 2 )
-      continue;
-
-    double tol = path.myLength / path.myPoints.size() / 1000.;
-    if ( !nPrev || ( SMESH_NodeXYZ( nPrev ) - path.myPoints[0] ).SquareModulus() > tol*tol )
-    {
-      nPrev = mesh->AddNode( path.myPoints[0].X(), path.myPoints[0].Y(), path.myPoints[0].Z() );
-      myLastCreatedNodes.push_back( nPrev );
-    }
-    for ( size_t iP = 1; iP < path.myPoints.size(); ++iP )
-    {
-      n = mesh->AddNode( path.myPoints[iP].X(), path.myPoints[iP].Y(), path.myPoints[iP].Z() );
-      myLastCreatedNodes.push_back( n );
-
-      const SMDS_MeshElement* elem = mesh->AddEdge( nPrev, n );
-      myLastCreatedElems.push_back( elem );
-      if ( theGroup )
-        theGroup->Add( elem );
-
-      nPrev = n;
-    }
-
-    // return a vector
-
-    gp_XYZ pMid = 0.5 * ( path.myPoints[0] + path.myPoints.back() );
-    if ( isVectorOK[ iSeg ])
-    {
-      // find the most distance point of a path
-      double maxDist = 0;
-      for ( size_t iP = 1; iP < path.myPoints.size(); ++iP )
-      {
-        double dist = Abs( theSegments[iSeg].myVector * ( path.myPoints[iP] - path.myPoints[0] ));
-        if ( dist > maxDist )
-        {
-          maxDist = dist;
-          theSegments[iSeg].myMidProjPoint = path.myPoints[iP];
-        }
-      }
-      if ( maxDist < Precision::Confusion() ) // planar case
-        theSegments[iSeg].myMidProjPoint =
-          pMid + theSegments[iSeg].myVector.XYZ().Normalized() * path.myLength * planarCoef;
-    }
-    theSegments[iSeg].myVector = gp_Vec( pMid, theSegments[iSeg].myMidProjPoint );
-  }
-
-  return;
-}
index e5e558b..221a78d 100644 (file)
@@ -717,49 +717,6 @@ public:
                        bool                    toAddExistingBondary = false,
                        bool                    aroundElements = false);
 
-
-  // structure used in MakePolyLine() to define a cutting plane
-  struct PolySegment
-  {
-    // 2 points, each defined as follows:
-    // ( myNode1 &&  myNode2 ) ==> point is in the middle of an edge defined by two nodes
-    // ( myNode1 && !myNode2 ) ==> point is at myNode1
-    // else                    ==> point is at myXYZ
-    const SMDS_MeshNode*    myNode1[2];
-    const SMDS_MeshNode*    myNode2[2];
-    gp_XYZ                  myXYZ  [2];
-
-    // face on which myXYZ projects (found by MakePolyLine())
-    const SMDS_MeshElement* myFace [2];
-
-    // vector on the plane; to use a default plane set vector = (0,0,0)
-    gp_Vec myVector;
-
-    // point to return coordinates of a middle of the two points, projected to mesh
-    gp_Pnt myMidProjPoint;
-  };
-  typedef std::vector<PolySegment> TListOfPolySegments;
-
-  /*!
-   * \brief Create a polyline consisting of 1D mesh elements each lying on a 2D element of
-   *        the initial mesh. Positions of new nodes are found by cutting the mesh by the
-   *        plane passing through pairs of points specified by each PolySegment structure.
-   *        If there are several paths connecting a pair of points, the shortest path is
-   *        selected by the module. Position of the cutting plane is defined by the two
-   *        points and an optional vector lying on the plane specified by a PolySegment.
-   *        By default the vector is defined by Mesh module as following. A middle point
-   *        of the two given points is computed. The middle point is projected to the mesh.
-   *        The vector goes from the middle point to the projection point. In case of planar
-   *        mesh, the vector is normal to the mesh.
-   *  \param [inout] segments - PolySegment's defining positions of cutting planes.
-   *        Return the used vector and position of the middle point.
-   *  \param [in] group - an optional group where created mesh segments will
-   *        be added.
-   */
-  void MakePolyLine( TListOfPolySegments&   segments,
-                     SMESHDS_Group*         group=0,
-                     SMESH_ElementSearcher* searcher=0);
-
  private:
 
   /*!
index 3159231..2e16075 100644 (file)
@@ -65,6 +65,8 @@
 #define SPACING 6
 #define MARGIN  11
 
+enum { NEW_MESH_ID, APPEND_TO_ID };
+
 //=================================================================================
 // name    : SMESHGUI_BuildCompoundDlg
 // Purpose :
@@ -103,16 +105,28 @@ SMESHGUI_BuildCompoundDlg::SMESHGUI_BuildCompoundDlg( SMESHGUI* theModule )
   ButtonGroup->addButton(Constructor1, 0);
 
   /***************************************************************/
-  GroupName = new QGroupBox(tr("RESULT_NAME"), this);
-  QHBoxLayout* GroupNameLayout = new QHBoxLayout(GroupName);
-  GroupNameLayout->setSpacing(SPACING);
-  GroupNameLayout->setMargin(MARGIN);
-
-  TextLabelName = new QLabel(tr("SMESH_NAME"), GroupName);
-  LineEditName = new QLineEdit(GroupName);
-
-  GroupNameLayout->addWidget(TextLabelName);
-  GroupNameLayout->addWidget(LineEditName);
+  GroupResult = new QGroupBox(tr("RESULT_NAME"), this);
+  QGridLayout* GroupResultLayout = new QGridLayout(GroupResult);
+  GroupResultLayout->setSpacing(SPACING);
+  GroupResultLayout->setMargin(MARGIN);
+
+  QRadioButton* newMeshRadioBtn = new QRadioButton( tr("NEW_MESH_NAME"), GroupResult );
+  QRadioButton* appendToRadioBtn = new QRadioButton( tr("MESH_APPEND_TO"), GroupResult );
+  LineEditNewName = new QLineEdit(GroupResult);
+  LineEditAppendTo = new QLineEdit(GroupResult);
+  SelectButtonAppendTo = new QPushButton(GroupResult);
+  SelectButtonAppendTo->setIcon(image1);
+  SelectButtonAppendTo->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
+  ResultButtonGroup = new QButtonGroup( GroupResult );
+  ResultButtonGroup->addButton( newMeshRadioBtn,  NEW_MESH_ID );
+  ResultButtonGroup->addButton( appendToRadioBtn, APPEND_TO_ID );
+  newMeshRadioBtn->setChecked( true );
+
+  GroupResultLayout->addWidget( newMeshRadioBtn,      0, 0, 1, 2 );
+  GroupResultLayout->addWidget( LineEditNewName,      0, 2 );
+  GroupResultLayout->addWidget( appendToRadioBtn,     1, 0 );
+  GroupResultLayout->addWidget( SelectButtonAppendTo, 1, 1 );
+  GroupResultLayout->addWidget( LineEditAppendTo,     1, 2 );
 
   /***************************************************************/
   GroupArgs = new QGroupBox(tr("SMESH_ARGUMENTS"), this);
@@ -175,7 +189,7 @@ SMESHGUI_BuildCompoundDlg::SMESHGUI_BuildCompoundDlg( SMESHGUI* theModule )
 
   /***************************************************************/
   aTopLayout->addWidget(GroupConstructors);
-  aTopLayout->addWidget(GroupName);
+  aTopLayout->addWidget(GroupResult);
   aTopLayout->addWidget(GroupArgs);
   aTopLayout->addWidget(GroupButtons);
 
@@ -200,11 +214,11 @@ void SMESHGUI_BuildCompoundDlg::Init()
 {
   mySMESHGUI->SetActiveDialogBox((QDialog*)this);
 
-  myMesh = SMESH::SMESH_IDSource::_nil();
+  myMeshToAppendTo = SMESH::SMESH_Mesh::_nil();
+  myMeshArray      = new SMESH::ListOfIDSources();
 
-  myMeshFilter = new SMESH_TypeFilter (SMESH::IDSOURCE);
-
-  myMeshArray = new SMESH::ListOfIDSources();
+  myMeshFilter     = new SMESH_TypeFilter (SMESH::IDSOURCE);
+  myAppendToFilter = new SMESH_TypeFilter (SMESH::MESH);
 
   // signals and slots connections
   connect(buttonOk,     SIGNAL(clicked()), this, SLOT(ClickOnOk()));
@@ -212,7 +226,10 @@ void SMESHGUI_BuildCompoundDlg::Init()
   connect(buttonApply,  SIGNAL(clicked()), this, SLOT(ClickOnApply()));
   connect(buttonHelp,   SIGNAL(clicked()), this, SLOT(ClickOnHelp()));
 
-  connect(SelectButton, SIGNAL(clicked()), this, SLOT(SelectionIntoArgument()));
+  connect(ResultButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(onResultTypeChange(int)));
+
+  connect(SelectButtonAppendTo, SIGNAL(clicked()), this, SLOT(onSelectionButton()));
+  connect(SelectButton, SIGNAL(clicked()), this, SLOT(onSelectionButton()));
 
   connect(CheckBoxMerge, SIGNAL(toggled(bool)), this, SLOT(onSelectMerge(bool)));
 
@@ -221,8 +238,7 @@ void SMESHGUI_BuildCompoundDlg::Init()
   connect(mySMESHGUI, SIGNAL(SignalDeactivateActiveDialog()), this, SLOT(DeactivateActiveDialog()));
   connect(mySMESHGUI, SIGNAL(SignalCloseAllDialogs()),        this, SLOT(reject()));
 
-  LineEditName->setText(GetDefaultName(tr("COMPOUND_MESH")));
-  LineEditMeshes->setFocus();
+  LineEditNewName->setText(GetDefaultName(tr("COMPOUND_MESH")));
 
   ComboBoxUnion->addItem(tr("UNITE"));
   ComboBoxUnion->addItem(tr("RENAME"));
@@ -235,10 +251,9 @@ void SMESHGUI_BuildCompoundDlg::Init()
 
   SpinBoxTol->setEnabled(CheckBoxMerge->isChecked());
 
-  mySelectionMgr->clearFilters();
-  mySelectionMgr->installFilter(myMeshFilter);
+  onResultTypeChange( ResultButtonGroup->checkedId() );
 
-  SelectionIntoArgument();
+  onSelectionButton();
 }
 
 //=================================================================================
@@ -290,7 +305,9 @@ bool SMESHGUI_BuildCompoundDlg::ClickOnApply()
 
   SMESH::SMESH_Mesh_var aMesh;
 
-  if (!myMesh->_is_nil())
+  int nbMeshes = myMeshArray->length() + ( !myMeshToAppendTo->_is_nil() );
+
+  if ( nbMeshes > 1 )
   {
     QStringList aParameters;
     aParameters << (CheckBoxMerge->isChecked() ? SpinBoxTol->text() : QString(" "));
@@ -307,16 +324,19 @@ bool SMESHGUI_BuildCompoundDlg::ClickOnApply()
         aMesh = aSMESHGen->ConcatenateWithGroups(myMeshArray,
                                                  !(ComboBoxUnion->currentIndex()),
                                                  CheckBoxMerge->isChecked(),
-                                                 SpinBoxTol->GetValue());
+                                                 SpinBoxTol->GetValue(),
+                                                 myMeshToAppendTo);
       else
         aMesh = aSMESHGen->Concatenate(myMeshArray,
                                        !(ComboBoxUnion->currentIndex()),
                                        CheckBoxMerge->isChecked(),
-                                       SpinBoxTol->GetValue());
+                                       SpinBoxTol->GetValue(),
+                                       myMeshToAppendTo);
 
       _PTR(SObject) aSO = SMESH::FindSObject( aMesh );
       if( aSO ) {
-        SMESH::SetName( aSO, LineEditName->text() );
+        if ( myMeshToAppendTo->_is_nil() )
+          SMESH::SetName( aSO, LineEditNewName->text() );
         anEntryList.append( aSO->GetID().c_str() );
       }
       mySMESHGUI->updateObjBrowser();
@@ -324,7 +344,7 @@ bool SMESHGUI_BuildCompoundDlg::ClickOnApply()
       return false;
     }
 
-    LineEditName->setText(GetDefaultName(tr("COMPOUND_MESH")));
+    LineEditNewName->setText(GetDefaultName(tr("COMPOUND_MESH")));
 
     // IPAL21468 Compound is hidden after creation.
     if ( SMESHGUI::automaticUpdate() ) {
@@ -401,30 +421,41 @@ void SMESHGUI_BuildCompoundDlg::SelectionIntoArgument()
     return;
 
   QString aString = "";
-
   SALOME_ListIO aList;
+
   mySelectionMgr->selectedObjects(aList);
   int nbSel = SMESH::GetNameOfSelectedIObjects(mySelectionMgr, aString);
 
-  if (nbSel != 0) {
-    myMeshArray->length(nbSel);
-    for (int i = 0; nbSel != 0; i++, nbSel--) {
-      Handle(SALOME_InteractiveObject) IO = aList.First();
+  bool toAppend = ( CurrentLineEdit == LineEditAppendTo );
+  bool     isOk = toAppend ? ( nbSel == 1 ) : ( nbSel > 0 );
+  if ( !isOk )
+    aString = "";
+
+  if ( toAppend )
+  {
+    myMeshToAppendTo = SMESH::SMESH_Mesh::_nil();
+    if ( isOk )
+      myMeshToAppendTo = SMESH::IObjectToInterface<SMESH::SMESH_Mesh>( aList.First() );
+  }
+  else
+  {
+    myMeshArray->length( nbSel );
+    for ( int i = 0; !aList.IsEmpty(); i++ ) {
+      myMeshArray[i] = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>(aList.First());
       aList.RemoveFirst();
-      myMesh = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>(IO);
-      myMeshArray[i] = myMesh;
     }
   }
-  else {
-    myMesh = SMESH::SMESH_IDSource::_nil();
-    aString = "";
-  }
-
-  LineEditMeshes->setText(aString);
-
-  bool isEnabled = (!myMesh->_is_nil());
-  buttonOk->setEnabled(isEnabled);
-  buttonApply->setEnabled(isEnabled);
+  CurrentLineEdit->setText(aString);
+
+  bool isEnabled;
+  if ( ResultButtonGroup->checkedId() == NEW_MESH_ID )
+    isEnabled = ( myMeshArray->length() > 1 );
+  else
+    isEnabled = ( myMeshArray->length() > 0 &&
+                  !myMeshToAppendTo->_is_nil() &&
+                  LineEditAppendTo->text() != LineEditMeshes->text() );
+  buttonOk   ->setEnabled( isEnabled );
+  buttonApply->setEnabled( isEnabled );
 }
 
 //=================================================================================
@@ -435,7 +466,7 @@ void SMESHGUI_BuildCompoundDlg::DeactivateActiveDialog()
 {
   if (GroupConstructors->isEnabled()) {
     GroupConstructors->setEnabled(false);
-    GroupName->setEnabled(false);
+    GroupResult->setEnabled(false);
     GroupArgs->setEnabled(false);
     GroupButtons->setEnabled(false);
     mySMESHGUI->ResetState();
@@ -452,7 +483,7 @@ void SMESHGUI_BuildCompoundDlg::ActivateThisDialog()
   /* Emit a signal to deactivate the active dialog */
   mySMESHGUI->EmitSignalDeactivateDialog();
   GroupConstructors->setEnabled(true);
-  GroupName->setEnabled(true);
+  GroupResult->setEnabled(true);
   GroupArgs->setEnabled(true);
   GroupButtons->setEnabled(true);
 
@@ -500,6 +531,56 @@ void SMESHGUI_BuildCompoundDlg::onSelectMerge(bool toMerge)
     SpinBoxTol->SetValue(1e-05);
 }
 
+//=======================================================================
+//function : onResultTypeChange
+//purpose  : 
+//=======================================================================
+
+void SMESHGUI_BuildCompoundDlg::onResultTypeChange( int buttonID )
+{
+  LineEditNewName     ->setEnabled( buttonID == NEW_MESH_ID );
+  SelectButtonAppendTo->setEnabled( buttonID == APPEND_TO_ID );
+  LineEditAppendTo    ->setEnabled( buttonID == APPEND_TO_ID );
+
+  if ( CurrentLineEdit == LineEditAppendTo && buttonID == NEW_MESH_ID )
+    onSelectionButton(); // to select into myMeshArray
+    
+  if ( buttonID == NEW_MESH_ID )
+  {
+    myMeshToAppendTo = SMESH::SMESH_Mesh::_nil();
+    LineEditAppendTo->setText("");
+  }
+  else
+  {
+    // activate selection of myMeshToAppendTo
+    SelectButtonAppendTo->click();
+    LineEditAppendTo->setFocus();
+  }
+}
+
+//=======================================================================
+//function : onSelectionButton
+//purpose  : 
+//=======================================================================
+
+void SMESHGUI_BuildCompoundDlg::onSelectionButton()
+{
+  mySelectionMgr->clearFilters();
+  if ( sender() == SelectButtonAppendTo )
+  {
+    mySelectionMgr->installFilter( myAppendToFilter );
+    CurrentLineEdit = LineEditAppendTo;
+  }
+  else
+  {
+    mySelectionMgr->installFilter( myMeshFilter );
+    CurrentLineEdit = LineEditMeshes;
+  }
+  CurrentLineEdit->setFocus();
+
+  SelectionIntoArgument();
+}
+
 //=================================================================================
 // function : isValid
 // purpose  :
index f54e59e..b401d2c 100644 (file)
 #include CORBA_SERVER_HEADER(SMESH_Gen)
 #include CORBA_SERVER_HEADER(SMESH_Mesh)
 
+class LightApp_SelectionMgr;
+class QButtonGroup;
+class QCheckBox;
+class QComboBox;
 class QGroupBox;
 class QLabel;
 class QLineEdit;
 class QPushButton;
 class QRadioButton;
-class QCheckBox;
-class QComboBox;
 class SMESHGUI;
 class SMESHGUI_SpinBox;
-class LightApp_SelectionMgr;
 class SUIT_SelectionFilter;
 
 //=================================================================================
@@ -80,9 +81,10 @@ private:
   SMESHGUI*               mySMESHGUI;     /* Current SMESHGUI object */
   LightApp_SelectionMgr*  mySelectionMgr; /* User shape selection */
 
-  SMESH::SMESH_IDSource_var  myMesh;
-  SUIT_SelectionFilter*      myMeshFilter;
+  SMESH::SMESH_Mesh_var      myMeshToAppendTo;
   SMESH::ListOfIDSources_var myMeshArray;
+  SUIT_SelectionFilter*      myMeshFilter;
+  SUIT_SelectionFilter*      myAppendToFilter;
 
   // Widgets
   QGroupBox*              GroupConstructors;
@@ -94,9 +96,11 @@ private:
   QPushButton*            buttonApply;
   QPushButton*            buttonHelp;
 
-  QGroupBox*              GroupName;
-  QLabel*                 TextLabelName;
-  QLineEdit*              LineEditName;
+  QGroupBox*              GroupResult;
+  QButtonGroup*           ResultButtonGroup;
+  QLineEdit*              LineEditNewName;
+  QPushButton*            SelectButtonAppendTo;
+  QLineEdit*              LineEditAppendTo;
 
   QGroupBox*              GroupArgs;
   QLabel*                 TextLabelMeshes;
@@ -109,6 +113,8 @@ private:
   QLabel*                 TextLabelTol;
   SMESHGUI_SpinBox*       SpinBoxTol;
 
+  QLineEdit*              CurrentLineEdit;
+
   QString                 myHelpFileName;
 
   bool                    myIsApplyAndClose;
@@ -124,6 +130,8 @@ private slots:
   void                    DeactivateActiveDialog();
   void                    ActivateThisDialog();
   void                    onSelectMerge( bool );
+  void                    onResultTypeChange( int );
+  void                    onSelectionButton();
 };
 
 #endif // SMESHGUI_BUILDCOMPOUNDDLG_H
index 8e19cdd..852bca2 100644 (file)
@@ -173,11 +173,11 @@ SMESHGUI_MinDistance::SMESHGUI_MinDistance( QWidget* parent )
   aSOrigin->setChecked( true );
 #ifndef MINDIST_ENABLE_ELEMENT
   aFElem->setEnabled( false );   // NOT AVAILABLE YET
-  aSElem->setEnabled( false );   // NOT AVAILABLE YET
+  //aSElem->setEnabled( false );   // NOT AVAILABLE YET
 #endif
 #ifndef MINDIST_ENABLE_OBJECT
   aFObject->setEnabled( false ); // NOT AVAILABLE YET
-  aSObject->setEnabled( false ); // NOT AVAILABLE YET
+  //aSObject->setEnabled( false ); // NOT AVAILABLE YET
 #endif
   myDX->setReadOnly( true );
   myDY->setReadOnly( true );
@@ -595,10 +595,14 @@ void SMESHGUI_MinDistance::compute()
     if ( isOrigin ) {
       x2 = y2 = z2 = 0.;
     }
-    else {
+    else if ( mySecond->checkedId() == NodeTgt ) {
       coord = s2->GetMesh()->GetNodeXYZ( result.node2 );
       x2 = coord[0]; y2 = coord[1]; z2 = coord[2];
     }
+    else
+    {
+      x2 = result.maxX; y2 = result.maxY; z2 = result.maxZ; 
+    }
     createPreview( x1, y1, z1, x2, y2, z2 );
     displayPreview();
   }
index 41d27f5..c4ffdde 100644 (file)
@@ -5119,6 +5119,14 @@ Please, create VTK viewer and try again</translation>
         <translation>Meshes, sub-meshes, groups</translation>
     </message>
     <message>
+        <source>NEW_MESH_NAME</source>
+        <translation>Create new mesh named</translation>
+    </message>
+    <message>
+        <source>MESH_APPEND_TO</source>
+        <translation>Append to mesh</translation>
+    </message>
+    <message>
         <source>PROCESSING_IDENTICAL_GROUPS</source>
         <translation>Processing identical groups</translation>
     </message>
@@ -5128,7 +5136,7 @@ Please, create VTK viewer and try again</translation>
     </message>
     <message>
         <source>RESULT_NAME</source>
-        <translation>Result name</translation>
+        <translation>Result</translation>
     </message>
     <message>
         <source>UNITE</source>
index ae011b7..d1f527b 100644 (file)
@@ -82,6 +82,8 @@ SET(SMESHUtils_SOURCES
   SMESH_FillHole.cxx
   SMESH_Triangulate.cxx
   SMESH_Offset.cxx
+  SMESH_Slot.cxx
+  SMESH_PolyLine.cxx
   )
 
 # --- rules ---
index 019f577..6cd891c 100644 (file)
@@ -23,7 +23,7 @@
 // Created   : Tue Apr 30 18:00:36 2013
 // Author    : Edward AGAPOV (eap)
 
-// This file holds some low level algorithms extracted from SMESH_MeshEditor
+// Initially this file held some low level algorithms extracted from SMESH_MeshEditor
 // to make them accessible from Controls package
 
 #include "SMESH_MeshAlgos.hxx"
@@ -285,6 +285,11 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
 
     TElementBoxPool& elBoPool = getLimitAndPool()->_elBoPool;
 
+#ifdef _DEBUG_
+    if ( theElemIt && !theElemIt->more() )
+      std::cout << "WARNING: ElementBndBoxTree constructed on empty iterator!" << std::endl;
+#endif
+
     SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
     while ( elemIt->more() )
     {
@@ -874,7 +879,7 @@ SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt&       point,
         radius = point.Distance( boxCenter ) - 0.5 * ebbTree->maxSize();
       if ( radius < 0 )
         radius = ebbTree->maxSize() / pow( 2., getTreeHeight()) / 2;
-      while ( suspectElems.empty() )
+      while ( suspectElems.empty() && radius < 1e100 )
       {
         ebbTree->getElementsInSphere( point.XYZ(), radius, suspectElems );
         radius *= 1.1;
@@ -1253,7 +1258,7 @@ gp_XYZ SMESH_ElementSearcherImpl::Project(const gp_Pnt&            point,
 
   ElementBndBoxTree::TElemSeq elems;
   ebbTree->getElementsInSphere( p, radius, elems );
-  while ( elems.empty() )
+  while ( elems.empty() && radius < 1e100 )
   {
     radius *= 1.5;
     ebbTree->getElementsInSphere( p, radius, elems );
@@ -1264,7 +1269,7 @@ gp_XYZ SMESH_ElementSearcherImpl::Project(const gp_Pnt&            point,
   ElementBndBoxTree::TElemSeq::iterator e = elems.begin();
   for ( ; e != elems.end(); ++e )
   {
-    double d = SMESH_MeshAlgos::GetDistance( *e, p, &proj );
+    double d = SMESH_MeshAlgos::GetDistance( *e, point, &proj );
     if ( d < minDist )
     {
       bestProj = proj;
@@ -1460,7 +1465,8 @@ namespace
   //            .  RIGHT    .
   //            .           .
   enum PositionName { POS_LEFT = 1, POS_VERTEX = 2, POS_RIGHT = 4, //POS_ON = 8,
-                      POS_ALL = POS_LEFT | POS_RIGHT | POS_VERTEX };
+                      POS_ALL = POS_LEFT | POS_RIGHT | POS_VERTEX,
+                      POS_MAX = POS_RIGHT };
   struct PointPos
   {
     PositionName _name;
@@ -1558,10 +1564,35 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face,
   const double badDistance = -1;
   if ( !face ) return badDistance;
 
+  int nbCorners = face->NbCornerNodes();
+  if ( nbCorners > 3 )
+  {
+    std::vector< const SMDS_MeshNode* > nodes;
+    int nbTria = SMESH_MeshAlgos::Triangulate().GetTriangles( face, nodes );
+
+    double minDist = Precision::Infinite();
+    gp_XYZ cp;
+    for ( int i = 0; i < 3 * nbTria; i += 3 )
+    {
+      SMDS_FaceOfNodes triangle( nodes[i], nodes[i+1], nodes[i+2] );
+      double dist = GetDistance( &triangle, point, closestPnt );
+      if ( dist < minDist )
+      {
+        minDist = dist;
+        if ( closestPnt )
+          cp = *closestPnt;
+      }
+    }
+
+    if ( closestPnt )
+      *closestPnt = cp;
+    return minDist;
+  }
+
   // coordinates of nodes (medium nodes, if any, ignored)
   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator;
   std::vector<gp_XYZ> xyz( TXyzIterator( face->nodesIterator()), TXyzIterator() );
-  xyz.resize( face->NbCornerNodes()+1 );
+  xyz.resize( 4 );
 
   // transformation to get xyz[0] lies on the origin, xyz[1] lies on the Z axis,
   // and xyz[2] lies in the XZ plane. This is to pass to 2D space on XZ plane.
@@ -1585,7 +1616,7 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face,
 
   // move all the nodes to 2D
   std::vector<gp_XY> xy( xyz.size() );
-  for ( size_t i = 0;i < xyz.size()-1; ++i )
+  for ( size_t i = 0; i < 3; ++i )
   {
     gp_XYZ p3d = xyz[i];
     trsf.Transforms( p3d );
@@ -1600,71 +1631,63 @@ 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
-  std::set< PointPos > pntPosSet;
+  std::vector< PointPos > pntPosByType[ POS_MAX + 1 ];
   for ( size_t i = 1; i < xy.size(); ++i )
   {
     PointPos pos = getPointPosition( point2D, &xy[0], i-1 );
-    pntPosSet.insert( pos );
+    pntPosByType[ pos._name ].push_back( pos );
   }
 
   // compute distance
 
-  double minDist2 = Precision::Infinite();
-  for ( std::set< PointPos >::iterator posIt = pntPosSet.begin(); posIt != pntPosSet.end(); ++posIt)
+  double dist = badDistance;
+
+  if ( pntPosByType[ POS_LEFT ].size() > 0 ) // point is most close to an edge
   {
-    PointPos pos = *posIt;
-    if ( pos._name != pntPosSet.begin()->_name )
-      break;
-    switch ( pos._name )
-    {
-    case POS_LEFT: // point is most close to an edge
-    {
-      gp_Vec edge( xyz[ pos._index ], xyz[ pos._index+1 ]);
-      gp_Vec n1p ( xyz[ pos._index ], point  );
-      double u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge
-      // projection of the point on the edge
-      gp_XYZ proj = xyz[ pos._index ] + u * edge.XYZ();
-      double dist2 = point.SquareDistance( proj );
-      if ( dist2 < minDist2 )
-      {
-        if ( closestPnt ) *closestPnt = proj;
-        minDist2 = dist2;
-      }
-      break;
-    }
+    PointPos& pos = pntPosByType[ POS_LEFT ][0];
+
+    gp_Vec edge( xyz[ pos._index ], xyz[ pos._index+1 ]);
+    gp_Vec n1p ( xyz[ pos._index ], point  );
+    double u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge
+    gp_XYZ proj = xyz[ pos._index ] + u * edge.XYZ(); // projection on the edge
+    dist = point.Distance( proj );
+    if ( closestPnt ) *closestPnt = proj;
+  }
 
-    case POS_RIGHT: // point is inside the face
+  else if ( pntPosByType[ POS_RIGHT ].size() >= 2 ) // point is inside the face
+  {
+    dist = Abs( tmpPnt.Y() );
+    if ( closestPnt )
     {
-      double distToFacePlane = Abs( tmpPnt.Y() );
-      if ( closestPnt )
-      {
-        if ( distToFacePlane < std::numeric_limits<double>::min() ) {
-          *closestPnt = point.XYZ();
-        }
-        else {
-          tmpPnt.SetY( 0 );
-          trsf.Inverted().Transforms( tmpPnt );
-          *closestPnt = tmpPnt;
-        }
+      if ( dist < std::numeric_limits<double>::min() ) {
+        *closestPnt = point.XYZ();
+      }
+      else {
+        tmpPnt.SetY( 0 );
+        trsf.Inverted().Transforms( tmpPnt );
+        *closestPnt = tmpPnt;
       }
-      return distToFacePlane;
     }
+  }
 
-    case POS_VERTEX: // point is most close to a node
+  else if ( pntPosByType[ POS_VERTEX ].size() > 0 ) // point is most close to a node
+  {
+    double minDist2 = Precision::Infinite();
+    for ( size_t i = 0; i < pntPosByType[ POS_VERTEX ].size(); ++i )
     {
-      double dist2 = point.SquareDistance( xyz[ pos._index ]);
-      if ( dist2 < minDist2 )
+      PointPos& pos = pntPosByType[ POS_VERTEX ][i];
+
+      double d2 = point.SquareDistance( xyz[ pos._index ]);
+      if ( minDist2 > d2 )
       {
         if ( closestPnt ) *closestPnt = xyz[ pos._index ];
-        minDist2 = dist2;
+        minDist2 = d2;
       }
-      break;
-    }
-    default:;
-      return badDistance;
     }
+    dist = Sqrt( minDist2 );
   }
-  return Sqrt( minDist2 );
+
+  return dist;
 }
 
 //=======================================================================
@@ -2168,6 +2191,207 @@ bool SMESH_MeshAlgos::IsRightOrder( const SMDS_MeshElement* face,
 
 //=======================================================================
 /*!
+ * \brief Partition given 1D elements into groups of contiguous edges.
+ *        A node where number of meeting edges != 2 is a group end.
+ *        An optional startNode is used to orient groups it belongs to.
+ * \return a list of edge groups and a list of corresponding node groups.
+ *         If a group is closed, the first and last nodes of the group are same.
+ */
+//=======================================================================
+
+void SMESH_MeshAlgos::Get1DBranches( SMDS_ElemIteratorPtr theEdgeIt,
+                                     TElemGroupVector&    theEdgeGroups,
+                                     TNodeGroupVector&    theNodeGroups,
+                                     const SMDS_MeshNode* theStartNode )
+{
+  if ( !theEdgeIt )
+    return;
+
+  // build map of nodes and their adjacent edges
+
+  typedef std::vector< const SMDS_MeshNode* >                                 TNodeVec;
+  typedef std::vector< const SMDS_MeshElement* >                              TEdgeVec;
+  typedef NCollection_DataMap< const SMDS_MeshNode*, TEdgeVec, SMESH_Hasher > TEdgesByNodeMap;
+  TEdgesByNodeMap edgesByNode;
+
+  while ( theEdgeIt->more() )
+  {
+    const SMDS_MeshElement* edge = theEdgeIt->next();
+    if ( edge->GetType() != SMDSAbs_Edge )
+      continue;
+
+    const SMDS_MeshNode* nodes[2] = { edge->GetNode(0), edge->GetNode(1) };
+    for ( int i = 0; i < 2; ++i )
+    {
+      TEdgeVec* nodeEdges = edgesByNode.ChangeSeek( nodes[i] );
+      if ( !nodeEdges )
+      {
+        nodeEdges = edgesByNode.Bound( nodes[i], TEdgeVec() );
+        nodeEdges->reserve(2);
+      }
+      nodeEdges->push_back( edge );
+    }
+  }
+
+  if ( edgesByNode.IsEmpty() )
+    return;
+
+
+  // build edge branches
+
+  TElemGroupVector branches(2);
+  TNodeGroupVector nodeBranches(2);
+
+  while ( !edgesByNode.IsEmpty() )
+  {
+    if ( !theStartNode || !edgesByNode.IsBound( theStartNode ))
+    {
+      theStartNode = TEdgesByNodeMap::Iterator( edgesByNode ).Key();
+    }
+
+    size_t nbBranches = 0;
+    bool startIsBranchEnd = false;
+
+    while ( edgesByNode.IsBound( theStartNode ))
+    {
+      // initialize a new branch
+
+      ++nbBranches;
+      if ( branches.size() < nbBranches )
+      {
+        branches.push_back   ( TEdgeVec() );
+        nodeBranches.push_back( TNodeVec() );
+      }
+      TEdgeVec & branch     = branches    [ nbBranches - 1 ];
+      TNodeVec & nodeBranch = nodeBranches[ nbBranches - 1 ];
+      branch.clear();
+      nodeBranch.clear();
+      {
+        TEdgeVec& edges = edgesByNode( theStartNode );
+        startIsBranchEnd = ( edges.size() != 2 );
+
+        int nbEdges = 0;
+        const SMDS_MeshElement* startEdge = 0;
+        for ( size_t i = 0; i < edges.size(); ++i )
+        {
+          if ( !startEdge && edges[i] )
+          {
+            startEdge = edges[i];
+            edges[i] = 0;
+          }
+          nbEdges += bool( edges[i] );
+        }
+        if ( nbEdges == 0 )
+          edgesByNode.UnBind( theStartNode );
+        if ( !startEdge )
+          continue;
+
+        branch.push_back( startEdge );
+
+        nodeBranch.push_back( theStartNode );
+        nodeBranch.push_back( branch.back()->GetNode(0) );
+        if ( nodeBranch.back() == theStartNode )
+          nodeBranch.back() = branch.back()->GetNode(1);
+      }
+
+      // fill the branch
+
+      bool isBranchEnd = false;
+      TEdgeVec* edgesPtr;
+
+      while (( !isBranchEnd ) && ( edgesPtr = edgesByNode.ChangeSeek( nodeBranch.back() )))
+      {
+        TEdgeVec& edges = *edgesPtr;
+
+        isBranchEnd = ( edges.size() != 2 );
+
+        const SMDS_MeshNode* lastNode = nodeBranch.back();
+
+        switch ( edges.size() )
+        {
+        case 1:
+          edgesByNode.UnBind( lastNode );
+          break;
+
+        case 2:
+        {
+          if ( const SMDS_MeshElement* nextEdge = edges[ edges[0] == branch.back() ])
+          {
+            branch.push_back( nextEdge );
+
+            const SMDS_MeshNode* nextNode = nextEdge->GetNode(0);
+            if ( nodeBranch.back() == nextNode )
+              nextNode = nextEdge->GetNode(1);
+            nodeBranch.push_back( nextNode );
+          }
+          edgesByNode.UnBind( lastNode );
+          break;
+        }
+
+        default:
+          int nbEdges = 0;
+          for ( size_t i = 0; i < edges.size(); ++i )
+          {
+            if ( edges[i] == branch.back() )
+              edges[i] = 0;
+            nbEdges += bool( edges[i] );
+          }
+          if ( nbEdges == 0 )
+            edgesByNode.UnBind( lastNode );
+        }
+      }
+    } // while ( edgesByNode.IsBound( theStartNode ))
+
+
+    // put the found branches to the result
+
+    if ( nbBranches == 2 && !startIsBranchEnd ) // join two branches starting at the same node
+    {
+      if ( nodeBranches[0].back() == nodeBranches[1].back() )
+      {
+        // it is a closed branch, keep theStartNode first
+        nodeBranches[0].pop_back();
+        nodeBranches[0].reserve( nodeBranches[0].size() + nodeBranches[1].size() );
+        nodeBranches[0].insert( nodeBranches[0].end(),
+                                nodeBranches[1].rbegin(), nodeBranches[1].rend() );
+        branches[0].reserve( branches[0].size() + branches[1].size() );
+        branches[0].insert( branches[0].end(), branches[1].rbegin(), branches[1].rend() );
+      }
+      else
+      {
+        std::reverse( nodeBranches[0].begin(), nodeBranches[0].end() );
+        nodeBranches[0].pop_back();
+        nodeBranches[0].reserve( nodeBranches[0].size() + nodeBranches[1].size() );
+        nodeBranches[0].insert( nodeBranches[0].end(),
+                                nodeBranches[1].begin(), nodeBranches[1].end() );
+
+        std::reverse( branches[0].begin(), branches[0].end() );
+        branches[0].reserve( branches[0].size() + branches[1].size() );
+        branches[0].insert( branches[0].end(), branches[1].begin(), branches[1].end() );
+      }
+      nodeBranches[1].clear();
+      branches[1].clear();
+    }
+
+    for ( size_t i = 0; i < nbBranches; ++i )
+    {
+      if ( branches[i].empty() )
+        continue;
+
+      theEdgeGroups.push_back( TEdgeVec() );
+      theEdgeGroups.back().swap( branches[i] );
+
+      theNodeGroups.push_back( TNodeVec() );
+      theNodeGroups.back().swap( nodeBranches[i] );
+    }
+
+  } // while ( !edgesByNode.IsEmpty() )
+
+  return;
+}
+
+//=======================================================================
+/*!
  * \brief Return SMESH_NodeSearcher
  */
 //=======================================================================
index 6a507f1..c696505 100644 (file)
@@ -23,7 +23,7 @@
 // Created   : Tue Apr 30 18:00:36 2013
 // Author    : Edward AGAPOV (eap)
 
-// This file holds some low level algorithms extracted from SMESH_MeshEditor
+// Initially this file held some low level algorithms extracted from SMESH_MeshEditor
 // to make them accessible from Controls package, and more
 
 
 #include "SMESH_TypeDefs.hxx"
 
 #include <TopAbs_State.hxx>
+#include <gp_Pnt.hxx>
+#include <gp_Vec.hxx>
+
 #include <vector>
 
-class gp_Pnt;
-class gp_Ax1;
 class Bnd_B3d;
-class SMDS_MeshNode;
-class SMDS_MeshElement;
+class gp_Ax1;
 class SMDS_Mesh;
+class SMDS_MeshElement;
+class SMDS_MeshGroup;
+class SMDS_MeshNode;
 
 //=======================================================================
 /*!
@@ -198,6 +201,22 @@ namespace SMESH_MeshAlgos
   bool IsRightOrder( const SMDS_MeshElement* face,
                      const SMDS_MeshNode*    node0,
                      const SMDS_MeshNode*    node1 );
+
+  typedef std::vector< std::vector< const SMDS_MeshElement* > > TElemGroupVector;
+  typedef std::vector< std::vector< const SMDS_MeshNode* > >    TNodeGroupVector;
+  /*!
+   * \brief Partition given 1D elements into groups of contiguous edges.
+   *        A node where number of meeting edges != 2 is a group end.
+   *        An optional startNode is used to orient groups it belongs to.
+   * \return a list of edge groups and a list of corresponding node groups.
+   *         If a group is closed, the first and last nodes of the group are same.
+   */
+  SMESHUtils_EXPORT
+  void Get1DBranches( SMDS_ElemIteratorPtr edgeIt,
+                      TElemGroupVector&    edgeGroups,
+                      TNodeGroupVector&    nodeGroups,
+                      const SMDS_MeshNode* startNode = 0 );
+
   /*!
    * \brief Mark elements given by SMDS_Iterator
    */
@@ -320,7 +339,6 @@ namespace SMESH_MeshAlgos
                 std::vector<const SMDS_MeshElement*>& newFaces);
   // Implemented in ./SMESH_FillHole.cxx
 
-
   /*!
    * \brief Find nodes whose merge makes the element invalid
    */
@@ -331,8 +349,8 @@ namespace SMESH_MeshAlgos
   // Implemented in SMESH_DeMerge.cxx
 
 
-  typedef std::vector< std::pair< const SMDS_MeshElement*, const SMDS_MeshElement* > > TEPairVec;
-  typedef std::vector< std::pair< const SMDS_MeshNode*, const SMDS_MeshNode* > >       TNPairVec;
+  typedef std::vector< std::pair< const SMDS_MeshElement*, int > > TElemIntPairVec;
+  typedef std::vector< std::pair< const SMDS_MeshNode*,    int > > TNodeIntPairVec;
   /*!
    * \brief Create an offset mesh of given faces
    *  \param [in] faceIt - the input faces
@@ -346,20 +364,77 @@ namespace SMESH_MeshAlgos
                          SMDS_Mesh&           mesh,
                          const double         offset,
                          const bool           theFixIntersections,
-                         TEPairVec&           new2OldFaces,
-                         TNPairVec&           new2OldNodes );
+                         TElemIntPairVec&           new2OldFaces,
+                         TNodeIntPairVec&           new2OldNodes );
   // Implemented in ./SMESH_Offset.cxx
 
 
+  //=======================================================================
+  /*!
+   * \brief Cut faces of a triangular mesh.
+   *  Usage work-flow: 1) call Cut() methods as many times as needed
+   *                   2) call MakeNewFaces() to really modify the mesh faces
+   */
+  //=======================================================================
+  // implemented in SMESH_Offset.cxx
+
+  class SMESHUtils_EXPORT Intersector
+  {
+  public:
+    Intersector( SMDS_Mesh* mesh, double tol, const std::vector< gp_XYZ >& normals );
+    ~Intersector();
+
+    //! Compute cut of two faces of the mesh
+    void Cut( const SMDS_MeshElement* face1,
+              const SMDS_MeshElement* face2,
+              const int               nbCommonNodes = -1 );
+
+    //! Store a face cut by a line given by its ends lying either on face edges or inside the face.
+    //  Line ends are accompanied by indices of intersected face edges.
+    //  Edge index is <0 if a line end is inside the face.
+    void Cut( const SMDS_MeshElement* face,
+              SMESH_NodeXYZ&          lineEnd1,
+              int                     edgeIndex1,
+              SMESH_NodeXYZ&          lineEnd2,
+              int                     edgeIndex2 );
+
+    //! Split all faces intersected by Cut() methods.
+    //  theSign = (-1|1) is used to choose which part of a face cut by another one to remove.
+    //  1 means to remove a part opposite to face normal.
+    //  Optionally optimize quality of split faces by edge swapping.
+    void MakeNewFaces( SMESH_MeshAlgos::TElemIntPairVec& theNew2OldFaces,
+                       SMESH_MeshAlgos::TNodeIntPairVec& theNew2OldNodes,
+                       const double                      theSign = 1.,
+                       const bool                        theOptimize = false );
+
+    typedef std::vector< SMESH_NodeXYZ > TFace;
+
+    //! Cut a face by planes, whose normals point to parts to keep.
+    //  Return true if the whole face is cut off
+    static bool CutByPlanes(const SMDS_MeshElement*       face,
+                            const std::vector< gp_Ax1 > & planes,
+                            const double                  tol,
+                            std::vector< TFace > &        newFaceConnectivity );
+
+  private:
+    struct Algo;
+    Algo* myAlgo;
+  };
+
+  //=======================================================================
   /*!
    * \brief Divide a mesh face into triangles
    */
+  //=======================================================================
   // Implemented in ./SMESH_Triangulate.cxx
 
   class SMESHUtils_EXPORT Triangulate
   {
   public:
 
+    Triangulate(bool optimize=false);
+    ~Triangulate();
+
     static int GetNbTriangles( const SMDS_MeshElement* face );
 
     int GetTriangles( const SMDS_MeshElement*             face,
@@ -374,19 +449,81 @@ namespace SMESH_MeshAlgos
     struct PolyVertex
     {
       SMESH_NodeXYZ _nxyz;
+      size_t        _index;
       gp_XY         _xy;
       PolyVertex*   _prev;
       PolyVertex*   _next;
 
-      void   SetNodeAndNext( const SMDS_MeshNode* n, PolyVertex& v );
-      void   GetTriaNodes( const SMDS_MeshNode** nodes) const;
+      void   SetNodeAndNext( const SMDS_MeshNode* n, PolyVertex& v, size_t index );
+      void   GetTriaNodes( const SMDS_MeshNode** nodes, size_t* nodeIndices) const;
       double TriaArea() const;
       bool   IsInsideTria( const PolyVertex* v );
       PolyVertex* Delete();
     };
+    struct Optimizer;
+
     std::vector< PolyVertex > _pv;
+    std::vector< size_t >     _nodeIndex;
+    Optimizer*                _optimizer;
   };
 
+  // structure used in MakePolyLine() to define a cutting plane
+  struct PolySegment
+  {
+    // 2 points, each defined as follows:
+    // ( myNode1 &&  myNode2 ) ==> point is in the middle of an edge defined by two nodes
+    // ( myNode1 && !myNode2 ) ==> point is at myNode1 of a some face
+    // else                    ==> point is at myXYZ
+    const SMDS_MeshNode*    myNode1[2];
+    const SMDS_MeshNode*    myNode2[2];
+    gp_XYZ                  myXYZ  [2];
+
+    // face on which myXYZ projects (found by MakePolyLine())
+    const SMDS_MeshElement* myFace [2];
+
+    // vector on the plane; to use a default plane set vector = (0,0,0)
+    gp_Vec myVector;
+
+    // point returning coordinates of a middle of the two points, projected to mesh
+    gp_Pnt myMidProjPoint;
+  };
+  typedef std::vector<PolySegment> TListOfPolySegments;
+
+  /*!
+   * \brief Create a polyline consisting of 1D mesh elements each lying on a 2D element of
+   *        the initial mesh. Positions of new nodes are found by cutting the mesh by the
+   *        plane passing through pairs of points specified by each PolySegment structure.
+   *        If there are several paths connecting a pair of points, the shortest path is
+   *        selected by the module. Position of the cutting plane is defined by the two
+   *        points and an optional vector lying on the plane specified by a PolySegment.
+   *        By default the vector is defined by Mesh module as following. A middle point
+   *        of the two given points is computed. The middle point is projected to the mesh.
+   *        The vector goes from the middle point to the projection point. In case of planar
+   *        mesh, the vector is normal to the mesh.
+   *  \param [inout] segments - PolySegment's defining positions of cutting planes.
+   *        Return the used vector and position of the middle point.
+   *  \param [in] group - an optional group where created mesh segments will
+   *        be added.
+   */
+  // Implemented in ./SMESH_PolyLine.cxx
+  SMESHUtils_EXPORT
+  void MakePolyLine( SMDS_Mesh*                            mesh,
+                     TListOfPolySegments&                  segments,
+                     std::vector<const SMDS_MeshElement*>& newEdges,
+                     std::vector<const SMDS_MeshNode*>&    newNodes,
+                     SMDS_MeshGroup*                       group=0,
+                     SMESH_ElementSearcher*                searcher=0);
+
+  /*!
+   * Create a slot of given width around given 1D elements lying on a triangle mesh.
+   * The slot is consrtucted by cutting faces by cylindrical surfaces made around each segment.
+   * \return Edges located at the slot boundary
+   */
+  // Implemented in ./SMESH_Slot.cxx
+  SMESHUtils_EXPORT
+  std::vector< Edge > MakeSlot( SMDS_ElemIteratorPtr segmentIt,
+                                double               width,
+                                SMDS_Mesh*           mesh);
 
 } // namespace SMESH_MeshAlgos
 
index 33d5b1c..29aed95 100644 (file)
@@ -42,8 +42,8 @@ namespace
 {
   const int 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;
+  typedef NCollection_DataMap< const SMDS_MeshNode*, const SMDS_MeshNode*, SMESH_Hasher > TNNMap;
+  typedef NCollection_Map< SMESH_Link, SMESH_Link >                                       TLinkMap;
 
   //--------------------------------------------------------------------------------
   /*!
@@ -53,7 +53,7 @@ namespace
   struct CutLink
   {
     bool                     myReverse;
-    const SMDS_MeshNode*     myNode[2]; // side nodes
+    const SMDS_MeshNode*     myNode[2]; // side nodes. WARNING: don't set them directly, use Set()
     mutable SMESH_NodeXYZ    myIntNode; // intersection node
     const SMDS_MeshElement*  myFace;    // cutter face
     int                      myIndex;   // index of a node on the same link
@@ -694,11 +694,15 @@ namespace
     return useOneNormal;
   }
 
+} // namespace
+
+namespace SMESH_MeshAlgos
+{
   //--------------------------------------------------------------------------------
   /*!
    * \brief Intersect faces of a mesh
    */
-  struct Intersector
+  struct Intersector::Algo
   {
     SMDS_Mesh*                   myMesh;
     double                       myTol, myEps;
@@ -716,7 +720,7 @@ namespace
     int                          myNbOnPlane1, myNbOnPlane2;
     TIntPointSet                 myIntPointSet;
 
-    Intersector( SMDS_Mesh* mesh, double tol, const std::vector< gp_XYZ >& normals )
+    Algo( SMDS_Mesh* mesh, double tol, const std::vector< gp_XYZ >& normals )
       : myMesh( mesh ),
         myTol( tol ),
         myEps( 1e-100 ),
@@ -727,9 +731,20 @@ namespace
     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 );
+    void Cut( const SMDS_MeshElement* face,
+              SMESH_NodeXYZ&          lineEnd1,
+              int                     edgeIndex1,
+              SMESH_NodeXYZ&          lineEnd2,
+              int                     edgeIndex2 );
+    void MakeNewFaces( TElemIntPairVec& theNew2OldFaces,
+                       TNodeIntPairVec& theNew2OldNodes,
+                       const double     theSign,
+                       const bool       theOptimize );
+
+    //! Cut a face by planes, whose normals point to parts to keep
+    bool CutByPlanes(const SMDS_MeshElement*        face,
+                     const std::vector< gp_Ax1 > &  planes,
+                     std::vector< SMESH_NodeXYZ > & newConnectivity );
 
   private:
 
@@ -805,7 +820,7 @@ namespace
    */
   //================================================================================
 
-  const SMDS_MeshNode* Intersector::createNode( const gp_XYZ& p )
+  const SMDS_MeshNode* Intersector::Algo::createNode( const gp_XYZ& p )
   {
     const SMDS_MeshNode* n = myMesh->AddNode( p.X(), p.Y(), p.Z() );
     n->setIsMarked( true ); // cut nodes are marked
@@ -818,7 +833,7 @@ namespace
    */
   //================================================================================
 
-  void Intersector::addLink( CutLink& link )
+  void Intersector::Algo::addLink( CutLink& link )
   {
     link.myIndex = 0;
     const CutLink* added = & myCutLinks.Added( link );
@@ -844,7 +859,7 @@ namespace
    */
   //================================================================================
 
-  bool Intersector::findLink( CutLink& link )
+  bool Intersector::Algo::findLink( CutLink& link )
   {
     link.myIndex = 0;
     while ( myCutLinks.Contains( link ))
@@ -872,12 +887,12 @@ namespace
    */
   //================================================================================
 
-  bool Intersector::isPlaneIntersected( const gp_XYZ&                       n2,
-                                        const double                        d2,
-                                        const std::vector< SMESH_NodeXYZ >& nodes1,
-                                        std::vector< double > &             dist1,
-                                        int &                               nbOnPlane1,
-                                        int &                               iNotOnPlane1)
+  bool Intersector::Algo::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() );
@@ -915,12 +930,12 @@ namespace
    */
   //================================================================================
 
-  void Intersector::computeIntervals( const std::vector< SMESH_NodeXYZ >& nodes,
-                                      const std::vector< double >&        dist,
-                                      const int                           nbOnPln, 
-                                      const int                           iMaxCoo,
-                                      double *                            u,
-                                      int*                                iE)
+  void Intersector::Algo::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 )
     {
@@ -961,9 +976,9 @@ namespace
    */
   //================================================================================
 
-  void Intersector::findIntPointOnPlane( const std::vector< SMESH_NodeXYZ >& nodes,
-                                         const std::vector< double > &       dist,
-                                         CutLink&                            link )
+  void Intersector::Algo::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;
@@ -978,11 +993,11 @@ namespace
    */
   //================================================================================
 
-  void Intersector::intersectLink( const std::vector< SMESH_NodeXYZ >& nodes1,
-                                   const std::vector< double > &       dist1,
-                                   const int                           iEdge1,
-                                   const SMDS_MeshElement*             face2,
-                                   CutLink&                            link1)
+  void Intersector::Algo::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 ];
@@ -1028,15 +1043,15 @@ namespace
    */
   //================================================================================
 
-  void Intersector::replaceIntNode( const SMDS_MeshNode* nToKeep,
-                                    const SMDS_MeshNode* nToRemove )
+  void Intersector::Algo::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 );
+      myRemove2KeepNodes.Bind( nToKeep, nToRemove );
     else
-      myRemove2KeepNodes.Bind((void*) nToRemove, nToKeep );
+      myRemove2KeepNodes.Bind( nToRemove, nToKeep );
   }
 
   //================================================================================
@@ -1053,13 +1068,13 @@ namespace
    */
   //================================================================================
 
-  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)
+  void Intersector::Algo::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 )
     {
@@ -1100,11 +1115,11 @@ namespace
    */
   //================================================================================
 
-  void Intersector::cutCollinearLink( const int                           iNotOnPlane1,
-                                      const std::vector< SMESH_NodeXYZ >& nodes1,
-                                      const SMDS_MeshElement*             face2,
-                                      const CutLink&                      link1,
-                                      const CutLink&                      link2)
+  void Intersector::Algo::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;
@@ -1128,7 +1143,7 @@ namespace
    */
   //================================================================================
 
-  void Intersector::setPlaneIndices( const gp_XYZ& planeNorm )
+  void Intersector::Algo::setPlaneIndices( const gp_XYZ& planeNorm )
   {
     switch ( MaxIndex( planeNorm )) {
     case 1: myInd1 = 2; myInd2 = 3; break;
@@ -1143,9 +1158,9 @@ namespace
    */
   //================================================================================
 
-  void Intersector::Cut( const SMDS_MeshElement* face1,
-                         const SMDS_MeshElement* face2,
-                         const int               nbCommonNodes)
+  void Intersector::Algo::Cut( const SMDS_MeshElement* face1,
+                               const SMDS_MeshElement* face2,
+                               const int               nbCommonNodes)
   {
     myFace1 = face1;
     myFace2 = face2;
@@ -1243,14 +1258,81 @@ namespace
 
   //================================================================================
   /*!
+   * \brief Store a face cut by a line given by its ends
+   *        accompanied by indices of intersected face edges.
+   *        Edge index is <0 if a line end is inside the face.
+   *  \param [in] face - a face to cut
+   *  \param [inout] lineEnd1 - line end coordinates + optional node existing at this point
+   *  \param [in] edgeIndex1 - index of face edge cut by lineEnd1
+   *  \param [inout] lineEnd2 - line end coordinates + optional node existing at this point
+   *  \param [in] edgeIndex2 - index of face edge cut by lineEnd2
+   */
+  //================================================================================
+
+  void Intersector::Algo::Cut( const SMDS_MeshElement* face,
+                               SMESH_NodeXYZ&          lineEnd1,
+                               int                     edgeIndex1,
+                               SMESH_NodeXYZ&          lineEnd2,
+                               int                     edgeIndex2 )
+  {
+    if ( lineEnd1.Node() && lineEnd2.Node() &&
+         face->GetNodeIndex( lineEnd1.Node() ) >= 0 &&
+         face->GetNodeIndex( lineEnd2.Node() ) >= 0 )
+      return; // intersection at a face node or edge
+
+    if ((int) myNormals.size() <= face->GetID() )
+      const_cast< std::vector< gp_XYZ >& >( myNormals ).resize( face->GetID() + 1 );
+
+    const CutFace& cf = myCutFaces.Added( CutFace( face ));
+    cf.InitLinks();
+
+    // look for intersection nodes coincident with line ends
+    CutLink links[2];
+    for ( int is2nd = 0; is2nd < 2; ++is2nd )
+    {
+      SMESH_NodeXYZ& lineEnd = is2nd ? lineEnd2 : lineEnd1;
+      int          edgeIndex = is2nd ? edgeIndex2 : edgeIndex1;
+      CutLink &         link = links[ is2nd ];
+
+      link.myIntNode = lineEnd;
+
+      for ( size_t i = ( edgeIndex < 0 ? 3 : 0  ); i < cf.myLinks.size(); ++i )
+        if ( coincide( lineEnd, SMESH_NodeXYZ( cf.myLinks[i].myNode1 ), myTol ))
+        {
+          link.myIntNode = cf.myLinks[i].myNode1;
+          break;
+        }
+
+      if ( edgeIndex >= 0 )
+      {
+        link.Set( face->GetNode    ( edgeIndex ),
+                  face->GetNodeWrap( edgeIndex + 1 ),
+                  /*cuttingFace=*/0);
+        findLink( link );
+      }
+
+      if ( !link.myIntNode )
+        link.myIntNode.Set( createNode( lineEnd ));
+
+      lineEnd._node = link.IntNode();
+
+      if ( link.myNode[0] )
+        addLink( link );
+    }
+
+    cf.AddEdge( links[0], links[1], /*face=*/0, /*nbOnPlane=*/0, /*iNotOnPlane=*/-1 );
+  }
+
+  //================================================================================
+  /*!
    * \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 )
+  bool Intersector::Algo::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;
@@ -1306,7 +1388,7 @@ namespace
    */
   //================================================================================
 
-  bool Intersector::intersectEdgeEdge( int iE1, int iE2, IntPoint2D& intPoint )
+  bool Intersector::Algo::intersectEdgeEdge( int iE1, int iE2, IntPoint2D& intPoint )
   {
     int i01 = iE1, i11 = ( iE1 + 1 ) % 3;
     int i02 = iE2, i12 = ( iE2 + 1 ) % 3;
@@ -1422,7 +1504,7 @@ namespace
    */
   //================================================================================
 
-  bool Intersector::isPointInTriangle( const gp_XYZ& p, const std::vector< SMESH_NodeXYZ >& nodes )
+  bool Intersector::Algo::isPointInTriangle( const gp_XYZ& p, const std::vector< SMESH_NodeXYZ >& nodes )
   {
     double bc1, bc2;
     SMESH_MeshAlgos::GetBarycentricCoords( p2D( p ),
@@ -1437,7 +1519,7 @@ namespace
    */
   //================================================================================
 
-  void Intersector::cutCoplanar()
+  void Intersector::Algo::cutCoplanar()
   {
     // find intersections of edges
 
@@ -1554,7 +1636,7 @@ namespace
     }
     return;
 
-  } // Intersector::cutCoplanar()
+  } // Intersector::Algo::cutCoplanar()
 
   //================================================================================
   /*!
@@ -1562,13 +1644,19 @@ namespace
    */
   //================================================================================
 
-  void Intersector::intersectNewEdges( const CutFace& cf )
+  void Intersector::Algo::intersectNewEdges( const CutFace& cf )
   {
     IntPoint2D intPoint;
 
     if ( cf.NbInternalEdges() < 2 )
       return;
 
+    if ( myNodes1.empty() )
+    {
+      myNodes1.resize(2);
+      myNodes2.resize(2);
+    }
+
     const gp_XYZ& faceNorm = myNormals[ cf.myInitFace->GetID() ];
     setPlaneIndices( faceNorm ); // choose indices on an axis-aligned plane
 
@@ -1753,7 +1841,7 @@ namespace
           }
         }
         if ( cf.myLinks.size() >= limit )
-          throw SALOME_Exception( "Infinite loop in Intersector::intersectNewEdges()" );
+          throw SALOME_Exception( "Infinite loop in Intersector::Algo::intersectNewEdges()" );
       }
       ++i1; // each internal edge encounters twice
     }
@@ -1766,10 +1854,23 @@ namespace
    */
   //================================================================================
 
-  void Intersector::MakeNewFaces( SMESH_MeshAlgos::TEPairVec& theNew2OldFaces,
-                                  SMESH_MeshAlgos::TNPairVec& theNew2OldNodes,
-                                  const double                theSign)
+  void Intersector::Algo::MakeNewFaces( SMESH_MeshAlgos::TElemIntPairVec& theNew2OldFaces,
+                                        SMESH_MeshAlgos::TNodeIntPairVec& theNew2OldNodes,
+                                        const double                      theSign,
+                                        const bool                        theOptimize)
   {
+    // fill theNew2OldFaces if empty
+    TCutFaceMap::const_iterator cutFacesIt = myCutFaces.cbegin();
+    if ( theNew2OldFaces.empty() )
+      for ( ; cutFacesIt != myCutFaces.cend(); ++cutFacesIt )
+      {
+        const CutFace& cf = *cutFacesIt;
+        int index = cf.myInitFace->GetID(); // index in theNew2OldFaces
+        if ((int) theNew2OldFaces.size() <= index )
+          theNew2OldFaces.resize( index + 1 );
+        theNew2OldFaces[ index ] = std::make_pair( cf.myInitFace, index );
+      }
+
     // unmark all nodes except intersection ones
 
     for ( SMDS_NodeIteratorPtr nIt = myMesh->nodesIterator(); nIt->more(); )
@@ -1790,8 +1891,7 @@ namespace
 
     // intersect edges added to myCutFaces
 
-    TCutFaceMap::const_iterator cutFacesIt = myCutFaces.cbegin();
-    for ( ; cutFacesIt != myCutFaces.cend(); ++cutFacesIt )
+    for ( cutFacesIt = myCutFaces.cbegin(); cutFacesIt != myCutFaces.cend(); ++cutFacesIt )
     {
       const CutFace& cf = *cutFacesIt;
       cf.ReplaceNodes( myRemove2KeepNodes );
@@ -1801,11 +1901,11 @@ namespace
     // make new faces
 
     EdgeLoopSet                            loopSet;
-    SMESH_MeshAlgos::Triangulate           triangulator;
+    SMESH_MeshAlgos::Triangulate           triangulator( theOptimize );
     std::vector< EdgePart >                cutOffLinks;
     TLinkMap                               cutOffCoplanarLinks;
     std::vector< const CutFace* >          touchedFaces;
-    SMESH_MeshAlgos::TEPairVec::value_type new2OldTria;
+    SMESH_MeshAlgos::TElemIntPairVec::value_type new2OldTria;
     CutFace                                cutFace(0);
     std::vector< const SMDS_MeshNode* >    nodes;
     std::vector<const SMDS_MeshElement *>  faces;
@@ -1877,13 +1977,14 @@ namespace
     // remove split faces
     for ( size_t id = 1; id < theNew2OldFaces.size(); ++id )
     {
-      if ( theNew2OldFaces[id].first )
+      if ( theNew2OldFaces[id].first ||
+           theNew2OldFaces[id].second == 0 )
         continue;
       if ( const SMDS_MeshElement* f = myMesh->FindElement( id ))
         myMesh->RemoveFreeElement( f );
     }
 
-    // remove face connected to cut off parts of cf.myInitFace
+    // remove faces connected to cut off parts of cf.myInitFace
 
     nodes.resize(2);
     for ( size_t i = 0; i < cutOffLinks.size(); ++i )
@@ -1954,8 +2055,8 @@ namespace
 
 
     // add used new nodes to theNew2OldNodes
-    SMESH_MeshAlgos::TNPairVec::value_type new2OldNode;
-    new2OldNode.second = NULL;
+    SMESH_MeshAlgos::TNodeIntPairVec::value_type new2OldNode;
+    new2OldNode.second = 0;
     for ( cutLinksIt = myCutLinks.cbegin(); cutLinksIt != myCutLinks.cend(); ++cutLinksIt )
     {
       const CutLink& link = *cutLinksIt;
@@ -1970,6 +2071,185 @@ namespace
   }
 
   //================================================================================
+  Intersector::Intersector( SMDS_Mesh* mesh, double tol, const std::vector< gp_XYZ >& normals )
+  {
+    myAlgo = new Algo( mesh, tol, normals );
+  }
+  //================================================================================
+  Intersector::~Intersector()
+  {
+    delete myAlgo;
+  }
+  //================================================================================
+  //! compute cut of two faces of the mesh
+  void Intersector::Cut( const SMDS_MeshElement* face1,
+                         const SMDS_MeshElement* face2,
+                         const int               nbCommonNodes )
+  {
+    myAlgo->Cut( face1, face2, nbCommonNodes );
+  }
+  //================================================================================
+  //! store a face cut by a line given by its ends
+  //  accompanied by indices of intersected face edges.
+  //  Edge index is <0 if a line end is inside the face.
+  void Intersector::Cut( const SMDS_MeshElement* face,
+                         SMESH_NodeXYZ&          lineEnd1,
+                         int                     edgeIndex1,
+                         SMESH_NodeXYZ&          lineEnd2,
+                         int                     edgeIndex2 )
+  {
+    myAlgo->Cut( face, lineEnd1, edgeIndex1, lineEnd2, edgeIndex2 );
+  }
+  //================================================================================
+  //! split all face intersected by Cut() methods
+  void Intersector::MakeNewFaces( SMESH_MeshAlgos::TElemIntPairVec& theNew2OldFaces,
+                                  SMESH_MeshAlgos::TNodeIntPairVec& theNew2OldNodes,
+                                  const double                      theSign,
+                                  const bool                        theOptimize )
+  {
+    myAlgo->MakeNewFaces( theNew2OldFaces, theNew2OldNodes, theSign, theOptimize );
+  }
+  //================================================================================
+  //! Cut a face by planes, whose normals point to parts to keep
+  bool Intersector::CutByPlanes(const SMDS_MeshElement*        theFace,
+                                const std::vector< gp_Ax1 > &  thePlanes,
+                                const double                   theTol,
+                                std::vector< TFace > &         theNewFaceConnectivity )
+  {
+    theNewFaceConnectivity.clear();
+
+    // check if theFace is wholly cut off
+    std::vector< SMESH_NodeXYZ > facePoints( theFace->begin_nodes(), theFace->end_nodes() );
+    facePoints.resize( theFace->NbCornerNodes() );
+    for ( size_t iP = 0; iP < thePlanes.size(); ++iP )
+    {
+      size_t nbOut = 0;
+      const gp_Pnt& O = thePlanes[iP].Location();
+      for ( size_t i = 0; i < facePoints.size(); ++i )
+      {
+        gp_Vec Op( O, facePoints[i] );
+        nbOut += ( Op * thePlanes[iP].Direction() <= 0 );
+      }
+      if ( nbOut == facePoints.size() )
+        return true;
+    }
+
+    // copy theFace into a temporary mesh
+    SMDS_Mesh mesh;
+    Bnd_B3d faceBox;
+    std::vector< const SMDS_MeshNode* > faceNodes;
+    faceNodes.resize( facePoints.size() );
+    for ( size_t i = 0; i < facePoints.size(); ++i )
+    {
+      const SMESH_NodeXYZ& n = facePoints[i];
+      faceNodes[i] = mesh.AddNode( n.X(), n.Y(), n.Z() );
+      faceBox.Add( n );
+    }
+    const SMDS_MeshElement* faceToCut = 0;
+    switch ( theFace->NbCornerNodes() )
+    {
+    case 3:
+      faceToCut = mesh.AddFace( faceNodes[0], faceNodes[1], faceNodes[2] );
+      break;
+    case 4:
+      faceToCut = mesh.AddFace( faceNodes[0], faceNodes[1], faceNodes[2], faceNodes[3] );
+      break;
+    default:
+      faceToCut = mesh.AddPolygonalFace( faceNodes );
+    }
+
+    std::vector< gp_XYZ > normals( 2 + thePlanes.size() );
+    SMESH_MeshAlgos::FaceNormal( faceToCut, normals[ faceToCut->GetID() ]);
+
+    // add faces corresponding to thePlanes
+    std::vector< const SMDS_MeshElement* > planeFaces;
+    double faceSize = Sqrt( faceBox.SquareExtent() );
+    gp_XYZ   center = 0.5 * ( faceBox.CornerMin() + faceBox.CornerMax() );
+    for ( size_t i = 0; i < thePlanes.size(); ++i )
+    {
+      gp_Ax2 plnAx( thePlanes[i].Location(), thePlanes[i].Direction() );
+      gp_XYZ O = plnAx.Location().XYZ();
+      gp_XYZ X = plnAx.XDirection().XYZ();
+      gp_XYZ Y = plnAx.YDirection().XYZ();
+      gp_XYZ Z = plnAx.Direction().XYZ();
+
+      double dot = ( O - center ) * Z;
+      gp_XYZ o = center + Z * dot; // center projected to a plane
+
+      gp_XYZ p1 = o + X * faceSize * 2;
+      gp_XYZ p2 = o + Y * faceSize * 2;
+      gp_XYZ p3 = o - (X + Y ) * faceSize * 2;
+
+      const SMDS_MeshNode* n1 = mesh.AddNode( p1.X(), p1.Y(), p1.Z() );
+      const SMDS_MeshNode* n2 = mesh.AddNode( p2.X(), p2.Y(), p2.Z() );
+      const SMDS_MeshNode* n3 = mesh.AddNode( p3.X(), p3.Y(), p3.Z() );
+      planeFaces.push_back( mesh.AddFace( n1, n2, n3 ));
+
+      normals[ planeFaces.back()->GetID() ] = thePlanes[i].Direction().XYZ();
+    }
+
+    // cut theFace
+    Algo algo ( &mesh, theTol, normals );
+    for ( size_t i = 0; i < planeFaces.size(); ++i )
+    {
+      algo.Cut( faceToCut, planeFaces[i], 0 );
+    }
+
+    // retrieve a result
+    SMESH_MeshAlgos::TElemIntPairVec new2OldFaces;
+    SMESH_MeshAlgos::TNodeIntPairVec new2OldNodes;
+    TCutFaceMap::const_iterator cutFacesIt= algo.myCutFaces.cbegin();
+    for ( ; cutFacesIt != algo.myCutFaces.cend(); ++cutFacesIt )
+    {
+      const CutFace& cf = *cutFacesIt;
+      if ( cf.myInitFace != faceToCut )
+        continue;
+
+      if ( !cf.IsCut() )
+      {
+        theNewFaceConnectivity.push_back( facePoints );
+        break;
+      }
+      // form loops of new faces
+      EdgeLoopSet loopSet;
+      cf.MakeLoops( loopSet, normals[ faceToCut->GetID() ]);
+
+      // erase loops that are cut off by thePlanes
+      const double sign = 1;
+      std::vector< EdgePart > cutOffLinks;
+      TLinkMap                cutOffCoplanarLinks;
+      cf.CutOffLoops( loopSet, sign, normals, cutOffLinks, cutOffCoplanarLinks );
+
+      for ( size_t iL = 0; iL < loopSet.myNbLoops; ++iL )
+      {
+        EdgeLoop& loop = loopSet.myLoops[ iL ];
+        if ( loop.myLinks.size() > 0 )
+        {
+          facePoints.clear();
+          for ( SMDS_NodeIteratorPtr nIt = loop.nodeIterator(); nIt->more(); )
+          {
+            const SMDS_MeshNode* n = nIt->next();
+            facePoints.push_back( n );
+            int iN = faceToCut->GetNodeIndex( n );
+            if ( iN < 0 )
+              facePoints.back()._node = 0; // an intersection point
+            else
+              facePoints.back()._node = theFace->GetNode( iN );
+          }
+          theNewFaceConnectivity.push_back( facePoints );
+        }
+      }
+      break;
+    }
+
+    return theNewFaceConnectivity.empty();
+  }
+
+} // namespace SMESH_MeshAlgos
+
+namespace
+{
+  //================================================================================
   /*!
    * \brief Debug
    */
@@ -2190,11 +2470,11 @@ namespace
     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( myLinks[i].myNode1 ))
+        replaced = ( myLinks[i].myNode1 = theRm2KeepMap( myLinks[i].myNode1 ));
 
-      while ( theRm2KeepMap.IsBound((Standard_Address) myLinks[i].myNode2 ))
-        replaced = ( myLinks[i].myNode2 = theRm2KeepMap((Standard_Address) myLinks[i].myNode2 ));
+      while ( theRm2KeepMap.IsBound( myLinks[i].myNode2 ))
+        replaced = ( myLinks[i].myNode2 = theRm2KeepMap( myLinks[i].myNode2 ));
     }
 
     //if ( replaced ) // remove equal links
@@ -2615,7 +2895,7 @@ namespace
 
   //================================================================================
   /*!
-   * \brief Replace _COPLANAR cut edge by _INTERNAL oe vice versa
+   * \brief Replace _COPLANAR cut edge by _INTERNAL or vice versa
    */
   //================================================================================
 
@@ -2643,8 +2923,8 @@ 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
+ *  \param [out] new2OldFaces - history of faces (new face -> old face ID)
+ *  \param [out] new2OldNodes - history of nodes (new node -> old node ID)
  *  \return SMDS_Mesh* - the new offset mesh, a caller should delete
  */
 //================================================================================
@@ -2653,8 +2933,8 @@ SMDS_Mesh* SMESH_MeshAlgos::MakeOffset( SMDS_ElemIteratorPtr theFaceIt,
                                         SMDS_Mesh&           theSrcMesh,
                                         const double         theOffset,
                                         const bool           theFixIntersections,
-                                        TEPairVec&           theNew2OldFaces,
-                                        TNPairVec&           theNew2OldNodes)
+                                        TElemIntPairVec&     theNew2OldFaces,
+                                        TNodeIntPairVec&     theNew2OldNodes)
 {
   if ( theSrcMesh.GetMeshInfo().NbFaces( ORDER_QUADRATIC ) > 0 )
     throw SALOME_Exception( "Offset of quadratic mesh not supported" );
@@ -2665,8 +2945,7 @@ SMDS_Mesh* SMESH_MeshAlgos::MakeOffset( SMDS_ElemIteratorPtr theFaceIt,
   theNew2OldFaces.clear();
   theNew2OldNodes.clear();
   theNew2OldFaces.push_back
-    ( std::make_pair(( const SMDS_MeshElement*) 0,
-                     ( const SMDS_MeshElement*) 0)); // to have index == face->GetID()
+    ( std::make_pair(( const SMDS_MeshElement*) 0, 0)); // to have index == face->GetID()
 
   // copy input faces to the newMesh keeping IDs of nodes
 
@@ -2687,7 +2966,7 @@ SMDS_Mesh* SMESH_MeshAlgos::MakeOffset( SMDS_ElemIteratorPtr theFaceIt,
       {
         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] ));
+        theNew2OldNodes.push_back( std::make_pair( newNode, nodes[i]->GetID() ));
         nodes[i] = newNode;
       }
     }
@@ -2725,7 +3004,7 @@ SMDS_Mesh* SMESH_MeshAlgos::MakeOffset( SMDS_ElemIteratorPtr theFaceIt,
     default:
       continue;
     }
-    theNew2OldFaces.push_back( std::make_pair( newFace, face ));
+    theNew2OldFaces.push_back( std::make_pair( newFace, face->GetID() ));
 
     SMESH_NodeXYZ pPrev = nodes.back(), p;
     for ( size_t i = 0; i < nodes.size(); ++i )
@@ -2743,7 +3022,7 @@ SMDS_Mesh* SMESH_MeshAlgos::MakeOffset( SMDS_ElemIteratorPtr theFaceIt,
   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] ))
+    if ( !SMESH_MeshAlgos::FaceNormal( theNew2OldFaces[i].first, normals[i] ))
       normals[i].SetCoord( 0,0,0 ); // TODO find norm by neighbors
   }
 
@@ -2792,7 +3071,7 @@ SMDS_Mesh* SMESH_MeshAlgos::MakeOffset( SMDS_ElemIteratorPtr theFaceIt,
         {
           newNode = newMesh->AddNode( newXYZ.X(), newXYZ.Y(), newXYZ.Z() );
           newNode->setIsMarked( true );
-          theNew2OldNodes.push_back( std::make_pair( newNode, theNew2OldNodes[i].second ));
+          theNew2OldNodes.push_back( std::make_pair( newNode, 0 ));
           multiPos.emplace_back( newNode );
         }
       }
diff --git a/src/SMESHUtils/SMESH_PolyLine.cxx b/src/SMESHUtils/SMESH_PolyLine.cxx
new file mode 100644 (file)
index 0000000..4916e7c
--- /dev/null
@@ -0,0 +1,595 @@
+// Copyright (C) 2018  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      : SMESH_PolyLine.cxx
+// Created   : Thu Dec  6 17:33:26 2018
+// Author    : Edward AGAPOV (eap)
+
+#include "SMESH_MeshAlgos.hxx"
+
+#include "SMDS_MeshGroup.hxx"
+#include "SMDS_LinearEdge.hxx"
+#include "SMDS_Mesh.hxx"
+#include "SMESH_TryCatch.hxx"
+
+#include <OSD_Parallel.hxx>
+#include <Precision.hxx>
+
+namespace
+{
+  //================================================================================
+  /*!
+   * \brief Sequence of found points and a current point data
+   */
+  struct Path
+  {
+    std::vector< gp_XYZ >   myPoints;
+    double                  myLength;
+
+    const SMDS_MeshElement* myFace;
+    SMESH_NodeXYZ           myNode1; // nodes of the edge the path entered myFace
+    SMESH_NodeXYZ           myNode2;
+    int                     myNodeInd1;
+    int                     myNodeInd2;
+    double                  myDot1;
+    double                  myDot2;
+
+    int                     mySrcPntInd; //!< start point index
+    TIDSortedElemSet        myElemSet, myAvoidSet;
+
+    Path(): myLength(0.0), myFace(0) {}
+
+    bool SetCutAtCorner( const SMESH_NodeXYZ&    cornerNode,
+                         const SMDS_MeshElement* face,
+                         const gp_XYZ&           plnNorm,
+                         const gp_XYZ&           plnOrig );
+
+    void AddPoint( const gp_XYZ& p );
+
+    bool Extend( const gp_XYZ& plnNorm, const gp_XYZ& plnOrig );
+
+    bool ReachSamePoint( const Path& other );
+
+    static void Remove( std::vector< Path > & paths, size_t& i );
+  };
+
+  //================================================================================
+  /*!
+   * \brief Return true if this Path meats another
+   */
+  //================================================================================
+
+  bool Path::ReachSamePoint( const Path& other )
+  {
+    return ( mySrcPntInd != other.mySrcPntInd &&
+             myFace == other.myFace );
+  }
+
+  //================================================================================
+  /*!
+   * \brief Remove a path from a vector
+   */
+  //================================================================================
+
+  void Path::Remove( std::vector< Path > & paths, size_t& i )
+  {
+    if ( paths.size() > 1 )
+    {
+      size_t j = paths.size() - 1; // last item to be removed
+      if ( i < j )
+      {
+        paths[ i ].myPoints.swap( paths[ j ].myPoints );
+        paths[ i ].myLength    = paths[ j ].myLength;
+        paths[ i ].mySrcPntInd = paths[ j ].mySrcPntInd;
+        paths[ i ].myFace      = paths[ j ].myFace;
+        paths[ i ].myNode1     = paths[ j ].myNode1;
+        paths[ i ].myNode2     = paths[ j ].myNode2;
+        paths[ i ].myNodeInd1  = paths[ j ].myNodeInd1;
+        paths[ i ].myNodeInd2  = paths[ j ].myNodeInd2;
+        paths[ i ].myDot1      = paths[ j ].myDot1;
+        paths[ i ].myDot2      = paths[ j ].myDot2;
+      }
+    }
+    paths.pop_back();
+    if ( i > 0 )
+      --i;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Store a point that is at a node of a face if the face is intersected by plane.
+   *        Return false if the node is a sole intersection point of the face and the plane
+   */
+  //================================================================================
+
+  bool Path::SetCutAtCorner( const SMESH_NodeXYZ&    cornerNode,
+                             const SMDS_MeshElement* face,
+                             const gp_XYZ&           plnNorm,
+                             const gp_XYZ&           plnOrig )
+  {
+    if ( face == myFace )
+      return false;
+    myNodeInd1 = face->GetNodeIndex( cornerNode._node );
+    myNodeInd2 = ( myNodeInd1 + 1 ) % face->NbCornerNodes();
+    int   ind3 = ( myNodeInd1 + 2 ) % face->NbCornerNodes();
+    myNode1.Set( face->GetNode( ind3 ));
+    myNode2.Set( face->GetNode( myNodeInd2 ));
+
+    myDot1 = plnNorm * ( myNode1 - plnOrig );
+    myDot2 = plnNorm * ( myNode2 - plnOrig );
+
+    bool ok = ( myDot1 * myDot2 < 0 );
+    if ( !ok && myDot1 * myDot2 == 0 )
+    {
+      ok = ( myDot1 != myDot2 );
+      if ( ok && myFace )
+        ok = ( myFace->GetNodeIndex(( myDot1 == 0 ? myNode1 : myNode2 )._node ) < 0 );
+    }
+    if ( ok )
+    {
+      myFace = face;
+      myDot1 = 0;
+      AddPoint( cornerNode );
+    }
+    return ok;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Store a point and update myLength
+   */
+  //================================================================================
+
+  void Path::AddPoint( const gp_XYZ& p )
+  {
+    if ( !myPoints.empty() )
+      myLength += ( p - myPoints.back() ).Modulus();
+    else
+      myLength = 0;
+    myPoints.push_back( p );
+  }
+
+  //================================================================================
+  /*!
+   * \brief Try to find the next point
+   *  \param [in] plnNorm - cutting plane normal
+   *  \param [in] plnOrig - cutting plane origin
+   */
+  //================================================================================
+
+  bool Path::Extend( const gp_XYZ& plnNorm, const gp_XYZ& plnOrig )
+  {
+    int nodeInd3 = ( myNodeInd1 + 1 ) % myFace->NbCornerNodes();
+    if ( myNodeInd2 == nodeInd3 )
+      nodeInd3 = ( myNodeInd1 + 2 ) % myFace->NbCornerNodes();
+
+    SMESH_NodeXYZ node3 = myFace->GetNode( nodeInd3 );
+    double         dot3 = plnNorm * ( node3 - plnOrig );
+
+    if ( dot3 * myDot1 < 0. )
+    {
+      myNode2    = node3;
+      myNodeInd2 = nodeInd3;
+      myDot2     = dot3;
+    }
+    else if ( dot3 * myDot2 < 0. )
+    {
+      myNode1    = node3;
+      myNodeInd1 = nodeInd3;
+      myDot1     = dot3;
+    }
+    else if ( dot3 == 0. )
+    {
+      SMDS_ElemIteratorPtr fIt = node3._node->GetInverseElementIterator(SMDSAbs_Face);
+      while ( fIt->more() )
+        if ( SetCutAtCorner( node3, fIt->next(), plnNorm, plnOrig ))
+          return true;
+      return false;
+    }
+    else if ( myDot2 == 0. )
+    {
+      SMESH_NodeXYZ node2 = myNode2; // copy as myNode2 changes in SetCutAtCorner()
+      SMDS_ElemIteratorPtr fIt = node2._node->GetInverseElementIterator(SMDSAbs_Face);
+      while ( fIt->more() )
+        if ( SetCutAtCorner( node2, fIt->next(), plnNorm, plnOrig ))
+          return true;
+      return false;
+    }
+
+    double r = Abs( myDot1 / ( myDot2 - myDot1 ));
+    AddPoint( myNode1 * ( 1 - r ) + myNode2 * r );
+
+    myAvoidSet.clear();
+    myAvoidSet.insert( myFace );
+    myFace = SMESH_MeshAlgos::FindFaceInSet( myNode1._node, myNode2._node,
+                                             myElemSet,   myAvoidSet,
+                                             &myNodeInd1, &myNodeInd2 );
+    return myFace;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Compute a path between two points of PolySegment
+   */
+  struct PolyPathCompute
+  {
+    SMESH_MeshAlgos::TListOfPolySegments& mySegments; //!< inout PolySegment's
+    std::vector< Path >&                  myPaths;    //!< path of each of segments to compute
+    SMDS_Mesh*                            myMesh;
+    mutable std::vector< std::string >    myErrors;
+
+    PolyPathCompute( SMESH_MeshAlgos::TListOfPolySegments& theSegments,
+                     std::vector< Path >&                  thePaths,
+                     SMDS_Mesh*                            theMesh):
+      mySegments( theSegments ),
+      myPaths( thePaths ),
+      myMesh( theMesh ),
+      myErrors( theSegments.size() )
+    {
+    }
+
+#undef SMESH_CAUGHT
+#define SMESH_CAUGHT myErrors[i] =
+    void operator() ( const int i ) const
+    {
+      SMESH_TRY;
+      const_cast< PolyPathCompute* >( this )->Compute( i );
+      SMESH_CATCH( SMESH::returnError );
+    }
+#undef SMESH_CAUGHT
+
+    //================================================================================
+    /*!
+     * \brief Compute a path of a given segment
+     */
+    //================================================================================
+
+    void Compute( const int iSeg )
+    {
+      SMESH_MeshAlgos::PolySegment& polySeg = mySegments[ iSeg ];
+
+      // the cutting plane
+      gp_XYZ plnNorm = ( polySeg.myXYZ[0] - polySeg.myXYZ[1] ) ^ polySeg.myVector.XYZ();
+      gp_XYZ plnOrig = polySeg.myXYZ[1];
+
+      // Find paths connecting the 2 end points of polySeg
+
+      std::vector< Path > paths; paths.reserve(10);
+
+      // 1) initialize paths; two paths starts at each end point
+
+      for ( int iP = 0; iP < 2; ++iP ) // loop on the polySeg end points
+      {
+        Path path;
+        path.mySrcPntInd = iP;
+        size_t nbPaths = paths.size();
+
+        if ( polySeg.myFace[ iP ]) // the end point lies on polySeg.myFace[ iP ]
+        {
+          // check coincidence of polySeg.myXYZ[ iP ] with nodes
+          const double tol = 1e-20;
+          SMESH_NodeXYZ nodes[4];
+          for ( int i = 0; i < 3 &&  !polySeg.myNode1[ iP ]; ++i )
+          {
+            nodes[ i ] = polySeg.myFace[ iP ]->GetNode( i );
+            if (( nodes[ i ] - polySeg.myXYZ[ iP ]).SquareModulus() < tol*tol )
+              polySeg.myNode1[ iP ] = nodes[ i ].Node();
+          }
+          nodes[ 3 ] = nodes[ 0 ];
+
+          // check coincidence of polySeg.myXYZ[ iP ] with edges
+          for ( int i = 0; i < 3 &&  !polySeg.myNode1[ iP ]; ++i )
+          {
+            SMDS_LinearEdge edge( nodes[i].Node(), nodes[i+1].Node() );
+            if ( SMESH_MeshAlgos::GetDistance( &edge, polySeg.myXYZ[ iP ]) < tol )
+            {
+              polySeg.myNode1[ iP ] = nodes[ i     ].Node();
+              polySeg.myNode2[ iP ] = nodes[ i + 1 ].Node();
+            }
+          }
+
+          if ( !polySeg.myNode1[ iP ] ) // polySeg.myXYZ[ iP ] is within polySeg.myFace[ iP ]
+          {
+            double dot[ 4 ];
+            for ( int i = 0; i < 3; ++i )
+              dot[ i ] = plnNorm * ( nodes[ i ] - plnOrig );
+            dot[ 3 ] = dot[ 0 ];
+
+            int iCut = 0; // index of a cut edge
+            if      ( dot[ 1 ] * dot[ 2 ] < 0. ) iCut = 1;
+            else if ( dot[ 2 ] * dot[ 3 ] < 0. ) iCut = 2;
+
+            // initialize path so as if it entered the face via iCut-th edge
+            path.myFace = polySeg.myFace[ iP ];
+            path.myNodeInd1 = iCut;
+            path.myNodeInd2 = iCut + 1;
+            path.myNode1.Set( nodes[ iCut     ].Node() );
+            path.myNode2.Set( nodes[ iCut + 1 ].Node() );
+            path.myDot1 = dot[ iCut ];
+            path.myDot2 = dot[ iCut + 1 ];
+            path.myPoints.clear();
+            path.AddPoint( polySeg.myXYZ[ iP ]);
+            paths.push_back( path );
+
+            path.Extend( plnNorm, plnOrig ); // to get another edge cut
+            path.myFace = polySeg.myFace[ iP ];
+            if ( path.myDot1 == 0. ) // cut at a node
+            {
+              path.myNodeInd1 = ( iCut + 2 ) % 3;
+              path.myNodeInd2 = ( iCut + 3 ) % 3;
+              path.myNode2.Set( path.myFace->GetNode( path.myNodeInd2 ));
+              path.myDot2 = dot[ path.myNodeInd2 ];
+            }
+            else
+            {
+              path.myNodeInd1 = path.myFace->GetNodeIndex( path.myNode1.Node() );
+              path.myNodeInd2 = path.myFace->GetNodeIndex( path.myNode2.Node() );
+            }
+            path.myPoints.clear();
+            path.AddPoint( polySeg.myXYZ[ iP ]);
+            paths.push_back( path );
+          }
+        }
+
+        if ( polySeg.myNode2[ iP ] && polySeg.myNode2[ iP ] != polySeg.myNode1[ iP ] )
+        {
+          // the end point is on an edge
+          while (( path.myFace = SMESH_MeshAlgos::FindFaceInSet( polySeg.myNode1[ iP ],
+                                                                 polySeg.myNode2[ iP ],
+                                                                 path.myElemSet,
+                                                                 path.myAvoidSet,
+                                                                 &path.myNodeInd1,
+                                                                 &path.myNodeInd2 )))
+          {
+            path.myNode1.Set( polySeg.myNode1[ iP ]);
+            path.myNode2.Set( polySeg.myNode2[ iP ]);
+            path.myDot1 = plnNorm * ( path.myNode1 - plnOrig );
+            path.myDot2 = plnNorm * ( path.myNode2 - plnOrig );
+            path.myPoints.clear();
+            path.AddPoint( polySeg.myXYZ[ iP ]);
+            path.myAvoidSet.insert( path.myFace );
+            paths.push_back( path );
+          }
+          if ( nbPaths == paths.size() )
+            throw SALOME_Exception ( SMESH_Comment("No face edge found by point ") << iP+1
+                                     << " in a PolySegment " << iSeg );
+        }
+        else if ( polySeg.myNode1[ iP ] ) // the end point is at a node
+        {
+          std::set<const SMDS_MeshNode* > nodes;
+          SMDS_ElemIteratorPtr fIt = polySeg.myNode1[ iP ]->GetInverseElementIterator(SMDSAbs_Face);
+          while ( fIt->more() )
+          {
+            path.myPoints.clear();
+            if ( path.SetCutAtCorner( polySeg.myNode1[ iP ], fIt->next(), plnNorm, plnOrig ))
+            {
+              if (( path.myDot1 * path.myDot2 != 0 ) ||
+                  ( nodes.insert( path.myDot1 == 0 ? path.myNode1._node : path.myNode2._node ).second ))
+                paths.push_back( path );
+            }
+          }
+        }
+
+        // look for a one-segment path
+        for ( size_t i = 0; i < nbPaths; ++i )
+          for ( size_t j = nbPaths; j < paths.size(); ++j )
+            if ( paths[i].myFace == paths[j].myFace )
+            {
+              myPaths[ iSeg ].myPoints.push_back( paths[i].myPoints[0] );
+              myPaths[ iSeg ].myPoints.push_back( paths[j].myPoints[0] );
+              paths.clear();
+            }
+      }
+
+      // 2) extend paths and compose the shortest one connecting the two points
+
+      myPaths[ iSeg ].myLength = 1e100;
+
+      while ( paths.size() >= 2 )
+      {
+        for ( size_t i = 0; i < paths.size(); ++i )
+        {
+          Path& path = paths[ i ];
+          if ( !path.Extend( plnNorm, plnOrig ) ||        // path reached a mesh boundary
+               path.myLength > myPaths[ iSeg ].myLength ) // path is longer than others
+          {
+            Path::Remove( paths, i );
+            continue;
+          }
+
+          // join paths that reach same point
+          for ( size_t j = 0; j < paths.size(); ++j )
+          {
+            if ( i != j && paths[i].ReachSamePoint( paths[j] ))
+            {
+              double   distLast = ( paths[i].myPoints.back() - paths[j].myPoints.back() ).Modulus();
+              double fullLength = ( paths[i].myLength + paths[j].myLength + distLast );
+              if ( fullLength < myPaths[ iSeg ].myLength )
+              {
+                myPaths[ iSeg ].myLength = fullLength;
+                std::vector< gp_XYZ > & allPoints = myPaths[ iSeg ].myPoints;
+                allPoints.swap( paths[i].myPoints );
+                allPoints.insert( allPoints.end(),
+                                  paths[j].myPoints.rbegin(),
+                                  paths[j].myPoints.rend() );
+              }
+              Path::Remove( paths, i );
+              Path::Remove( paths, j );
+            }
+          }
+        }
+        if ( !paths.empty() && (int) paths[0].myPoints.size() > myMesh->NbFaces() )
+          throw SALOME_Exception(LOCALIZED( "Infinite loop in MakePolyLine()"));
+      }
+
+      if ( myPaths[ iSeg ].myPoints.empty() )
+        throw SALOME_Exception( SMESH_Comment("Can't find a full path for PolySegment #") << iSeg );
+
+      // reverse the path
+      double d00 = ( polySeg.myXYZ[0] - myPaths[ iSeg ].myPoints.front() ).SquareModulus();
+      double d01 = ( polySeg.myXYZ[0] - myPaths[ iSeg ].myPoints.back()  ).SquareModulus();
+      if ( d00 > d01 )
+        std::reverse( myPaths[ iSeg ].myPoints.begin(), myPaths[ iSeg ].myPoints.end() );
+
+    } // PolyPathCompute::Compute()
+
+  }; // struct PolyPathCompute
+
+} // namespace
+
+//=======================================================================
+//function : MakePolyLine
+//purpose  : Create a polyline consisting of 1D mesh elements each lying on a 2D element of
+//           the initial mesh
+//=======================================================================
+
+void SMESH_MeshAlgos::MakePolyLine( SMDS_Mesh*                            theMesh,
+                                    TListOfPolySegments&                  theSegments,
+                                    std::vector<const SMDS_MeshElement*>& theNewEdges,
+                                    std::vector< const SMDS_MeshNode* >&  theNewNodes,
+                                    SMDS_MeshGroup*                       theGroup,
+                                    SMESH_ElementSearcher*                theSearcher)
+{
+  std::vector< Path > segPaths( theSegments.size() ); // path of each of segments
+
+  SMESH_ElementSearcher* searcher = theSearcher;
+  SMESHUtils::Deleter<SMESH_ElementSearcher> delSearcher;
+  if ( !searcher )
+  {
+    searcher = SMESH_MeshAlgos::GetElementSearcher( *theMesh );
+    delSearcher._obj = searcher;
+  }
+
+  // get cutting planes
+
+  std::vector< bool > isVectorOK( theSegments.size(), true );
+  const double planarCoef = 0.333; // plane height in planar case
+
+  for ( size_t iSeg = 0; iSeg < theSegments.size(); ++iSeg )
+  {
+    PolySegment& polySeg = theSegments[ iSeg ];
+
+    gp_XYZ p1 = SMESH_NodeXYZ( polySeg.myNode1[0] );
+    gp_XYZ p2 = SMESH_NodeXYZ( polySeg.myNode1[1] );
+    if ( polySeg.myNode2[0] ) p1 = 0.5 * ( p1 + SMESH_NodeXYZ( polySeg.myNode2[0] ));
+    if ( polySeg.myNode2[1] ) p2 = 0.5 * ( p2 + SMESH_NodeXYZ( polySeg.myNode2[1] ));
+
+    polySeg.myFace[0] = polySeg.myFace[1] = 0;
+    if ( !polySeg.myNode1[0] && !polySeg.myNode2[0] )
+    {
+      p1 = searcher->Project( polySeg.myXYZ[0], SMDSAbs_Face, &polySeg.myFace[0] );
+    }
+    if ( !polySeg.myNode1[1] && !polySeg.myNode2[1] )
+    {
+      p2 = searcher->Project( polySeg.myXYZ[1], SMDSAbs_Face, &polySeg.myFace[1] );
+    }
+    polySeg.myXYZ[0] = p1;
+    polySeg.myXYZ[1] = p2;
+
+    gp_XYZ plnNorm = ( p1 - p2 ) ^ polySeg.myVector.XYZ();
+
+    isVectorOK[ iSeg ] = ( plnNorm.Modulus() > std::numeric_limits<double>::min() );
+    if ( !isVectorOK[ iSeg ])
+    {
+      gp_XYZ pMid = 0.5 * ( p1 + p2 );
+      const SMDS_MeshElement* face;
+      polySeg.myMidProjPoint = searcher->Project( pMid, SMDSAbs_Face, &face );
+      polySeg.myVector       = polySeg.myMidProjPoint.XYZ() - pMid;
+
+      gp_XYZ faceNorm;
+      SMESH_MeshAlgos::FaceNormal( face, faceNorm );
+
+      if ( polySeg.myVector.Magnitude() < Precision::Confusion() ||
+           polySeg.myVector * faceNorm  < Precision::Confusion() )
+      {
+        polySeg.myVector = faceNorm;
+        polySeg.myMidProjPoint = pMid + faceNorm * ( p1 - p2 ).Modulus() * planarCoef;
+      }
+    }
+    else
+    {
+      polySeg.myVector = plnNorm ^ ( p1 - p2 );
+    }
+  }
+
+  // assure that inverse elements are constructed, avoid their concurrent building in threads
+  theMesh->nodesIterator()->next()->NbInverseElements();
+
+  // find paths
+
+  PolyPathCompute algo( theSegments, segPaths, theMesh );
+  OSD_Parallel::For( 0, theSegments.size(), algo, theSegments.size() == 1 );
+
+  for ( size_t iSeg = 0; iSeg < theSegments.size(); ++iSeg )
+    if ( !algo.myErrors[ iSeg ].empty() )
+      throw SALOME_Exception( algo.myErrors[ iSeg ].c_str() );
+
+  // create an 1D mesh
+
+  const SMDS_MeshNode *n, *nPrev = 0;
+
+  for ( size_t iSeg = 0; iSeg < theSegments.size(); ++iSeg )
+  {
+    const Path& path = segPaths[iSeg];
+    if ( path.myPoints.size() < 2 )
+      continue;
+
+    double tol = path.myLength / path.myPoints.size() / 1000.;
+    if ( !nPrev || ( SMESH_NodeXYZ( nPrev ) - path.myPoints[0] ).SquareModulus() > tol*tol )
+    {
+      nPrev = theMesh->AddNode( path.myPoints[0].X(), path.myPoints[0].Y(), path.myPoints[0].Z() );
+      theNewNodes.push_back( nPrev );
+    }
+    for ( size_t iP = 1; iP < path.myPoints.size(); ++iP )
+    {
+      n = theMesh->AddNode( path.myPoints[iP].X(), path.myPoints[iP].Y(), path.myPoints[iP].Z() );
+      theNewNodes.push_back( n );
+
+      const SMDS_MeshElement* elem = theMesh->AddEdge( nPrev, n );
+      theNewEdges.push_back( elem );
+      if ( theGroup )
+        theGroup->Add( elem );
+
+      nPrev = n;
+    }
+
+    // return a vector
+
+    gp_XYZ pMid = 0.5 * ( path.myPoints[0] + path.myPoints.back() );
+    if ( isVectorOK[ iSeg ])
+    {
+      // find the most distant point of a path
+      double maxDist = 0;
+      for ( size_t iP = 1; iP < path.myPoints.size(); ++iP )
+      {
+        double dist = Abs( theSegments[iSeg].myVector * ( path.myPoints[iP] - path.myPoints[0] ));
+        if ( dist > maxDist )
+        {
+          maxDist = dist;
+          theSegments[iSeg].myMidProjPoint = path.myPoints[iP];
+        }
+      }
+      if ( maxDist < Precision::Confusion() ) // planar case
+        theSegments[iSeg].myMidProjPoint =
+          pMid + theSegments[iSeg].myVector.XYZ().Normalized() * path.myLength * planarCoef;
+    }
+    theSegments[iSeg].myVector = gp_Vec( pMid, theSegments[iSeg].myMidProjPoint );
+  }
+
+  return;
+}
diff --git a/src/SMESHUtils/SMESH_Slot.cxx b/src/SMESHUtils/SMESH_Slot.cxx
new file mode 100644 (file)
index 0000000..0ceca4a
--- /dev/null
@@ -0,0 +1,720 @@
+// Copyright (C) 2018  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      : SMESH_Slot.cxx
+// Created   : Fri Nov 30 15:58:37 2018
+// Author    : Edward AGAPOV (eap)
+
+#include "SMESH_MeshAlgos.hxx"
+
+#include "ObjectPool.hxx"
+#include "SMDS_LinearEdge.hxx"
+#include "SMDS_Mesh.hxx"
+
+#include <IntAna_IntConicQuad.hxx>
+#include <IntAna_Quadric.hxx>
+#include <NCollection_DataMap.hxx>
+#include <NCollection_Map.hxx>
+#include <Precision.hxx>
+#include <gp_Ax1.hxx>
+#include <gp_Cylinder.hxx>
+#include <gp_Dir.hxx>
+#include <gp_Lin.hxx>
+#include <gp_Pln.hxx>
+#include <gp_Pnt.hxx>
+#include <gp_Vec.hxx>
+
+#include <Utils_SALOME_Exception.hxx>
+
+#include <boost/container/flat_set.hpp>
+
+namespace
+{
+  typedef SMESH_MeshAlgos::Edge TEdge;
+
+  //================================================================================
+  //! point of intersection of a face edge with the cylinder
+  struct IntPoint
+  {
+    SMESH_NodeXYZ myNode;        // point and a node
+    int           myEdgeIndex;   // face edge index
+    bool          myIsOutPln[2]; // isOut of two planes
+  };
+
+  //================================================================================
+  //! poly-line segment
+  struct Segment
+  {
+    typedef boost::container::flat_set< const SMDS_MeshNode* > TNodeSet;
+    //typedef std::list< TEdge > TEdgeList;
+
+    const SMDS_MeshElement* myEdge;
+    TNodeSet                myEndNodes; // ends of cut edges
+    //TEdgeList               myCutEdges[2];
+    
+
+    // return its axis
+    gp_Ax1 Ax1( bool reversed = false ) const
+    {
+      SMESH_NodeXYZ n1 = myEdge->GetNode(  reversed );
+      SMESH_NodeXYZ n2 = myEdge->GetNode( !reversed );
+      return gp_Ax1( n1, gp_Dir( n2 - n1 ));
+    }
+    // return a node
+    const SMDS_MeshNode* Node(int i) const
+    {
+      return myEdge->GetNode( i % 2 );
+    }
+    // store an intersection edge forming the slot border
+    void AddEdge( TEdge& e, double tol )
+    {
+      const SMDS_MeshNode** nodes = & e._node1;
+      for ( int i = 0; i < 2; ++i )
+      {
+        std::pair< TNodeSet::iterator, bool > nItAdded = myEndNodes.insert( nodes[ i ]);
+        if ( !nItAdded.second )
+          myEndNodes.erase( nItAdded.first );
+      }
+    }
+    // { -- PREV version
+    //   int i = myCutEdges[0].empty() ? 0 : 1;
+    //   std::insert_iterator< TEdgeList > where = inserter( myCutEdges[i], myCutEdges[i].begin() );
+
+    //   //double minDist = 1e100;
+    //   SMESH_NodeXYZ nNew[2] = { e._node1, e._node2 };
+    //   int iNewMin = 0, iCurMin = 1;
+    //   for ( i = 0; i < 2; ++i )
+    //   {
+    //     if ( myCutEdges[i].empty() )
+    //       continue;
+    //     SMESH_NodeXYZ nCur[2] = { myCutEdges[i].front()._node1,
+    //                               myCutEdges[i].back()._node2 };
+    //     for   ( int iN = 0; iN < 2; ++iN )
+    //       for ( int iC = 0; iC < 2; ++iC )
+    //       {
+    //         if (( nCur[iC].Node() && nCur[iC] == nNew[iN] ) ||
+    //             ( nCur[iC] - nNew[iN] ).SquareModulus() < tol * tol )
+    //         {
+    //           where   = inserter( myCutEdges[i], iC ? myCutEdges[i].end() : myCutEdges[i].begin() );
+    //           iNewMin = iN;
+    //           iCurMin = iC;
+    //           //minDist = dist;
+    //           iN = 2;
+    //           break;
+    //         }
+    //       }
+    //   }
+    //   if ( iNewMin == iCurMin )
+    //     std::swap( e._node1, e._node2 );
+
+    //   where = e;
+    // }
+    Segment( const SMDS_MeshElement* e = 0 ): myEdge(e) { myEndNodes.reserve( 4 ); }
+  };
+  typedef ObjectPoolIterator<Segment> TSegmentIterator;
+
+  
+  //================================================================================
+  /*!
+   * \brief Intersect a face edge given by its nodes with a cylinder.
+   */
+  //================================================================================
+
+  void intersectEdge( const gp_Cylinder&      cyl,
+                      const SMESH_NodeXYZ&    n1,
+                      const SMESH_NodeXYZ&    n2,
+                      const double            tol,
+                      std::vector< IntPoint >& intPoints )
+  {
+    gp_Lin line( gp_Ax1( n1, gp_Dir( n2 - n1 )));
+    IntAna_IntConicQuad intersection( line, IntAna_Quadric( cyl ));
+
+    if ( !intersection.IsDone()     ||
+         intersection.IsParallel()  ||
+         intersection.IsInQuadric() ||
+         intersection.NbPoints() == 0 )
+      return;
+
+    gp_Vec edge( n1, n2 );
+
+    size_t oldNbPnts = intPoints.size();
+    for ( int iP = 1; iP <= intersection.NbPoints(); ++iP )
+    {
+      const gp_Pnt& p = intersection.Point( iP );
+
+      gp_Vec n1p ( n1, p );
+      const SMDS_MeshNode* n = 0;
+
+      double u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge
+      if ( u <= 0. ) {
+        if ( p.SquareDistance( n1 ) < tol * tol )
+          n = n1.Node();
+        else
+          continue;
+      }
+      else if ( u >= 1. ) {
+        if ( p.SquareDistance( n2 ) < tol * tol )
+          n = n2.Node();
+        else
+          continue;
+      }
+      else {
+        if      ( p.SquareDistance( n1 ) < tol * tol )
+          n = n1.Node();
+        else if ( p.SquareDistance( n2 ) < tol * tol )
+          n = n2.Node();
+      }
+
+      intPoints.push_back( IntPoint() );
+      if ( n )
+        intPoints.back().myNode.Set( n );
+      else
+        intPoints.back().myNode.SetCoord( p.X(),p.Y(),p.Z() );
+    }
+
+    // set points order along an edge
+    if ( intPoints.size() - oldNbPnts == 2 &&
+         intersection.ParamOnConic( 1 ) > intersection.ParamOnConic( 2 ))
+    {
+      int i = intPoints.size() - 1;
+      std::swap( intPoints[ i ], intPoints[ i - 1 ]);
+    }
+
+    return;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Return signed distance between a point and a plane
+   */
+  //================================================================================
+
+  double signedDist( const gp_Pnt& p, const gp_Ax1& planeNormal )
+  {
+    const gp_Pnt& O = planeNormal.Location();
+    gp_Vec Op( O, p );
+    return Op * planeNormal.Direction();
+  }
+
+  //================================================================================
+  /*!
+   * \brief Check if a point is outside a segment domain bound by two planes
+   */
+  //================================================================================
+
+  bool isOut( const gp_Pnt& p, const gp_Ax1* planeNormal, bool* isOutPtr )
+  {
+    isOutPtr[0] = isOutPtr[1] = false;
+
+    for ( int i = 0; i < 2; ++i )
+    {
+      isOutPtr[i] = ( signedDist( p, planeNormal[i] ) <= 0. );
+    }
+    return ( isOutPtr[0] && isOutPtr[1] );
+  }
+
+  //================================================================================
+  /*!
+   * \brief Check if a segment between two points is outside a segment domain bound by two planes
+   */
+  //================================================================================
+
+  bool isSegmentOut( bool* isOutPtr1, bool* isOutPtr2 )
+  {
+    return (( isOutPtr1[0] && isOutPtr2[0] ) ||
+            ( isOutPtr1[1] && isOutPtr2[1] ));
+  }
+
+  //================================================================================
+  /*!
+   * \brief cut off ip1 from edge (ip1 - ip2) by a plane
+   */
+  //================================================================================
+
+  void cutOff( IntPoint & ip1, const IntPoint & ip2, const gp_Ax1& planeNormal, double tol )
+  {
+    gp_Lin lin( ip1.myNode, ( ip2.myNode - ip1.myNode ));
+    gp_Pln pln( planeNormal.Location(), planeNormal.Direction() );
+
+    IntAna_IntConicQuad intersection( lin, pln, Precision::Angular/*Tolerance*/() );
+    if ( intersection.IsDone()      &&
+         !intersection.IsParallel()  &&
+         !intersection.IsInQuadric() &&
+         intersection.NbPoints() == 1 )
+    {
+      if ( intersection.Point( 1 ).SquareDistance( ip1.myNode ) > tol * tol )
+      {
+        static_cast< gp_XYZ& >( ip1.myNode ) = intersection.Point( 1 ).XYZ();
+        ip1.myNode._node = 0;
+        ip1.myEdgeIndex = -1;
+      }
+    }
+  }
+
+  //================================================================================
+  /*!
+   * \brief Assure that face normal is computed in faceNormals vector 
+   */
+  //================================================================================
+
+  const gp_XYZ& computeNormal( const SMDS_MeshElement* face,
+                               std::vector< gp_XYZ >&  faceNormals )
+  {
+    bool toCompute;
+    if ((int) faceNormals.size() <= face->GetID() )
+    {
+      toCompute = true;
+      faceNormals.resize( face->GetID() + 1 );
+    }
+    else
+    {
+      toCompute = faceNormals[ face->GetID() ].SquareModulus() == 0.;
+    }
+    if ( toCompute )
+      SMESH_MeshAlgos::FaceNormal( face, faceNormals[ face->GetID() ], /*normalized=*/false );
+
+    return faceNormals[ face->GetID() ];
+  }
+}
+
+//================================================================================
+/*!
+ * \brief Create a slot of given width around given 1D elements lying on a triangle mesh.
+ * The slot is consrtucted by cutting faces by cylindrical surfaces made around each segment.
+ * \return Edges located at the slot boundary
+ */
+//================================================================================
+
+std::vector< SMESH_MeshAlgos::Edge >
+SMESH_MeshAlgos::MakeSlot( SMDS_ElemIteratorPtr theSegmentIt,
+                           double               theWidth,
+                           SMDS_Mesh*           theMesh)
+{
+  std::vector< Edge > bndEdges;
+
+  if ( !theSegmentIt || !theSegmentIt->more() || !theMesh || theWidth == 0.)
+    return bndEdges;
+
+  // put the input segments to a data map in order to be able finding neighboring ones
+
+  typedef std::vector< Segment* >                                                TSegmentVec;
+  typedef NCollection_DataMap< const SMDS_MeshNode*, TSegmentVec, SMESH_Hasher > TSegmentsOfNode;
+  TSegmentsOfNode segmentsOfNode;
+  ObjectPool< Segment > segmentPool;
+
+  while( theSegmentIt->more() )
+  {
+    const SMDS_MeshElement* edge = theSegmentIt->next();
+    if ( edge->GetType() != SMDSAbs_Edge )
+      throw SALOME_Exception( "A segment is not a mesh edge");
+
+    Segment* segment = segmentPool.getNew();
+    segment->myEdge = edge;
+
+    for ( SMDS_NodeIteratorPtr nIt = edge->nodeIterator(); nIt->more(); )
+    {
+      const SMDS_MeshNode* n = nIt->next();
+      TSegmentVec* segVec = segmentsOfNode.ChangeSeek( n );
+      if ( !segVec )
+        segVec = segmentsOfNode.Bound( n, TSegmentVec() );
+      segVec->reserve(2);
+      segVec->push_back( segment );
+    }
+  }
+
+  // Cut the mesh around the segments
+
+  const double tol = Precision::Confusion();
+  std::vector< gp_XYZ > faceNormals;
+  SMESH_MeshAlgos::Intersector meshIntersector( theMesh, tol, faceNormals );
+  std::unique_ptr< SMESH_ElementSearcher> faceSearcher;
+
+  std::vector< NLink > startEdges;
+  std::vector< const SMDS_MeshNode* > faceNodes(4), edgeNodes(2);
+  std::vector<const SMDS_MeshElement *> faces(2);
+  NCollection_Map<const SMDS_MeshElement*, SMESH_Hasher > checkedFaces;
+  std::vector< IntPoint > intPoints, p(2);
+  std::vector< SMESH_NodeXYZ > facePoints(4);
+  std::vector< Intersector::TFace > cutFacePoints;
+
+  std::vector< gp_Ax1 > planeNormalVec(2);
+  gp_Ax1 * planeNormal = & planeNormalVec[0];
+  
+  for ( TSegmentIterator segIt( segmentPool ); segIt.more(); ) // loop on all segments
+  {
+    Segment* segment = const_cast< Segment* >( segIt.next() );
+
+    gp_Lin      segLine( segment->Ax1() );
+    gp_Ax3      cylAxis( segLine.Location(), segLine.Direction() );
+    gp_Cylinder segCylinder( cylAxis, 0.5 * theWidth );
+    double      radius2( segCylinder.Radius() * segCylinder.Radius() );
+
+    // get normals of planes separating domains of neighboring segments
+    for ( int i = 0; i < 2; ++i ) // loop on 2 segment ends
+    {
+      planeNormal[i] = segment->Ax1(i);
+
+      const SMDS_MeshNode*    n = segment->Node( i );
+      const TSegmentVec& segVec = segmentsOfNode( n );
+      for ( size_t iS = 0; iS < segVec.size(); ++iS )
+      {
+        if ( segVec[iS] == segment )
+          continue;
+
+        gp_Ax1 axis2 = segVec[iS]->Ax1();
+        if ( n != segVec[iS]->Node( 1 ))
+          axis2.Reverse(); // along a wire
+
+        planeNormal[i].SetDirection( planeNormal[i].Direction().XYZ() + axis2.Direction().XYZ() );
+      }
+    }
+
+    // we explore faces around a segment starting from face edges;
+    // initialize a list of starting edges
+    startEdges.clear();
+    {
+      // get a face to start searching intersected faces from
+      const SMDS_MeshNode*      n0 = segment->Node( 0 );
+      SMDS_ElemIteratorPtr     fIt = n0->GetInverseElementIterator( SMDSAbs_Face );
+      const SMDS_MeshElement* face = ( fIt->more() ) ? fIt->next() : 0;
+      if ( !theMesh->Contains( face ))
+      {
+        if ( !faceSearcher )
+          faceSearcher.reset( SMESH_MeshAlgos::GetElementSearcher( *theMesh ));
+        face = faceSearcher->FindClosestTo( SMESH_NodeXYZ( n0 ), SMDSAbs_Face );
+      }
+      // collect face edges
+      int nbNodes = face->NbCornerNodes();
+      faceNodes.assign( face->begin_nodes(), face->end_nodes() );
+      faceNodes.resize( nbNodes + 1 );
+      faceNodes[ nbNodes ] = faceNodes[ 0 ];
+      for ( int i = 0; i < nbNodes; ++i )
+        startEdges.push_back( NLink( faceNodes[i], faceNodes[i+1] ));
+    }
+
+    // intersect faces located around a segment
+    checkedFaces.Clear();
+    while ( !startEdges.empty() )
+    {
+      edgeNodes[0] = startEdges[0].first;
+      edgeNodes[1] = startEdges[0].second;
+
+      theMesh->GetElementsByNodes( edgeNodes, faces, SMDSAbs_Face );
+      for ( size_t iF = 0; iF < faces.size(); ++iF ) // loop on faces sharing a start edge
+      {
+        const SMDS_MeshElement* face = faces[iF];
+        if ( !checkedFaces.Add( face ))
+          continue;
+
+        int nbNodes = face->NbCornerNodes();
+        if ( nbNodes != 3 )
+          throw SALOME_Exception( "MakeSlot() accepts triangles only" );
+        facePoints.assign( face->begin_nodes(), face->end_nodes() );
+        facePoints.resize( nbNodes + 1 );
+        facePoints[ nbNodes ] = facePoints[ 0 ];
+
+        // check if cylinder axis || face        
+        const gp_XYZ& faceNorm = computeNormal( face, faceNormals );
+        bool isCylinderOnFace  = ( Abs( faceNorm * cylAxis.Direction().XYZ() ) < tol );
+
+        if ( !isCylinderOnFace )
+        {
+          if ( Intersector::CutByPlanes( face, planeNormalVec, tol, cutFacePoints ))
+            continue; // whole face cut off
+          facePoints.swap( cutFacePoints[0] );
+          facePoints.push_back( facePoints[0] );
+        }
+
+        // find intersection points on face edges
+        intPoints.clear();
+        int nbPoints = facePoints.size()-1;
+        int nbFarPoints = 0;
+        for ( int i = 0; i < nbPoints; ++i )
+        {
+          const SMESH_NodeXYZ& n1 = facePoints[i];
+          const SMESH_NodeXYZ& n2 = facePoints[i+1];
+
+          size_t iP = intPoints.size();
+          intersectEdge( segCylinder, n1, n2, tol, intPoints );
+
+          // save edge index
+          if ( isCylinderOnFace )
+            for ( ; iP < intPoints.size(); ++iP )
+              intPoints[ iP ].myEdgeIndex = i;
+          else
+            for ( ; iP < intPoints.size(); ++iP )
+              if ( n1.Node() && n2.Node() )
+                intPoints[ iP ].myEdgeIndex = face->GetNodeIndex( n1.Node() );
+              else
+                intPoints[ iP ].myEdgeIndex = -(i+1);
+
+          nbFarPoints += ( segLine.SquareDistance( n1 ) > radius2 );
+        }
+
+        // feed startEdges
+        if ( nbFarPoints < nbPoints || !intPoints.empty() )
+          for ( int i = 0; i < nbPoints; ++i )
+          {
+            const SMESH_NodeXYZ& n1 = facePoints[i];
+            const SMESH_NodeXYZ& n2 = facePoints[i+1];
+            if ( n1.Node() && n2.Node() )
+            {
+              isOut( n1, planeNormal, p[0].myIsOutPln );
+              isOut( n2, planeNormal, p[1].myIsOutPln );
+              if ( !isSegmentOut( p[0].myIsOutPln, p[1].myIsOutPln ))
+              {
+                startEdges.push_back( NLink( n1.Node(), n2.Node() ));
+              }
+            }
+          }
+
+        if ( intPoints.size() < 2 )
+          continue;
+
+        // classify intPoints by planes
+        for ( size_t i = 0; i < intPoints.size(); ++i )
+          isOut( intPoints[i].myNode, planeNormal, intPoints[i].myIsOutPln );
+
+        // cut the face
+
+        if ( intPoints.size() > 2 )
+          intPoints.push_back( intPoints[0] );
+
+        for ( size_t iE = 1; iE < intPoints.size(); ++iE ) // 2 <= intPoints.size() <= 5
+        {
+          if (( intPoints[iE].myIsOutPln[0] && intPoints[iE].myIsOutPln[1]   ) ||
+              ( isSegmentOut( intPoints[iE].myIsOutPln, intPoints[iE-1].myIsOutPln )))
+            continue; // intPoint is out of domain
+
+          // check if a cutting edge connecting two intPoints is on cylinder surface
+          if ( intPoints[iE].myEdgeIndex == intPoints[iE-1].myEdgeIndex )
+            continue; // on same edge
+          if ( intPoints[iE].myNode.Node() &&
+               intPoints[iE].myNode == intPoints[iE-1].myNode ) // coincide
+            continue;
+
+          gp_XYZ edegDir = intPoints[iE].myNode - intPoints[iE-1].myNode;
+
+          bool toCut; // = edegDir.SquareModulus() > tol * tol;
+          if ( intPoints.size() == 2 )
+            toCut = true;
+          else if ( isCylinderOnFace )
+            toCut = cylAxis.Direction().IsParallel( edegDir, tol );
+          else
+          {
+            SMESH_NodeXYZ nBetween;
+            int eInd = intPoints[iE-1].myEdgeIndex;
+            if ( eInd < 0 )
+              nBetween = facePoints[( 1 - (eInd-1)) % nbPoints ];
+            else
+              nBetween = faceNodes[( 1 + eInd ) % nbNodes ];
+            toCut = ( segLine.SquareDistance( nBetween ) > radius2 );
+          }
+          if ( !toCut )
+            continue;
+
+          // limit the edge by planes
+          if ( intPoints[iE].myIsOutPln[0] ||
+               intPoints[iE].myIsOutPln[1] )
+            cutOff( intPoints[iE], intPoints[iE-1],
+                    planeNormal[ intPoints[iE].myIsOutPln[1] ], tol );
+
+          if ( intPoints[iE-1].myIsOutPln[0] ||
+               intPoints[iE-1].myIsOutPln[1] )
+            cutOff( intPoints[iE-1], intPoints[iE],
+                    planeNormal[ intPoints[iE-1].myIsOutPln[1] ], tol );
+
+          edegDir = intPoints[iE].myNode - intPoints[iE-1].myNode;
+          if ( edegDir.SquareModulus() < tol * tol )
+            continue; // fully cut off
+
+          // face cut
+          meshIntersector.Cut( face,
+                               intPoints[iE-1].myNode, intPoints[iE-1].myEdgeIndex,
+                               intPoints[iE  ].myNode, intPoints[iE  ].myEdgeIndex );
+
+          Edge e = { intPoints[iE].myNode.Node(), intPoints[iE-1].myNode.Node(), 0 };
+          segment->AddEdge( e, tol );
+          bndEdges.push_back( e );
+        }
+      }  // loop on faces sharing an edge
+
+      startEdges[0] = startEdges.back();
+      startEdges.pop_back();
+
+    } // loop on startEdges
+  } // loop on all input segments
+
+
+  // Make cut at the end of group of segments
+
+  std::vector<const SMDS_MeshElement*> polySegments;
+
+  for ( TSegmentsOfNode::Iterator nSegsIt( segmentsOfNode ); nSegsIt.More(); nSegsIt.Next() )
+  {
+    const TSegmentVec& segVec = nSegsIt.Value();
+    if ( segVec.size() != 1 )
+      continue;
+
+    const Segment*       segment = segVec[0];
+    const SMDS_MeshNode* segNode = nSegsIt.Key();
+
+    // find two end nodes of cut edges to make a cut between
+    if ( segment->myEndNodes.size() != 4 )
+      throw SALOME_Exception( "MakeSlot(): too short end edge?" );
+    SMESH_MeshAlgos::PolySegment linkNodes;
+    gp_Ax1 planeNorm = segment->Ax1( segNode != segment->Node(0) );
+    double minDist[2] = { 1e100, 1e100 };
+    Segment::TNodeSet::const_iterator nIt = segment->myEndNodes.begin();
+    for ( ; nIt != segment->myEndNodes.end(); ++nIt )
+    {
+      SMESH_NodeXYZ n = *nIt;
+      double d = Abs( signedDist( n, planeNorm ));
+      double diff1 = minDist[0] - d, diff2 = minDist[1] - d;
+      int i;
+      if ( diff1 > 0 && diff2 > 0 )
+      {
+        i = ( diff1 < diff2 );
+      }
+      else if ( diff1 > 0 )
+      {
+        i = 0;
+      }
+      else if ( diff2 > 0 )
+      {
+        i = 1;
+      }
+      else
+      {
+        continue;
+      }
+      linkNodes.myXYZ[ i ] = n;
+      minDist        [ i ] = d;
+    }
+    // for ( int iSide = 0; iSide < 2; ++iSide )
+    // {
+    //   if ( segment->myCutEdges[ iSide ].empty() )
+    //     throw SALOME_Exception( "MakeSlot(): too short end edge?" );
+    //   SMESH_NodeXYZ n1 = segment->myCutEdges[ iSide ].front()._node1;
+    //   SMESH_NodeXYZ n2 = segment->myCutEdges[ iSide ].back ()._node2;
+    //   double d1 = Abs( signedDist( n1, planeNorm ));
+    //   double d2 = Abs( signedDist( n2, planeNorm ));
+    //   linkNodes.myXYZ  [ iSide ] = ( d1 < d2 ) ? n1 : n2;
+    //   linkNodes.myNode1[ iSide ] = linkNodes.myNode2[ iSide ] = 0;
+    // }
+    linkNodes.myVector = planeNorm.Direction() ^ (linkNodes.myXYZ[0] - linkNodes.myXYZ[1]);
+    linkNodes.myNode1[ 0 ] = linkNodes.myNode2[ 0 ] = 0;
+    linkNodes.myNode1[ 1 ] = linkNodes.myNode2[ 1 ] = 0;
+
+    // create segments connecting linkNodes
+    std::vector<const SMDS_MeshElement*> newSegments;
+    std::vector<const SMDS_MeshNode*>    newNodes;
+    SMESH_MeshAlgos::TListOfPolySegments polySegs(1, linkNodes);
+    SMESH_MeshAlgos::MakePolyLine( theMesh, polySegs, newSegments, newNodes,
+                                   /*group=*/0, faceSearcher.get() );
+    // cut faces by newSegments
+    intPoints.resize(2);
+    for ( size_t i = 0; i < newSegments.size(); ++i )
+    {
+      intPoints[0].myNode = edgeNodes[0] = newSegments[i]->GetNode(0);
+      intPoints[1].myNode = edgeNodes[1] = newSegments[i]->GetNode(1);
+
+      // find an underlying face
+      gp_XYZ                middle = 0.5 * ( intPoints[0].myNode + intPoints[1].myNode );
+      const SMDS_MeshElement* face = faceSearcher->FindClosestTo( middle, SMDSAbs_Face );
+
+      // find intersected edges of the face
+      int nbNodes = face->NbCornerNodes();
+      faceNodes.assign( face->begin_nodes(), face->end_nodes() );
+      faceNodes.resize( nbNodes + 1 );
+      faceNodes[ nbNodes ] = faceNodes[ 0 ];
+      for ( int iP = 0; iP < 2; ++iP )
+      {
+        intPoints[iP].myEdgeIndex = -1;
+        for ( int iN = 0; iN < nbNodes &&  intPoints[iP].myEdgeIndex < 0; ++iN )
+        {
+          SMDS_LinearEdge edge( faceNodes[iN], faceNodes[iN+1] );
+          if ( SMESH_MeshAlgos::GetDistance( &edge, intPoints[iP].myNode) < tol )
+            intPoints[iP].myEdgeIndex = iN;
+        }
+      }
+
+
+      // face cut
+      computeNormal( face, faceNormals );
+      meshIntersector.Cut( face,
+                           intPoints[0].myNode, intPoints[0].myEdgeIndex,
+                           intPoints[1].myNode, intPoints[1].myEdgeIndex );
+
+      Edge e = { intPoints[0].myNode.Node(), intPoints[1].myNode.Node(), 0 };
+      bndEdges.push_back( e );
+
+      // add cut points to an adjacent face at ends of poly-line
+      // if they fall onto face edges
+      if (( i == 0                       && intPoints[0].myEdgeIndex >= 0 ) ||
+          ( i == newSegments.size() - 1  && intPoints[1].myEdgeIndex >= 0 ))
+      {
+        for ( int iE = 0; iE < 2; ++iE ) // loop on ends of a new segment
+        {
+          if ( iE ? ( i != newSegments.size() - 1 ) : ( i != 0 ))
+            continue;
+          int iEdge = intPoints[ iE ].myEdgeIndex;
+          edgeNodes[0] = faceNodes[ iEdge ];
+          edgeNodes[1] = faceNodes[ iEdge+1 ];
+          theMesh->GetElementsByNodes( edgeNodes, faces, SMDSAbs_Face );
+          for ( size_t iF = 0; iF < faces.size(); ++iF )
+            if ( faces[iF] != face )
+            {
+              int iN1 = faces[iF]->GetNodeIndex( edgeNodes[0] );
+              int iN2 = faces[iF]->GetNodeIndex( edgeNodes[1] );
+              intPoints[ iE ].myEdgeIndex = Abs( iN1 - iN2 ) == 1 ? Min( iN1, iN2 ) : 2;
+              computeNormal( faces[iF], faceNormals );
+              meshIntersector.Cut( faces[iF],
+                                   intPoints[iE].myNode, intPoints[iE].myEdgeIndex,
+                                   intPoints[iE].myNode, intPoints[iE].myEdgeIndex );
+            }
+        }
+      }
+
+    } // loop on newSegments
+
+    polySegments.insert( polySegments.end(), newSegments.begin(), newSegments.end() );
+
+  } // loop on map of input segments
+
+  // actual mesh splitting
+  TElemIntPairVec new2OldFaces;
+  TNodeIntPairVec new2OldNodes;
+  meshIntersector.MakeNewFaces( new2OldFaces, new2OldNodes, /*sign=*/1, /*optimize=*/true );
+
+  // remove poly-line edges
+  for ( size_t i = 0; i < polySegments.size(); ++i )
+  {
+    edgeNodes[0] = polySegments[i]->GetNode(0);
+    edgeNodes[1] = polySegments[i]->GetNode(1);
+
+    theMesh->RemoveFreeElement( polySegments[i] );
+
+    if ( edgeNodes[0]->NbInverseElements() == 0 )
+      theMesh->RemoveNode( edgeNodes[0] );
+    if ( edgeNodes[1]->NbInverseElements() == 0 )
+      theMesh->RemoveNode( edgeNodes[1] );
+  }
+
+  return bndEdges;
+}
index 6652aea..b391aba 100644 (file)
 #include <Standard_Failure.hxx>
 #include <gp_Ax2.hxx>
 
+#include <boost/container/flat_set.hpp>
+
 using namespace SMESH_MeshAlgos;
 
+namespace
+{
+  struct Node // node of a triangle
+  {
+    size_t _triaIndex; // triangle index == index of the 1st triangle node in triangulation array
+    size_t _nodeIndex; // node index within triangle [0-2]
+
+    //! return node index within the node array
+    size_t Index() const { return  _triaIndex + _nodeIndex; }
+
+    //! return local 3-d index [0-2]
+    static size_t ThirdIndex( size_t i1, size_t i2 )
+    {
+      size_t i3 = ( i2 + 1 ) % 3;
+      if ( i3 == i1 )
+        i3 = ( i2 + 2 ) % 3;
+      return i3;
+    }
+    //! return 3-d node index within the node array
+    static size_t ThirdIndex( const Node& n1, const Node& n2 )
+    {
+      return n1._triaIndex + ThirdIndex( n1._nodeIndex, n2._nodeIndex );
+    }
+    bool operator<(const Node& other) const { return _triaIndex < other._triaIndex; }
+  };
+  typedef boost::container::flat_set< Node > TNodeSet;
+
+}
+
+struct Triangulate::Optimizer
+{
+  std::vector< TNodeSet > _nodeUsage; // inclusions of a node in triangles
+
+  //================================================================================
+  /*!
+   * \brief Optimize triangles by edge swapping
+   *  \param [inout] nodes - polygon triangulation, i.e. connectivity of all triangles to optimize
+   *  \param [in] points - coordinates of nodes of the input polygon
+   *  \param [in] nodeIndices - indices of triangulation nodes within the input polygon
+   */
+  //================================================================================
+
+  void optimize( std::vector< const SMDS_MeshNode*>& nodes,
+                 std::vector< PolyVertex > &         points,
+                 std::vector< size_t > &             nodeIndices)
+  {
+    // for each node of the polygon, remember triangles using it
+    _nodeUsage.resize( points.size() );
+    for ( size_t i = 0; i < points.size(); ++i ) // clear old data
+    {
+      _nodeUsage[ i ].clear();
+    }
+    for ( size_t i = 0, iTria = 0; i < nodeIndices.size(); ++iTria )
+    {
+      _nodeUsage[ nodeIndices[ i++ ]].insert({ iTria * 3, 0 });
+      _nodeUsage[ nodeIndices[ i++ ]].insert({ iTria * 3, 1 });
+      _nodeUsage[ nodeIndices[ i++ ]].insert({ iTria * 3, 2 });
+    }
+
+    // optimization
+    for ( size_t iTria = 0; iTria < nodeIndices.size(); iTria += 3 )
+    {
+      double badness1 = computeBadness( nodeIndices[ iTria + 0 ],
+                                        nodeIndices[ iTria + 1 ],
+                                        nodeIndices[ iTria + 2 ],
+                                        points );
+      for ( size_t i = 0; i < 3; ++i ) // loop on triangle edges to find a neighbor triangle
+      {
+        size_t i1 = iTria + i; // node index in nodeIndices
+        size_t i2 = iTria + ( i + 1 ) % 3;
+        size_t ind1 = nodeIndices[ i1 ]; // node index in points
+        size_t ind2 = nodeIndices[ i2 ];
+        TNodeSet & usage1 = _nodeUsage[ ind1 ]; // triangles using a node
+        TNodeSet & usage2 = _nodeUsage[ ind2 ];
+        if ( usage1.size() < 2 ||
+             usage2.size() < 2 )
+          continue;
+
+        // look for another triangle using two nodes
+        TNodeSet::iterator usIt1 = usage1.begin();
+        for ( ; usIt1 != usage1.end(); ++usIt1 )
+        {
+          if ( usIt1->_triaIndex == iTria )
+            continue; // current triangle
+          TNodeSet::iterator usIt2 = usage2.find( *usIt1 );
+          if ( usIt2 == usage2.end() )
+            continue; // no common _triaIndex in two usages
+
+          size_t i3 = iTria + ( i + 2 ) % 3;
+          size_t i4 = Node::ThirdIndex( *usIt1, *usIt2 ); // 4th node of quadrangle
+          size_t ind3 = nodeIndices[ i3 ];
+          size_t ind4 = nodeIndices[ i4 ];
+
+          double badness2 = computeBadness( ind2, ind1, ind4, points );
+          double badness3 = computeBadness( ind1, ind4, ind3, points, /*checkArea=*/true );
+          double badness4 = computeBadness( ind2, ind3, ind4, points, /*checkArea=*/true );
+
+          if ( Max( badness1, badness2 ) < Max( badness3, badness4 ))
+            continue;
+
+          // swap edge by modifying nodeIndices
+
+          nodeIndices[ i2 ] = ind4;
+          _nodeUsage[ ind2 ].erase ({ iTria, i2 - iTria });
+          _nodeUsage[ ind4 ].insert({ iTria, i2 - iTria });
+
+          i1 = usIt1->Index();
+          nodeIndices[ i1 ] = ind3;
+          _nodeUsage[ ind1 ].erase ( *usIt1 );
+          _nodeUsage[ ind3 ].insert( *usIt1 );
+
+          --i; // to re-check a current edge
+          badness1 = badness3;
+          break;
+        }
+      }
+    }
+
+    // update nodes by updated nodeIndices
+    for ( size_t i = 0; i < nodeIndices.size(); ++i )
+      nodes[ i ] = points[ nodeIndices[ i ]]._nxyz.Node();
+
+    return;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Return 1./area. Initially: max cos^2 of triangle angles
+   */
+  //================================================================================
+
+  double computeBadness( size_t i1, size_t i2, size_t i3,
+                         std::vector< PolyVertex > & points,
+                         bool                        checkArea = false )
+  {
+    //if ( checkArea )
+    {
+      points[ i2 ]._prev = & points[ i1 ];
+      points[ i2 ]._next = & points[ i3 ];
+      double a = points[ i2 ].TriaArea();
+      if ( a < 0 )
+        return std::numeric_limits<double>::max();
+      return 1. / a;
+
+      if ( points[ i2 ].TriaArea() < 0 )
+        return 2;
+    }
+    const gp_XY & p1 = points[ i1 ]._xy;
+    const gp_XY & p2 = points[ i2 ]._xy;
+    const gp_XY & p3 = points[ i3 ]._xy;
+    gp_XY vec[3] = { p2 - p1,
+                     p3 - p2,
+                     p1 - p3 };
+    double len[3] = { vec[0].SquareModulus(),
+                      vec[1].SquareModulus(),
+                      vec[2].SquareModulus() };
+    if ( len[0] < gp::Resolution() ||
+         len[1] < gp::Resolution() ||
+         len[2] < gp::Resolution() )
+      return 2;
+
+    double maxCos2 = 0;
+    for ( int i = 0; i < 3; ++i )
+    {
+      int i2 = ( i+1 ) % 3;
+      double dot = -vec[ i ] * vec[ i2 ];
+      if ( dot > 0 )
+        maxCos2 = Max( maxCos2, dot * dot / len[ i ] / len[ i2 ] );
+    }
+    return maxCos2;
+  }
+};
+
 //================================================================================
 /*!
  * \brief Initialization
@@ -40,11 +215,13 @@ using namespace SMESH_MeshAlgos;
 //================================================================================
 
 void Triangulate::PolyVertex::SetNodeAndNext( const SMDS_MeshNode* n,
-                                              PolyVertex&          v )
+                                              PolyVertex&          v,
+                                              size_t               index )
 {
   _nxyz.Set( n );
   _next = &v;
   v._prev = this;
+  _index = index;
 }
 //================================================================================
 /*!
@@ -65,11 +242,15 @@ Triangulate::PolyVertex* Triangulate::PolyVertex::Delete()
  */
 //================================================================================
 
-void Triangulate::PolyVertex::GetTriaNodes( const SMDS_MeshNode** nodes) const
+  void Triangulate::PolyVertex::GetTriaNodes( const SMDS_MeshNode** nodes,
+                                              size_t*               nodeIndices) const
 {
   nodes[0] = _prev->_nxyz._node;
   nodes[1] =  this->_nxyz._node;
   nodes[2] = _next->_nxyz._node;
+  nodeIndices[0] = _prev->_index;
+  nodeIndices[1] =  this->_index;
+  nodeIndices[2] = _next->_index;
 }
 
 //================================================================================
@@ -112,7 +293,7 @@ bool Triangulate::PolyVertex::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;
+  const double tol = -1e-7;
   return (( p ^ t ) >= tol &&
           ( t ^ n ) >= tol &&
           ( n ^ p ) >= tol );
@@ -128,13 +309,13 @@ bool Triangulate::PolyVertex::IsInsideTria( const PolyVertex* v )
 //================================================================================
 
 bool Triangulate::triangulate( std::vector< const SMDS_MeshNode*>& nodes,
-                               const size_t                        nbNodes )
+                               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] );
+    _pv[i-1].SetNodeAndNext( nodes[i-1], _pv[i], i-1 );
+  _pv[ nbNodes-1 ].SetNodeAndNext( nodes[ nbNodes-1 ], _pv[0], nbNodes-1 );
 
   // get a polygon normal
   gp_XYZ normal(0,0,0), p0,v01,v02;
@@ -163,7 +344,8 @@ bool Triangulate::triangulate( std::vector< const SMDS_MeshNode*>& nodes,
 
   // in a loop, find triangles with positive area and having no vertices inside
   int iN = 0, nbTria = nbNodes - 2;
-  nodes.reserve( nbTria * 3 );
+  nodes.resize( nbTria * 3 );
+  _nodeIndex.resize( nbTria * 3 );
   const double minArea = 1e-6;
   PolyVertex* v = &_pv[0], *vi;
   int nbVertices = nbNodes, nbBadTria = 0, isGoodTria;
@@ -182,13 +364,15 @@ bool Triangulate::triangulate( std::vector< const SMDS_MeshNode*>& nodes,
     }
     if ( isGoodTria )
     {
-      v->GetTriaNodes( &nodes[ iN ] );
+      v->GetTriaNodes( &nodes[ iN ], &_nodeIndex[ iN ] );
       iN += 3;
       v = v->Delete();
       if ( --nbVertices == 3 )
       {
         // last triangle remains
-        v->GetTriaNodes( &nodes[ iN ] );
+        v->GetTriaNodes( &nodes[ iN ], &_nodeIndex[ iN ] );
+        if ( _optimizer )
+          _optimizer->optimize( nodes, _pv, _nodeIndex );
         return true;
       }
       nbBadTria = 0;
@@ -207,13 +391,13 @@ bool Triangulate::triangulate( std::vector< const SMDS_MeshNode*>& nodes,
     isGoodTria = v->TriaArea() > minArea;
     if ( isGoodTria )
     {
-      v->GetTriaNodes( &nodes[ iN ] );
+      v->GetTriaNodes( &nodes[ iN ], &_nodeIndex[ iN ] );
       iN += 3;
       v = v->Delete();
       if ( --nbVertices == 3 )
       {
         // last triangle remains
-        v->GetTriaNodes( &nodes[ iN ] );
+        v->GetTriaNodes( &nodes[ iN ], &_nodeIndex[ iN ] );
         return true;
       }
       nbBadTria = 0;
@@ -228,7 +412,7 @@ bool Triangulate::triangulate( std::vector< const SMDS_MeshNode*>& nodes,
   // add all the rest triangles
   while ( nbVertices >= 3 )
   {
-    v->GetTriaNodes( &nodes[ iN ] );
+    v->GetTriaNodes( &nodes[ iN ], &_nodeIndex[ iN ] );
     iN += 3;
     v = v->Delete();
     --nbVertices;
@@ -240,6 +424,30 @@ bool Triangulate::triangulate( std::vector< const SMDS_MeshNode*>& nodes,
 
 //================================================================================
 /*!
+ * \brief Constructor
+ */
+//================================================================================
+
+Triangulate::Triangulate( bool optimize ): _optimizer(0)
+{
+  if ( optimize )
+    _optimizer = new Optimizer;
+}
+
+//================================================================================
+/*!
+ * \brief Destructor
+ */
+//================================================================================
+
+Triangulate::~Triangulate()
+{
+  delete _optimizer;
+  _optimizer = 0;
+}
+
+//================================================================================
+/*!
  * \brief Return nb triangles in a decomposed mesh face
  *  \retval int - number of triangles
  */
diff --git a/src/SMESHUtils/SMESH_Triangulate.hxx b/src/SMESHUtils/SMESH_Triangulate.hxx
deleted file mode 100644 (file)
index 8734c4b..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-// 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.hxx
-// Created   : Thu Jan 18 17:51:34 2018
-// Author    : Edward AGAPOV (eap)
-
-
-#ifndef __SMESH_Triangulate_HXX__
-#define __SMESH_Triangulate_HXX__
-
-/*!
- * \brief Divide a mesh face into triangles
- */
-class SMESHUtils_EXPORT SMESH_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 );
-
-  struct PolyVertex;
-  std::vector< PolyVertex > _pv;
-};
-
-
-#endif
index 9fbc5b0..f523fdd 100644 (file)
@@ -185,6 +185,21 @@ struct SMESH_TNodeXYZ : public gp_XYZ
 };
 typedef SMESH_TNodeXYZ SMESH_NodeXYZ;
 
+// --------------------------------------------------------------------------------
+// SMESH_Hasher provide methods needed to put mesh data to NCollection maps
+
+struct SMESH_Hasher
+{
+  static Standard_Integer HashCode(const SMDS_MeshElement* e, const Standard_Integer upper)
+  {
+    return ::HashCode( e->GetID(), upper );
+  }
+  static Standard_Boolean IsEqual( const SMDS_MeshElement* e1, const SMDS_MeshElement* e2 )
+  {
+    return ( e1 == e2 );
+  }
+};
+
 //--------------------------------------------------
 /*!
  * \brief Data of a node generated on FACE boundary
index 435080b..7a9b20b 100644 (file)
@@ -2577,6 +2577,36 @@ GetElementsId( SMESH_Mesh_ptr theMesh )
   return anArray._retn();
 }
 
+SMESH::long_array*
+Filter_i::
+GetElementsIdFromParts( const ListOfIDSources& theParts )
+{
+  SMESH::long_array_var array = new SMESH::long_array;
+  if ( theParts.length() > 0 && myPredicate )
+  {
+    SMESH_Mesh_ptr mesh = theParts[0]->GetMesh();
+    mesh->Load();
+    const SMDS_Mesh* meshDS = MeshPtr2SMDSMesh( mesh );
+    Controls::Filter::TIdSequence totalSequence;
+    for ( CORBA::ULong i = 0; i < theParts.length(); ++i )
+    {
+      if ( SMESH::Filter_i* filter = SMESH::DownCast<SMESH::Filter_i*>( theParts[i] ))
+        filter->SetMesh( mesh );
+      SMDS_ElemIteratorPtr iter = SMESH_Mesh_i::GetElements( theParts[i], GetElementType() );
+      if ( iter && meshDS )
+      {
+        Controls::Filter::TIdSequence sequence;
+        Controls::Filter::GetElementsId( meshDS, myPredicate->GetPredicate(), sequence, iter );
+        totalSequence.insert( totalSequence.end(), sequence.begin(), sequence.end() );
+      }
+    }
+    array->length( totalSequence.size() );
+    for ( size_t i = 0; i < totalSequence.size(); ++i )
+      array[ i ] = totalSequence[ i ];
+  }
+  return array._retn();
+}
+
 //=============================================================================
 /*!
  * \brief Returns number of mesh elements per each \a EntityType
index 3643bd7..9d976ef 100644 (file)
@@ -996,7 +996,11 @@ namespace SMESH
     GetElementsId( SMESH_Mesh_ptr );
 
     virtual
-    ElementType      
+    long_array*
+    GetElementsIdFromParts( const ListOfIDSources& theParts );
+
+    virtual
+    ElementType
     GetElementType();
     
     virtual
index 86f9daa..2e902f5 100644 (file)
@@ -2431,14 +2431,16 @@ SMESH::SMESH_Mesh_ptr
 SMESH_Gen_i::Concatenate(const SMESH::ListOfIDSources& theMeshesArray,
                          CORBA::Boolean                theUniteIdenticalGroups,
                          CORBA::Boolean                theMergeNodesAndElements,
-                         CORBA::Double                 theMergeTolerance)
+                         CORBA::Double                 theMergeTolerance,
+                         SMESH::SMESH_Mesh_ptr         theMeshToAppendTo)
   throw ( SALOME::SALOME_Exception )
 {
   return ConcatenateCommon(theMeshesArray,
                            theUniteIdenticalGroups,
                            theMergeNodesAndElements,
                            theMergeTolerance,
-                           false);
+                           false,
+                           theMeshToAppendTo);
 }
 
 //================================================================================
@@ -2454,14 +2456,16 @@ SMESH::SMESH_Mesh_ptr
 SMESH_Gen_i::ConcatenateWithGroups(const SMESH::ListOfIDSources& theMeshesArray,
                                    CORBA::Boolean                theUniteIdenticalGroups,
                                    CORBA::Boolean                theMergeNodesAndElements,
-                                   CORBA::Double                 theMergeTolerance)
+                                   CORBA::Double                 theMergeTolerance,
+                                   SMESH::SMESH_Mesh_ptr         theMeshToAppendTo)
   throw ( SALOME::SALOME_Exception )
 {
   return ConcatenateCommon(theMeshesArray,
                            theUniteIdenticalGroups,
                            theMergeNodesAndElements,
                            theMergeTolerance,
-                           true);
+                           true,
+                           theMeshToAppendTo);
 }
 
 //================================================================================
@@ -2477,16 +2481,22 @@ SMESH_Gen_i::ConcatenateCommon(const SMESH::ListOfIDSources& theMeshesArray,
                                CORBA::Boolean                theUniteIdenticalGroups,
                                CORBA::Boolean                theMergeNodesAndElements,
                                CORBA::Double                 theMergeTolerance,
-                               CORBA::Boolean                theCommonGroups)
+                               CORBA::Boolean                theCommonGroups,
+                               SMESH::SMESH_Mesh_ptr         theMeshToAppendTo)
   throw ( SALOME::SALOME_Exception )
 {
   std::unique_ptr< TPythonDump > pPythonDump( new TPythonDump );
   TPythonDump& pythonDump = *pPythonDump; // prevent dump of called methods
 
-  // create mesh
-  SMESH::SMESH_Mesh_var newMesh = CreateEmptyMesh();
-  SMESH_Mesh_i*         newImpl = SMESH::DownCast<SMESH_Mesh_i*>( newMesh );
+  // create mesh if theMeshToAppendTo not provided
+  SMESH::SMESH_Mesh_var newMesh;
+  if ( CORBA::is_nil( theMeshToAppendTo ))
+    newMesh = CreateEmptyMesh();
+  else
+    newMesh = SMESH::SMESH_Mesh::_duplicate( theMeshToAppendTo );
+  SMESH_Mesh_i* newImpl = SMESH::DownCast<SMESH_Mesh_i*>( newMesh );
   if ( !newImpl ) return newMesh._retn();
+  newImpl->Load();
 
   ::SMESH_Mesh&   locMesh = newImpl->GetImpl();
   SMESHDS_Mesh* newMeshDS = locMesh.GetMeshDS();
@@ -2507,6 +2517,8 @@ SMESH_Gen_i::ConcatenateCommon(const SMESH::ListOfIDSources& theMeshesArray,
     SMESH::SMESH_Mesh_var initMesh = theMeshesArray[i]->GetMesh();
     SMESH_Mesh_i*         initImpl = SMESH::DownCast<SMESH_Mesh_i*>( initMesh );
     if ( !initImpl ) continue;
+    if ( initMesh->_is_equivalent( theMeshToAppendTo ))
+      continue;
     initImpl->Load();
 
     // assure that IDs increments by one during iteration
@@ -2693,11 +2705,12 @@ SMESH_Gen_i::ConcatenateCommon(const SMESH::ListOfIDSources& theMeshesArray,
 
   // Update Python script
   pythonDump << newMesh << " = " << this
-             << "." << ( theCommonGroups ? "ConcatenateWithGroups" : "Concatenate" ) << "("
+             << "." << ( theCommonGroups ? "ConcatenateWithGroups" : "Concatenate" ) << "( "
              << theMeshesArray << ", "
              << theUniteIdenticalGroups << ", "
              << theMergeNodesAndElements << ", "
-             << TVar( theMergeTolerance ) << ")";
+             << TVar( theMergeTolerance ) << ", "
+             << theMeshToAppendTo << " )";
 
   pPythonDump.reset(); // enable python dump from GetGroups()
 
@@ -4011,7 +4024,7 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent,
                 CORBA::String_var objStr = GetORB()->object_to_string( grImpl->_this() );
                 int anId = myStudyContext->findId( string( objStr.in() ) );
                 char grpName[ 30 ];
-                sprintf( grpName, "Group %d", anId );
+                sprintf( grpName, "Group %d %d", anId, grImpl->GetLocalID() );
                 SMESHDS_GroupBase* aGrpBaseDS = grImpl->GetGroupDS();
                 aGrpBaseDS->SetStoreName( grpName );
               }
@@ -5334,7 +5347,7 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
       // get mesh old id
       CORBA::String_var iorString = GetORB()->object_to_string( myNewMeshImpl->_this() );
       int newId = myStudyContext->findId( iorString.in() );
-      int id = myStudyContext->getOldId( newId );
+      int meshOldId = myStudyContext->getOldId( newId );
 
       // try to find mesh data dataset
       if ( aTopGroup->ExistInternalObject( "Has data" ) ) {
@@ -5346,10 +5359,6 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
         aDataset->ReadFromDisk( strHasData );
         aDataset->CloseOnDisk();
         if ( strcmp( strHasData, "1") == 0 ) {
-          // read mesh data from MED file
-          // myReader.SetMesh( mySMESHDSMesh );
-          // myReader.SetMeshId( id );
-          // myReader.Perform();
           hasData = true;
         }
         delete [] strHasData;
@@ -5616,9 +5625,13 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
             // check if it is a group
             if ( name_dataset.substr( 0, 5 ) == "Group" ) {
               // --> get group id
-              int subid = atoi( name_dataset.substr( 5 ).c_str() );
+              char * endptr;
+              int subid = strtol( name_dataset.data() + 5, &endptr, 10 );
               if ( subid <= 0 )
                 continue;
+              int groupID = -1; // group local ID (also persistent)
+              if ( *endptr )
+                groupID = atoi( endptr + 1 );
               aDataset = new HDFdataset( name_dataset.c_str(), aGroup );
               aDataset->OpenOnDisk();
 
@@ -5675,7 +5688,7 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
               // Create group servant
               SMESH::ElementType type = (SMESH::ElementType)(ii - GetNodeGroupsTag() + 1);
               SMESH::SMESH_GroupBase_var aNewGroup = SMESH::SMESH_GroupBase::_duplicate
-                ( myNewMeshImpl->createGroup( type, nameFromFile, aShape, predicate ) );
+                ( myNewMeshImpl->createGroup( type, nameFromFile, groupID, aShape, predicate ) );
               delete [] nameFromFile;
               // Obtain a SMESHDS_Group object
               if ( aNewGroup->_is_nil() )
@@ -5724,10 +5737,10 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
       } // reading GROUPs
 
       // instead of reading mesh data, we read only brief information of all
-      // objects: mesh, groups, sub-meshes (issue 0021208 )
+      // objects: mesh, groups, sub-meshes (issue 0021208)
       if ( hasData )
       {
-        SMESH_PreMeshInfo::LoadFromFile( myNewMeshImpl, id,
+        SMESH_PreMeshInfo::LoadFromFile( myNewMeshImpl, meshOldId,
                                          meshfile.ToCString(), filename.ToCString(),
                                          !isMultiFile );
       }
index 1209ec7..f713e84 100644 (file)
@@ -307,7 +307,7 @@ public:
   // Returns errors of hypotheses definition
   SMESH::algo_error_array* GetAlgoState( SMESH::SMESH_Mesh_ptr theMesh,
                                          GEOM::GEOM_Object_ptr theSubObject )
-      throw ( SALOME::SALOME_Exception );
+    throw ( SALOME::SALOME_Exception );
 
   // Return mesh elements preventing computation of a subshape
   SMESH::MeshPreviewStruct* GetBadInputElements( SMESH::SMESH_Mesh_ptr theMesh,
@@ -341,14 +341,16 @@ public:
                                           CORBA::Boolean                uniteIdenticalGroups,
                                           CORBA::Boolean                mergeNodesAndElements,
                                           CORBA::Double                 mergeTolerance,
-                                          CORBA::Boolean                commonGroups)
+                                          CORBA::Boolean                commonGroups,
+                                          SMESH::SMESH_Mesh_ptr         meshToAppendTo)
     throw ( SALOME::SALOME_Exception );
 
   // Concatenate the given meshes into one mesh
   SMESH::SMESH_Mesh_ptr Concatenate(const SMESH::ListOfIDSources& meshesArray,
                                     CORBA::Boolean                uniteIdenticalGroups,
                                     CORBA::Boolean                mergeNodesAndElements,
-                                    CORBA::Double                 mergeTolerance)
+                                    CORBA::Double                 mergeTolerance,
+                                    SMESH::SMESH_Mesh_ptr         meshToAppendTo)
     throw ( SALOME::SALOME_Exception );
 
   // Concatenate the given meshes into one mesh
@@ -356,7 +358,8 @@ public:
   SMESH::SMESH_Mesh_ptr ConcatenateWithGroups(const SMESH::ListOfIDSources& meshesArray,
                                               CORBA::Boolean                uniteIdenticalGroups,
                                               CORBA::Boolean                mergeNodesAndElements,
-                                              CORBA::Double                 mergeTolerance)
+                                              CORBA::Double                 mergeTolerance,
+                                              SMESH::SMESH_Mesh_ptr         meshToAppendTo)
     throw ( SALOME::SALOME_Exception );
 
   // Get version of MED format being used.
index e6e5493..4d57398 100644 (file)
@@ -120,6 +120,33 @@ static bool getNodeNodeDistance (SMESH::Measure& theMeasure,
   return true;
 }
 
+static bool getNodeElemDistance (SMESH::Measure&        theMeasure,
+                                 const SMDS_MeshNode*   theNode,
+                                 SMESH_ElementSearcher* theElemSearcher)
+{
+  if ( !theNode || !theElemSearcher )
+    return false;
+
+  const SMDS_MeshElement* closestElement = 0;
+  gp_Pnt        point = SMESH_NodeXYZ( theNode );
+  gp_Pnt closestPoint = theElemSearcher->Project( point, SMDSAbs_All, &closestElement );
+
+  if ( closestElement )
+  {
+    theMeasure.value = point.Distance( closestPoint );
+    theMeasure.node1 = theNode->GetID();
+    theMeasure.elem2 = closestElement->GetID();
+    theMeasure.maxX  = closestPoint.X();
+    theMeasure.maxY  = closestPoint.Y();
+    theMeasure.maxZ  = closestPoint.Z();
+    theMeasure.minX  = closestPoint.X() - point.X();
+    theMeasure.minY  = closestPoint.Y() - point.Y();
+    theMeasure.minZ  = closestPoint.Z() - point.Z();
+  }
+
+  return closestElement;
+}
+
 static SMESHDS_Mesh* getMesh(SMESH::SMESH_IDSource_ptr theSource)
 {
   if (!CORBA::is_nil( theSource ))
@@ -183,7 +210,6 @@ SMESH::Measure Measurements_i::MinDistance
 
   SMESH::long_array_var aElementsId1 = theSource1->GetIDs();
   SMESH::long_array_var aElementsId2;
-  if ( !isOrigin ) aElementsId2 = theSource2->GetIDs();
 
   // compute distance between two entities
   /* NOTE: currently only node-to-node case is implemented
@@ -196,10 +222,25 @@ SMESH::Measure Measurements_i::MinDistance
     // node - node
     const SMESHDS_Mesh* aMesh1 = getMesh( theSource1 );
     const SMESHDS_Mesh* aMesh2 = isOrigin ? 0 : getMesh( theSource2 );
+    if ( !isOrigin ) aElementsId2 = theSource2->GetIDs();
     const SMDS_MeshNode* theNode1 = aMesh1 ? aMesh1->FindNode( aElementsId1[0] ) : 0;
     const SMDS_MeshNode* theNode2 = aMesh2 ? aMesh2->FindNode( aElementsId2[0] ) : 0;
     getNodeNodeDistance( aMeasure, theNode1, theNode2 );
   }
+  if (isNode1 && !isNode2 && aElementsId1->length() == 1 )
+  {
+    // node - elements
+    SMESHDS_Mesh* aMesh1 = getMesh( theSource1 );
+    SMESHDS_Mesh* aMesh2 = getMesh( theSource2 );
+    if ( aMesh1 && aMesh2 )
+    {
+      const SMDS_MeshNode* aNode    = aMesh1->FindNode( aElementsId1[0] );
+      SMDS_ElemIteratorPtr anElemIt = SMESH_Mesh_i::GetElements( theSource2, SMESH::ALL );
+      std::unique_ptr< SMESH_ElementSearcher > aSearcher
+        ( SMESH_MeshAlgos::GetElementSearcher( *aMesh2, anElemIt ));
+      getNodeElemDistance( aMeasure, aNode, aSearcher.get() );
+    }
+  }
   else
   {
     // NOT_IMPLEMENTED
index 2e8fda8..f1e40ec 100644 (file)
@@ -383,6 +383,8 @@ namespace MeshEditor_I {
 
   string getPartIOR( SMESH::SMESH_IDSource_ptr theMeshPart, SMESH::ElementType type = SMESH::ALL )
   {
+    if ( SMESH::DownCast<SMESH_Mesh_i*>( theMeshPart ))
+      return "";
     string partIOR = SMESH_Gen_i::GetORB()->object_to_string( theMeshPart );
     if ( SMESH_Group_i* group_i = SMESH::DownCast<SMESH_Group_i*>( theMeshPart ))
       // take into account passible group modification
@@ -2066,9 +2068,10 @@ void SMESH_MeshEditor_i::SplitVolumesIntoTetra (SMESH::SMESH_IDSource_ptr elems,
 
   ::SMESH_MeshEditor::TFacetOfElem elemSet;
   const int noneFacet = -1;
-  SMDS_ElemIteratorPtr volIt = myMesh_i->GetElements( elems, SMESH::VOLUME );
-  while( volIt->more() )
-    elemSet.insert( elemSet.end(), make_pair( volIt->next(), noneFacet ));
+  prepareIdSource( elems );
+  if ( SMDS_ElemIteratorPtr volIt = myMesh_i->GetElements( elems, SMESH::VOLUME ))
+    while ( volIt->more() )
+      elemSet.insert( elemSet.end(), make_pair( volIt->next(), noneFacet ));
 
   getEditor().SplitVolumes( elemSet, int( methodFlags ));
   declareMeshModified( /*isReComputeSafe=*/true ); // it does not influence Compute()
@@ -2109,6 +2112,7 @@ void SMESH_MeshEditor_i::SplitHexahedraIntoPrisms( SMESH::SMESH_IDSource_ptr  el
                             facetToSplitNormal.PS.y,
                             facetToSplitNormal.PS.z ));
   TIDSortedElemSet elemSet;
+  prepareIdSource( elems );
   SMESH::long_array_var anElementsId = elems->GetIDs();
   SMDS_MeshElement::GeomFilter filter( SMDSGeom_HEXA );
   arrayToSet( anElementsId, getMeshDS(), elemSet, SMDSAbs_Volume, &filter );
@@ -2423,8 +2427,8 @@ SMESH_MeshEditor_i::RotationSweepObjects(const SMESH::ListOfIDSources & theNodes
 
   TIDSortedElemSet elemsNodes[2];
   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
-    SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
-    while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
+    if ( SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE ))
+      while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
   }
   for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
     idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
@@ -2621,8 +2625,8 @@ SMESH_MeshEditor_i::ExtrusionSweepObjects(const SMESH::ListOfIDSources & theNode
 
   TIDSortedElemSet elemsNodes[2];
   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
-    SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
-    while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
+    if ( SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE ))
+      while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
   }
   for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
     idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
@@ -2900,8 +2904,8 @@ SMESH_MeshEditor_i::ExtrusionAlongPathObjects(const SMESH::ListOfIDSources & the
 
   TIDSortedElemSet elemsNodes[2];
   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
-    SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
-    while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
+    if ( SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE ))
+      while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
   }
   for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
     idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
@@ -4180,6 +4184,7 @@ FindCoincidentNodesOnPart(SMESH::SMESH_IDSource_ptr      theObject,
   initData();
 
   TIDSortedNodeSet nodes;
+  prepareIdSource( theObject );
   idSourceToNodeSet( theObject, getMeshDS(), nodes );
 
   findCoincidentNodes( nodes, Tolerance, GroupsOfNodes, SeparateCornersAndMedium );
@@ -4211,14 +4216,15 @@ FindCoincidentNodesOnPartBut(SMESH::SMESH_IDSource_ptr      theObject,
   initData();
 
   TIDSortedNodeSet nodes;
+  prepareIdSource( theObject );
   idSourceToNodeSet( theObject, getMeshDS(), nodes );
 
   for ( CORBA::ULong i = 0; i < theExceptSubMeshOrGroups.length(); ++i )
   {
-    SMDS_ElemIteratorPtr nodeIt = myMesh_i->GetElements( theExceptSubMeshOrGroups[i],
-                                                         SMESH::NODE );
-    while ( nodeIt->more() )
-      nodes.erase( cast2Node( nodeIt->next() ));
+    if ( SMDS_ElemIteratorPtr nodeIt = myMesh_i->GetElements( theExceptSubMeshOrGroups[i],
+                                                              SMESH::NODE ))
+      while ( nodeIt->more() )
+        nodes.erase( cast2Node( nodeIt->next() ));
   }
   findCoincidentNodes( nodes, theTolerance, theGroupsOfNodes, theSeparateCornersAndMedium );
 
@@ -4253,9 +4259,9 @@ void SMESH_MeshEditor_i::MergeNodes (const SMESH::array_of_long_array& GroupsOfN
   for ( CORBA::ULong i = 0; i < NodesToKeep.length(); ++i )
   {
     prepareIdSource( NodesToKeep[i] );
-    SMDS_ElemIteratorPtr nodeIt = myMesh_i->GetElements( NodesToKeep[i], SMESH::NODE );
-    while ( nodeIt->more() )
-      setOfNodesToKeep.insert( setOfNodesToKeep.end(), cast2Node( nodeIt->next() ));
+    if ( SMDS_ElemIteratorPtr nodeIt = myMesh_i->GetElements( NodesToKeep[i], SMESH::NODE ))
+      while ( nodeIt->more() )
+        setOfNodesToKeep.insert( setOfNodesToKeep.end(), cast2Node( nodeIt->next() ));
   }
 
   ::SMESH_MeshEditor::TListOfListOfNodes aListOfListOfNodes;
@@ -4304,7 +4310,7 @@ void SMESH_MeshEditor_i::FindEqualElements(SMESH::SMESH_IDSource_ptr      theObj
   initData();
 
   SMESH::SMESH_GroupBase_var group = SMESH::SMESH_GroupBase::_narrow(theObject);
-  if ( !(!group->_is_nil() && group->GetType() == SMESH::NODE) )
+  if ( !( !group->_is_nil() && group->GetType() == SMESH::NODE ))
   {
     TIDSortedElemSet elems;
     idSourceToSet( theObject, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true);
@@ -4606,6 +4612,7 @@ SMESH_MeshEditor_i::FindAmongElementsByPoint(SMESH::SMESH_IDSource_ptr elementID
   SMESH_TRY;
   SMESH::long_array_var res = new SMESH::long_array;
 
+  prepareIdSource( elementIDs );
   if ( type != SMESH::NODE )
   {
     SMESH::array_of_ElementType_var types = elementIDs->GetTypes();
@@ -4614,6 +4621,16 @@ SMESH_MeshEditor_i::FindAmongElementsByPoint(SMESH::SMESH_IDSource_ptr elementID
          type != types[0] ) // but search of elements of dim > 0
       return res._retn();
   }
+
+  SMESH::SMESH_Mesh_var mesh = elementIDs->GetMesh();
+  SMESH_Mesh_i*       mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
+  if ( mesh_i != myMesh_i )
+  {
+    SMESH::SMESH_MeshEditor_var editor=
+      myIsPreviewMode ? mesh_i->GetMeshEditPreviewer() : mesh_i->GetMeshEditor();
+    return editor->FindAmongElementsByPoint( elementIDs, x,y,z, type );
+  }
+
   if ( SMESH::DownCast<SMESH_Mesh_i*>( elementIDs )) // elementIDs is the whole mesh 
     return FindElementsByPoint( x,y,z, type );
 
@@ -4623,18 +4640,15 @@ SMESH_MeshEditor_i::FindAmongElementsByPoint(SMESH::SMESH_IDSource_ptr elementID
   if ( !theElementSearcher )
   {
     // create a searcher from elementIDs
-    SMESH::SMESH_Mesh_var mesh = elementIDs->GetMesh();
-    SMESHDS_Mesh* meshDS = SMESH::DownCast<SMESH_Mesh_i*>( mesh )->GetImpl().GetMeshDS();
-
-    if ( !idSourceToSet( elementIDs, meshDS, elements,
-                         ( type == SMESH::NODE ? SMDSAbs_All : (SMDSAbs_ElementType) type ),
-                         /*emptyIfIsMesh=*/true))
-      return res._retn();
-
-    typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator > TIter;
-    SMDS_ElemIteratorPtr elemsIt( new TIter( elements.begin(), elements.end() ));
-
-    theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), elemsIt );
+    SMDS_ElemIteratorPtr elemIt;
+    if ( ! SMESH::DownCast<SMESH_Mesh_i*>( elementIDs ))
+    {
+      //prepareIdSource( elementIDs );
+      elemIt = myMesh_i->GetElements( elementIDs, type );
+      if ( !elemIt )
+        return res._retn();
+    }
+    theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), elemIt );
   }
 
   vector< const SMDS_MeshElement* > foundElems;
@@ -4663,8 +4677,8 @@ SMESH_MeshEditor_i::FindAmongElementsByPoint(SMESH::SMESH_IDSource_ptr elementID
 CORBA::Long SMESH_MeshEditor_i::ProjectPoint(CORBA::Double             x,
                                              CORBA::Double             y,
                                              CORBA::Double             z,
-                                             SMESH::SMESH_IDSource_ptr meshObject,
                                              SMESH::ElementType        type,
+                                             SMESH::SMESH_IDSource_ptr meshObject,
                                              SMESH::double_array_out   projecton)
   throw (SALOME::SALOME_Exception)
 {
@@ -4679,19 +4693,23 @@ CORBA::Long SMESH_MeshEditor_i::ProjectPoint(CORBA::Double             x,
   {
     SMESH::SMESH_MeshEditor_var editor=
       myIsPreviewMode ? mesh_i->GetMeshEditPreviewer() : mesh_i->GetMeshEditor();
-    return editor->ProjectPoint( x,y,z, meshObject, type, projecton );
+    return editor->ProjectPoint( x,y,z, type, meshObject, projecton );
   }
 
 
-  theSearchersDeleter.Set( myMesh, getPartIOR( meshObject ));
+  theSearchersDeleter.Set( myMesh, getPartIOR( meshObject, type ));
   if ( !theElementSearcher )
   {
     // create a searcher from meshObject
 
     SMDS_ElemIteratorPtr elemIt;
     if ( ! SMESH::DownCast<SMESH_Mesh_i*>( meshObject ))
+    {
+      prepareIdSource( meshObject );
       elemIt = myMesh_i->GetElements( meshObject, type );
-
+      if ( !elemIt )
+        return -1;
+    }
     theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), elemIt );
   }
 
@@ -4780,6 +4798,59 @@ CORBA::Boolean SMESH_MeshEditor_i::IsCoherentOrientation2D()
 }
 
 //=======================================================================
+//function : Get1DBranches
+//purpose  : Partition given 1D elements into groups of contiguous edges.
+//           A node where number of meeting edges != 2 is a group end.
+//           An optional startNode is used to orient groups it belongs to.
+//return   : a list of edge groups and a list of corresponding node groups.
+//           If a group is closed, the first and last nodes of the group are same.
+//=======================================================================
+
+SMESH::array_of_long_array*
+SMESH_MeshEditor_i::Get1DBranches( SMESH::SMESH_IDSource_ptr      theEdges,
+                                   CORBA::Long                    theStartNode,
+                                   SMESH::array_of_long_array_out theNodeGroups )
+  throw (SALOME::SALOME_Exception)
+{
+  if ( CORBA::is_nil( theEdges ))
+    THROW_SALOME_CORBA_EXCEPTION("Get1DBranches(): NULL group given", SALOME::BAD_PARAM);
+
+  SMESH::array_of_long_array_var edgeGroupArray = new SMESH::array_of_long_array;
+  theNodeGroups = new SMESH::array_of_long_array;
+
+  SMESH_TRY;
+
+  prepareIdSource( theEdges );
+
+  SMESH_MeshAlgos::TElemGroupVector edgeBranches;
+  SMESH_MeshAlgos::TNodeGroupVector nodeBranches;
+  SMESH_MeshAlgos::Get1DBranches( SMESH_Mesh_i::GetElements( theEdges, SMESH::EDGE ),
+                                  edgeBranches,
+                                  nodeBranches,
+                                  getMeshDS()->FindNode( theStartNode ));
+
+  edgeGroupArray->length( edgeBranches.size() );
+  for ( size_t iG = 0; iG < edgeBranches.size(); ++iG )
+  {
+    edgeGroupArray[ iG ].length( edgeBranches[ iG ].size() );
+    for ( size_t i = 0; i < edgeBranches[ iG ].size(); ++i )
+      edgeGroupArray[ iG ][ i ] = edgeBranches[ iG ][ i ]->GetID();
+  }
+
+  theNodeGroups->length( nodeBranches.size() );
+  for ( size_t iG = 0; iG < nodeBranches.size(); ++iG )
+  {
+    theNodeGroups[ iG ].length( nodeBranches[ iG ].size() );
+    for ( size_t i = 0; i < nodeBranches[ iG ].size(); ++i )
+      theNodeGroups[ iG ][ i ] = nodeBranches[ iG ][ i ]->GetID();
+  }
+
+  SMESH_CATCH( SMESH::throwCorbaException );
+
+  return edgeGroupArray._retn();
+}
+
+//=======================================================================
 //function : FindSharpEdges
 //purpose  : Return sharp edges of faces and non-manifold ones. Optionally add existing edges.
 //=======================================================================
@@ -5525,8 +5596,8 @@ void SMESH_MeshEditor_i::convertToQuadratic(CORBA::Boolean            theForce3d
   bool elemsOK;
   if ( !( elemsOK = CORBA::is_nil( theObject )))
   {
-    elemsOK =  idSourceToSet( theObject, getMeshDS(), elems,
-                              SMDSAbs_All, /*emptyIfIsMesh=*/true );
+    elemsOK = idSourceToSet( theObject, getMeshDS(), elems,
+                             SMDSAbs_All, /*emptyIfIsMesh=*/true );
   }
   if ( elemsOK )
   {
@@ -7087,7 +7158,7 @@ CORBA::Long SMESH_MeshEditor_i::MakeBoundaryElements(SMESH::Bnd_Dimension dim,
   for ( CORBA::ULong i = 0; i < groups.length(); ++i )
   {
     SMESH::SMESH_Mesh_var m = groups[i]->GetMesh();
-    if ( myMesh_i != SMESH::DownCast<SMESH_Mesh_i*>( m ))
+    if ( !m->_is_nil() && myMesh_i != SMESH::DownCast<SMESH_Mesh_i*>( m ))
       groupsOfOtherMesh[ nbGroupsOfOtherMesh++ ] = groups[i];
     else
       groupsOfThisMesh[ nbGroups++ ] = groups[i];
@@ -7267,11 +7338,11 @@ void SMESH_MeshEditor_i::MakePolyLine(SMESH::ListOfPolySegments& theSegments,
   }
 
   // convert input polySegments
-  ::SMESH_MeshEditor::TListOfPolySegments segments( theSegments.length() );
+  SMESH_MeshAlgos::TListOfPolySegments segments( theSegments.length() );
   for ( CORBA::ULong i = 0; i < theSegments.length(); ++i )
   {
-    SMESH::PolySegment&               segIn = theSegments[ i ];
-    ::SMESH_MeshEditor::PolySegment& segOut = segments[ i ];
+    SMESH::PolySegment&            segIn = theSegments[ i ];
+    SMESH_MeshAlgos::PolySegment& segOut = segments[ i ];
     segOut.myNode1[0] = meshDS->FindNode( segIn.node1ID1 );
     segOut.myNode2[0] = meshDS->FindNode( segIn.node1ID2 );
     segOut.myNode1[1] = meshDS->FindNode( segIn.node2ID1 );
@@ -7294,15 +7365,24 @@ void SMESH_MeshEditor_i::MakePolyLine(SMESH::ListOfPolySegments& theSegments,
     theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() );
 
   // compute
-  getEditor().MakePolyLine( segments, groupDS, theElementSearcher );
+  std::vector<const SMDS_MeshElement*> newEdges;
+  std::vector<const SMDS_MeshNode*>    newNodes;
+  SMESH_MeshAlgos::MakePolyLine( meshDS, segments, newEdges, newNodes,
+                                 groupDS ? &groupDS->SMDSGroup() : 0,
+                                 theElementSearcher );
+
+  const_cast< SMESH_SequenceOfElemPtr& >( getEditor().GetLastCreatedElems() ).
+    swap( newEdges );
+  const_cast< SMESH_SequenceOfElemPtr& >( getEditor().GetLastCreatedNodes() ).
+    assign( newNodes.begin(), newNodes.end() );
 
   // return vectors
   if ( myIsPreviewMode )
   {
     for ( CORBA::ULong i = 0; i < theSegments.length(); ++i )
     {
-      SMESH::PolySegment&             segOut = theSegments[ i ];
-      ::SMESH_MeshEditor::PolySegment& segIn = segments[ i ];
+      SMESH::PolySegment&           segOut = theSegments[ i ];
+      SMESH_MeshAlgos::PolySegment& segIn = segments[ i ];
       segOut.vector.PS.x = segIn.myVector.X();
       segOut.vector.PS.y = segIn.myVector.Y();
       segOut.vector.PS.z = segIn.myVector.Z();
@@ -7330,3 +7410,49 @@ void SMESH_MeshEditor_i::MakePolyLine(SMESH::ListOfPolySegments& theSegments,
   SMESH_CATCH( SMESH::throwCorbaException );
   return;
 }
+
+//================================================================================
+/*!
+ * \brief Create a slot of given width around given 1D elements lying on a triangle mesh.
+ *        The slot is consrtucted by cutting faces by cylindrical surfaces made
+ *        around each segment. Segments are expected to be created by MakePolyLine().
+ * \return Edges located at the slot boundary
+ */
+//================================================================================
+
+SMESH::ListOfEdges* SMESH_MeshEditor_i::MakeSlot(SMESH::SMESH_GroupBase_ptr theSegments,
+                                                 CORBA::Double              theWidth)
+  throw (SALOME::SALOME_Exception)
+{
+  if ( CORBA::is_nil( theSegments ) ||
+       theSegments->GetType() != SMESH::EDGE )
+    THROW_SALOME_CORBA_EXCEPTION("No segments given", SALOME::BAD_PARAM );
+  if ( myMesh->NbFaces() == 0 )
+    THROW_SALOME_CORBA_EXCEPTION("No faces in the mesh", SALOME::BAD_PARAM );
+
+  SMESH::ListOfEdges_var resultEdges = new SMESH::ListOfEdges;
+
+  SMESH_TRY;
+  initData(/*deleteSearchers=*/false);
+
+  SMESHDS_Mesh* meshDS = getMeshDS();
+
+  std::vector< SMESH_MeshAlgos::Edge > edges =
+    SMESH_MeshAlgos::MakeSlot( SMESH_Mesh_i::GetElements( theSegments, SMESH::EDGE ),
+                               theWidth, meshDS );
+
+  resultEdges->length( edges.size() );
+  for ( size_t i = 0; i < edges.size(); ++i )
+  {
+    resultEdges[ i ].node1  = edges[i]._node1->GetID();
+    resultEdges[ i ].node2  = edges[i]._node2->GetID();
+    resultEdges[ i ].medium = edges[i]._medium ? edges[i]._medium->GetID() : 0;
+  }
+
+  meshDS->Modified();
+  SMESH_CATCH( SMESH::throwCorbaException );
+
+  TSearchersDeleter::Delete(); // face searcher becomes invalid as some faces were removed
+
+  return resultEdges._retn();
+}
index 89c730f..462d42d 100644 (file)
@@ -560,8 +560,8 @@ public:
   CORBA::Long ProjectPoint(CORBA::Double             x,
                            CORBA::Double             y,
                            CORBA::Double             z,
-                           SMESH::SMESH_IDSource_ptr meshObject,
                            SMESH::ElementType        type,
+                           SMESH::SMESH_IDSource_ptr meshObject,
                            SMESH::double_array_out   projecton)
     throw (SALOME::SALOME_Exception);
 
@@ -585,6 +585,18 @@ public:
     throw (SALOME::SALOME_Exception);
 
   /*!
+   * Partition given 1D elements into groups of contiguous edges.
+   * A node where number of meeting edges != 2 is a group end.
+   * An optional startNode is used to orient groups it belongs to.
+   * \return a list of edge groups and a list of corresponding node groups.
+   *         If a group is closed, the first and last nodes of the group are same.
+   */
+  SMESH::array_of_long_array* Get1DBranches( SMESH::SMESH_IDSource_ptr      edges,
+                                             CORBA::Long                    startNode,
+                                             SMESH::array_of_long_array_out nodeGroups)
+    throw (SALOME::SALOME_Exception);
+
+  /*!
    * Return sharp edges of faces and non-manifold ones. Optionally adds existing edges.
    */
   SMESH::ListOfEdges* FindSharpEdges(CORBA::Double angle, CORBA::Boolean addExisting)
@@ -920,7 +932,17 @@ public:
    *        be added.
    */
   void MakePolyLine(SMESH::ListOfPolySegments& segments,
-                    const char*               groupName)
+                    const char*                groupName)
+    throw (SALOME::SALOME_Exception);
+
+  /*!
+   * \brief Create a slot of given width around given 1D elements lying on a triangle mesh.
+   *        The slot is consrtucted by cutting faces by cylindrical surfaces made
+   *        around each segment. Segments are expected to be created by MakePolyLine().
+   * \return Edges located at the slot boundary
+   */
+  SMESH::ListOfEdges* MakeSlot(SMESH::SMESH_GroupBase_ptr segments,
+                               CORBA::Double              width)
     throw (SALOME::SALOME_Exception);
 
 
index 802186a..016bf65 100644 (file)
@@ -1020,7 +1020,7 @@ SMESH_Mesh_i::CreateGroupFromGEOM (SMESH::ElementType    theElemType,
   if ( !aShape.IsNull() )
   {
     aNewGroup =
-      SMESH::SMESH_GroupOnGeom::_narrow( createGroup( theElemType, theName, aShape ));
+      SMESH::SMESH_GroupOnGeom::_narrow( createGroup( theElemType, theName, /*id=*/-1, aShape ));
 
     if ( _gen_i->CanPublishInStudy( aNewGroup ) )
     {
@@ -1064,7 +1064,7 @@ SMESH_Mesh_i::CreateGroupFromFilter(SMESH::ElementType theElemType,
     THROW_SALOME_CORBA_EXCEPTION("Invalid filter", SALOME::BAD_PARAM);
 
   SMESH::SMESH_GroupOnFilter_var aNewGroup = SMESH::SMESH_GroupOnFilter::_narrow
-    ( createGroup( theElemType, theName, TopoDS_Shape(), predicate ));
+    ( createGroup( theElemType, theName, /*id=*/-1, TopoDS_Shape(), predicate ));
 
   TPythonDump pd;
   if ( !aNewGroup->_is_nil() )
@@ -2429,10 +2429,10 @@ void SMESH_Mesh_i::CheckGeomGroupModif()
         SALOMEDS::SObject_wrap groupSO = _gen_i->ObjectToSObject( _mapGroups[oldID] );
         CORBA::String_var      name    = groupSO->GetName();
         // update
-        SMESH_GroupBase_i*  group_i    = SMESH::DownCast<SMESH_GroupBase_i*>(_mapGroups[oldID] );
-        int newID;
-        if ( group_i && _impl->AddGroup( geomType->second, name.in(), newID, geom._shape ))
-          group_i->changeLocalId( newID );
+        if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>(_mapGroups[oldID]))
+          if ( SMESH_Group* group = _impl->AddGroup( geomType->second, name.in(),
+                                                     /*id=*/-1, geom._shape ))
+            group_i->changeLocalId( group->GetID() );
       }
 
       break; // everything has been updated
@@ -2685,6 +2685,7 @@ bool SMESH_Mesh_i::removeSubMesh (SMESH::SMESH_subMesh_ptr theSubMesh,
 
 SMESH::SMESH_GroupBase_ptr SMESH_Mesh_i::createGroup (SMESH::ElementType        theElemType,
                                                       const char*               theName,
+                                                      const int                 theID,
                                                       const TopoDS_Shape&       theShape,
                                                       const SMESH_PredicatePtr& thePredicate )
 {
@@ -2703,10 +2704,11 @@ SMESH::SMESH_GroupBase_ptr SMESH_Mesh_i::createGroup (SMESH::ElementType
     } while ( !presentNames.insert( newName ).second );
     theName = newName.c_str();
   }
-  int anId;
   SMESH::SMESH_GroupBase_var aGroup;
-  if ( _impl->AddGroup( (SMDSAbs_ElementType)theElemType, theName, anId, theShape, thePredicate ))
+  if ( SMESH_Group* g = _impl->AddGroup( (SMDSAbs_ElementType)theElemType, theName,
+                                         theID, theShape, thePredicate ))
   {
+    int anId = g->GetID();
     SMESH_GroupBase_i* aGroupImpl;
     if ( !theShape.IsNull() )
       aGroupImpl = new SMESH_GroupOnGeom_i( SMESH_Gen_i::GetPOA(), this, anId );
@@ -2722,7 +2724,7 @@ SMESH::SMESH_GroupBase_ptr SMESH_Mesh_i::createGroup (SMESH::ElementType
     // register CORBA object for persistence
     int nextId = _gen_i->RegisterObject( aGroup );
     if(MYDEBUG) { MESSAGE( "Add group to map with id = "<< nextId); }
-    else        { nextId = 0; } // avoid "unused variable" warning in release mode
+    else        { nextId = ( nextId > 0 ); } // avoid "unused variable" warning in release mode
 
     // to track changes of GEOM groups
     if ( !theShape.IsNull() ) {
@@ -4475,7 +4477,8 @@ SMESH::double_array* SMESH_Mesh_i::GetNodeXYZ(const CORBA::Long id)
  */
 //=============================================================================
 
-SMESH::long_array* SMESH_Mesh_i::GetNodeInverseElements(const CORBA::Long id)
+SMESH::long_array* SMESH_Mesh_i::GetNodeInverseElements(const CORBA::Long  id,
+                                                        SMESH::ElementType elemType)
 {
   if ( _preMeshInfo )
     _preMeshInfo->FullLoadFromFile();
@@ -4486,13 +4489,14 @@ SMESH::long_array* SMESH_Mesh_i::GetNodeInverseElements(const CORBA::Long id)
     return aResult._retn();
 
   // find node
-  const SMDS_MeshNode* aNode = aMeshDS->FindNode(id);
-  if(!aNode)
+  const SMDS_MeshNode* aNode = aMeshDS->FindNode( id );
+  if ( !aNode )
     return aResult._retn();
 
   // find inverse elements
-  SMDS_ElemIteratorPtr eIt = aNode->GetInverseElementIterator();
-  aResult->length( aNode->NbInverseElements() );
+  SMDSAbs_ElementType type = SMDSAbs_ElementType( elemType );
+  SMDS_ElemIteratorPtr eIt = aNode->GetInverseElementIterator( type );
+  aResult->length( aNode->NbInverseElements( type ));
   for( int i = 0; eIt->more(); ++i )
   {
     const SMDS_MeshElement* elem = eIt->next();
@@ -5513,10 +5517,12 @@ namespace /* Iterators used in SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_v
     SMDS_ElemIteratorPtr    _elemIter;
     PredicatePtr            _predicate;
     const SMDS_MeshElement* _elem;
+    SMDSAbs_ElementType     _type;
 
-    PredicateIterator( SMDS_ElemIteratorPtr   iterator,
-                       PredicatePtr predicate):
-      _elemIter(iterator), _predicate(predicate)
+    PredicateIterator( SMDS_ElemIteratorPtr iterator,
+                       PredicatePtr         predicate,
+                       SMDSAbs_ElementType  type):
+      _elemIter(iterator), _predicate(predicate), _type(type)
     {
       next();
     }
@@ -5530,8 +5536,9 @@ namespace /* Iterators used in SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_v
       _elem = 0;
       while ( _elemIter->more() && !_elem )
       {
-        _elem = _elemIter->next();
-        if ( _elem && ( !_predicate->IsSatisfy( _elem->GetID() )))
+        if ((_elem = _elemIter->next()) &&
+            (( _type != SMDSAbs_All && _type != _elem->GetType() ) ||
+             ( !_predicate->IsSatisfy( _elem->GetID() ))))
           _elem = 0;
       }
       return res;
@@ -5685,6 +5692,7 @@ SMDS_ElemIteratorPtr SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_ptr theObje
   else if ( SMESH::Filter_i* filter_i = SMESH::DownCast<SMESH::Filter_i*>( theObject ))
   {
     if ( filter_i->GetElementType() == theType ||
+         filter_i->GetElementType() == SMESH::ALL ||
          elemType == SMDSAbs_Node ||
          elemType == SMDSAbs_All)
     {
@@ -5693,8 +5701,10 @@ SMDS_ElemIteratorPtr SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_ptr theObje
       {
         SMDSAbs_ElementType filterType = SMDSAbs_ElementType( filter_i->GetElementType() );
         SMDS_ElemIteratorPtr allElemIt = meshDS->elementsIterator( filterType );
-        elemIt = SMDS_ElemIteratorPtr( new PredicateIterator( allElemIt, pred_i->GetPredicate() ));
-        typeOK = ( filterType == elemType || elemType == SMDSAbs_All );
+        SMDSAbs_ElementType   iterType = elemType == SMDSAbs_Node ? filterType : elemType;
+        elemIt = SMDS_ElemIteratorPtr
+          ( new PredicateIterator( allElemIt, pred_i->GetPredicate(), iterType ));
+        typeOK = ( elemType == SMDSAbs_Node ? filterType == SMDSAbs_Node : elemIt->more() );
       }
     }
   }
@@ -5704,16 +5714,17 @@ SMDS_ElemIteratorPtr SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_ptr theObje
     const bool                    isNodes = ( types->length() == 1 && types[0] == SMESH::NODE );
     if ( isNodes && elemType != SMDSAbs_Node && elemType != SMDSAbs_All )
       return elemIt;
+    SMDSAbs_ElementType iterType = isNodes ? SMDSAbs_Node : elemType;
     if ( SMESH_MeshEditor_i::IsTemporaryIDSource( theObject ))
     {
       int nbIds;
       if ( CORBA::Long* ids = SMESH_MeshEditor_i::GetTemporaryIDs( theObject, nbIds ))
-        elemIt = SMDS_ElemIteratorPtr( new IDSourceIterator( meshDS, ids, nbIds, elemType ));
+        elemIt = SMDS_ElemIteratorPtr( new IDSourceIterator( meshDS, ids, nbIds, iterType ));
     }
     else
     {
       SMESH::long_array_var ids = theObject->GetIDs();
-      elemIt = SMDS_ElemIteratorPtr( new IDSourceIterator( meshDS, ids._retn(), elemType ));
+      elemIt = SMDS_ElemIteratorPtr( new IDSourceIterator( meshDS, ids._retn(), iterType ));
     }
     typeOK = ( isNodes == ( elemType == SMDSAbs_Node )) || ( elemType == SMDSAbs_All );
   }
index d06a704..34c7c30 100644 (file)
@@ -440,6 +440,7 @@ public:
 
   SMESH::SMESH_GroupBase_ptr createGroup(SMESH::ElementType        theElemType,
                                          const char*               theName,
+                                         const int                 theID = -1,
                                          const TopoDS_Shape&       theShape = TopoDS_Shape(),
                                          const SMESH_PredicatePtr& thePred = SMESH_PredicatePtr());
 
@@ -501,7 +502,8 @@ public:
    * For given node returns list of IDs of inverse elements
    * If there is not node for given ID - returns empty list
    */
-  SMESH::long_array* GetNodeInverseElements(CORBA::Long id);
+  SMESH::long_array* GetNodeInverseElements(CORBA::Long        id,
+                                            SMESH::ElementType elemType);
 
   /*!
    * \brief Return position of a node on shape
index 35198fe..0268587 100755 (executable)
@@ -733,10 +733,10 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ):
 
     def Concatenate( self, meshes, uniteIdenticalGroups,
                      mergeNodesAndElements = False, mergeTolerance = 1e-5, allGroups = False,
-                     name = ""):
+                     name = "", meshToAppendTo = None):
         """
-        Concatenate the given meshes into one mesh. All groups of input meshes will be
-        present in the new mesh.
+        Concatenate the given meshes into one mesh, optionally to meshToAppendTo.
+        All groups of input meshes will be present in the new mesh.
 
         Parameters:
                 meshes: :class:`meshes, sub-meshes, groups or filters <SMESH.SMESH_IDSource>` to combine into one mesh
@@ -745,6 +745,7 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ):
                 mergeTolerance: tolerance for merging nodes
                 allGroups: forces creation of groups corresponding to every input mesh
                 name: name of a new mesh
+                meshToAppendTo a mesh to append all given meshes
 
         Returns:
                 an instance of class :class:`Mesh`
@@ -755,13 +756,21 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ):
             if isinstance(m, Mesh):
                 meshes[i] = m.GetMesh()
         mergeTolerance,Parameters,hasVars = ParseParameters(mergeTolerance)
-        meshes[0].SetParameters(Parameters)
+        if hasattr(meshes[0], "SetParameters"):
+            meshes[0].SetParameters(Parameters)
+        else:
+            meshes[0].GetMesh().SetParameters(Parameters)
+        if isinstance( meshToAppendTo, Mesh ):
+            meshToAppendTo = meshToAppendTo.GetMesh()
         if allGroups:
             aSmeshMesh = SMESH._objref_SMESH_Gen.ConcatenateWithGroups(
-                self,meshes,uniteIdenticalGroups,mergeNodesAndElements,mergeTolerance)
+                self,meshes,uniteIdenticalGroups,mergeNodesAndElements,
+                mergeTolerance,meshToAppendTo)
         else:
             aSmeshMesh = SMESH._objref_SMESH_Gen.Concatenate(
-                self,meshes,uniteIdenticalGroups,mergeNodesAndElements,mergeTolerance)
+                self,meshes,uniteIdenticalGroups,mergeNodesAndElements,
+                mergeTolerance,meshToAppendTo)
+
         aMesh = Mesh(self, self.geompyD, aSmeshMesh, name=name)
         return aMesh
 
@@ -1428,13 +1437,16 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ):
 
     def GetGravityCenter(self, obj):
         """
-        Get gravity center of all nodes of the mesh object.
+        Get gravity center of all nodes of a mesh object.
         
         Parameters:            
                 obj: :class:`mesh, sub-mesh, group or filter <SMESH.SMESH_IDSource>`
 
         Returns:        
-            Three components of the gravity center (x,y,z)
+                Three components of the gravity center (x,y,z)
+
+        See also: 
+                :meth:`Mesh.BaryCenter`
         """
         if isinstance(obj, Mesh): obj = obj.mesh
         if isinstance(obj, Mesh_Algorithm): obj = obj.GetSubMesh()
@@ -1618,6 +1630,18 @@ class Mesh(metaclass = MeshMeta):
 
         return self.mesh
 
+    def GetEngine(self):
+        """
+        Return a smeshBuilder instance created this mesh
+        """
+        return self.smeshpyD
+
+    def GetGeomEngine(self):
+        """
+        Return a geomBuilder instance
+        """
+        return self.geompyD
+
     def GetName(self):
         """
         Get the name of the mesh
@@ -2881,7 +2905,7 @@ class Mesh(metaclass = MeshMeta):
         Create a standalone group of entities basing on nodes of other groups.
 
         Parameters:
-                groups: list of reference :class:`sub-meshes, groups or filters <SMESH.SMESH_IDSource>`, of any type.
+                groups: list of :class:`sub-meshes, groups or filters <SMESH.SMESH_IDSource>`, of any type.
                 elemType: a type of elements to include to the new group; either of
                         (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME).
                 name: a name of the new group.
@@ -3532,16 +3556,20 @@ class Mesh(metaclass = MeshMeta):
 
         return self.mesh.GetNodeXYZ(id)
 
-    def GetNodeInverseElements(self, id):
+    def GetNodeInverseElements(self, id, elemType=SMESH.ALL):
         """
         Return list of IDs of inverse elements for the given node.
         If there is no node for the given ID - return an empty list
 
+        Parameters:
+                id: node ID
+                elementType: :class:`type of elements <SMESH.ElementType>` (SMESH.EDGE, SMESH.FACE, SMESH.VOLUME, etc.)
+
         Returns:
             list of integer values
         """
 
-        return self.mesh.GetNodeInverseElements(id)
+        return self.mesh.GetNodeInverseElements(id,elemType)
 
     def GetNodePosition(self,NodeID):
         """
@@ -3715,26 +3743,40 @@ class Mesh(metaclass = MeshMeta):
 
         Returns:
             a list of three double values
+
+        See also: 
+                :meth:`smeshBuilder.GetGravityCenter`
         """
 
         return self.mesh.BaryCenter(id)
 
-    def GetIdsFromFilter(self, theFilter):
+    def GetIdsFromFilter(self, filter, meshParts=[] ):
         """
         Pass mesh elements through the given filter and return IDs of fitting elements
 
         Parameters:
-                theFilter: :class:`SMESH.Filter`
+                filter: :class:`SMESH.Filter`
+                meshParts: list of mesh parts (:class:`sub-mesh, group or filter <SMESH.SMESH_IDSource>`) to filter
 
         Returns:
             a list of ids
 
         See Also:
             :meth:`SMESH.Filter.GetIDs`
+            :meth:`SMESH.Filter.GetElementsIdFromParts`
         """
 
-        theFilter.SetMesh( self.mesh )
-        return theFilter.GetIDs()
+        filter.SetMesh( self.mesh )
+
+        if meshParts:
+            if isinstance( meshParts, Mesh ):
+                filter.SetMesh( meshParts.GetMesh() )
+                return theFilter.GetIDs()
+            if isinstance( meshParts, SMESH._objref_SMESH_IDSource ):
+                meshParts = [ meshParts ]
+            return filter.GetElementsIdFromParts( meshParts )
+
+        return filter.GetIDs()
 
     # Get mesh measurements information:
     # ------------------------------------
@@ -4256,8 +4298,6 @@ class Mesh(metaclass = MeshMeta):
             the ID of a node
         """
 
-        #preview = self.mesh.GetMeshEditPreviewer()
-        #return preview.MoveClosestNodeToPoint(x, y, z, -1)
         return self.editor.FindNodeClosestTo(x, y, z)
 
     def FindElementsByPoint(self, x, y, z, elementType = SMESH.ALL, meshPart=None):
@@ -4278,16 +4318,18 @@ class Mesh(metaclass = MeshMeta):
         else:
             return self.editor.FindElementsByPoint(x, y, z, elementType)
 
-    def ProjectPoint(self, x,y,z, meshObject, elementType):
+    def ProjectPoint(self, x,y,z, elementType, meshObject=None):
         """
         Project a point to a mesh object.
         Return ID of an element of given type where the given point is projected
         and coordinates of the projection point.
         In the case if nothing found, return -1 and []
         """
-        if ( isinstance( meshObject, Mesh )):
+        if isinstance( meshObject, Mesh ):
             meshObject = meshObject.GetMesh()
-        return self.editor.ProjectPoint( x,y,z, meshObject, elementType )
+        if not meshObject:
+            meshObject = self.GetMesh()
+        return self.editor.ProjectPoint( x,y,z, elementType, meshObject )
 
     def GetPointState(self, x, y, z):
         """
@@ -4312,6 +4354,25 @@ class Mesh(metaclass = MeshMeta):
 
         return self.editor.IsCoherentOrientation2D()
 
+    def Get1DBranches( self, edges, startNode = 0 ):
+        """
+        Partition given 1D elements into groups of contiguous edges.
+        A node where number of meeting edges != 2 is a group end.
+        An optional startNode is used to orient groups it belongs to.
+
+        Returns:
+             A list of edge groups and a list of corresponding node groups,
+             where the group is a list of IDs of edges or elements.
+             If a group is closed, the first and last nodes of the group are same.
+        """
+        if isinstance( edges, Mesh ):
+            edges = edges.GetMesh()
+        unRegister = genObjUnRegister()
+        if isinstance( edges, list ):
+            edges = self.GetIDSource( edges, SMESH.EDGE )
+            unRegister.set( edges )
+        return self.editor.Get1DBranches( edges, startNode )
+    
     def FindSharpEdges( self, angle, addExisting=False ):
         """
         Return sharp edges of faces and non-manifold ones.
@@ -5102,7 +5163,7 @@ class Mesh(metaclass = MeshMeta):
                 groups: list of :class:`sub-meshes, groups or filters <SMESH.SMESH_IDSource>` of elements to make boundary around
 
         Returns:
-                tuple( long, mesh, groups )
+                tuple( long, mesh, group )
                        - long - number of added boundary elements
                        - mesh - the :class:`Mesh` where elements were added to
                        - group - the :class:`group <SMESH.SMESH_Group>` of boundary elements or None
@@ -6178,7 +6239,7 @@ class Mesh(metaclass = MeshMeta):
 
         Parameters:
             Tolerance: the value of tolerance
-            SubMeshOrGroup: :class:`sub-mesh, group or filter <SMESH.SMESH_IDSource>`
+            SubMeshOrGroup: :class:`sub-mesh, group or filter <SMESH.SMESH_IDSource>` or node IDs
             exceptNodes: list of either SubMeshes, Groups or node IDs to exclude from search
             SeparateCornerAndMediumNodes: if *True*, in quadratic mesh puts
                 corner and medium nodes in separate groups thus preventing
@@ -6191,11 +6252,16 @@ class Mesh(metaclass = MeshMeta):
         unRegister = genObjUnRegister()
         if (isinstance( SubMeshOrGroup, Mesh )):
             SubMeshOrGroup = SubMeshOrGroup.GetMesh()
+        if isinstance( SubMeshOrGroup, list ):
+            SubMeshOrGroup = self.GetIDSource( SubMeshOrGroup, SMESH.NODE )
+            unRegister.set( SubMeshOrGroup )
+
         if not isinstance( exceptNodes, list ):
             exceptNodes = [ exceptNodes ]
         if exceptNodes and isinstance( exceptNodes[0], int ):
             exceptNodes = [ self.GetIDSource( exceptNodes, SMESH.NODE )]
             unRegister.set( exceptNodes )
+
         return self.editor.FindCoincidentNodesOnPartBut(SubMeshOrGroup, Tolerance,
                                                         exceptNodes, SeparateCornerAndMediumNodes)
 
@@ -6755,7 +6821,18 @@ class Mesh(metaclass = MeshMeta):
             segments[i].vector = seg.vector
         if isPreview:
             return editor.GetPreviewData()
-        return None        
+        return None
+
+    def MakeSlot(self, segmentGroup, width ):
+        """
+        Create a slot of given width around given 1D elements lying on a triangle mesh.
+        The slot is consrtucted by cutting faces by cylindrical surfaces made
+        around each segment. Segments are expected to be created by MakePolyLine().
+
+        Returns:
+               FaceEdge's located at the slot boundary
+        """
+        return self.editor.MakeSlot( segmentGroup, width )
 
     def GetFunctor(self, funcType ):
         """
@@ -6856,11 +6933,15 @@ class Mesh(metaclass = MeshMeta):
                 node1,node2,node3: IDs of the three nodes
 
         Returns:        
-            Angle in radians
+            Angle in radians [0,PI]. -1 if failure case.
         """
-        return self.smeshpyD.GetAngle( self.GetNodeXYZ( node1 ),
-                                       self.GetNodeXYZ( node2 ),
-                                       self.GetNodeXYZ( node3 ))
+        p1 = self.GetNodeXYZ( node1 )
+        p2 = self.GetNodeXYZ( node2 )
+        p3 = self.GetNodeXYZ( node3 )
+        if p1 and p2 and p3:
+            return self.smeshpyD.GetAngle( p1,p2,p3 )
+        return -1.
+
 
     def GetMaxElementLength(self, elemId):
         """
index 2002098..a313cd6 100644 (file)
@@ -911,7 +911,7 @@ void StdMeshers_Import_1D::importMesh(const SMESH_Mesh*          srcMesh,
         int nb = 1;
         while ( !namesByType[ srcGroupDS->GetType() ].insert( name ).second )
           name = SMESH_Comment(srcGroup->GetName()) << "_imported_" << nb++;
-        SMESH_Group* newGroup = tgtMesh.AddGroup( srcGroupDS->GetType(), name.c_str(), nb );
+        SMESH_Group* newGroup = tgtMesh.AddGroup( srcGroupDS->GetType(), name.c_str() );
         SMESHDS_Group* newGroupDS = (SMESHDS_Group*)newGroup->GetGroupDS();
         resultGroups.push_back( newGroup );