Salome HOME
f20ffec66497868c4b59faa2d36637ef442d7b01
[modules/smesh.git] / src / SMESH_I / SMESH_MeshEditor_i.cxx
1 // Copyright (C) 2007-2020  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //  File   : SMESH_MeshEditor_i.cxx
23 //  Author : Nicolas REJNERI
24 //  Module : SMESH
25
26 #ifdef WIN32
27 #define NOMINMAX
28 #endif
29
30 // A macro used in SMESH_TryCatch.hxx,
31 // it re-raises a CORBA SALOME exception thrown by SMESH_MeshEditor_i and caught by SMESH_CATCH
32 #define SMY_OWN_CATCH \
33   catch ( SALOME::SALOME_Exception & e ) { throw e; }
34
35 #include "SMESH_MeshEditor_i.hxx"
36
37 #include "SMDS_EdgePosition.hxx"
38 #include "SMDS_ElemIterator.hxx"
39 #include "SMDS_FacePosition.hxx"
40 #include "SMDS_IteratorOnIterators.hxx"
41 #include "SMDS_LinearEdge.hxx"
42 #include "SMDS_Mesh0DElement.hxx"
43 #include "SMDS_MeshFace.hxx"
44 #include "SMDS_MeshVolume.hxx"
45 #include "SMDS_SetIterator.hxx"
46 #include "SMDS_VolumeTool.hxx"
47 #include "SMESHDS_Group.hxx"
48 #include "SMESHDS_GroupOnGeom.hxx"
49 #include "SMESH_ControlsDef.hxx"
50 #include "SMESH_Filter_i.hxx"
51 #include "SMESH_Gen_i.hxx"
52 #include "SMESH_Group.hxx"
53 #include "SMESH_Group_i.hxx"
54 #include "SMESH_MeshAlgos.hxx"
55 #include "SMESH_MeshPartDS.hxx"
56 #include "SMESH_MesherHelper.hxx"
57 #include "SMESH_PythonDump.hxx"
58 #include "SMESH_subMeshEventListener.hxx"
59 #include "SMESH_subMesh_i.hxx"
60
61 #include <utilities.h>
62 #include <Utils_ExceptHandlers.hxx>
63 #include <Utils_CorbaException.hxx>
64 #include <SALOMEDS_wrap.hxx>
65 #include <SALOME_GenericObj_i.hh>
66
67 #include <BRepAdaptor_Surface.hxx>
68 #include <BRep_Tool.hxx>
69 #include <TopExp_Explorer.hxx>
70 #include <TopoDS.hxx>
71 #include <TopoDS_Edge.hxx>
72 #include <TopoDS_Face.hxx>
73 #include <gp_Ax1.hxx>
74 #include <gp_Ax2.hxx>
75 #include <gp_Vec.hxx>
76
77 #include <Standard_Failure.hxx>
78 #include <Standard_ErrorHandler.hxx>
79
80 #include <sstream>
81 #include <limits>
82
83 #include "SMESH_TryCatch.hxx" // include after OCCT headers!
84
85 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
86
87 using namespace std;
88 using SMESH::TPythonDump;
89 using SMESH::TVar;
90
91 namespace MeshEditor_I {
92
93   //=============================================================================
94   /*!
95    * \brief Mesh to apply modifications for preview purposes
96    */
97   //=============================================================================
98
99   struct TPreviewMesh: public SMESH_Mesh
100   {
101     SMDSAbs_ElementType myPreviewType; // type to show
102     //!< Constructor
103     TPreviewMesh(SMDSAbs_ElementType previewElements = SMDSAbs_All) {
104       _isShapeToMesh = (_id = 0);
105       _myMeshDS  = new SMESHDS_Mesh( _id, true );
106       myPreviewType = previewElements;
107     }
108     //!< Copy a set of elements
109     void Copy(const TIDSortedElemSet & theElements,
110               TIDSortedElemSet&        theCopyElements,
111               SMDSAbs_ElementType      theSelectType = SMDSAbs_All,
112               SMDSAbs_ElementType      theAvoidType = SMDSAbs_All)
113     {
114       // loop on theIDsOfElements
115       TIDSortedElemSet::const_iterator eIt = theElements.begin();
116       for ( ; eIt != theElements.end(); ++eIt )
117       {
118         const SMDS_MeshElement* anElem = *eIt;
119         if ( !anElem ) continue;
120         SMDSAbs_ElementType type = anElem->GetType();
121         if ( type == theAvoidType ||
122              ( theSelectType != SMDSAbs_All && type != theSelectType ))
123           continue;
124         const SMDS_MeshElement* anElemCopy;
125         if ( type == SMDSAbs_Node)
126           anElemCopy = Copy( cast2Node(anElem) );
127         else
128           anElemCopy = Copy( anElem );
129         if ( anElemCopy )
130           theCopyElements.insert( theCopyElements.end(), anElemCopy );
131       }
132     }
133     //!< Copy an element
134     SMDS_MeshElement* Copy( const SMDS_MeshElement* anElem )
135     {
136       // copy element nodes
137       int anElemNbNodes = anElem->NbNodes();
138       vector< int > anElemNodesID( anElemNbNodes ) ;
139       SMDS_ElemIteratorPtr itElemNodes = anElem->nodesIterator();
140       for ( int i = 0; itElemNodes->more(); i++)
141       {
142         const SMDS_MeshNode* anElemNode = cast2Node( itElemNodes->next() );
143         Copy( anElemNode );
144         anElemNodesID[i] = anElemNode->GetID();
145       }
146
147       // creates a corresponding element on copied nodes
148       ::SMESH_MeshEditor::ElemFeatures elemType;
149       elemType.Init( anElem, /*basicOnly=*/false );
150       elemType.SetID( anElem->GetID() );
151       SMDS_MeshElement* anElemCopy =
152         ::SMESH_MeshEditor(this).AddElement( anElemNodesID, elemType );
153       return anElemCopy;
154     }
155     //!< Copy a node
156     SMDS_MeshNode* Copy( const SMDS_MeshNode* anElemNode )
157     {
158       return _myMeshDS->AddNodeWithID(anElemNode->X(), anElemNode->Y(), anElemNode->Z(),
159                                       anElemNode->GetID());
160     }
161     void RemoveAll()
162     {
163       GetMeshDS()->ClearMesh();
164     }
165     void Remove( SMDSAbs_ElementType type )
166     {
167       Remove( GetMeshDS()->elementsIterator( type ));
168     }
169     void Remove( SMDS_ElemIteratorPtr eIt )
170     {
171       while ( eIt->more() )
172         GetMeshDS()->RemoveFreeElement( eIt->next(), /*sm=*/0, /*fromGroups=*/false );
173     }
174   };// struct TPreviewMesh
175
176   static SMESH_NodeSearcher *    theNodeSearcher    = 0;
177   static SMESH_ElementSearcher * theElementSearcher = 0;
178
179   //=============================================================================
180   /*!
181    * \brief Deleter of theNodeSearcher and theElementSearcher at any compute event occurred
182    */
183   //=============================================================================
184
185   struct TSearchersDeleter : public SMESH_subMeshEventListener
186   {
187     SMESH_Mesh* myMesh;
188     string      myMeshPartIOR;
189     //!< Constructor
190     TSearchersDeleter(): SMESH_subMeshEventListener( false, // won't be deleted by submesh
191                                                      "SMESH_MeshEditor_i::TSearchersDeleter"),
192                          myMesh(0) {}
193     //!< Delete theNodeSearcher
194     static void Delete()
195     {
196       if ( theNodeSearcher )    delete theNodeSearcher;    theNodeSearcher    = 0;
197       if ( theElementSearcher ) delete theElementSearcher; theElementSearcher = 0;
198     }
199     typedef map < int, SMESH_subMesh * > TDependsOnMap;
200     //!< The meshod called by submesh: do my main job
201     void ProcessEvent(const int, const int eventType, SMESH_subMesh* sm,
202                       SMESH_subMeshEventListenerData*,const SMESH_Hypothesis*)
203     {
204       if ( eventType == SMESH_subMesh::COMPUTE_EVENT ) {
205         Delete();
206         Unset( sm->GetFather() );
207       }
208     }
209     //!< set self on all submeshes and delete theNodeSearcher if other mesh is set
210     void Set(SMESH_Mesh* mesh, const string& meshPartIOR = string())
211     {
212       if ( myMesh != mesh || myMeshPartIOR != meshPartIOR)
213       {
214         if ( myMesh ) {
215           Delete();
216           Unset( myMesh );
217         }
218         myMesh = mesh;
219         myMeshPartIOR = meshPartIOR;
220         SMESH_subMesh* sm = mesh->GetSubMesh( mesh->GetShapeToMesh() );
221         SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator( /*includeSelf=*/true );
222         while ( smIt->more() )
223         {
224           sm = smIt->next();
225           sm->SetEventListener( this, 0, sm );
226         }
227       }
228     }
229     //!<  delete self from all submeshes
230     void Unset(SMESH_Mesh* mesh)
231     {
232       if ( SMESH_subMesh* sm = mesh->GetSubMeshContaining(1) ) {
233         SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator( /*includeSelf=*/true );
234         while ( smIt->more() )
235           smIt->next()->DeleteEventListener( this );
236       }
237       myMesh = 0;
238     }
239
240   } theSearchersDeleter;
241
242   TCollection_AsciiString mirrorTypeName( SMESH::SMESH_MeshEditor::MirrorType theMirrorType )
243   {
244     TCollection_AsciiString typeStr;
245     switch ( theMirrorType ) {
246     case  SMESH::SMESH_MeshEditor::POINT:
247       typeStr = "SMESH.SMESH_MeshEditor.POINT";
248       break;
249     case  SMESH::SMESH_MeshEditor::AXIS:
250       typeStr = "SMESH.SMESH_MeshEditor.AXIS";
251       break;
252     default:
253       typeStr = "SMESH.SMESH_MeshEditor.PLANE";
254     }
255     return typeStr;
256   }
257   //================================================================================
258   /*!
259    * \brief function for conversion of long_array to TIDSortedElemSet
260    * \param IDs - array of IDs
261    * \param aMesh - mesh
262    * \param aMap - collection to fill
263    * \param aType - element type
264    */
265   //================================================================================
266
267   void arrayToSet(const SMESH::long_array & IDs,
268                   const SMESHDS_Mesh*       aMesh,
269                   TIDSortedElemSet&         aMap,
270                   const SMDSAbs_ElementType aType = SMDSAbs_All,
271                   SMDS_MeshElement::Filter* aFilter = NULL)
272   {
273     SMDS_MeshElement::NonNullFilter filter1;
274     SMDS_MeshElement::TypeFilter    filter2( aType );
275
276     if ( aFilter == NULL )
277       aFilter = ( aType == SMDSAbs_All ) ? (SMDS_MeshElement::Filter*) &filter1 : (SMDS_MeshElement::Filter*) &filter2;
278     
279     SMDS_MeshElement::Filter & filter = *aFilter;
280
281     if ( aType == SMDSAbs_Node )
282       for ( CORBA::ULong i = 0; i < IDs.length(); i++ ) {
283         const SMDS_MeshElement * elem = aMesh->FindNode( IDs[i] );
284         if ( filter( elem ))
285           aMap.insert( aMap.end(), elem );
286       }
287     else
288       for ( CORBA::ULong i = 0; i<IDs.length(); i++) {
289         const SMDS_MeshElement * elem = aMesh->FindElement( IDs[i] );
290         if ( filter( elem ))
291           aMap.insert( aMap.end(), elem );
292       }
293   }
294
295   //================================================================================
296   /*!
297    * \brief Retrieve nodes from SMESH_IDSource
298    */
299   //================================================================================
300
301   void idSourceToNodeSet(SMESH::SMESH_IDSource_ptr theObject,
302                          const SMESHDS_Mesh*       theMeshDS,
303                          TIDSortedNodeSet&         theNodeSet)
304
305   {
306     if ( CORBA::is_nil( theObject ) )
307       return;
308     if ( SMESH::DownCast<SMESH_Mesh_i*>( theObject ))
309     {
310       for ( SMDS_NodeIteratorPtr nIt = theMeshDS->nodesIterator(); nIt->more(); )
311         if ( const SMDS_MeshElement * elem = nIt->next() )
312           theNodeSet.insert( elem->begin_nodes(), elem->end_nodes());
313     }
314     else
315     {
316       SMESH::array_of_ElementType_var types = theObject->GetTypes();
317       SMESH::long_array_var     aElementsId = theObject->GetIDs();
318       if ( types->length() == 1 && types[0] == SMESH::NODE)
319       {
320         for ( CORBA::ULong i = 0; i < aElementsId->length(); i++ )
321           if ( const SMDS_MeshNode * n = theMeshDS->FindNode( aElementsId[i] ))
322             theNodeSet.insert( theNodeSet.end(), n);
323       }
324       else
325       {
326         for ( CORBA::ULong i = 0; i < aElementsId->length(); i++ )
327           if ( const SMDS_MeshElement * elem = theMeshDS->FindElement( aElementsId[i] ))
328             theNodeSet.insert( elem->begin_nodes(), elem->end_nodes());
329       }
330     }
331   }
332
333   //================================================================================
334   /*!
335    * \brief Returns elements connected to the given elements
336    */
337   //================================================================================
338
339   void getElementsAround(const TIDSortedElemSet& theElements,
340                          const SMESHDS_Mesh*     theMeshDS,
341                          TIDSortedElemSet&       theElementsAround)
342   {
343     if ( theElements.empty() ) return;
344
345     SMDSAbs_ElementType elemType    = (*theElements.begin())->GetType();
346     bool sameElemType = ( elemType == (*theElements.rbegin())->GetType() );
347     if ( sameElemType &&
348          theMeshDS->GetMeshInfo().NbElements( elemType ) == (int) theElements.size() )
349       return; // all the elements are in theElements
350
351     if ( !sameElemType )
352       elemType = SMDSAbs_All;
353
354     vector<bool> isNodeChecked( theMeshDS->NbNodes(), false );
355
356     TIDSortedElemSet::const_iterator elemIt = theElements.begin();
357     for ( ; elemIt != theElements.end(); ++elemIt )
358     {
359       const SMDS_MeshElement* e = *elemIt;
360       int i = e->NbCornerNodes();
361       while ( --i != -1 )
362       {
363         const SMDS_MeshNode* n = e->GetNode( i );
364         if ( !isNodeChecked[ n->GetID() ])
365         {
366           isNodeChecked[ n->GetID() ] = true;
367           SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator(elemType);
368           while ( invIt->more() )
369           {
370             const SMDS_MeshElement* elemAround = invIt->next();
371             if ( !theElements.count( elemAround ))
372               theElementsAround.insert( elemAround );
373           }
374         }
375       }
376     }
377   }
378
379   //================================================================================
380   /*!
381    * \brief Return a string used to detect change of mesh part on which theElementSearcher
382    * is going to be used
383    */
384   //================================================================================
385
386   string getPartIOR( SMESH::SMESH_IDSource_ptr theMeshPart, SMESH::ElementType type = SMESH::ALL )
387   {
388     if ( SMESH::DownCast<SMESH_Mesh_i*>( theMeshPart ))
389       return "";
390     string partIOR = SMESH_Gen_i::GetORB()->object_to_string( theMeshPart );
391     if ( SMESH_Group_i* group_i = SMESH::DownCast<SMESH_Group_i*>( theMeshPart ))
392       // take into account passible group modification
393       partIOR += SMESH_Comment( ((SMESHDS_Group*)group_i->GetGroupDS())->SMDSGroup().Tic() );
394     partIOR += SMESH_Comment( type );
395     return partIOR;
396   }
397
398 } // namespace MeshEditor_I
399
400 using namespace MeshEditor_I;
401
402 //=============================================================================
403 /*!
404  *
405  */
406 //=============================================================================
407
408 SMESH_MeshEditor_i::SMESH_MeshEditor_i(SMESH_Mesh_i* theMesh, bool isPreview):
409   myMesh_i( theMesh ),
410   myMesh( &theMesh->GetImpl() ),
411   myEditor( myMesh ),
412   myIsPreviewMode ( isPreview ),
413   myPreviewMesh( 0 ),
414   myPreviewEditor( 0 )
415 {
416 }
417
418 //================================================================================
419 /*!
420  * \brief Destructor
421  */
422 //================================================================================
423
424 SMESH_MeshEditor_i::~SMESH_MeshEditor_i()
425 {
426   PortableServer::POA_var poa = SMESH_Gen_i::GetPOA();
427   PortableServer::ObjectId_var anObjectId = poa->servant_to_id(this);
428   poa->deactivate_object(anObjectId.in());
429
430   //deleteAuxIDSources();
431   delete myPreviewMesh;   myPreviewMesh = 0;
432   delete myPreviewEditor; myPreviewEditor = 0;
433 }
434
435 //================================================================================
436 /*!
437  * \brief Returns the mesh
438  */
439 //================================================================================
440
441 SMESH::SMESH_Mesh_ptr SMESH_MeshEditor_i::GetMesh()
442 {
443   return myMesh_i->_this();
444 }
445
446 //================================================================================
447 /*!
448  * \brief Clear members
449  */
450 //================================================================================
451
452 void SMESH_MeshEditor_i::initData(bool deleteSearchers)
453 {
454   if ( myIsPreviewMode ) {
455     if ( myPreviewMesh ) myPreviewMesh->RemoveAll();
456   }
457   else {
458     if ( deleteSearchers )
459       TSearchersDeleter::Delete();
460   }
461   getEditor().GetError().reset();
462   getEditor().ClearLastCreated();
463 }
464
465 //================================================================================
466 /*!
467  * \brief Increment mesh modif time and optionally record that the performed
468  *        modification may influence further mesh re-compute.
469  *  \param [in] isReComputeSafe - true if the modification does not influence
470  *              further mesh re-compute
471  */
472 //================================================================================
473
474 void SMESH_MeshEditor_i::declareMeshModified( bool isReComputeSafe )
475 {
476   myMesh->GetMeshDS()->Modified();
477   if ( !isReComputeSafe )
478     myMesh->SetIsModified( true );
479 }
480
481 //================================================================================
482 /*!
483  * \brief Return either myEditor or myPreviewEditor depending on myIsPreviewMode.
484  *        WARNING: in preview mode call getPreviewMesh() before getEditor()!
485  */
486 //================================================================================
487
488 ::SMESH_MeshEditor& SMESH_MeshEditor_i::getEditor()
489 {
490   if ( myIsPreviewMode && !myPreviewEditor ) {
491     if ( !myPreviewMesh ) getPreviewMesh();
492     myPreviewEditor = new ::SMESH_MeshEditor( myPreviewMesh );
493   }
494   return myIsPreviewMode ? *myPreviewEditor : myEditor;
495 }
496
497 //================================================================================
498 /*!
499  * \brief Initialize and return myPreviewMesh
500  *  \param previewElements - type of elements to show in preview
501  *
502  *  WARNING: call it once per method!
503  */
504 //================================================================================
505
506 TPreviewMesh * SMESH_MeshEditor_i::getPreviewMesh(SMDSAbs_ElementType previewElements)
507 {
508   if ( !myPreviewMesh || myPreviewMesh->myPreviewType != previewElements )
509   {
510     delete myPreviewEditor;
511     myPreviewEditor = 0;
512     delete myPreviewMesh;
513     myPreviewMesh = new TPreviewMesh( previewElements );
514   }
515   myPreviewMesh->Clear();
516   return myPreviewMesh;
517 }
518
519 //================================================================================
520 /*!
521  * Return data of mesh edition preview
522  */
523 //================================================================================
524
525 SMESH::MeshPreviewStruct* SMESH_MeshEditor_i::GetPreviewData()
526 {
527   SMESH_TRY;
528   const bool hasBadElems = ( getEditor().GetError() && getEditor().GetError()->HasBadElems() );
529
530   if ( myIsPreviewMode || hasBadElems )
531   {
532     list<int> aNodesConnectivity;
533     typedef map<int, int> TNodesMap;
534     TNodesMap nodesMap;
535
536     SMESHDS_Mesh* aMeshDS;
537     std::unique_ptr< SMESH_MeshPartDS > aMeshPartDS;
538     if ( hasBadElems ) {
539       const list<const SMDS_MeshElement*>& badElems =
540         static_cast<SMESH_BadInputElements*>( getEditor().GetError().get() )->myBadElements;
541       aMeshPartDS.reset( new SMESH_MeshPartDS( badElems ));
542       aMeshDS = aMeshPartDS.get();
543     }
544     else {
545       aMeshDS = getEditor().GetMeshDS();
546     }
547     myPreviewData = new SMESH::MeshPreviewStruct();
548     myPreviewData->nodesXYZ.length(aMeshDS->NbNodes());
549
550
551     SMDSAbs_ElementType previewType = SMDSAbs_All;
552     if ( !hasBadElems )
553       if (TPreviewMesh * aPreviewMesh = dynamic_cast< TPreviewMesh* >( getEditor().GetMesh() )) {
554         previewType = aPreviewMesh->myPreviewType;
555         switch ( previewType ) {
556         case SMDSAbs_Edge  : break;
557         case SMDSAbs_Face  : break;
558         case SMDSAbs_Volume: break;
559         default:;
560           if ( aMeshDS->GetMeshInfo().NbElements() == 0 ) previewType = SMDSAbs_Node;
561         }
562       }
563
564     myPreviewData->elementTypes.length( aMeshDS->GetMeshInfo().NbElements( previewType ));
565     int i = 0, j = 0;
566     SMDS_ElemIteratorPtr itMeshElems = aMeshDS->elementsIterator(previewType);
567
568     while ( itMeshElems->more() ) {
569       const SMDS_MeshElement* aMeshElem = itMeshElems->next();
570       SMDS_NodeIteratorPtr itElemNodes = 
571         (( aMeshElem->GetEntityType() == SMDSEntity_Quad_Polygon ) ?
572          aMeshElem->interlacedNodesIterator() :
573          aMeshElem->nodeIterator() );
574       while ( itElemNodes->more() ) {
575         const SMDS_MeshNode* aMeshNode = itElemNodes->next();
576         int aNodeID = aMeshNode->GetID();
577         TNodesMap::iterator anIter = nodesMap.find(aNodeID);
578         if ( anIter == nodesMap.end() ) {
579           // filling the nodes coordinates
580           myPreviewData->nodesXYZ[j].x = aMeshNode->X();
581           myPreviewData->nodesXYZ[j].y = aMeshNode->Y();
582           myPreviewData->nodesXYZ[j].z = aMeshNode->Z();
583           anIter = nodesMap.insert( make_pair(aNodeID, j) ).first;
584           j++;
585         }
586         aNodesConnectivity.push_back(anIter->second);
587       }
588
589       // filling the elements types
590       SMDSAbs_ElementType aType = aMeshElem->GetType();
591       bool               isPoly = aMeshElem->IsPoly();
592       myPreviewData->elementTypes[i].SMDS_ElementType = (SMESH::ElementType) aType;
593       myPreviewData->elementTypes[i].isPoly           = isPoly;
594       myPreviewData->elementTypes[i].nbNodesInElement = aMeshElem->NbNodes();
595       i++;
596     }
597     myPreviewData->nodesXYZ.length( j );
598
599     // filling the elements connectivities
600     list<int>::iterator aConnIter = aNodesConnectivity.begin();
601     myPreviewData->elementConnectivities.length(aNodesConnectivity.size());
602     for( int i = 0; aConnIter != aNodesConnectivity.end(); aConnIter++, i++ )
603       myPreviewData->elementConnectivities[i] = *aConnIter;
604   }
605   return myPreviewData._retn();
606
607   SMESH_CATCH( SMESH::throwCorbaException );
608   return 0;
609 }
610
611 //================================================================================
612 /*!
613  * \brief Returns list of it's IDs of created nodes
614  * \retval SMESH::long_array* - list of node ID
615  */
616 //================================================================================
617
618 SMESH::long_array* SMESH_MeshEditor_i::GetLastCreatedNodes()
619 {
620   SMESH_TRY;
621   SMESH::long_array_var myLastCreatedNodes = new SMESH::long_array();
622
623   const SMESH_SequenceOfElemPtr& aSeq = getEditor().GetLastCreatedNodes();
624   myLastCreatedNodes->length( aSeq.size() );
625   for ( size_t i = 0; i < aSeq.size(); i++)
626     myLastCreatedNodes[i] = aSeq[i]->GetID();
627
628   return myLastCreatedNodes._retn();
629   SMESH_CATCH( SMESH::throwCorbaException );
630   return 0;
631 }
632
633 //================================================================================
634 /*!
635  * \brief Returns list of it's IDs of created elements
636  * \retval SMESH::long_array* - list of elements' ID
637  */
638 //================================================================================
639
640 SMESH::long_array* SMESH_MeshEditor_i::GetLastCreatedElems()
641 {
642   SMESH_TRY;
643   SMESH::long_array_var myLastCreatedElems = new SMESH::long_array();
644
645   const SMESH_SequenceOfElemPtr& aSeq = getEditor().GetLastCreatedElems();
646   myLastCreatedElems->length( aSeq.size() );
647   for ( size_t i = 0; i < aSeq.size(); i++ )
648     myLastCreatedElems[i] = aSeq[i]->GetID();
649
650   return myLastCreatedElems._retn();
651   SMESH_CATCH( SMESH::throwCorbaException );
652   return 0;
653 }
654
655 //=======================================================================
656 //function : ClearLastCreated
657 //purpose  : Clears sequences of last created elements and nodes 
658 //=======================================================================
659
660 void SMESH_MeshEditor_i::ClearLastCreated()
661 {
662   SMESH_TRY;
663   getEditor().ClearLastCreated();
664   SMESH_CATCH( SMESH::throwCorbaException );
665 }
666
667 //=======================================================================
668 /*
669  * Returns description of an error/warning occurred during the last operation
670  * WARNING: ComputeError.code >= 100 and no corresponding enum in IDL API
671  */
672 //=======================================================================
673
674 SMESH::ComputeError* SMESH_MeshEditor_i::GetLastError()
675 {
676   SMESH_TRY;
677   SMESH::ComputeError_var errOut = new SMESH::ComputeError;
678   SMESH_ComputeErrorPtr&  errIn  = getEditor().GetError();
679   if ( errIn && !errIn->IsOK() )
680   {
681     errOut->code       = -( errIn->myName < 0 ? errIn->myName + 1: errIn->myName ); // -1 -> 0
682     errOut->comment    = errIn->myComment.c_str();
683     errOut->subShapeID = -1;
684     errOut->hasBadMesh = errIn->HasBadElems();
685   }
686   else
687   {
688     errOut->code       = 0;
689     errOut->subShapeID = -1;
690     errOut->hasBadMesh = false;
691   }
692
693   return errOut._retn();
694   SMESH_CATCH( SMESH::throwCorbaException );
695   return 0;
696 }
697
698 //=======================================================================
699 //function : MakeIDSource
700 //purpose  : Wrap a sequence of ids in a SMESH_IDSource.
701 //           Call UnRegister() as you fininsh using it!!
702 //=======================================================================
703
704 struct SMESH_MeshEditor_i::_IDSource : public virtual POA_SMESH::SMESH_IDSource,
705                                        public virtual SALOME::GenericObj_i
706 {
707   SMESH::long_array     _ids;
708   SMESH::ElementType    _type;
709   SMESH::SMESH_Mesh_ptr _mesh;
710   SMESH::long_array* GetIDs()      { return new SMESH::long_array( _ids ); }
711   SMESH::long_array* GetMeshInfo() { return 0; }
712   SMESH::long_array* GetNbElementsByType()
713   {
714     SMESH::long_array_var aRes = new SMESH::long_array();
715     aRes->length(SMESH::NB_ELEMENT_TYPES);
716     for (int i = 0; i < SMESH::NB_ELEMENT_TYPES; i++)
717       aRes[ i ] = ( i == _type ) ? _ids.length() : 0;
718     return aRes._retn();  
719   }
720   SMESH::SMESH_Mesh_ptr GetMesh()  { return SMESH::SMESH_Mesh::_duplicate( _mesh ); }
721   bool IsMeshInfoCorrect()         { return true; }
722   SMESH::array_of_ElementType* GetTypes()
723   {
724     SMESH::array_of_ElementType_var types = new SMESH::array_of_ElementType;
725     if ( _ids.length() > 0 ) {
726       types->length( 1 );
727       types[0] = _type;
728     }
729     return types._retn();
730   }
731   SALOMEDS::TMPFile* GetVtkUgStream()
732   {
733     SALOMEDS::TMPFile_var SeqFile;
734     return SeqFile._retn();
735   }
736 };
737
738 SMESH::SMESH_IDSource_ptr SMESH_MeshEditor_i::MakeIDSource(const SMESH::long_array& ids,
739                                                            SMESH::ElementType       type)
740 {
741   _IDSource* idSrc = new _IDSource;
742   idSrc->_mesh = myMesh_i->_this();
743   idSrc->_ids  = ids;
744   idSrc->_type = type;
745   if ( type == SMESH::ALL && ids.length() > 0 )
746     idSrc->_type = myMesh_i->GetElementType( ids[0], true );
747
748   SMESH::SMESH_IDSource_var anIDSourceVar = idSrc->_this();
749
750   return anIDSourceVar._retn();
751 }
752
753 bool SMESH_MeshEditor_i::IsTemporaryIDSource( SMESH::SMESH_IDSource_ptr& idSource )
754 {
755   return SMESH::DownCast<SMESH_MeshEditor_i::_IDSource*>( idSource );
756 }
757
758 CORBA::Long* SMESH_MeshEditor_i::GetTemporaryIDs( SMESH::SMESH_IDSource_ptr& idSource,
759                                                   int&                       nbIds)
760 {
761   if ( _IDSource* tmpIdSource = SMESH::DownCast<SMESH_MeshEditor_i::_IDSource*>( idSource ))
762   {
763     nbIds = (int) tmpIdSource->_ids.length();
764     return & tmpIdSource->_ids[0];
765   }
766   nbIds = 0;
767   return 0;
768 }
769
770 // void SMESH_MeshEditor_i::deleteAuxIDSources()
771 // {
772 //   std::list< _IDSource* >::iterator idSrcIt = myAuxIDSources.begin();
773 //   for ( ; idSrcIt != myAuxIDSources.end(); ++idSrcIt )
774 //     delete *idSrcIt;
775 //   myAuxIDSources.clear();
776 // }
777
778 //=============================================================================
779 /*!
780  *
781  */
782 //=============================================================================
783
784 CORBA::Boolean
785 SMESH_MeshEditor_i::RemoveElements(const SMESH::long_array & IDsOfElements)
786 {
787   SMESH_TRY;
788   initData();
789
790   list< int > IdList;
791
792   for ( CORBA::ULong i = 0; i < IDsOfElements.length(); i++ )
793     IdList.push_back( IDsOfElements[i] );
794
795   // Update Python script
796   TPythonDump() << "isDone = " << this << ".RemoveElements( " << IDsOfElements << " )";
797
798   // Remove Elements
799   bool ret = getEditor().Remove( IdList, false );
800
801   declareMeshModified( /*isReComputeSafe=*/ IDsOfElements.length() == 0 ); // issue 0020693
802   return ret;
803
804   SMESH_CATCH( SMESH::throwCorbaException );
805   return 0;
806 }
807
808 //=============================================================================
809 /*!
810  *
811  */
812 //=============================================================================
813
814 CORBA::Boolean SMESH_MeshEditor_i::RemoveNodes(const SMESH::long_array & IDsOfNodes)
815 {
816   SMESH_TRY;
817   initData();
818
819   list< int > IdList;
820   for ( CORBA::ULong i = 0; i < IDsOfNodes.length(); i++)
821     IdList.push_back( IDsOfNodes[i] );
822
823   // Update Python script
824   TPythonDump() << "isDone = " << this << ".RemoveNodes( " << IDsOfNodes << " )";
825
826   bool ret = getEditor().Remove( IdList, true );
827
828   declareMeshModified( /*isReComputeSafe=*/ !ret ); // issue 0020693
829   return ret;
830
831   SMESH_CATCH( SMESH::throwCorbaException );
832   return 0;
833 }
834
835 //=============================================================================
836 /*!
837  *
838  */
839 //=============================================================================
840
841 CORBA::Long SMESH_MeshEditor_i::RemoveOrphanNodes()
842 {
843   SMESH_TRY;
844   initData();
845
846   // Update Python script
847   TPythonDump() << "nbRemoved = " << this << ".RemoveOrphanNodes()";
848
849   // Create filter to find all orphan nodes
850   SMESH::Controls::Filter::TIdSequence seq;
851   SMESH::Controls::PredicatePtr predicate( new SMESH::Controls::FreeNodes() );
852   SMESH::Controls::Filter::GetElementsId( getMeshDS(), predicate, seq );
853
854   // remove orphan nodes (if there are any)
855   list< int > IdList( seq.begin(), seq.end() );
856
857   int nbNodesBefore = myMesh->NbNodes();
858   getEditor().Remove( IdList, true );
859   int nbNodesAfter = myMesh->NbNodes();
860
861   declareMeshModified( /*isReComputeSafe=*/ IdList.size() == 0 ); // issue 0020693
862   return nbNodesBefore - nbNodesAfter;
863
864   SMESH_CATCH( SMESH::throwCorbaException );
865   return 0;
866 }
867
868 //=============================================================================
869 /*!
870  * Add a new node.
871  */
872 //=============================================================================
873
874 CORBA::Long SMESH_MeshEditor_i::AddNode(CORBA::Double x,CORBA::Double y, CORBA::Double z)
875 {
876   SMESH_TRY;
877   initData();
878
879   const SMDS_MeshNode* N = getMeshDS()->AddNode(x, y, z);
880
881   // Update Python script
882   TPythonDump() << "nodeID = " << this << ".AddNode( "
883                 << TVar( x ) << ", " << TVar( y ) << ", " << TVar( z )<< " )";
884
885   declareMeshModified( /*isReComputeSafe=*/false );
886   return N->GetID();
887
888   SMESH_CATCH( SMESH::throwCorbaException );
889   return 0;
890 }
891
892 //=============================================================================
893 /*!
894  * Create 0D element on the given node.
895  */
896 //=============================================================================
897
898 CORBA::Long SMESH_MeshEditor_i::Add0DElement(CORBA::Long    IDOfNode,
899                                              CORBA::Boolean DuplicateElements)
900 {
901   SMESH_TRY;
902   initData();
903
904   const SMDS_MeshNode* aNode = getMeshDS()->FindNode(IDOfNode);
905   SMDS_ElemIteratorPtr it0D = aNode->GetInverseElementIterator( SMDSAbs_0DElement );
906   
907   SMDS_MeshElement* elem = 0;
908   if ( DuplicateElements || !it0D->more() )
909     elem = getMeshDS()->Add0DElement(aNode);
910
911   // Update Python script
912   TPythonDump() << "elem0d = " << this << ".Add0DElement( " << IDOfNode <<" )";
913
914   declareMeshModified( /*isReComputeSafe=*/false );
915
916   return elem ? elem->GetID() : 0;
917
918   SMESH_CATCH( SMESH::throwCorbaException );
919   return 0;
920 }
921
922 //=============================================================================
923 /*!
924  * Create a ball element on the given node.
925  */
926 //=============================================================================
927
928 CORBA::Long SMESH_MeshEditor_i::AddBall(CORBA::Long IDOfNode, CORBA::Double diameter)
929 {
930   SMESH_TRY;
931   initData();
932
933   if ( diameter < std::numeric_limits<double>::min() )
934     THROW_SALOME_CORBA_EXCEPTION("Invalid diameter", SALOME::BAD_PARAM);
935
936   const SMDS_MeshNode* aNode = getMeshDS()->FindNode(IDOfNode);
937   SMDS_MeshElement* elem = getMeshDS()->AddBall(aNode, diameter);
938
939   // Update Python script
940   TPythonDump() << "ballElem = "
941                 << this << ".AddBall( " << IDOfNode << ", " << diameter <<" )";
942
943   declareMeshModified( /*isReComputeSafe=*/false );
944   return elem ? elem->GetID() : 0;
945
946   SMESH_CATCH( SMESH::throwCorbaException );
947   return 0;
948 }
949
950 //=============================================================================
951 /*!
952  * Create an edge, either linear and quadratic (this is determed
953  *  by number of given nodes, two or three)
954  */
955 //=============================================================================
956
957 CORBA::Long SMESH_MeshEditor_i::AddEdge(const SMESH::long_array & IDsOfNodes)
958 {
959   SMESH_TRY;
960   initData();
961
962   int NbNodes = IDsOfNodes.length();
963   SMDS_MeshElement* elem = 0;
964   if (NbNodes == 2)
965   {
966     CORBA::Long index1 = IDsOfNodes[0];
967     CORBA::Long index2 = IDsOfNodes[1];
968     elem = getMeshDS()->AddEdge( getMeshDS()->FindNode(index1),
969                                  getMeshDS()->FindNode(index2));
970
971     // Update Python script
972     TPythonDump() << "edge = " << this << ".AddEdge([ "
973                   << index1 << ", " << index2 <<" ])";
974   }
975   if (NbNodes == 3) {
976     CORBA::Long n1 = IDsOfNodes[0];
977     CORBA::Long n2 = IDsOfNodes[1];
978     CORBA::Long n12 = IDsOfNodes[2];
979     elem = getMeshDS()->AddEdge( getMeshDS()->FindNode(n1),
980                                  getMeshDS()->FindNode(n2),
981                                  getMeshDS()->FindNode(n12));
982     // Update Python script
983     TPythonDump() << "edgeID = " << this << ".AddEdge([ "
984                   <<n1<<", "<<n2<<", "<<n12<<" ])";
985   }
986
987   declareMeshModified( /*isReComputeSafe=*/false );
988   return elem ? elem->GetID() : 0;
989
990   SMESH_CATCH( SMESH::throwCorbaException );
991   return 0;
992 }
993
994 //=============================================================================
995 /*!
996  *  AddFace
997  */
998 //=============================================================================
999
1000 CORBA::Long SMESH_MeshEditor_i::AddFace(const SMESH::long_array & IDsOfNodes)
1001 {
1002   SMESH_TRY;
1003   initData();
1004
1005   int NbNodes = IDsOfNodes.length();
1006   if (NbNodes < 3)
1007   {
1008     return 0;
1009   }
1010
1011   std::vector<const SMDS_MeshNode*> nodes (NbNodes);
1012   for (int i = 0; i < NbNodes; i++)
1013     nodes[i] = getMeshDS()->FindNode(IDsOfNodes[i]);
1014
1015   SMDS_MeshElement* elem = 0;
1016   switch (NbNodes) {
1017   case 3: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2]); break;
1018   case 4: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3]); break;
1019   case 6: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
1020                                       nodes[4], nodes[5]); break;
1021   case 7: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
1022                                       nodes[4], nodes[5], nodes[6]); break;
1023   case 8: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
1024                                       nodes[4], nodes[5], nodes[6], nodes[7]); break;
1025   case 9: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
1026                                       nodes[4], nodes[5], nodes[6], nodes[7],
1027                                       nodes[8] ); break;
1028   default: elem = getMeshDS()->AddPolygonalFace(nodes);
1029   }
1030
1031   // Update Python script
1032   TPythonDump() << "faceID = " << this << ".AddFace( " << IDsOfNodes << " )";
1033
1034   declareMeshModified( /*isReComputeSafe=*/false );
1035
1036   return elem ? elem->GetID() : 0;
1037
1038   SMESH_CATCH( SMESH::throwCorbaException );
1039   return 0;
1040 }
1041
1042 //=============================================================================
1043 /*!
1044  *  AddPolygonalFace
1045  */
1046 //=============================================================================
1047
1048 CORBA::Long SMESH_MeshEditor_i::AddPolygonalFace (const SMESH::long_array & IDsOfNodes)
1049 {
1050   SMESH_TRY;
1051   initData();
1052
1053   int NbNodes = IDsOfNodes.length();
1054   std::vector<const SMDS_MeshNode*> nodes (NbNodes);
1055   for (int i = 0; i < NbNodes; i++)
1056     if ( ! ( nodes[i] = getMeshDS()->FindNode( IDsOfNodes[i] )))
1057       return 0;
1058
1059   if ( NbNodes == 0 )
1060   {
1061     INFOS("Polygon without nodes is forbidden");
1062     return 0;
1063   }
1064
1065   const SMDS_MeshElement* elem = getMeshDS()->AddPolygonalFace(nodes);
1066
1067   // Update Python script
1068   TPythonDump() <<"faceID = "<<this<<".AddPolygonalFace( "<<IDsOfNodes<<" )";
1069
1070   declareMeshModified( /*isReComputeSafe=*/false );
1071   return elem ? elem->GetID() : 0;
1072
1073   SMESH_CATCH( SMESH::throwCorbaException );
1074   return 0;
1075 }
1076
1077 //=============================================================================
1078 /*!
1079  *  AddQuadPolygonalFace
1080  */
1081 //=============================================================================
1082
1083 CORBA::Long SMESH_MeshEditor_i::AddQuadPolygonalFace (const SMESH::long_array & IDsOfNodes)
1084 {
1085   SMESH_TRY;
1086   initData();
1087
1088   int NbNodes = IDsOfNodes.length();
1089   std::vector<const SMDS_MeshNode*> nodes (NbNodes);
1090   for (int i = 0; i < NbNodes; i++)
1091     nodes[i] = getMeshDS()->FindNode(IDsOfNodes[i]);
1092
1093   if ( NbNodes == 0 )
1094   {
1095     INFOS("Polygon without nodes is forbidden");
1096     return 0;
1097   }
1098
1099   const SMDS_MeshElement* elem = getMeshDS()->AddQuadPolygonalFace(nodes);
1100
1101   // Update Python script
1102   TPythonDump() <<"faceID = "<<this<<".AddPolygonalFace( "<<IDsOfNodes<<" )";
1103
1104   declareMeshModified( /*isReComputeSafe=*/false );
1105   return elem ? elem->GetID() : 0;
1106
1107   SMESH_CATCH( SMESH::throwCorbaException );
1108   return 0;
1109 }
1110
1111 //=============================================================================
1112 /*!
1113  * Create volume, either linear and quadratic (this is determed
1114  *  by number of given nodes)
1115  */
1116 //=============================================================================
1117
1118 CORBA::Long SMESH_MeshEditor_i::AddVolume(const SMESH::long_array & IDsOfNodes)
1119 {
1120   SMESH_TRY;
1121   initData();
1122
1123   int NbNodes = IDsOfNodes.length();
1124   vector< const SMDS_MeshNode*> n(NbNodes);
1125   for(int i=0;i<NbNodes;i++)
1126     n[i]= getMeshDS()->FindNode(IDsOfNodes[i]);
1127
1128   SMDS_MeshElement* elem = 0;
1129   switch(NbNodes)
1130   {
1131   case 4 :elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3]); break;
1132   case 5 :elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4]); break;
1133   case 6 :elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5]); break;
1134   case 8 :elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7]); break;
1135   case 10:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],
1136                                         n[6],n[7],n[8],n[9]);
1137     break;
1138   case 12:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],
1139                                         n[6],n[7],n[8],n[9],n[10],n[11]);
1140     break;
1141   case 13:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],
1142                                         n[7],n[8],n[9],n[10],n[11],n[12]);
1143     break;
1144   case 15:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7],n[8],
1145                                         n[9],n[10],n[11],n[12],n[13],n[14]);
1146     break;
1147   case 20:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7],
1148                                         n[8],n[9],n[10],n[11],n[12],n[13],n[14],
1149                                         n[15],n[16],n[17],n[18],n[19]);
1150     break;
1151   case 18:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7],
1152                                         n[8],n[9],n[10],n[11],n[12],n[13],n[14],
1153                                         n[15],n[16],n[17]);
1154     break;
1155   case 27:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7],
1156                                         n[8],n[9],n[10],n[11],n[12],n[13],n[14],
1157                                         n[15],n[16],n[17],n[18],n[19],
1158                                         n[20],n[21],n[22],n[23],n[24],n[25],n[26]);
1159     break;
1160   }
1161
1162   // Update Python script
1163   TPythonDump() << "volID = " << this << ".AddVolume( " << IDsOfNodes << " )";
1164
1165   declareMeshModified( /*isReComputeSafe=*/false );
1166   return elem ? elem->GetID() : 0;
1167
1168   SMESH_CATCH( SMESH::throwCorbaException );
1169   return 0;
1170 }
1171
1172 //=============================================================================
1173 /*!
1174  *  AddPolyhedralVolume
1175  */
1176 //=============================================================================
1177 CORBA::Long SMESH_MeshEditor_i::AddPolyhedralVolume (const SMESH::long_array & IDsOfNodes,
1178                                                      const SMESH::long_array & Quantities)
1179 {
1180   SMESH_TRY;
1181   initData();
1182
1183   int NbNodes = IDsOfNodes.length();
1184   std::vector<const SMDS_MeshNode*> n (NbNodes);
1185   for (int i = 0; i < NbNodes; i++)
1186     {
1187       const SMDS_MeshNode* aNode = getMeshDS()->FindNode(IDsOfNodes[i]);
1188       if (!aNode) return 0;
1189       n[i] = aNode;
1190     }
1191
1192   int NbFaces = Quantities.length();
1193   std::vector<int> q (NbFaces);
1194   for (int j = 0; j < NbFaces; j++)
1195     q[j] = Quantities[j];
1196
1197   const SMDS_MeshElement* elem = getMeshDS()->AddPolyhedralVolume(n, q);
1198
1199   // Update Python script
1200   TPythonDump() << "volID = " << this << ".AddPolyhedralVolume( "
1201                 << IDsOfNodes << ", " << Quantities << " )";
1202
1203   declareMeshModified( /*isReComputeSafe=*/false );
1204   return elem ? elem->GetID() : 0;
1205
1206   SMESH_CATCH( SMESH::throwCorbaException );
1207   return 0;
1208 }
1209
1210 //=============================================================================
1211 /*!
1212  *  AddPolyhedralVolumeByFaces
1213  */
1214 //=============================================================================
1215
1216 CORBA::Long SMESH_MeshEditor_i::AddPolyhedralVolumeByFaces (const SMESH::long_array & IdsOfFaces)
1217 {
1218   SMESH_TRY;
1219   initData();
1220
1221   int NbFaces = IdsOfFaces.length();
1222   std::vector<const SMDS_MeshNode*> poly_nodes;
1223   std::vector<int> quantities (NbFaces);
1224
1225   for (int i = 0; i < NbFaces; i++) {
1226     const SMDS_MeshElement* aFace = getMeshDS()->FindElement(IdsOfFaces[i]);
1227     quantities[i] = aFace->NbNodes();
1228
1229     SMDS_ElemIteratorPtr It = aFace->nodesIterator();
1230     while (It->more()) {
1231       poly_nodes.push_back(static_cast<const SMDS_MeshNode *>(It->next()));
1232     }
1233   }
1234
1235   const SMDS_MeshElement* elem = getMeshDS()->AddPolyhedralVolume(poly_nodes, quantities);
1236
1237   // Update Python script
1238   TPythonDump() << "volID = " << this << ".AddPolyhedralVolumeByFaces( "
1239                 << IdsOfFaces << " )";
1240
1241   declareMeshModified( /*isReComputeSafe=*/false );
1242   return elem ? elem->GetID() : 0;
1243
1244   SMESH_CATCH( SMESH::throwCorbaException );
1245   return 0;
1246 }
1247
1248 //=============================================================================
1249 //
1250 // \brief Create 0D elements on all nodes of the given object.
1251 //  \param theObject object on whose nodes 0D elements will be created.
1252 //  \param theGroupName optional name of a group to add 0D elements created
1253 //         and/or found on nodes of \a theObject.
1254 //  \param DuplicateElements to add one more 0D element to a node or not.
1255 //  \return an object (a new group or a temporary SMESH_IDSource) holding
1256 //          ids of new and/or found 0D elements.
1257 //
1258 //=============================================================================
1259
1260 SMESH::SMESH_IDSource_ptr
1261 SMESH_MeshEditor_i::Create0DElementsOnAllNodes(SMESH::SMESH_IDSource_ptr theObject,
1262                                                const char*               theGroupName,
1263                                                CORBA::Boolean            theDuplicateElements)
1264 {
1265   SMESH_TRY;
1266   initData();
1267
1268   SMESH::SMESH_IDSource_var result;
1269   TPythonDump pyDump;
1270
1271   TIDSortedElemSet elements, elems0D;
1272   if ( idSourceToSet( theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
1273     getEditor().Create0DElementsOnAllNodes( elements, elems0D, theDuplicateElements );
1274
1275   SMESH::long_array_var newElems = new SMESH::long_array;
1276   newElems->length( elems0D.size() );
1277   TIDSortedElemSet::iterator eIt = elems0D.begin();
1278   for ( size_t i = 0; i < elems0D.size(); ++i, ++eIt )
1279     newElems[ i ] = (*eIt)->GetID();
1280
1281   SMESH::SMESH_GroupBase_var groupToFill;
1282   if ( theGroupName && strlen( theGroupName ))
1283   {
1284     // Get existing group named theGroupName
1285     SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
1286     for (int i = 0, nbGroups = groups->length(); i < nbGroups; i++ ) {
1287       SMESH::SMESH_GroupBase_var group = groups[i];
1288       if ( !group->_is_nil() ) {
1289         CORBA::String_var name = group->GetName();
1290         if ( strcmp( name.in(), theGroupName ) == 0 && group->GetType() == SMESH::ELEM0D ) {
1291           groupToFill = group;
1292           break;
1293         }
1294       }
1295     }
1296     if ( groupToFill->_is_nil() )
1297       groupToFill = myMesh_i->CreateGroup( SMESH::ELEM0D, theGroupName );
1298     else if ( !SMESH::DownCast< SMESH_Group_i* > ( groupToFill ))
1299       groupToFill = myMesh_i->ConvertToStandalone( groupToFill );
1300   }
1301
1302   if ( SMESH_Group_i* group_i = SMESH::DownCast< SMESH_Group_i* > ( groupToFill ))
1303   {
1304     group_i->Add( newElems );
1305     result = SMESH::SMESH_IDSource::_narrow( groupToFill );
1306     pyDump << groupToFill;
1307   }
1308   else
1309   {
1310     result = MakeIDSource( newElems, SMESH::ELEM0D );
1311     pyDump << "elem0DIDs";
1312   }
1313
1314   pyDump << " = " << this << ".Create0DElementsOnAllNodes( "
1315          << theObject << ", '" << theGroupName << "' )";
1316
1317   return result._retn();
1318
1319   SMESH_CATCH( SMESH::throwCorbaException );
1320   return 0;
1321 }
1322
1323 //=============================================================================
1324 /*!
1325  * \brief Bind a node to a vertex
1326  * \param NodeID - node ID
1327  * \param VertexID - vertex ID available through GEOM_Object.GetSubShapeIndices()[0]
1328  * \retval boolean - false if NodeID or VertexID is invalid
1329  */
1330 //=============================================================================
1331
1332 void SMESH_MeshEditor_i::SetNodeOnVertex(CORBA::Long NodeID, CORBA::Long VertexID)
1333 {
1334   SMESH_TRY;
1335
1336   SMESHDS_Mesh * mesh = getMeshDS();
1337   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
1338   if ( !node )
1339     THROW_SALOME_CORBA_EXCEPTION("Invalid NodeID", SALOME::BAD_PARAM);
1340
1341   if ( mesh->MaxShapeIndex() < VertexID )
1342     THROW_SALOME_CORBA_EXCEPTION("Invalid VertexID", SALOME::BAD_PARAM);
1343
1344   TopoDS_Shape shape = mesh->IndexToShape( VertexID );
1345   if ( shape.ShapeType() != TopAbs_VERTEX )
1346     THROW_SALOME_CORBA_EXCEPTION("Invalid VertexID", SALOME::BAD_PARAM);
1347
1348   mesh->SetNodeOnVertex( node, VertexID );
1349
1350   myMesh->SetIsModified( true );
1351
1352   SMESH_CATCH( SMESH::throwCorbaException );
1353 }
1354
1355 //=============================================================================
1356 /*!
1357  * \brief Store node position on an edge
1358  * \param NodeID - node ID
1359  * \param EdgeID - edge ID available through GEOM_Object.GetSubShapeIndices()[0]
1360  * \param paramOnEdge - parameter on edge where the node is located
1361  * \retval boolean - false if any parameter is invalid
1362  */
1363 //=============================================================================
1364
1365 void SMESH_MeshEditor_i::SetNodeOnEdge(CORBA::Long NodeID, CORBA::Long EdgeID,
1366                                        CORBA::Double paramOnEdge)
1367 {
1368   SMESH_TRY;
1369
1370   SMESHDS_Mesh * mesh = getMeshDS();
1371   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
1372   if ( !node )
1373     THROW_SALOME_CORBA_EXCEPTION("Invalid NodeID", SALOME::BAD_PARAM);
1374
1375   if ( mesh->MaxShapeIndex() < EdgeID )
1376     THROW_SALOME_CORBA_EXCEPTION("Invalid EdgeID", SALOME::BAD_PARAM);
1377
1378   TopoDS_Shape shape = mesh->IndexToShape( EdgeID );
1379   if ( shape.ShapeType() != TopAbs_EDGE )
1380     THROW_SALOME_CORBA_EXCEPTION("Invalid EdgeID", SALOME::BAD_PARAM);
1381
1382   Standard_Real f,l;
1383   BRep_Tool::Range( TopoDS::Edge( shape ), f,l);
1384   if ( paramOnEdge < f || paramOnEdge > l )
1385   {
1386     SMESH_Comment txt("Invalid paramOnEdge. It must vary in range [ ");
1387     txt << f << ", " << l << " ]";
1388     THROW_SALOME_CORBA_EXCEPTION(txt.c_str(), SALOME::BAD_PARAM);
1389   }
1390   mesh->SetNodeOnEdge( node, EdgeID, paramOnEdge );
1391
1392   myMesh->SetIsModified( true );
1393
1394   SMESH_CATCH( SMESH::throwCorbaException );
1395 }
1396
1397 //=============================================================================
1398 /*!
1399  * \brief Store node position on a face
1400  * \param NodeID - node ID
1401  * \param FaceID - face ID available through GEOM_Object.GetSubShapeIndices()[0]
1402  * \param u - U parameter on face where the node is located
1403  * \param v - V parameter on face where the node is located
1404  * \retval boolean - false if any parameter is invalid
1405  */
1406 //=============================================================================
1407
1408 void SMESH_MeshEditor_i::SetNodeOnFace(CORBA::Long NodeID, CORBA::Long FaceID,
1409                                        CORBA::Double u, CORBA::Double v)
1410 {
1411   SMESH_TRY;
1412   SMESHDS_Mesh * mesh = getMeshDS();
1413   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
1414   if ( !node )
1415     THROW_SALOME_CORBA_EXCEPTION("Invalid NodeID", SALOME::BAD_PARAM);
1416
1417   if ( mesh->MaxShapeIndex() < FaceID )
1418     THROW_SALOME_CORBA_EXCEPTION("Invalid FaceID", SALOME::BAD_PARAM);
1419
1420   TopoDS_Shape shape = mesh->IndexToShape( FaceID );
1421   if ( shape.ShapeType() != TopAbs_FACE )
1422     THROW_SALOME_CORBA_EXCEPTION("Invalid FaceID", SALOME::BAD_PARAM);
1423
1424   BRepAdaptor_Surface surf( TopoDS::Face( shape ));
1425   bool isOut = ( u < surf.FirstUParameter() ||
1426                  u > surf.LastUParameter()  ||
1427                  v < surf.FirstVParameter() ||
1428                  v > surf.LastVParameter() );
1429
1430   if ( isOut ) {
1431     SMESH_Comment txt("Invalid UV. U must vary in range [ ");
1432     txt << surf.FirstUParameter() << ", " << surf.LastUParameter() << " ], ";
1433     txt << "V must vary in range [ ";
1434     txt << surf.FirstVParameter() << ", " << surf.LastVParameter() << " ]";
1435     THROW_SALOME_CORBA_EXCEPTION(txt.c_str(), SALOME::BAD_PARAM);
1436   }
1437
1438   mesh->SetNodeOnFace( node, FaceID, u, v );
1439   myMesh->SetIsModified( true );
1440
1441   SMESH_CATCH( SMESH::throwCorbaException );
1442 }
1443
1444 //=============================================================================
1445 /*!
1446  * \brief Bind a node to a solid
1447  * \param NodeID - node ID
1448  * \param SolidID - vertex ID available through GEOM_Object.GetSubShapeIndices()[0]
1449  * \retval boolean - false if NodeID or SolidID is invalid
1450  */
1451 //=============================================================================
1452
1453 void SMESH_MeshEditor_i::SetNodeInVolume(CORBA::Long NodeID, CORBA::Long SolidID)
1454 {
1455   SMESH_TRY;
1456   SMESHDS_Mesh * mesh = getMeshDS();
1457   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
1458   if ( !node )
1459     THROW_SALOME_CORBA_EXCEPTION("Invalid NodeID", SALOME::BAD_PARAM);
1460
1461   if ( mesh->MaxShapeIndex() < SolidID )
1462     THROW_SALOME_CORBA_EXCEPTION("Invalid SolidID", SALOME::BAD_PARAM);
1463
1464   TopoDS_Shape shape = mesh->IndexToShape( SolidID );
1465   if ( shape.ShapeType() != TopAbs_SOLID &&
1466        shape.ShapeType() != TopAbs_SHELL)
1467     THROW_SALOME_CORBA_EXCEPTION("Invalid SolidID", SALOME::BAD_PARAM);
1468
1469   mesh->SetNodeInVolume( node, SolidID );
1470
1471   SMESH_CATCH( SMESH::throwCorbaException );
1472 }
1473
1474 //=============================================================================
1475 /*!
1476  * \brief Bind an element to a shape
1477  * \param ElementID - element ID
1478  * \param ShapeID - shape ID available through GEOM_Object.GetSubShapeIndices()[0]
1479  */
1480 //=============================================================================
1481
1482 void SMESH_MeshEditor_i::SetMeshElementOnShape(CORBA::Long ElementID,
1483                                                CORBA::Long ShapeID)
1484 {
1485   SMESH_TRY;
1486   SMESHDS_Mesh * mesh = getMeshDS();
1487   SMDS_MeshElement* elem = const_cast<SMDS_MeshElement*>(mesh->FindElement(ElementID));
1488   if ( !elem )
1489     THROW_SALOME_CORBA_EXCEPTION("Invalid ElementID", SALOME::BAD_PARAM);
1490
1491   if ( mesh->MaxShapeIndex() < ShapeID || ShapeID < 1 )
1492     THROW_SALOME_CORBA_EXCEPTION("Invalid ShapeID", SALOME::BAD_PARAM);
1493
1494   TopoDS_Shape shape = mesh->IndexToShape( ShapeID );
1495   if ( shape.ShapeType() != TopAbs_EDGE &&
1496        shape.ShapeType() != TopAbs_FACE &&
1497        shape.ShapeType() != TopAbs_SOLID &&
1498        shape.ShapeType() != TopAbs_SHELL )
1499     THROW_SALOME_CORBA_EXCEPTION("Invalid shape type", SALOME::BAD_PARAM);
1500
1501   mesh->SetMeshElementOnShape( elem, ShapeID );
1502
1503   myMesh->SetIsModified( true );
1504
1505   SMESH_CATCH( SMESH::throwCorbaException );
1506 }
1507
1508 //=============================================================================
1509 /*!
1510  *
1511  */
1512 //=============================================================================
1513
1514 CORBA::Boolean SMESH_MeshEditor_i::InverseDiag(CORBA::Long NodeID1,
1515                                                CORBA::Long NodeID2)
1516 {
1517   SMESH_TRY;
1518   initData();
1519
1520   const SMDS_MeshNode * n1 = getMeshDS()->FindNode( NodeID1 );
1521   const SMDS_MeshNode * n2 = getMeshDS()->FindNode( NodeID2 );
1522   if ( !n1 || !n2 )
1523     return false;
1524
1525   // Update Python script
1526   TPythonDump() << "isDone = " << this << ".InverseDiag( "
1527                 << NodeID1 << ", " << NodeID2 << " )";
1528
1529   int ret =  getEditor().InverseDiag ( n1, n2 );
1530
1531   declareMeshModified( /*isReComputeSafe=*/false );
1532   return ret;
1533
1534   SMESH_CATCH( SMESH::throwCorbaException );
1535   return 0;
1536 }
1537
1538 //=============================================================================
1539 /*!
1540  *
1541  */
1542 //=============================================================================
1543
1544 CORBA::Boolean SMESH_MeshEditor_i::DeleteDiag(CORBA::Long NodeID1,
1545                                               CORBA::Long NodeID2)
1546 {
1547   SMESH_TRY;
1548   initData();
1549
1550   const SMDS_MeshNode * n1 = getMeshDS()->FindNode( NodeID1 );
1551   const SMDS_MeshNode * n2 = getMeshDS()->FindNode( NodeID2 );
1552   if ( !n1 || !n2 )
1553     return false;
1554
1555   // Update Python script
1556   TPythonDump() << "isDone = " << this << ".DeleteDiag( "
1557                 << NodeID1 << ", " << NodeID2 <<  " )";
1558
1559
1560   bool stat = getEditor().DeleteDiag ( n1, n2 );
1561
1562   declareMeshModified( /*isReComputeSafe=*/!stat );
1563
1564   return stat;
1565
1566   SMESH_CATCH( SMESH::throwCorbaException );
1567   return 0;
1568 }
1569
1570 //=============================================================================
1571 /*!
1572  *
1573  */
1574 //=============================================================================
1575
1576 CORBA::Boolean SMESH_MeshEditor_i::Reorient(const SMESH::long_array & IDsOfElements)
1577 {
1578   SMESH_TRY;
1579   initData();
1580
1581   for ( CORBA::ULong i = 0; i < IDsOfElements.length(); i++ )
1582   {
1583     CORBA::Long index = IDsOfElements[i];
1584     const SMDS_MeshElement * elem = getMeshDS()->FindElement(index);
1585     if ( elem )
1586       getEditor().Reorient( elem );
1587   }
1588   // Update Python script
1589   TPythonDump() << "isDone = " << this << ".Reorient( " << IDsOfElements << " )";
1590
1591   declareMeshModified( /*isReComputeSafe=*/ IDsOfElements.length() == 0 );
1592   return true;
1593
1594   SMESH_CATCH( SMESH::throwCorbaException );
1595   return 0;
1596 }
1597
1598 //=============================================================================
1599 /*!
1600  *
1601  */
1602 //=============================================================================
1603
1604 CORBA::Boolean SMESH_MeshEditor_i::ReorientObject(SMESH::SMESH_IDSource_ptr theObject)
1605 {
1606   SMESH_TRY;
1607   initData();
1608
1609   TPythonDump aTPythonDump; // suppress dump in Reorient()
1610
1611   prepareIdSource( theObject );
1612
1613   SMESH::long_array_var anElementsId = theObject->GetIDs();
1614   CORBA::Boolean isDone = Reorient(anElementsId);
1615
1616   // Update Python script
1617   aTPythonDump << "isDone = " << this << ".ReorientObject( " << theObject << " )";
1618
1619   declareMeshModified( /*isReComputeSafe=*/ anElementsId->length() == 0 );
1620   return isDone;
1621
1622   SMESH_CATCH( SMESH::throwCorbaException );
1623   return 0;
1624 }
1625
1626 //=======================================================================
1627 //function : Reorient2D
1628 //purpose  : Reorient faces contained in \a the2Dgroup.
1629 //           the2Dgroup   - the mesh or its part to reorient
1630 //           theDirection - desired direction of normal of \a theFace
1631 //           theFace      - ID of face whose orientation is checked.
1632 //           It can be < 1 then \a thePoint is used to find a face.
1633 //           thePoint     - is used to find a face if \a theFace < 1.
1634 //           return number of reoriented elements.
1635 //=======================================================================
1636
1637 CORBA::Long SMESH_MeshEditor_i::Reorient2D(SMESH::SMESH_IDSource_ptr the2Dgroup,
1638                                            const SMESH::DirStruct&   theDirection,
1639                                            CORBA::Long               theFace,
1640                                            const SMESH::PointStruct& thePoint)
1641 {
1642   SMESH_TRY;
1643   initData(/*deleteSearchers=*/false);
1644
1645   TIDSortedElemSet elements;
1646   IDSource_Error error;
1647   idSourceToSet( the2Dgroup, getMeshDS(), elements, SMDSAbs_Face, /*emptyIfIsMesh=*/1, &error );
1648   if ( error == IDSource_EMPTY )
1649     return 0;
1650   if ( error == IDSource_INVALID )
1651     THROW_SALOME_CORBA_EXCEPTION("No faces in given group", SALOME::BAD_PARAM);
1652
1653
1654   const SMDS_MeshElement* face = 0;
1655   if ( theFace > 0 )
1656   {
1657     face = getMeshDS()->FindElement( theFace );
1658     if ( !face )
1659       THROW_SALOME_CORBA_EXCEPTION("Inexistent face given", SALOME::BAD_PARAM);
1660     if ( face->GetType() != SMDSAbs_Face )
1661       THROW_SALOME_CORBA_EXCEPTION("Wrong element type", SALOME::BAD_PARAM);
1662   }
1663   else
1664   {
1665     // create theElementSearcher if needed
1666     theSearchersDeleter.Set( myMesh, getPartIOR( the2Dgroup, SMESH::FACE ));
1667     if ( !theElementSearcher )
1668     {
1669       if ( elements.empty() ) // search in the whole mesh
1670       {
1671         if ( myMesh->NbFaces() == 0 )
1672           THROW_SALOME_CORBA_EXCEPTION("No faces in the mesh", SALOME::BAD_PARAM);
1673
1674         theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() );
1675       }
1676       else
1677       {
1678         typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator > TIter;
1679         SMDS_ElemIteratorPtr elemsIt( new TIter( elements.begin(), elements.end() ));
1680
1681         theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), elemsIt);
1682       }
1683     }
1684     // find a face
1685     gp_Pnt p( thePoint.x, thePoint.y, thePoint.z );
1686     face = theElementSearcher->FindClosestTo( p, SMDSAbs_Face );
1687
1688     if ( !face )
1689       THROW_SALOME_CORBA_EXCEPTION("No face found by point", SALOME::INTERNAL_ERROR );
1690     if ( !elements.empty() && !elements.count( face ))
1691       THROW_SALOME_CORBA_EXCEPTION("Found face is not in the group", SALOME::BAD_PARAM );
1692   }
1693
1694   const SMESH::PointStruct * P = &theDirection.PS;
1695   gp_Vec dirVec( P->x, P->y, P->z );
1696   if ( dirVec.Magnitude() < std::numeric_limits< double >::min() )
1697     THROW_SALOME_CORBA_EXCEPTION("Zero size vector", SALOME::BAD_PARAM);
1698
1699   int nbReori = getEditor().Reorient2D( elements, dirVec, face );
1700
1701   if ( nbReori ) {
1702     declareMeshModified( /*isReComputeSafe=*/false );
1703   }
1704   TPythonDump() << this << ".Reorient2D( "
1705                 << the2Dgroup << ", "
1706                 << theDirection << ", "
1707                 << theFace << ", "
1708                 << thePoint << " )";
1709
1710   return nbReori;
1711
1712   SMESH_CATCH( SMESH::throwCorbaException );
1713   return 0;
1714 }
1715
1716 //=======================================================================
1717 //function : Reorient2DBy3D
1718 //purpose  : Reorient faces basing on orientation of adjacent volumes.
1719 //=======================================================================
1720
1721 CORBA::Long SMESH_MeshEditor_i::Reorient2DBy3D(const SMESH::ListOfIDSources& faceGroups,
1722                                                SMESH::SMESH_IDSource_ptr     volumeGroup,
1723                                                CORBA::Boolean                outsideNormal)
1724 {
1725   SMESH_TRY;
1726   initData();
1727
1728   TIDSortedElemSet volumes;
1729   IDSource_Error volsError;
1730   idSourceToSet( volumeGroup, getMeshDS(), volumes, SMDSAbs_Volume, /*emptyIfMesh=*/1, &volsError);
1731
1732   int nbReori = 0;
1733   for ( size_t i = 0; i < faceGroups.length(); ++i )
1734   {
1735     SMESH::SMESH_IDSource_ptr faceGrp = faceGroups[i].in();
1736
1737     TIDSortedElemSet faces;
1738     IDSource_Error error;
1739     idSourceToSet( faceGrp, getMeshDS(), faces, SMDSAbs_Face, /*emptyIfIsMesh=*/1, &error );
1740     if ( error == IDSource_INVALID && faceGroups.length() == 1 )
1741       THROW_SALOME_CORBA_EXCEPTION("No faces in a given object", SALOME::BAD_PARAM);
1742     if ( error == IDSource_OK && volsError != IDSource_OK )
1743       THROW_SALOME_CORBA_EXCEPTION("No volumes in a given object", SALOME::BAD_PARAM);
1744
1745     nbReori += getEditor().Reorient2DBy3D( faces, volumes, outsideNormal );
1746
1747     if ( error != IDSource_EMPTY && faces.empty() ) // all faces in the mesh treated
1748       break;
1749   }
1750
1751   if ( nbReori ) {
1752     declareMeshModified( /*isReComputeSafe=*/false );
1753   }
1754   TPythonDump() << this << ".Reorient2DBy3D( "
1755                 << faceGroups << ", "
1756                 << volumeGroup << ", "
1757                 << outsideNormal << " )";
1758
1759   return nbReori;
1760
1761   SMESH_CATCH( SMESH::throwCorbaException );
1762   return 0;
1763 }
1764
1765 //=============================================================================
1766 /*!
1767  * \brief Fuse neighbour triangles into quadrangles.
1768  */
1769 //=============================================================================
1770
1771 CORBA::Boolean SMESH_MeshEditor_i::TriToQuad (const SMESH::long_array &   IDsOfElements,
1772                                               SMESH::NumericalFunctor_ptr Criterion,
1773                                               CORBA::Double               MaxAngle)
1774 {
1775   SMESH_TRY;
1776   initData();
1777
1778   SMESHDS_Mesh* aMesh = getMeshDS();
1779   TIDSortedElemSet faces,copyFaces;
1780   SMDS_MeshElement::GeomFilter triaFilter(SMDSGeom_TRIANGLE);
1781   arrayToSet(IDsOfElements, aMesh, faces, SMDSAbs_Face, & triaFilter);
1782   TIDSortedElemSet* workElements = & faces;
1783
1784   if ( myIsPreviewMode ) {
1785     SMDSAbs_ElementType select =  SMDSAbs_Face;
1786     getPreviewMesh( SMDSAbs_Face )->Copy( faces, copyFaces, select );
1787     workElements = & copyFaces;
1788   }
1789
1790   SMESH::NumericalFunctor_i* aNumericalFunctor =
1791     dynamic_cast<SMESH::NumericalFunctor_i*>( SMESH_Gen_i::GetServant( Criterion ).in() );
1792   SMESH::Controls::NumericalFunctorPtr aCrit;
1793   if ( !aNumericalFunctor )
1794     aCrit.reset( new SMESH::Controls::MaxElementLength2D() );
1795   else
1796     aCrit = aNumericalFunctor->GetNumericalFunctor();
1797
1798   if ( !myIsPreviewMode ) {
1799     // Update Python script
1800     TPythonDump() << "isDone = " << this << ".TriToQuad( "
1801                   << IDsOfElements << ", " << aNumericalFunctor << ", " << TVar( MaxAngle ) << " )";
1802   }
1803
1804   bool stat = getEditor().TriToQuad( *workElements, aCrit, MaxAngle );
1805
1806   declareMeshModified( /*isReComputeSafe=*/!stat );
1807   return stat;
1808
1809   SMESH_CATCH( SMESH::throwCorbaException );
1810   return 0;
1811 }
1812
1813 //=============================================================================
1814 /*!
1815  * \brief Fuse neighbour triangles into quadrangles.
1816  */
1817 //=============================================================================
1818
1819 CORBA::Boolean SMESH_MeshEditor_i::TriToQuadObject (SMESH::SMESH_IDSource_ptr   theObject,
1820                                                     SMESH::NumericalFunctor_ptr Criterion,
1821                                                     CORBA::Double               MaxAngle)
1822 {
1823   SMESH_TRY;
1824   initData();
1825
1826   TPythonDump aTPythonDump;  // suppress dump in TriToQuad()
1827
1828   prepareIdSource( theObject );
1829   SMESH::long_array_var anElementsId = theObject->GetIDs();
1830   CORBA::Boolean isDone = TriToQuad(anElementsId, Criterion, MaxAngle);
1831
1832   if ( !myIsPreviewMode ) {
1833     SMESH::NumericalFunctor_i* aNumericalFunctor =
1834       SMESH::DownCast<SMESH::NumericalFunctor_i*>( Criterion );
1835
1836     // Update Python script
1837     aTPythonDump << "isDone = " << this << ".TriToQuadObject("
1838                  << theObject << ", " << aNumericalFunctor << ", " << TVar( MaxAngle ) << " )";
1839   }
1840
1841   return isDone;
1842
1843   SMESH_CATCH( SMESH::throwCorbaException );
1844   return 0;
1845 }
1846
1847 //=============================================================================
1848 /*!
1849  * \brief Split quadrangles into triangles.
1850  */
1851 //=============================================================================
1852
1853 CORBA::Boolean SMESH_MeshEditor_i::QuadToTri (const SMESH::long_array &   IDsOfElements,
1854                                               SMESH::NumericalFunctor_ptr Criterion)
1855 {
1856   SMESH_TRY;
1857   initData();
1858
1859   SMESHDS_Mesh* aMesh = getMeshDS();
1860   TIDSortedElemSet faces;
1861   arrayToSet(IDsOfElements, aMesh, faces, SMDSAbs_Face);
1862
1863   SMESH::NumericalFunctor_i* aNumericalFunctor =
1864     dynamic_cast<SMESH::NumericalFunctor_i*>( SMESH_Gen_i::GetServant( Criterion ).in() );
1865   SMESH::Controls::NumericalFunctorPtr aCrit;
1866   if ( !aNumericalFunctor )
1867     aCrit.reset( new SMESH::Controls::AspectRatio() );
1868   else
1869     aCrit = aNumericalFunctor->GetNumericalFunctor();
1870
1871
1872   // Update Python script
1873   TPythonDump() << "isDone = " << this << ".QuadToTri( " << IDsOfElements << ", " << aNumericalFunctor << " )";
1874
1875   CORBA::Boolean stat = getEditor().QuadToTri( faces, aCrit );
1876
1877   declareMeshModified( /*isReComputeSafe=*/false );
1878   return stat;
1879
1880   SMESH_CATCH( SMESH::throwCorbaException );
1881   return 0;
1882 }
1883
1884 //=============================================================================
1885 /*!
1886  * \brief Split quadrangles into triangles.
1887  */
1888 //=============================================================================
1889
1890 CORBA::Boolean SMESH_MeshEditor_i::QuadToTriObject (SMESH::SMESH_IDSource_ptr   theObject,
1891                                                     SMESH::NumericalFunctor_ptr Criterion)
1892 {
1893   SMESH_TRY;
1894   initData();
1895
1896   TPythonDump aTPythonDump;  // suppress dump in QuadToTri()
1897
1898   prepareIdSource( theObject );
1899   SMESH::long_array_var anElementsId = theObject->GetIDs();
1900   CORBA::Boolean isDone = QuadToTri(anElementsId, Criterion);
1901
1902   SMESH::NumericalFunctor_i* aNumericalFunctor =
1903     SMESH::DownCast<SMESH::NumericalFunctor_i*>( Criterion );
1904
1905   // Update Python script
1906   aTPythonDump << "isDone = " << this << ".QuadToTriObject( " << theObject << ", " << aNumericalFunctor << " )";
1907
1908   declareMeshModified( /*isReComputeSafe=*/false );
1909   return isDone;
1910
1911   SMESH_CATCH( SMESH::throwCorbaException );
1912   return 0;
1913 }
1914
1915 //================================================================================
1916 /*!
1917  * \brief Split each of quadrangles into 4 triangles.
1918  *  \param [in] theObject - theQuads Container of quadrangles to split.
1919  */
1920 //================================================================================
1921
1922 void SMESH_MeshEditor_i::QuadTo4Tri (SMESH::SMESH_IDSource_ptr theObject)
1923 {
1924   SMESH_TRY;
1925   initData();
1926
1927   TIDSortedElemSet faces;
1928   if ( !idSourceToSet( theObject, getMeshDS(), faces, SMDSAbs_Face, /*emptyIfIsMesh=*/true ) &&
1929        faces.empty() )
1930     THROW_SALOME_CORBA_EXCEPTION("No faces given", SALOME::BAD_PARAM);
1931
1932   getEditor().QuadTo4Tri( faces );
1933   TPythonDump() << this << ".QuadTo4Tri( " << theObject << " )";
1934
1935   SMESH_CATCH( SMESH::throwCorbaException );
1936 }
1937
1938 //=============================================================================
1939 /*!
1940  * \brief Split quadrangles into triangles.
1941  */
1942 //=============================================================================
1943
1944 CORBA::Boolean SMESH_MeshEditor_i::SplitQuad (const SMESH::long_array & IDsOfElements,
1945                                               CORBA::Boolean            Diag13)
1946 {
1947   SMESH_TRY;
1948   initData();
1949
1950   SMESHDS_Mesh* aMesh = getMeshDS();
1951   TIDSortedElemSet faces;
1952   arrayToSet(IDsOfElements, aMesh, faces, SMDSAbs_Face);
1953
1954   // Update Python script
1955   TPythonDump() << "isDone = " << this << ".SplitQuad( "
1956                 << IDsOfElements << ", " << Diag13 << " )";
1957
1958   CORBA::Boolean stat = getEditor().QuadToTri( faces, Diag13 );
1959
1960   declareMeshModified( /*isReComputeSafe=*/ !stat );
1961   return stat;
1962
1963   SMESH_CATCH( SMESH::throwCorbaException );
1964   return 0;
1965 }
1966
1967 //=============================================================================
1968 /*!
1969  * \brief Split quadrangles into triangles.
1970  */
1971 //=============================================================================
1972
1973 CORBA::Boolean SMESH_MeshEditor_i::SplitQuadObject (SMESH::SMESH_IDSource_ptr theObject,
1974                                                     CORBA::Boolean            Diag13)
1975 {
1976   SMESH_TRY;
1977   initData();
1978
1979   TPythonDump aTPythonDump;  // suppress dump in SplitQuad()
1980
1981   prepareIdSource( theObject );
1982   SMESH::long_array_var anElementsId = theObject->GetIDs();
1983   CORBA::Boolean isDone = SplitQuad(anElementsId, Diag13);
1984
1985   // Update Python script
1986   aTPythonDump << "isDone = " << this << ".SplitQuadObject( "
1987                << theObject << ", " << Diag13 << " )";
1988
1989   declareMeshModified( /*isReComputeSafe=*/!isDone );
1990   return isDone;
1991
1992   SMESH_CATCH( SMESH::throwCorbaException );
1993   return 0;
1994 }
1995
1996
1997 //=============================================================================
1998 /*!
1999  * Find better splitting of the given quadrangle.
2000  *  \param IDOfQuad  ID of the quadrangle to be split.
2001  *  \param Criterion A criterion to choose a diagonal for splitting.
2002  *  \return 1 if 1-3 diagonal is better, 2 if 2-4
2003  *          diagonal is better, 0 if error occurs.
2004  */
2005 //=============================================================================
2006
2007 CORBA::Long SMESH_MeshEditor_i::BestSplit (CORBA::Long                 IDOfQuad,
2008                                            SMESH::NumericalFunctor_ptr Criterion)
2009 {
2010   SMESH_TRY;
2011   initData();
2012
2013   const SMDS_MeshElement* quad = getMeshDS()->FindElement(IDOfQuad);
2014   if (quad && quad->GetType() == SMDSAbs_Face && quad->NbNodes() == 4)
2015   {
2016     SMESH::NumericalFunctor_i* aNumericalFunctor =
2017       dynamic_cast<SMESH::NumericalFunctor_i*>(SMESH_Gen_i::GetServant(Criterion).in());
2018     SMESH::Controls::NumericalFunctorPtr aCrit;
2019     if (aNumericalFunctor)
2020       aCrit = aNumericalFunctor->GetNumericalFunctor();
2021     else
2022       aCrit.reset(new SMESH::Controls::AspectRatio());
2023
2024     int id = getEditor().BestSplit(quad, aCrit);
2025     declareMeshModified( /*isReComputeSafe=*/ id < 1 );
2026     return id;
2027   }
2028
2029   SMESH_CATCH( SMESH::throwCorbaException );
2030   return 0;
2031 }
2032
2033 //================================================================================
2034 /*!
2035  * \brief Split volumic elements into tetrahedrons
2036  */
2037 //================================================================================
2038
2039 void SMESH_MeshEditor_i::SplitVolumesIntoTetra (SMESH::SMESH_IDSource_ptr elems,
2040                                                 CORBA::Short              methodFlags)
2041 {
2042   SMESH_TRY;
2043   initData();
2044
2045   ::SMESH_MeshEditor::TFacetOfElem elemSet;
2046   const int noneFacet = -1;
2047   prepareIdSource( elems );
2048   if ( SMDS_ElemIteratorPtr volIt = myMesh_i->GetElements( elems, SMESH::VOLUME ))
2049     while ( volIt->more() )
2050       elemSet.insert( elemSet.end(), make_pair( volIt->next(), noneFacet ));
2051
2052   getEditor().SplitVolumes( elemSet, int( methodFlags ));
2053   declareMeshModified( /*isReComputeSafe=*/true ); // it does not influence Compute()
2054
2055   TPythonDump() << this << ".SplitVolumesIntoTetra( "
2056                 << elems << ", " << methodFlags << " )";
2057
2058   SMESH_CATCH( SMESH::throwCorbaException );
2059 }
2060
2061 //================================================================================
2062 /*!
2063  * \brief Split hexahedra into triangular prisms
2064  *  \param elems - elements to split
2065  *  \param facetToSplitNormal - normal used to find a facet of hexahedron
2066  *         to split into triangles
2067  *  \param methodFlags - flags passing splitting method:
2068  *         1 - split the hexahedron into 2 prisms
2069  *         2 - split the hexahedron into 4 prisms
2070  */
2071 //================================================================================
2072
2073 void SMESH_MeshEditor_i::SplitHexahedraIntoPrisms( SMESH::SMESH_IDSource_ptr  elems,
2074                                                    const SMESH::PointStruct & startHexPoint,
2075                                                    const SMESH::DirStruct&    facetToSplitNormal,
2076                                                    CORBA::Short               methodFlags,
2077                                                    CORBA::Boolean             allDomains)
2078 {
2079   SMESH_TRY;
2080   initData();
2081   prepareIdSource( elems );
2082
2083   gp_Ax1 facetNorm( gp_Pnt( startHexPoint.x,
2084                             startHexPoint.y,
2085                             startHexPoint.z ),
2086                     gp_Dir( facetToSplitNormal.PS.x,
2087                             facetToSplitNormal.PS.y,
2088                             facetToSplitNormal.PS.z ));
2089   TIDSortedElemSet elemSet;
2090   prepareIdSource( elems );
2091   SMESH::long_array_var anElementsId = elems->GetIDs();
2092   SMDS_MeshElement::GeomFilter filter( SMDSGeom_HEXA );
2093   arrayToSet( anElementsId, getMeshDS(), elemSet, SMDSAbs_Volume, &filter );
2094
2095   ::SMESH_MeshEditor::TFacetOfElem elemFacets;
2096   while ( !elemSet.empty() )
2097   {
2098     getEditor().GetHexaFacetsToSplit( elemSet, facetNorm, elemFacets );
2099     if ( !allDomains )
2100       break;
2101
2102     ::SMESH_MeshEditor::TFacetOfElem::iterator ef = elemFacets.begin();
2103     for ( ; ef != elemFacets.end(); ++ef )
2104       elemSet.erase( ef->first );
2105   }
2106
2107   if ( methodFlags == 2 )
2108     methodFlags = int( ::SMESH_MeshEditor::HEXA_TO_4_PRISMS );
2109   else
2110     methodFlags = int( ::SMESH_MeshEditor::HEXA_TO_2_PRISMS );
2111
2112   getEditor().SplitVolumes( elemFacets, int( methodFlags ));
2113   declareMeshModified( /*isReComputeSafe=*/true ); // it does not influence Compute()
2114
2115   TPythonDump() << this << ".SplitHexahedraIntoPrisms( "
2116                 << elems << ", "
2117                 << startHexPoint << ", "
2118                 << facetToSplitNormal<< ", "
2119                 << methodFlags<< ", "
2120                 << allDomains << " )";
2121
2122   SMESH_CATCH( SMESH::throwCorbaException );
2123 }
2124
2125 //================================================================================
2126 /*!
2127  * \brief Split bi-quadratic elements into linear ones without creation of additional nodes:
2128  *   - bi-quadratic triangle will be split into 3 linear quadrangles;
2129  *   - bi-quadratic quadrangle will be split into 4 linear quadrangles;
2130  *   - tri-quadratic hexahedron will be split into 8 linear hexahedra.
2131  *   Quadratic elements of lower dimension  adjacent to the split bi-quadratic element
2132  *   will be split in order to keep the mesh conformal.
2133  *  \param elems - elements to split
2134  */
2135 //================================================================================
2136
2137 void SMESH_MeshEditor_i::SplitBiQuadraticIntoLinear(const SMESH::ListOfIDSources& theElems)
2138 {
2139   SMESH_TRY;
2140   initData();
2141
2142   TIDSortedElemSet elemSet;
2143   for ( size_t i = 0; i < theElems.length(); ++i )
2144   {
2145     SMESH::SMESH_IDSource_ptr elems = theElems[i].in();
2146     SMESH::SMESH_Mesh_var      mesh = elems->GetMesh();
2147     if ( mesh->GetId() != myMesh_i->GetId() )
2148       THROW_SALOME_CORBA_EXCEPTION("Wrong mesh of IDSource", SALOME::BAD_PARAM);
2149
2150     idSourceToSet( elems, getMeshDS(), elemSet, SMDSAbs_All );
2151   }
2152   getEditor().SplitBiQuadraticIntoLinear( elemSet );
2153
2154   declareMeshModified( /*isReComputeSafe=*/true ); // it does not influence Compute()
2155
2156   TPythonDump() << this << ".SplitBiQuadraticIntoLinear( "
2157                 << theElems << " )";
2158
2159   SMESH_CATCH( SMESH::throwCorbaException );
2160 }
2161
2162 //=======================================================================
2163 //function : Smooth
2164 //purpose  :
2165 //=======================================================================
2166
2167 CORBA::Boolean
2168 SMESH_MeshEditor_i::Smooth(const SMESH::long_array &              IDsOfElements,
2169                            const SMESH::long_array &              IDsOfFixedNodes,
2170                            CORBA::Long                            MaxNbOfIterations,
2171                            CORBA::Double                          MaxAspectRatio,
2172                            SMESH::SMESH_MeshEditor::Smooth_Method Method)
2173 {
2174   return smooth( IDsOfElements, IDsOfFixedNodes, MaxNbOfIterations,
2175                  MaxAspectRatio, Method, false );
2176 }
2177
2178
2179 //=======================================================================
2180 //function : SmoothParametric
2181 //purpose  :
2182 //=======================================================================
2183
2184 CORBA::Boolean
2185 SMESH_MeshEditor_i::SmoothParametric(const SMESH::long_array &              IDsOfElements,
2186                                      const SMESH::long_array &              IDsOfFixedNodes,
2187                                      CORBA::Long                            MaxNbOfIterations,
2188                                      CORBA::Double                          MaxAspectRatio,
2189                                      SMESH::SMESH_MeshEditor::Smooth_Method Method)
2190 {
2191   return smooth( IDsOfElements, IDsOfFixedNodes, MaxNbOfIterations,
2192                  MaxAspectRatio, Method, true );
2193 }
2194
2195
2196 //=======================================================================
2197 //function : SmoothObject
2198 //purpose  :
2199 //=======================================================================
2200
2201 CORBA::Boolean
2202 SMESH_MeshEditor_i::SmoothObject(SMESH::SMESH_IDSource_ptr              theObject,
2203                                  const SMESH::long_array &              IDsOfFixedNodes,
2204                                  CORBA::Long                            MaxNbOfIterations,
2205                                  CORBA::Double                          MaxAspectRatio,
2206                                  SMESH::SMESH_MeshEditor::Smooth_Method Method)
2207 {
2208   return smoothObject (theObject, IDsOfFixedNodes, MaxNbOfIterations,
2209                        MaxAspectRatio, Method, false);
2210 }
2211
2212
2213 //=======================================================================
2214 //function : SmoothParametricObject
2215 //purpose  :
2216 //=======================================================================
2217
2218 CORBA::Boolean
2219 SMESH_MeshEditor_i::SmoothParametricObject(SMESH::SMESH_IDSource_ptr              theObject,
2220                                            const SMESH::long_array &              IDsOfFixedNodes,
2221                                            CORBA::Long                            MaxNbOfIterations,
2222                                            CORBA::Double                          MaxAspectRatio,
2223                                            SMESH::SMESH_MeshEditor::Smooth_Method Method)
2224 {
2225   return smoothObject (theObject, IDsOfFixedNodes, MaxNbOfIterations,
2226                        MaxAspectRatio, Method, true);
2227 }
2228
2229
2230 //=============================================================================
2231 /*!
2232  *
2233  */
2234 //=============================================================================
2235
2236 CORBA::Boolean
2237 SMESH_MeshEditor_i::smooth(const SMESH::long_array &              IDsOfElements,
2238                            const SMESH::long_array &              IDsOfFixedNodes,
2239                            CORBA::Long                            MaxNbOfIterations,
2240                            CORBA::Double                          MaxAspectRatio,
2241                            SMESH::SMESH_MeshEditor::Smooth_Method Method,
2242                            bool                                   IsParametric)
2243 {
2244   SMESH_TRY;
2245   initData();
2246
2247   SMESHDS_Mesh* aMesh = getMeshDS();
2248
2249   TIDSortedElemSet elements;
2250   arrayToSet(IDsOfElements, aMesh, elements, SMDSAbs_Face);
2251
2252   set<const SMDS_MeshNode*> fixedNodes;
2253   for ( CORBA::ULong i = 0; i < IDsOfFixedNodes.length(); i++) {
2254     CORBA::Long index = IDsOfFixedNodes[i];
2255     const SMDS_MeshNode * node = aMesh->FindNode(index);
2256     if ( node )
2257       fixedNodes.insert( node );
2258   }
2259   ::SMESH_MeshEditor::SmoothMethod method = ::SMESH_MeshEditor::LAPLACIAN;
2260   if ( Method != SMESH::SMESH_MeshEditor::LAPLACIAN_SMOOTH )
2261     method = ::SMESH_MeshEditor::CENTROIDAL;
2262
2263   getEditor().Smooth(elements, fixedNodes, method,
2264                   MaxNbOfIterations, MaxAspectRatio, IsParametric );
2265
2266   declareMeshModified( /*isReComputeSafe=*/true ); // does not prevent re-compute
2267
2268   // Update Python script
2269   TPythonDump() << "isDone = " << this << "."
2270                 << (IsParametric ? "SmoothParametric( " : "Smooth( ")
2271                 << IDsOfElements << ", "     << IDsOfFixedNodes << ", "
2272                 << TVar( MaxNbOfIterations ) << ", " << TVar( MaxAspectRatio ) << ", "
2273                 << "SMESH.SMESH_MeshEditor."
2274                 << ( Method == SMESH::SMESH_MeshEditor::CENTROIDAL_SMOOTH ?
2275                      "CENTROIDAL_SMOOTH )" : "LAPLACIAN_SMOOTH )");
2276
2277   return true;
2278
2279   SMESH_CATCH( SMESH::throwCorbaException );
2280   return 0;
2281 }
2282
2283 //=============================================================================
2284 /*!
2285  *
2286  */
2287 //=============================================================================
2288
2289 CORBA::Boolean
2290 SMESH_MeshEditor_i::smoothObject(SMESH::SMESH_IDSource_ptr              theObject,
2291                                  const SMESH::long_array &              IDsOfFixedNodes,
2292                                  CORBA::Long                            MaxNbOfIterations,
2293                                  CORBA::Double                          MaxAspectRatio,
2294                                  SMESH::SMESH_MeshEditor::Smooth_Method Method,
2295                                  bool                                   IsParametric)
2296 {
2297   SMESH_TRY;
2298   initData();
2299
2300   TPythonDump aTPythonDump;  // suppress dump in smooth()
2301
2302   prepareIdSource( theObject );
2303   SMESH::long_array_var anElementsId = theObject->GetIDs();
2304   CORBA::Boolean isDone = smooth (anElementsId, IDsOfFixedNodes, MaxNbOfIterations,
2305                                   MaxAspectRatio, Method, IsParametric);
2306
2307   // Update Python script
2308   aTPythonDump << "isDone = " << this << "."
2309                << (IsParametric ? "SmoothParametricObject( " : "SmoothObject( ")
2310                << theObject << ", " << IDsOfFixedNodes << ", "
2311                << TVar( MaxNbOfIterations ) << ", " << TVar( MaxAspectRatio ) << ", "
2312                << "SMESH.SMESH_MeshEditor."
2313                << ( Method == SMESH::SMESH_MeshEditor::CENTROIDAL_SMOOTH ?
2314                     "CENTROIDAL_SMOOTH )" : "LAPLACIAN_SMOOTH )");
2315
2316   return isDone;
2317
2318   SMESH_CATCH( SMESH::throwCorbaException );
2319   return 0;
2320 }
2321
2322 //=============================================================================
2323 /*!
2324  *
2325  */
2326 //=============================================================================
2327
2328 void SMESH_MeshEditor_i::RenumberNodes()
2329 {
2330   SMESH_TRY;
2331   // Update Python script
2332   TPythonDump() << this << ".RenumberNodes()";
2333
2334   getMeshDS()->Renumber( true );
2335
2336   SMESH_CATCH( SMESH::throwCorbaException );
2337 }
2338
2339 //=============================================================================
2340 /*!
2341  *
2342  */
2343 //=============================================================================
2344
2345 void SMESH_MeshEditor_i::RenumberElements()
2346 {
2347   SMESH_TRY;
2348   // Update Python script
2349   TPythonDump() << this << ".RenumberElements()";
2350
2351   getMeshDS()->Renumber( false );
2352
2353   SMESH_CATCH( SMESH::throwCorbaException );
2354 }
2355
2356 //=======================================================================
2357 /*!
2358  * \brief Return groups by their IDs
2359  */
2360 //=======================================================================
2361
2362 SMESH::ListOfGroups* SMESH_MeshEditor_i::getGroups(const std::list<int>* groupIDs)
2363 {
2364   SMESH_TRY;
2365   if ( !groupIDs )
2366     return 0;
2367   myMesh_i->CreateGroupServants();
2368   return myMesh_i->GetGroups( *groupIDs );
2369
2370   SMESH_CATCH( SMESH::throwCorbaException );
2371   return 0;
2372 }
2373
2374 //=======================================================================
2375 //function : RotationSweepObjects
2376 //purpose  :
2377 //=======================================================================
2378
2379 SMESH::ListOfGroups*
2380 SMESH_MeshEditor_i::RotationSweepObjects(const SMESH::ListOfIDSources & theNodes,
2381                                          const SMESH::ListOfIDSources & theEdges,
2382                                          const SMESH::ListOfIDSources & theFaces,
2383                                          const SMESH::AxisStruct &      theAxis,
2384                                          CORBA::Double                  theAngleInRadians,
2385                                          CORBA::Long                    theNbOfSteps,
2386                                          CORBA::Double                  theTolerance,
2387                                          const bool                     theMakeGroups)
2388 {
2389   SMESH_TRY;
2390   initData();
2391
2392   TIDSortedElemSet elemsNodes[2];
2393   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
2394     if ( SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE ))
2395       while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
2396   }
2397   for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
2398     idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
2399   for ( int i = 0, nb = theFaces.length(); i < nb; ++i )
2400     idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face );
2401
2402   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2403   bool              makeWalls=true;
2404   if ( myIsPreviewMode )
2405   {
2406     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2407     TPreviewMesh * tmpMesh = getPreviewMesh();
2408     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2409     tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid );
2410     workElements = & copyElements[0];
2411     //makeWalls = false; -- faces are needed for preview
2412   }
2413
2414   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2415
2416   gp_Ax1 Ax1 (gp_Pnt( theAxis.x,  theAxis.y,  theAxis.z ),
2417               gp_Vec( theAxis.vx, theAxis.vy, theAxis.vz ));
2418
2419   ::SMESH_MeshEditor::PGroupIDs groupIds =
2420       getEditor().RotationSweep (workElements, Ax1, theAngleInRadians,
2421                                  theNbOfSteps, theTolerance, theMakeGroups, makeWalls);
2422
2423   SMESH::ListOfGroups * aGroups = theMakeGroups ? getGroups( groupIds.get()) : 0;
2424
2425   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2426
2427   if ( !myIsPreviewMode )
2428   {
2429     dumpGroupsList( aPythonDump, aGroups );
2430     aPythonDump << this<< ".RotationSweepObjects( "
2431                 << theNodes                  << ", "
2432                 << theEdges                  << ", "
2433                 << theFaces                  << ", "
2434                 << theAxis                   << ", "
2435                 << TVar( theAngleInRadians ) << ", "
2436                 << TVar( theNbOfSteps      ) << ", "
2437                 << TVar( theTolerance      ) << ", "
2438                 << theMakeGroups             << " )";
2439   }
2440   else
2441   {
2442     getPreviewMesh()->Remove( SMDSAbs_Volume );
2443   }
2444
2445   return aGroups ? aGroups : new SMESH::ListOfGroups;
2446
2447   SMESH_CATCH( SMESH::throwCorbaException );
2448   return 0;
2449 }
2450
2451 namespace MeshEditor_I
2452 {
2453   /*!
2454    * \brief Structure used to pass extrusion parameters to ::SMESH_MeshEditor
2455    */
2456   struct ExtrusionParams : public ::SMESH_MeshEditor::ExtrusParam
2457   {
2458     bool myIsExtrusionByNormal;
2459
2460     static int makeFlags( CORBA::Boolean MakeGroups,
2461                           CORBA::Boolean ScaleVariation = false,
2462                           CORBA::Boolean AngleVariation = false,
2463                           CORBA::Boolean ByAverageNormal = false,
2464                           CORBA::Boolean UseInputElemsOnly = false,
2465                           CORBA::Long    Flags = 0,
2466                           CORBA::Boolean MakeBoundary = true )
2467     {
2468       if ( MakeGroups       ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_GROUPS;
2469       if ( ByAverageNormal  ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_BY_AVG_NORMAL;
2470       if ( UseInputElemsOnly) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_USE_INPUT_ELEMS_ONLY;
2471       if ( ScaleVariation  )  Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_SCALE_LINEAR_VARIATION;
2472       if ( AngleVariation  )  Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_ANGLE_LINEAR_VARIATION;
2473       if ( MakeBoundary     ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_BOUNDARY;
2474       return Flags;
2475     }
2476     // standard params
2477     ExtrusionParams(const SMESH::DirStruct &    theDir,
2478                     CORBA::Long                 theNbOfSteps,
2479                     const SMESH::double_array & theScaleFactors,
2480                     CORBA::Boolean              theScaleVariation,
2481                     const SMESH::double_array & theAngles,
2482                     CORBA::Boolean              theAngleVariation,
2483                     const SMESH::double_array & theBasePoint,
2484                     CORBA::Boolean              theMakeGroups):
2485       ::SMESH_MeshEditor::ExtrusParam ( gp_Vec( theDir.PS.x,
2486                                                 theDir.PS.y,
2487                                                 theDir.PS.z ),
2488                                         theNbOfSteps,
2489                                         toList( theScaleFactors ),
2490                                         toList( theAngles ),
2491                                         TBasePoint( theBasePoint ),
2492                                         makeFlags( theMakeGroups, theScaleVariation, theAngleVariation )),
2493       myIsExtrusionByNormal( false )
2494     {
2495     }
2496     // advanced params
2497     ExtrusionParams(const SMESH::DirStruct &  theDir,
2498                     CORBA::Long               theNbOfSteps,
2499                     CORBA::Boolean            theMakeGroups,
2500                     CORBA::Long               theExtrFlags,
2501                     CORBA::Double             theSewTolerance):
2502       ::SMESH_MeshEditor::ExtrusParam ( gp_Vec( theDir.PS.x,
2503                                                 theDir.PS.y,
2504                                                 theDir.PS.z ),
2505                                         theNbOfSteps,
2506                                         std::list<double>(),
2507                                         std::list<double>(),
2508                                         0,
2509                                         makeFlags( theMakeGroups, false, false, false, false,
2510                                                    theExtrFlags, false ),
2511                                         theSewTolerance ),
2512       myIsExtrusionByNormal( false )
2513     {
2514     }
2515     // params for extrusion by normal
2516     ExtrusionParams(CORBA::Double  theStepSize,
2517                     CORBA::Long    theNbOfSteps,
2518                     CORBA::Short   theDim,
2519                     CORBA::Boolean theByAverageNormal,
2520                     CORBA::Boolean theUseInputElemsOnly,
2521                     CORBA::Boolean theMakeGroups ):
2522       ::SMESH_MeshEditor::ExtrusParam ( theStepSize, 
2523                                         theNbOfSteps,
2524                                         makeFlags( theMakeGroups, false, false,
2525                                                    theByAverageNormal, theUseInputElemsOnly ),
2526                                         theDim),
2527       myIsExtrusionByNormal( true )
2528     {
2529     }
2530
2531     void SetNoGroups()
2532     {
2533       Flags() &= ~(::SMESH_MeshEditor::EXTRUSION_FLAG_GROUPS);
2534     }
2535
2536     static std::list<double> toList( const SMESH::double_array & theScaleFactors )
2537     {
2538       std::list<double> scales;
2539       for ( CORBA::ULong i = 0; i < theScaleFactors.length(); ++i )
2540         scales.push_back( theScaleFactors[i] );
2541       return scales;
2542     }
2543
2544   private:
2545
2546     // structure used to convert SMESH::double_array to gp_XYZ*
2547     struct TBasePoint
2548     {
2549       gp_XYZ *pp, p;
2550       TBasePoint( const SMESH::double_array & theBasePoint )
2551       {
2552         pp = 0;
2553         if ( theBasePoint.length() == 3 )
2554         {
2555           p.SetCoord( theBasePoint[0], theBasePoint[1], theBasePoint[2] );
2556           pp = &p;
2557         }
2558       }
2559       operator const gp_XYZ*() const { return pp; }
2560     };
2561   };
2562 }
2563
2564 //=======================================================================
2565 /*!
2566  * \brief Generate dim+1 elements by extrusion of elements along vector
2567  *  \param [in] edges - edges to extrude: a list including groups, sub-meshes or a mesh
2568  *  \param [in] faces - faces to extrude: a list including groups, sub-meshes or a mesh
2569  *  \param [in] nodes - nodes to extrude: a list including groups, sub-meshes or a mesh
2570  *  \param [in] stepVector - vector giving direction and distance of an extrusion step
2571  *  \param [in] nbOfSteps - number of elements to generate from one element
2572  *  \param [in] toMakeGroups - if true, new elements will be included into new groups
2573  *              corresponding to groups the input elements included in.
2574  *  \return ListOfGroups - new groups created if \a toMakeGroups is true
2575  */
2576 //=======================================================================
2577
2578 SMESH::ListOfGroups*
2579 SMESH_MeshEditor_i::ExtrusionSweepObjects(const SMESH::ListOfIDSources & theNodes,
2580                                           const SMESH::ListOfIDSources & theEdges,
2581                                           const SMESH::ListOfIDSources & theFaces,
2582                                           const SMESH::DirStruct &       theStepVector,
2583                                           CORBA::Long                    theNbOfSteps,
2584                                           CORBA::Boolean                 theToMakeGroups,
2585                                           const SMESH::double_array &    theScaleFactors,
2586                                           CORBA::Boolean                 theScalesVariation,
2587                                           const SMESH::double_array &    theBasePoint,
2588                                           const SMESH::double_array &    theAngles,
2589                                           CORBA::Boolean                 theAnglesVariation)
2590 {
2591   SMESH_TRY;
2592   initData();
2593
2594   ExtrusionParams params( theStepVector, theNbOfSteps, theScaleFactors, theScalesVariation,
2595                           theAngles, theAnglesVariation, theBasePoint, theToMakeGroups );
2596
2597   TIDSortedElemSet elemsNodes[2];
2598   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
2599     if ( SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE ))
2600       while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
2601   }
2602   for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
2603     idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
2604   for ( int i = 0, nb = theFaces.length(); i < nb; ++i )
2605     idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face );
2606
2607   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2608   SMDSAbs_ElementType previewType = SMDSAbs_All; //SMDSAbs_Face;
2609   if ( myIsPreviewMode )
2610   {
2611     // if ( (*elemsNodes.begin())->GetType() == SMDSAbs_Node )
2612     //   previewType = SMDSAbs_Edge;
2613
2614     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2615     TPreviewMesh * tmpMesh = getPreviewMesh( previewType );
2616     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2617     tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid );
2618     workElements = & copyElements[0];
2619
2620     params.SetNoGroups();
2621   }
2622   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2623
2624   ::SMESH_MeshEditor::TTElemOfElemListMap aHistory;
2625   ::SMESH_MeshEditor::PGroupIDs groupIds =
2626       getEditor().ExtrusionSweep( workElements, params, aHistory );
2627
2628   SMESH::ListOfGroups * aGroups = theToMakeGroups ? getGroups( groupIds.get()) : 0;
2629
2630   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2631
2632   if ( !myIsPreviewMode )
2633   {
2634     dumpGroupsList( aPythonDump, aGroups );
2635     aPythonDump << this<< ".ExtrusionSweepObjects( "
2636                 << theNodes                << ", "
2637                 << theEdges                << ", "
2638                 << theFaces                << ", "
2639                 << theStepVector           << ", "
2640                 << TVar( theNbOfSteps )    << ", "
2641                 << theToMakeGroups         << ", "
2642                 << TVar( theScaleFactors ) << ", "
2643                 << theScalesVariation      << ", "
2644                 << TVar( theBasePoint )    << ", "
2645                 << TVar( theAngles )       << ", "
2646                 << theAnglesVariation      << " )";
2647   }
2648   else
2649   {
2650     getPreviewMesh( previewType )->Remove( SMDSAbs_Volume );
2651   }
2652
2653   return aGroups ? aGroups : new SMESH::ListOfGroups;
2654
2655   SMESH_CATCH( SMESH::throwCorbaException );
2656   return 0;
2657 }
2658
2659 //=======================================================================
2660 //function : ExtrusionByNormal
2661 //purpose  :
2662 //=======================================================================
2663
2664 SMESH::ListOfGroups*
2665 SMESH_MeshEditor_i::ExtrusionByNormal(const SMESH::ListOfIDSources& objects,
2666                                       CORBA::Double                 stepSize,
2667                                       CORBA::Long                   nbOfSteps,
2668                                       CORBA::Boolean                byAverageNormal,
2669                                       CORBA::Boolean                useInputElemsOnly,
2670                                       CORBA::Boolean                makeGroups,
2671                                       CORBA::Short                  dim)
2672 {
2673   SMESH_TRY;
2674   initData();
2675
2676   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
2677
2678   ExtrusionParams params( stepSize, nbOfSteps, dim,
2679                           byAverageNormal, useInputElemsOnly, makeGroups );
2680
2681   SMDSAbs_ElementType elemType = ( dim == 1 ? SMDSAbs_Edge : SMDSAbs_Face );
2682   if ( objects.length() > 0 && !SMESH::DownCast<SMESH_Mesh_i*>( objects[0] ))
2683   {
2684     SMESH::array_of_ElementType_var elemTypes = objects[0]->GetTypes();
2685     if (( elemTypes->length() == 1 ) &&
2686         ( elemTypes[0] == SMESH::EDGE || elemTypes[0] == SMESH::FACE ))
2687       elemType = ( SMDSAbs_ElementType ) elemTypes[0];
2688   }
2689
2690   TIDSortedElemSet elemsNodes[2];
2691   for ( int i = 0, nb = objects.length(); i < nb; ++i )
2692     idSourceToSet( objects[i], getMeshDS(), elemsNodes[0], elemType );
2693
2694   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2695   SMDSAbs_ElementType previewType = SMDSAbs_Face;
2696   if ( myIsPreviewMode )
2697   {
2698     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2699     TPreviewMesh * tmpMesh = getPreviewMesh( previewType );
2700     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2701     workElements = & copyElements[0];
2702
2703     params.SetNoGroups();
2704   }
2705
2706   ::SMESH_MeshEditor::TTElemOfElemListMap aHistory;
2707   ::SMESH_MeshEditor::PGroupIDs groupIds =
2708       getEditor().ExtrusionSweep( workElements, params, aHistory );
2709
2710   SMESH::ListOfGroups * aGroups = makeGroups ? getGroups( groupIds.get()) : 0;
2711
2712   if (!myIsPreviewMode) {
2713     dumpGroupsList(aPythonDump, aGroups);
2714     aPythonDump << this << ".ExtrusionByNormal( " << objects
2715                 << ", " << TVar( stepSize )
2716                 << ", " << TVar( nbOfSteps )
2717                 << ", " << byAverageNormal
2718                 << ", " << useInputElemsOnly
2719                 << ", " << makeGroups
2720                 << ", " << dim
2721                 << " )";
2722   }
2723   else
2724   {
2725     getPreviewMesh( previewType )->Remove( SMDSAbs_Volume );
2726   }
2727
2728   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2729
2730   return aGroups ? aGroups : new SMESH::ListOfGroups;
2731
2732   SMESH_CATCH( SMESH::throwCorbaException );
2733   return 0;
2734 }
2735
2736 //=======================================================================
2737 //function : AdvancedExtrusion
2738 //purpose  :
2739 //=======================================================================
2740
2741 SMESH::ListOfGroups*
2742 SMESH_MeshEditor_i::AdvancedExtrusion(const SMESH::long_array & theIDsOfElements,
2743                                       const SMESH::DirStruct &  theStepVector,
2744                                       CORBA::Long               theNbOfSteps,
2745                                       CORBA::Long               theExtrFlags,
2746                                       CORBA::Double             theSewTolerance,
2747                                       CORBA::Boolean            theMakeGroups)
2748 {
2749   SMESH_TRY;
2750   initData();
2751
2752   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2753
2754   ExtrusionParams params( theStepVector, theNbOfSteps, theMakeGroups,
2755                           theExtrFlags, theSewTolerance );
2756
2757   TIDSortedElemSet elemsNodes[2];
2758   arrayToSet( theIDsOfElements, getMeshDS(), elemsNodes[0] );
2759
2760   ::SMESH_MeshEditor::TTElemOfElemListMap aHistory;
2761   ::SMESH_MeshEditor::PGroupIDs groupIds =
2762       getEditor().ExtrusionSweep( elemsNodes, params, aHistory );
2763
2764   SMESH::ListOfGroups * aGroups = theMakeGroups ? getGroups( groupIds.get()) : 0;
2765
2766   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2767
2768   if ( !myIsPreviewMode ) {
2769     dumpGroupsList(aPythonDump, aGroups);
2770     aPythonDump << this << ".AdvancedExtrusion( "
2771                 << theIDsOfElements << ", "
2772                 << theStepVector << ", "
2773                 << theNbOfSteps << ", "
2774                 << theExtrFlags << ", "
2775                 << theSewTolerance << ", "
2776                 << theMakeGroups << " )";
2777   }
2778   else
2779   {
2780     getPreviewMesh()->Remove( SMDSAbs_Volume );
2781   }
2782
2783   return aGroups ? aGroups : new SMESH::ListOfGroups;
2784
2785   SMESH_CATCH( SMESH::throwCorbaException );
2786   return 0;
2787 }
2788
2789 //================================================================================
2790 /*!
2791  * \brief Convert extrusion error to IDL enum
2792  */
2793 //================================================================================
2794
2795 namespace
2796 {
2797 #define RETCASE(enm) case ::SMESH_MeshEditor::enm: return SMESH::SMESH_MeshEditor::enm;
2798
2799   SMESH::SMESH_MeshEditor::Extrusion_Error convExtrError( ::SMESH_MeshEditor::Extrusion_Error e )
2800   {
2801     switch ( e ) {
2802       RETCASE( EXTR_OK );
2803       RETCASE( EXTR_NO_ELEMENTS );
2804       RETCASE( EXTR_PATH_NOT_EDGE );
2805       RETCASE( EXTR_BAD_PATH_SHAPE );
2806       RETCASE( EXTR_BAD_STARTING_NODE );
2807       RETCASE( EXTR_BAD_ANGLES_NUMBER );
2808       RETCASE( EXTR_CANT_GET_TANGENT );
2809     }
2810     return SMESH::SMESH_MeshEditor::EXTR_OK;
2811   }
2812 }
2813
2814 //=======================================================================
2815 //function : extrusionAlongPath
2816 //purpose  :
2817 //=======================================================================
2818 SMESH::ListOfGroups*
2819 SMESH_MeshEditor_i::ExtrusionAlongPathObjects(const SMESH::ListOfIDSources & theNodes,
2820                                               const SMESH::ListOfIDSources & theEdges,
2821                                               const SMESH::ListOfIDSources & theFaces,
2822                                               SMESH::SMESH_IDSource_ptr      thePathObject,
2823                                               GEOM::GEOM_Object_ptr          thePathShape,
2824                                               CORBA::Long                    theNodeStart,
2825                                               CORBA::Boolean                 theHasAngles,
2826                                               const SMESH::double_array &    theAngles,
2827                                               CORBA::Boolean                 theAnglesVariation,
2828                                               CORBA::Boolean                 theHasRefPoint,
2829                                               const SMESH::PointStruct &     theRefPoint,
2830                                               bool                           theMakeGroups,
2831                                               const SMESH::double_array &    theScaleFactors,
2832                                               CORBA::Boolean                 theScalesVariation,
2833                                               SMESH::SMESH_MeshEditor::Extrusion_Error& theError)
2834 {
2835   SMESH_TRY;
2836   initData();
2837
2838   SMESH::ListOfGroups_var aGroups = new SMESH::ListOfGroups;
2839
2840   theError = SMESH::SMESH_MeshEditor::EXTR_BAD_PATH_SHAPE;
2841   if ( thePathObject->_is_nil() )
2842     return aGroups._retn();
2843
2844
2845   SMDS_ElemIteratorPtr pathEdgesIterator;
2846
2847   SMESH_Mesh_i* aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( thePathObject );
2848   if ( !CORBA::is_nil( thePathShape ) && aMeshImp )
2849   {
2850     // get a sub-mesh of thePathShape
2851     TopoDS_Shape     aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( thePathShape );
2852     SMESH_subMesh* aSubMesh = aMeshImp->GetImpl().GetSubMesh( aShape );
2853     if ( !aSubMesh )
2854       return aGroups._retn();
2855
2856     if ( !aSubMesh->GetSubMeshDS() )
2857     {
2858       SMESHDS_Mesh * meshDS = aMeshImp->GetImpl().GetMeshDS();
2859       meshDS->AddCompoundSubmesh( aShape, TopAbs_EDGE );
2860       if ( !aSubMesh->GetSubMeshDS() )
2861         return aGroups._retn();
2862     }
2863     theError = SMESH::SMESH_MeshEditor::EXTR_PATH_NOT_EDGE;
2864     pathEdgesIterator = aSubMesh->GetSubMeshDS()->GetElements();
2865     if ( !pathEdgesIterator->more() ||
2866          pathEdgesIterator->next()->GetType() != SMDSAbs_Edge )
2867       return aGroups._retn();
2868
2869     pathEdgesIterator = aSubMesh->GetSubMeshDS()->GetElements();
2870   }
2871   else
2872   {
2873     theError = SMESH::SMESH_MeshEditor::EXTR_PATH_NOT_EDGE;
2874     prepareIdSource( thePathObject );
2875     pathEdgesIterator = SMESH_Mesh_i::GetElements( thePathObject, SMESH::EDGE );
2876     if ( !pathEdgesIterator || !pathEdgesIterator->more() )
2877       return aGroups._retn();
2878   }
2879
2880   if ( !aMeshImp )
2881   {
2882     SMESH::SMESH_Mesh_var pathMesh = thePathObject->GetMesh();
2883     aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( pathMesh );
2884   }
2885
2886
2887   theError = SMESH::SMESH_MeshEditor::EXTR_BAD_STARTING_NODE;
2888   const SMDS_MeshNode* nodeStart = aMeshImp->GetImpl().GetMeshDS()->FindNode( theNodeStart );
2889   if ( !nodeStart )
2890     return aGroups._retn();
2891
2892
2893   TIDSortedElemSet elemsNodes[2];
2894   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
2895     if ( SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE ))
2896       while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
2897   }
2898   for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
2899     idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
2900   for ( int i = 0, nb = theFaces.length(); i < nb; ++i )
2901     idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face );
2902
2903   list<double> angles = ExtrusionParams::toList( theAngles );
2904   list<double> scales = ExtrusionParams::toList( theScaleFactors );
2905
2906   gp_Pnt refPnt( theRefPoint.x, theRefPoint.y, theRefPoint.z );
2907   const gp_Pnt *refPntPtr = theHasRefPoint ? &refPnt : 0;
2908
2909   int nbOldGroups = myMesh->NbGroup();
2910
2911   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2912   if ( myIsPreviewMode )
2913   {
2914     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2915     TPreviewMesh * tmpMesh = getPreviewMesh();
2916     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2917     tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid );
2918     workElements = & copyElements[0];
2919     theMakeGroups = false;
2920   }
2921
2922   ::SMESH_MeshEditor::Extrusion_Error error =
2923       getEditor().ExtrusionAlongTrack( workElements,
2924                                        &(aMeshImp->GetImpl()), pathEdgesIterator, nodeStart,
2925                                        angles, theAnglesVariation,
2926                                        scales, theScalesVariation,
2927                                        refPntPtr, theMakeGroups );
2928
2929   declareMeshModified( /*isReComputeSafe=*/true );
2930   theError = convExtrError( error );
2931
2932   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2933   if ( theMakeGroups ) {
2934     list<int> groupIDs = myMesh->GetGroupIds();
2935     list<int>::iterator newBegin = groupIDs.begin();
2936     std::advance( newBegin, nbOldGroups ); // skip old groups
2937     groupIDs.erase( groupIDs.begin(), newBegin );
2938     aGroups = getGroups( & groupIDs );
2939     if ( ! &aGroups.in() ) aGroups = new SMESH::ListOfGroups;
2940   }
2941
2942   if ( !myIsPreviewMode ) {
2943     if ( aGroups->length() > 0 ) aPythonDump << "(" << aGroups << ", error) = ";
2944     else                         aPythonDump << "(_noGroups, error) = ";
2945     aPythonDump << this << ".ExtrusionAlongPathObjects( "
2946                 << theNodes            << ", "
2947                 << theEdges            << ", "
2948                 << theFaces            << ", "
2949                 << thePathObject       << ", "
2950                 << thePathShape        << ", "
2951                 << theNodeStart        << ", "
2952                 << theHasAngles        << ", "
2953                 << TVar( theAngles )   << ", "
2954                 << theAnglesVariation  << ", "
2955                 << theHasRefPoint      << ", "
2956                 << "SMESH.PointStruct( "
2957                 << TVar( theHasRefPoint ? theRefPoint.x : 0 ) << ", "
2958                 << TVar( theHasRefPoint ? theRefPoint.y : 0 ) << ", "
2959                 << TVar( theHasRefPoint ? theRefPoint.z : 0 ) << " ), "
2960                 << theMakeGroups           << ", "
2961                 << TVar( theScaleFactors ) << ", "
2962                 << theScalesVariation      << " )";
2963   }
2964   else
2965   {
2966     getPreviewMesh()->Remove( SMDSAbs_Volume );
2967   }
2968
2969   return aGroups._retn();
2970
2971   SMESH_CATCH( SMESH::throwCorbaException );
2972   return 0;
2973 }
2974
2975 //================================================================================
2976 /*!
2977  * \brief Compute rotation angles for ExtrusionAlongPath as linear variation
2978  * of given angles along path steps
2979  * \param PathMesh mesh containing a 1D sub-mesh on the edge, along
2980  *                which proceeds the extrusion
2981  * \param PathShape is shape(edge); as the mesh can be complex, the edge
2982  *                 is used to define the sub-mesh for the path
2983  */
2984 //================================================================================
2985
2986 SMESH::double_array*
2987 SMESH_MeshEditor_i::LinearAnglesVariation(SMESH::SMESH_Mesh_ptr       thePathMesh,
2988                                           GEOM::GEOM_Object_ptr       thePathShape,
2989                                           const SMESH::double_array & theAngles)
2990 {
2991   SMESH::double_array_var aResult = new SMESH::double_array();
2992   int nbAngles = theAngles.length();
2993   if ( nbAngles > 0 && !thePathMesh->_is_nil() && !thePathShape->_is_nil() )
2994   {
2995     SMESH_Mesh_i* aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( thePathMesh );
2996     TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( thePathShape );
2997     SMESH_subMesh* aSubMesh = aMeshImp->GetImpl().GetSubMesh( aShape );
2998     if ( !aSubMesh || !aSubMesh->GetSubMeshDS())
2999       return aResult._retn();
3000     int nbSteps = aSubMesh->GetSubMeshDS()->NbElements();
3001     if ( nbSteps == nbAngles )
3002     {
3003       aResult.inout() = theAngles;
3004     }
3005     else
3006     {
3007       aResult->length( nbSteps );
3008       double rAn2St = double( nbAngles ) / double( nbSteps );
3009       double angPrev = 0, angle;
3010       for ( int iSt = 0; iSt < nbSteps; ++iSt )
3011       {
3012         double angCur = rAn2St * ( iSt+1 );
3013         double angCurFloor  = floor( angCur );
3014         double angPrevFloor = floor( angPrev );
3015         if ( angPrevFloor == angCurFloor )
3016           angle = rAn2St * theAngles[ int( angCurFloor ) ];
3017         else
3018         {
3019           int iP = int( angPrevFloor );
3020           double angPrevCeil = ceil(angPrev);
3021           angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
3022
3023           int iC = int( angCurFloor );
3024           if ( iC < nbAngles )
3025             angle += ( angCur - angCurFloor ) * theAngles[ iC ];
3026
3027           iP = int( angPrevCeil );
3028           while ( iC-- > iP )
3029             angle += theAngles[ iC ];
3030         }
3031         aResult[ iSt ] = angle;
3032         angPrev = angCur;
3033       }
3034     }
3035   }
3036   // Update Python script
3037   TPythonDump() << "rotAngles = " << theAngles;
3038   TPythonDump() << "rotAngles = " << this << ".LinearAnglesVariation( "
3039                 << thePathMesh  << ", "
3040                 << thePathShape << ", "
3041                 << "rotAngles )";
3042
3043   return aResult._retn();
3044 }
3045
3046 //=======================================================================
3047 //function : mirror
3048 //purpose  :
3049 //=======================================================================
3050
3051 SMESH::ListOfGroups*
3052 SMESH_MeshEditor_i::mirror(TIDSortedElemSet &                  theElements,
3053                            const SMESH::AxisStruct &           theAxis,
3054                            SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
3055                            CORBA::Boolean                      theCopy,
3056                            bool                                theMakeGroups,
3057                            ::SMESH_Mesh*                       theTargetMesh)
3058 {
3059   SMESH_TRY;
3060   initData();
3061
3062   gp_Pnt P ( theAxis.x, theAxis.y, theAxis.z );
3063   gp_Vec V ( theAxis.vx, theAxis.vy, theAxis.vz );
3064
3065   if ( theTargetMesh )
3066     theCopy = false;
3067
3068   gp_Trsf aTrsf;
3069   switch ( theMirrorType ) {
3070   case  SMESH::SMESH_MeshEditor::POINT:
3071     aTrsf.SetMirror( P );
3072     break;
3073   case  SMESH::SMESH_MeshEditor::AXIS:
3074     aTrsf.SetMirror( gp_Ax1( P, V ));
3075     break;
3076   default:
3077     aTrsf.SetMirror( gp_Ax2( P, V ));
3078   }
3079
3080   TIDSortedElemSet  copyElements;
3081   TIDSortedElemSet* workElements = & theElements;
3082
3083   if ( myIsPreviewMode )
3084   {
3085     TPreviewMesh * tmpMesh = getPreviewMesh();
3086     tmpMesh->Copy( theElements, copyElements);
3087     if ( !theCopy && !theTargetMesh )
3088     {
3089       TIDSortedElemSet elemsAround, elemsAroundCopy;
3090       getElementsAround( theElements, getMeshDS(), elemsAround );
3091       tmpMesh->Copy( elemsAround, elemsAroundCopy);
3092     }
3093     workElements = & copyElements;
3094     theMakeGroups = false;
3095   }
3096
3097   ::SMESH_MeshEditor::PGroupIDs groupIds =
3098       getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
3099
3100   if ( !myIsPreviewMode )
3101   {
3102     if ( theTargetMesh )
3103       theTargetMesh->GetMeshDS()->Modified();
3104     else
3105       declareMeshModified( /*isReComputeSafe=*/false );
3106   }
3107
3108   return theMakeGroups ? getGroups(groupIds.get()) : 0;
3109
3110   SMESH_CATCH( SMESH::throwCorbaException );
3111   return 0;
3112 }
3113
3114 //=======================================================================
3115 //function : Mirror
3116 //purpose  :
3117 //=======================================================================
3118
3119 void SMESH_MeshEditor_i::Mirror(const SMESH::long_array &           theIDsOfElements,
3120                                 const SMESH::AxisStruct &           theAxis,
3121                                 SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
3122                                 CORBA::Boolean                      theCopy)
3123 {
3124   if ( !myIsPreviewMode ) {
3125     TPythonDump() << this << ".Mirror( "
3126                   << theIDsOfElements              << ", "
3127                   << theAxis                       << ", "
3128                   << mirrorTypeName(theMirrorType) << ", "
3129                   << theCopy                       << " )";
3130   }
3131   if ( theIDsOfElements.length() > 0 )
3132   {
3133     TIDSortedElemSet elements;
3134     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3135     mirror(elements, theAxis, theMirrorType, theCopy, false);
3136   }
3137 }
3138
3139
3140 //=======================================================================
3141 //function : MirrorObject
3142 //purpose  :
3143 //=======================================================================
3144
3145 void SMESH_MeshEditor_i::MirrorObject(SMESH::SMESH_IDSource_ptr           theObject,
3146                                       const SMESH::AxisStruct &           theAxis,
3147                                       SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
3148                                       CORBA::Boolean                      theCopy)
3149 {
3150   if ( !myIsPreviewMode ) {
3151     TPythonDump() << this << ".MirrorObject( "
3152                   << theObject                     << ", "
3153                   << theAxis                       << ", "
3154                   << mirrorTypeName(theMirrorType) << ", "
3155                   << theCopy                       << " )";
3156   }
3157   TIDSortedElemSet elements;
3158
3159   bool emptyIfIsMesh = myIsPreviewMode ? false : true;
3160
3161   if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
3162     mirror(elements, theAxis, theMirrorType, theCopy, false);
3163 }
3164
3165 //=======================================================================
3166 //function : MirrorMakeGroups
3167 //purpose  :
3168 //=======================================================================
3169
3170 SMESH::ListOfGroups*
3171 SMESH_MeshEditor_i::MirrorMakeGroups(const SMESH::long_array&            theIDsOfElements,
3172                                      const SMESH::AxisStruct&            theMirror,
3173                                      SMESH::SMESH_MeshEditor::MirrorType theMirrorType)
3174 {
3175   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3176
3177   SMESH::ListOfGroups * aGroups = 0;
3178   if ( theIDsOfElements.length() > 0 )
3179   {
3180     TIDSortedElemSet elements;
3181     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3182     aGroups = mirror(elements, theMirror, theMirrorType, true, true);
3183   }
3184   if (!myIsPreviewMode) {
3185     dumpGroupsList(aPythonDump, aGroups);
3186     aPythonDump << this << ".MirrorMakeGroups( "
3187                 << theIDsOfElements              << ", "
3188                 << theMirror                     << ", "
3189                 << mirrorTypeName(theMirrorType) << " )";
3190   }
3191   return aGroups;
3192 }
3193
3194 //=======================================================================
3195 //function : MirrorObjectMakeGroups
3196 //purpose  :
3197 //=======================================================================
3198
3199 SMESH::ListOfGroups*
3200 SMESH_MeshEditor_i::MirrorObjectMakeGroups(SMESH::SMESH_IDSource_ptr           theObject,
3201                                            const SMESH::AxisStruct&            theMirror,
3202                                            SMESH::SMESH_MeshEditor::MirrorType theMirrorType)
3203 {
3204   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3205
3206   SMESH::ListOfGroups * aGroups = 0;
3207   TIDSortedElemSet elements;
3208   if ( idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3209     aGroups = mirror(elements, theMirror, theMirrorType, true, true);
3210
3211   if (!myIsPreviewMode)
3212   {
3213     dumpGroupsList(aPythonDump,aGroups);
3214     aPythonDump << this << ".MirrorObjectMakeGroups( "
3215                 << theObject                     << ", "
3216                 << theMirror                     << ", "
3217                 << mirrorTypeName(theMirrorType) << " )";
3218   }
3219   return aGroups;
3220 }
3221
3222 //=======================================================================
3223 //function : MirrorMakeMesh
3224 //purpose  :
3225 //=======================================================================
3226
3227 SMESH::SMESH_Mesh_ptr
3228 SMESH_MeshEditor_i::MirrorMakeMesh(const SMESH::long_array&            theIDsOfElements,
3229                                    const SMESH::AxisStruct&            theMirror,
3230                                    SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
3231                                    CORBA::Boolean                      theCopyGroups,
3232                                    const char*                         theMeshName)
3233 {
3234   SMESH_Mesh_i* mesh_i;
3235   SMESH::SMESH_Mesh_var mesh;
3236   { // open new scope to dump "MakeMesh" command
3237     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3238
3239     TPythonDump pydump; // to prevent dump at mesh creation
3240
3241     mesh = makeMesh( theMeshName );
3242     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3243     if (mesh_i && theIDsOfElements.length() > 0 )
3244     {
3245       TIDSortedElemSet elements;
3246       arrayToSet(theIDsOfElements, getMeshDS(), elements);
3247       mirror(elements, theMirror, theMirrorType,
3248              false, theCopyGroups, & mesh_i->GetImpl());
3249       mesh_i->CreateGroupServants();
3250     }
3251
3252     if (!myIsPreviewMode) {
3253       pydump << mesh << " = " << this << ".MirrorMakeMesh( "
3254              << theIDsOfElements              << ", "
3255              << theMirror                     << ", "
3256              << mirrorTypeName(theMirrorType) << ", "
3257              << theCopyGroups                 << ", '"
3258              << theMeshName                   << "' )";
3259     }
3260   }
3261
3262   //dump "GetGroups"
3263   if (!myIsPreviewMode && mesh_i)
3264     mesh_i->GetGroups();
3265
3266   return mesh._retn();
3267 }
3268
3269 //=======================================================================
3270 //function : MirrorObjectMakeMesh
3271 //purpose  :
3272 //=======================================================================
3273
3274 SMESH::SMESH_Mesh_ptr
3275 SMESH_MeshEditor_i::MirrorObjectMakeMesh(SMESH::SMESH_IDSource_ptr           theObject,
3276                                          const SMESH::AxisStruct&            theMirror,
3277                                          SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
3278                                          CORBA::Boolean                      theCopyGroups,
3279                                          const char*                         theMeshName)
3280 {
3281   SMESH_Mesh_i* mesh_i;
3282   SMESH::SMESH_Mesh_var mesh;
3283   { // open new scope to dump "MakeMesh" command
3284     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3285
3286     TPythonDump pydump; // to prevent dump at mesh creation
3287
3288     mesh = makeMesh( theMeshName );
3289     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3290     TIDSortedElemSet elements;
3291     if ( mesh_i &&
3292          idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3293     {
3294       mirror(elements, theMirror, theMirrorType,
3295              false, theCopyGroups, & mesh_i->GetImpl());
3296       mesh_i->CreateGroupServants();
3297     }
3298     if (!myIsPreviewMode) {
3299       pydump << mesh << " = " << this << ".MirrorObjectMakeMesh( "
3300              << theObject                     << ", "
3301              << theMirror                     << ", "
3302              << mirrorTypeName(theMirrorType) << ", "
3303              << theCopyGroups                 << ", '"
3304              << theMeshName                   << "' )";
3305     }
3306   }
3307
3308   //dump "GetGroups"
3309   if (!myIsPreviewMode && mesh_i)
3310     mesh_i->GetGroups();
3311
3312   return mesh._retn();
3313 }
3314
3315 //=======================================================================
3316 //function : translate
3317 //purpose  :
3318 //=======================================================================
3319
3320 SMESH::ListOfGroups*
3321 SMESH_MeshEditor_i::translate(TIDSortedElemSet        & theElements,
3322                               const SMESH::DirStruct &  theVector,
3323                               CORBA::Boolean            theCopy,
3324                               bool                      theMakeGroups,
3325                               ::SMESH_Mesh*             theTargetMesh)
3326 {
3327   SMESH_TRY;
3328   initData();
3329
3330   if ( theTargetMesh )
3331     theCopy = false;
3332
3333   gp_Trsf aTrsf;
3334   const SMESH::PointStruct * P = &theVector.PS;
3335   aTrsf.SetTranslation( gp_Vec( P->x, P->y, P->z ));
3336
3337   TIDSortedElemSet  copyElements;
3338   TIDSortedElemSet* workElements = &theElements;
3339
3340   if ( myIsPreviewMode )
3341   {
3342     TPreviewMesh * tmpMesh = getPreviewMesh();
3343     tmpMesh->Copy( theElements, copyElements);
3344     if ( !theCopy && !theTargetMesh )
3345     {
3346       TIDSortedElemSet elemsAround, elemsAroundCopy;
3347       getElementsAround( theElements, getMeshDS(), elemsAround );
3348       tmpMesh->Copy( elemsAround, elemsAroundCopy);
3349     }
3350     workElements = & copyElements;
3351     theMakeGroups = false;
3352   }
3353
3354   ::SMESH_MeshEditor::PGroupIDs groupIds =
3355       getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
3356
3357   if ( !myIsPreviewMode )
3358   {
3359     if ( theTargetMesh )
3360       theTargetMesh->GetMeshDS()->Modified();
3361     else
3362       declareMeshModified( /*isReComputeSafe=*/false );
3363   }
3364
3365   return theMakeGroups ? getGroups(groupIds.get()) : 0;
3366
3367   SMESH_CATCH( SMESH::throwCorbaException );
3368   return 0;
3369 }
3370
3371 //=======================================================================
3372 //function : Translate
3373 //purpose  :
3374 //=======================================================================
3375
3376 void SMESH_MeshEditor_i::Translate(const SMESH::long_array & theIDsOfElements,
3377                                    const SMESH::DirStruct &  theVector,
3378                                    CORBA::Boolean            theCopy)
3379 {
3380   if (!myIsPreviewMode) {
3381     TPythonDump() << this << ".Translate( "
3382                   << theIDsOfElements << ", "
3383                   << theVector        << ", "
3384                   << theCopy          << " )";
3385   }
3386   if (theIDsOfElements.length()) {
3387     TIDSortedElemSet elements;
3388     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3389     translate(elements, theVector, theCopy, false);
3390   }
3391 }
3392
3393 //=======================================================================
3394 //function : TranslateObject
3395 //purpose  :
3396 //=======================================================================
3397
3398 void SMESH_MeshEditor_i::TranslateObject(SMESH::SMESH_IDSource_ptr theObject,
3399                                          const SMESH::DirStruct &  theVector,
3400                                          CORBA::Boolean            theCopy)
3401 {
3402   if (!myIsPreviewMode) {
3403     TPythonDump() << this << ".TranslateObject( "
3404                   << theObject << ", "
3405                   << theVector << ", "
3406                   << theCopy   << " )";
3407   }
3408   TIDSortedElemSet elements;
3409
3410   bool emptyIfIsMesh = myIsPreviewMode ? false : true;
3411
3412   if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
3413     translate(elements, theVector, theCopy, false);
3414 }
3415
3416 //=======================================================================
3417 //function : TranslateMakeGroups
3418 //purpose  :
3419 //=======================================================================
3420
3421 SMESH::ListOfGroups*
3422 SMESH_MeshEditor_i::TranslateMakeGroups(const SMESH::long_array& theIDsOfElements,
3423                                         const SMESH::DirStruct&  theVector)
3424 {
3425   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3426
3427   SMESH::ListOfGroups * aGroups = 0;
3428   if (theIDsOfElements.length()) {
3429     TIDSortedElemSet elements;
3430     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3431     aGroups = translate(elements,theVector,true,true);
3432   }
3433   if (!myIsPreviewMode) {
3434     dumpGroupsList(aPythonDump, aGroups);
3435     aPythonDump << this << ".TranslateMakeGroups( "
3436                 << theIDsOfElements << ", "
3437                 << theVector        << " )";
3438   }
3439   return aGroups;
3440 }
3441
3442 //=======================================================================
3443 //function : TranslateObjectMakeGroups
3444 //purpose  :
3445 //=======================================================================
3446
3447 SMESH::ListOfGroups*
3448 SMESH_MeshEditor_i::TranslateObjectMakeGroups(SMESH::SMESH_IDSource_ptr theObject,
3449                                               const SMESH::DirStruct&   theVector)
3450 {
3451   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3452
3453   SMESH::ListOfGroups * aGroups = 0;
3454   TIDSortedElemSet elements;
3455   if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3456     aGroups = translate(elements, theVector, true, true);
3457
3458   if (!myIsPreviewMode) {
3459     dumpGroupsList(aPythonDump, aGroups);
3460     aPythonDump << this << ".TranslateObjectMakeGroups( "
3461                 << theObject << ", "
3462                 << theVector << " )";
3463   }
3464   return aGroups;
3465 }
3466
3467 //=======================================================================
3468 //function : TranslateMakeMesh
3469 //purpose  :
3470 //=======================================================================
3471
3472 SMESH::SMESH_Mesh_ptr
3473 SMESH_MeshEditor_i::TranslateMakeMesh(const SMESH::long_array& theIDsOfElements,
3474                                       const SMESH::DirStruct&  theVector,
3475                                       CORBA::Boolean           theCopyGroups,
3476                                       const char*              theMeshName)
3477 {
3478   SMESH_Mesh_i* mesh_i;
3479   SMESH::SMESH_Mesh_var mesh;
3480
3481   { // open new scope to dump "MakeMesh" command
3482     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3483
3484     TPythonDump pydump; // to prevent dump at mesh creation
3485
3486     mesh = makeMesh( theMeshName );
3487     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3488
3489     if ( mesh_i && theIDsOfElements.length() )
3490     {
3491       TIDSortedElemSet elements;
3492       arrayToSet(theIDsOfElements, getMeshDS(), elements);
3493       translate(elements, theVector, false, theCopyGroups, & mesh_i->GetImpl());
3494       mesh_i->CreateGroupServants();
3495     }
3496
3497     if ( !myIsPreviewMode ) {
3498       pydump << mesh << " = " << this << ".TranslateMakeMesh( "
3499              << theIDsOfElements << ", "
3500              << theVector        << ", "
3501              << theCopyGroups    << ", '"
3502              << theMeshName      << "' )";
3503     }
3504   }
3505
3506   //dump "GetGroups"
3507   if (!myIsPreviewMode && mesh_i)
3508     mesh_i->GetGroups();
3509
3510   return mesh._retn();
3511 }
3512
3513 //=======================================================================
3514 //function : TranslateObjectMakeMesh
3515 //purpose  :
3516 //=======================================================================
3517
3518 SMESH::SMESH_Mesh_ptr
3519 SMESH_MeshEditor_i::TranslateObjectMakeMesh(SMESH::SMESH_IDSource_ptr theObject,
3520                                             const SMESH::DirStruct&   theVector,
3521                                             CORBA::Boolean            theCopyGroups,
3522                                             const char*               theMeshName)
3523 {
3524   SMESH_TRY;
3525   SMESH_Mesh_i* mesh_i;
3526   SMESH::SMESH_Mesh_var mesh;
3527   { // open new scope to dump "MakeMesh" command
3528     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3529
3530     TPythonDump pydump; // to prevent dump at mesh creation
3531     mesh = makeMesh( theMeshName );
3532     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3533
3534     TIDSortedElemSet elements;
3535     if ( mesh_i &&
3536          idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3537     {
3538       translate(elements, theVector,false, theCopyGroups, & mesh_i->GetImpl());
3539       mesh_i->CreateGroupServants();
3540     }
3541     if ( !myIsPreviewMode ) {
3542       pydump << mesh << " = " << this << ".TranslateObjectMakeMesh( "
3543              << theObject     << ", "
3544              << theVector     << ", "
3545              << theCopyGroups << ", '"
3546              << theMeshName   << "' )";
3547     }
3548   }
3549
3550   // dump "GetGroups"
3551   if (!myIsPreviewMode && mesh_i)
3552     mesh_i->GetGroups();
3553
3554   return mesh._retn();
3555
3556   SMESH_CATCH( SMESH::throwCorbaException );
3557   return 0;
3558 }
3559
3560 //=======================================================================
3561 //function : rotate
3562 //purpose  :
3563 //=======================================================================
3564
3565 SMESH::ListOfGroups*
3566 SMESH_MeshEditor_i::rotate(TIDSortedElemSet &        theElements,
3567                            const SMESH::AxisStruct & theAxis,
3568                            CORBA::Double             theAngle,
3569                            CORBA::Boolean            theCopy,
3570                            bool                      theMakeGroups,
3571                            ::SMESH_Mesh*             theTargetMesh)
3572 {
3573   SMESH_TRY;
3574   initData();
3575
3576   if ( theTargetMesh )
3577     theCopy = false;
3578
3579   gp_Pnt P ( theAxis.x, theAxis.y, theAxis.z );
3580   gp_Vec V ( theAxis.vx, theAxis.vy, theAxis.vz );
3581
3582   gp_Trsf aTrsf;
3583   aTrsf.SetRotation( gp_Ax1( P, V ), theAngle);
3584
3585   TIDSortedElemSet  copyElements;
3586   TIDSortedElemSet* workElements = &theElements;
3587   if ( myIsPreviewMode ) {
3588     TPreviewMesh * tmpMesh = getPreviewMesh();
3589     tmpMesh->Copy( theElements, copyElements );
3590     if ( !theCopy && !theTargetMesh )
3591     {
3592       TIDSortedElemSet elemsAround, elemsAroundCopy;
3593       getElementsAround( theElements, getMeshDS(), elemsAround );
3594       tmpMesh->Copy( elemsAround, elemsAroundCopy);
3595     }
3596     workElements = &copyElements;
3597     theMakeGroups = false;
3598   }
3599
3600   ::SMESH_MeshEditor::PGroupIDs groupIds =
3601       getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
3602
3603   if ( !myIsPreviewMode)
3604   {
3605     if ( theTargetMesh ) theTargetMesh->GetMeshDS()->Modified();
3606     else                 declareMeshModified( /*isReComputeSafe=*/false );
3607   }
3608
3609   return theMakeGroups ? getGroups(groupIds.get()) : 0;
3610
3611   SMESH_CATCH( SMESH::throwCorbaException );
3612   return 0;
3613 }
3614
3615 //=======================================================================
3616 //function : Rotate
3617 //purpose  :
3618 //=======================================================================
3619
3620 void SMESH_MeshEditor_i::Rotate(const SMESH::long_array & theIDsOfElements,
3621                                 const SMESH::AxisStruct & theAxis,
3622                                 CORBA::Double             theAngle,
3623                                 CORBA::Boolean            theCopy)
3624 {
3625   if (!myIsPreviewMode) {
3626     TPythonDump() << this << ".Rotate( "
3627                   << theIDsOfElements << ", "
3628                   << theAxis          << ", "
3629                   << TVar( theAngle ) << ", "
3630                   << theCopy          << " )";
3631   }
3632   if (theIDsOfElements.length() > 0)
3633   {
3634     TIDSortedElemSet elements;
3635     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3636     rotate(elements,theAxis,theAngle,theCopy,false);
3637   }
3638 }
3639
3640 //=======================================================================
3641 //function : RotateObject
3642 //purpose  :
3643 //=======================================================================
3644
3645 void SMESH_MeshEditor_i::RotateObject(SMESH::SMESH_IDSource_ptr theObject,
3646                                       const SMESH::AxisStruct & theAxis,
3647                                       CORBA::Double             theAngle,
3648                                       CORBA::Boolean            theCopy)
3649 {
3650   if ( !myIsPreviewMode ) {
3651     TPythonDump() << this << ".RotateObject( "
3652                   << theObject        << ", "
3653                   << theAxis          << ", "
3654                   << TVar( theAngle ) << ", "
3655                   << theCopy          << " )";
3656   }
3657   TIDSortedElemSet elements;
3658   bool emptyIfIsMesh = myIsPreviewMode ? false : true;
3659   if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
3660     rotate(elements,theAxis,theAngle,theCopy,false);
3661 }
3662
3663 //=======================================================================
3664 //function : RotateMakeGroups
3665 //purpose  :
3666 //=======================================================================
3667
3668 SMESH::ListOfGroups*
3669 SMESH_MeshEditor_i::RotateMakeGroups(const SMESH::long_array& theIDsOfElements,
3670                                      const SMESH::AxisStruct& theAxis,
3671                                      CORBA::Double            theAngle)
3672 {
3673   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3674
3675   SMESH::ListOfGroups * aGroups = 0;
3676   if (theIDsOfElements.length() > 0)
3677   {
3678     TIDSortedElemSet elements;
3679     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3680     aGroups = rotate(elements,theAxis,theAngle,true,true);
3681   }
3682   if (!myIsPreviewMode) {
3683     dumpGroupsList(aPythonDump, aGroups);
3684     aPythonDump << this << ".RotateMakeGroups( "
3685                 << theIDsOfElements << ", "
3686                 << theAxis          << ", "
3687                 << TVar( theAngle ) << " )";
3688   }
3689   return aGroups;
3690 }
3691
3692 //=======================================================================
3693 //function : RotateObjectMakeGroups
3694 //purpose  :
3695 //=======================================================================
3696
3697 SMESH::ListOfGroups*
3698 SMESH_MeshEditor_i::RotateObjectMakeGroups(SMESH::SMESH_IDSource_ptr theObject,
3699                                            const SMESH::AxisStruct&  theAxis,
3700                                            CORBA::Double             theAngle)
3701 {
3702   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3703
3704   SMESH::ListOfGroups * aGroups = 0;
3705   TIDSortedElemSet elements;
3706   if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3707     aGroups = rotate(elements, theAxis, theAngle, true, true);
3708
3709   if (!myIsPreviewMode) {
3710     dumpGroupsList(aPythonDump, aGroups);
3711     aPythonDump << this << ".RotateObjectMakeGroups( "
3712                 << theObject        << ", "
3713                 << theAxis          << ", "
3714                 << TVar( theAngle ) << " )";
3715   }
3716   return aGroups;
3717 }
3718
3719 //=======================================================================
3720 //function : RotateMakeMesh
3721 //purpose  :
3722 //=======================================================================
3723
3724 SMESH::SMESH_Mesh_ptr
3725 SMESH_MeshEditor_i::RotateMakeMesh(const SMESH::long_array& theIDsOfElements,
3726                                    const SMESH::AxisStruct& theAxis,
3727                                    CORBA::Double            theAngleInRadians,
3728                                    CORBA::Boolean           theCopyGroups,
3729                                    const char*              theMeshName)
3730 {
3731   SMESH_TRY;
3732   SMESH::SMESH_Mesh_var mesh;
3733   SMESH_Mesh_i* mesh_i;
3734
3735   { // open new scope to dump "MakeMesh" command
3736     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3737
3738     TPythonDump pydump; // to prevent dump at mesh creation
3739
3740     mesh = makeMesh( theMeshName );
3741     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3742
3743     if ( mesh_i && theIDsOfElements.length() > 0 )
3744     {
3745       TIDSortedElemSet elements;
3746       arrayToSet(theIDsOfElements, getMeshDS(), elements);
3747       rotate(elements, theAxis, theAngleInRadians,
3748              false, theCopyGroups, & mesh_i->GetImpl());
3749       mesh_i->CreateGroupServants();
3750     }
3751     if ( !myIsPreviewMode ) {
3752       pydump << mesh << " = " << this << ".RotateMakeMesh( "
3753              << theIDsOfElements          << ", "
3754              << theAxis                   << ", "
3755              << TVar( theAngleInRadians ) << ", "
3756              << theCopyGroups             << ", '"
3757              << theMeshName               << "' )";
3758     }
3759   }
3760
3761   // dump "GetGroups"
3762   if (!myIsPreviewMode && mesh_i && theIDsOfElements.length() > 0 )
3763     mesh_i->GetGroups();
3764
3765   return mesh._retn();
3766
3767   SMESH_CATCH( SMESH::throwCorbaException );
3768   return 0;
3769 }
3770
3771 //=======================================================================
3772 //function : RotateObjectMakeMesh
3773 //purpose  :
3774 //=======================================================================
3775
3776 SMESH::SMESH_Mesh_ptr
3777 SMESH_MeshEditor_i::RotateObjectMakeMesh(SMESH::SMESH_IDSource_ptr theObject,
3778                                          const SMESH::AxisStruct&  theAxis,
3779                                          CORBA::Double             theAngleInRadians,
3780                                          CORBA::Boolean            theCopyGroups,
3781                                          const char*               theMeshName)
3782 {
3783   SMESH_TRY;
3784   SMESH::SMESH_Mesh_var mesh;
3785   SMESH_Mesh_i* mesh_i;
3786
3787   {// open new scope to dump "MakeMesh" command
3788    // and then "GetGroups" using SMESH_Mesh::GetGroups()
3789
3790     TPythonDump pydump; // to prevent dump at mesh creation
3791     mesh = makeMesh( theMeshName );
3792     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3793
3794     TIDSortedElemSet elements;
3795     if (mesh_i &&
3796         idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3797     {
3798       rotate(elements, theAxis, theAngleInRadians,
3799              false, theCopyGroups, & mesh_i->GetImpl());
3800       mesh_i->CreateGroupServants();
3801     }
3802     if ( !myIsPreviewMode ) {
3803       pydump << mesh << " = " << this << ".RotateObjectMakeMesh( "
3804              << theObject                 << ", "
3805              << theAxis                   << ", "
3806              << TVar( theAngleInRadians ) << ", "
3807              << theCopyGroups             << ", '"
3808              << theMeshName               << "' )";
3809     }
3810   }
3811
3812   // dump "GetGroups"
3813   if (!myIsPreviewMode && mesh_i)
3814     mesh_i->GetGroups();
3815
3816   return mesh._retn();
3817
3818   SMESH_CATCH( SMESH::throwCorbaException );
3819   return 0;
3820 }
3821
3822 //=======================================================================
3823 //function : scale
3824 //purpose  :
3825 //=======================================================================
3826
3827 SMESH::ListOfGroups*
3828 SMESH_MeshEditor_i::scale(SMESH::SMESH_IDSource_ptr  theObject,
3829                           const SMESH::PointStruct&  thePoint,
3830                           const SMESH::double_array& theScaleFact,
3831                           CORBA::Boolean             theCopy,
3832                           bool                       theMakeGroups,
3833                           ::SMESH_Mesh*              theTargetMesh)
3834 {
3835   SMESH_TRY;
3836   initData();
3837   if ( theScaleFact.length() < 1 )
3838     THROW_SALOME_CORBA_EXCEPTION("Scale factor not given", SALOME::BAD_PARAM);
3839   if ( theScaleFact.length() == 2 )
3840     THROW_SALOME_CORBA_EXCEPTION("Invalid nb of scale factors : 2", SALOME::BAD_PARAM);
3841
3842   if ( theTargetMesh )
3843     theCopy = false;
3844
3845   TIDSortedElemSet elements;
3846   bool emptyIfIsMesh = myIsPreviewMode ? false : true;
3847   if ( !idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
3848     return 0;
3849
3850   double S[3] = {
3851     theScaleFact[0],
3852     (theScaleFact.length() == 1) ? theScaleFact[0] : theScaleFact[1],
3853     (theScaleFact.length() == 1) ? theScaleFact[0] : theScaleFact[2],
3854   };
3855   gp_Trsf aTrsf;
3856
3857   // fight against orthogonalization
3858   // aTrsf.SetValues( S[0], 0,    0,    thePoint.x * (1-S[0]),
3859   //                  0,    S[1], 0,    thePoint.y * (1-S[1]),
3860   //                  0,    0,    S[2], thePoint.z * (1-S[2]) );
3861   aTrsf.SetScale( gp::Origin(), 1.0 ); // set form which is used to make group names
3862   gp_XYZ & loc = ( gp_XYZ& ) aTrsf.TranslationPart();
3863   gp_Mat & M   = ( gp_Mat& ) aTrsf.HVectorialPart();
3864   loc.SetCoord( thePoint.x * (1-S[0]),
3865                 thePoint.y * (1-S[1]),
3866                 thePoint.z * (1-S[2]));
3867   M.SetDiagonal( S[0], S[1], S[2] );
3868
3869   TIDSortedElemSet  copyElements;
3870   TIDSortedElemSet* workElements = &elements;
3871   if ( myIsPreviewMode )
3872   {
3873     TPreviewMesh * tmpMesh = getPreviewMesh();
3874     tmpMesh->Copy( elements, copyElements);
3875     if ( !theCopy && !theTargetMesh )
3876     {
3877       TIDSortedElemSet elemsAround, elemsAroundCopy;
3878       getElementsAround( elements, getMeshDS(), elemsAround );
3879       tmpMesh->Copy( elemsAround, elemsAroundCopy);
3880     }
3881     workElements = & copyElements;
3882     theMakeGroups = false;
3883   }
3884
3885   ::SMESH_MeshEditor::PGroupIDs groupIds =
3886       getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
3887
3888   if ( !myIsPreviewMode )
3889   {
3890     if ( theTargetMesh ) theTargetMesh->GetMeshDS()->Modified();
3891     else                 declareMeshModified( /*isReComputeSafe=*/false );
3892   }
3893   return theMakeGroups ? getGroups(groupIds.get()) : 0;
3894
3895   SMESH_CATCH( SMESH::throwCorbaException );
3896   return 0;
3897 }
3898
3899 //=======================================================================
3900 //function : Scale
3901 //purpose  :
3902 //=======================================================================
3903
3904 void SMESH_MeshEditor_i::Scale(SMESH::SMESH_IDSource_ptr  theObject,
3905                                const SMESH::PointStruct&  thePoint,
3906                                const SMESH::double_array& theScaleFact,
3907                                CORBA::Boolean             theCopy)
3908   
3909 {
3910   if ( !myIsPreviewMode ) {
3911     TPythonDump() << this << ".Scale( "
3912                   << theObject            << ", "
3913                   << thePoint             << ", "
3914                   << TVar( theScaleFact ) << ", "
3915                   << theCopy              << " )";
3916   }
3917   scale(theObject, thePoint, theScaleFact, theCopy, false);
3918 }
3919
3920
3921 //=======================================================================
3922 //function : ScaleMakeGroups
3923 //purpose  :
3924 //=======================================================================
3925
3926 SMESH::ListOfGroups*
3927 SMESH_MeshEditor_i::ScaleMakeGroups(SMESH::SMESH_IDSource_ptr  theObject,
3928                                     const SMESH::PointStruct&  thePoint,
3929                                     const SMESH::double_array& theScaleFact)
3930 {
3931   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3932
3933   SMESH::ListOfGroups * aGroups = scale(theObject, thePoint, theScaleFact, true, true);
3934   if (!myIsPreviewMode) {
3935     dumpGroupsList(aPythonDump, aGroups);
3936     aPythonDump << this << ".Scale("
3937                 << theObject            << ","
3938                 << thePoint             << ","
3939                 << TVar( theScaleFact ) << ",True,True)";
3940   }
3941   return aGroups;
3942 }
3943
3944
3945 //=======================================================================
3946 //function : ScaleMakeMesh
3947 //purpose  :
3948 //=======================================================================
3949
3950 SMESH::SMESH_Mesh_ptr
3951 SMESH_MeshEditor_i::ScaleMakeMesh(SMESH::SMESH_IDSource_ptr  theObject,
3952                                   const SMESH::PointStruct&  thePoint,
3953                                   const SMESH::double_array& theScaleFact,
3954                                   CORBA::Boolean             theCopyGroups,
3955                                   const char*                theMeshName)
3956 {
3957   SMESH_Mesh_i* mesh_i;
3958   SMESH::SMESH_Mesh_var mesh;
3959   { // open new scope to dump "MakeMesh" command
3960     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3961
3962     TPythonDump pydump; // to prevent dump at mesh creation
3963     mesh   = makeMesh( theMeshName );
3964     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3965
3966     if ( mesh_i )
3967     {
3968       scale(theObject, thePoint, theScaleFact,false, theCopyGroups, & mesh_i->GetImpl());
3969       mesh_i->CreateGroupServants();
3970     }
3971     if ( !myIsPreviewMode )
3972       pydump << mesh << " = " << this << ".ScaleMakeMesh( "
3973              << theObject            << ", "
3974              << thePoint             << ", "
3975              << TVar( theScaleFact ) << ", "
3976              << theCopyGroups        << ", '"
3977              << theMeshName          << "' )";
3978   }
3979
3980   // dump "GetGroups"
3981   if (!myIsPreviewMode && mesh_i)
3982     mesh_i->GetGroups();
3983
3984   return mesh._retn();
3985 }
3986
3987 //================================================================================
3988 /*!
3989  * \brief Make an offset mesh from a source 2D mesh
3990  *  \param [inout] theObject - source mesh. New elements are added to this mesh
3991  *         if \a theMeshName is empty.
3992  *  \param [in] theValue - offset value
3993  *  \param [in] theCopyGroups - to generate groups
3994  *  \param [in] theMeshName - optional name of a new mesh
3995  *  \param [out] theGroups - new groups
3996  *  \return SMESH::SMESH_Mesh_ptr - the modified mesh
3997  */
3998 //================================================================================
3999
4000 SMESH::SMESH_Mesh_ptr SMESH_MeshEditor_i::Offset( SMESH::SMESH_IDSource_ptr theObject,
4001                                                   CORBA::Double             theValue,
4002                                                   CORBA::Boolean            theCopyGroups,
4003                                                   CORBA::Boolean            theCopyElements,
4004                                                   const char*               theMeshName,
4005                                                   SMESH::ListOfGroups_out   theGroups)
4006 {
4007   SMESH_TRY;
4008   initData();
4009
4010   SMESHDS_Mesh* aMeshDS = getMeshDS();
4011
4012   SMESH::SMESH_Mesh_var         mesh_var;
4013   ::SMESH_MeshEditor::PGroupIDs groupIds;
4014
4015   TPythonDump pyDump;
4016
4017   TIDSortedElemSet elements, copyElements;
4018   if ( idSourceToSet( theObject, aMeshDS, elements, SMDSAbs_Face,
4019                       /*emptyIfIsMesh=*/ !myIsPreviewMode ))
4020   {
4021     // mesh to modify
4022     SMESH_Mesh* tgtMesh = 0;
4023     if ( myIsPreviewMode )
4024     {
4025       TPreviewMesh * tmpMesh = getPreviewMesh();
4026       tgtMesh = tmpMesh;
4027       tmpMesh->Copy( elements, copyElements );
4028       elements.swap( copyElements );
4029       theCopyGroups = false;
4030       theCopyElements = false;
4031     }
4032     else
4033     {
4034       mesh_var =
4035         *theMeshName ? makeMesh( theMeshName ) : SMESH::SMESH_Mesh::_duplicate( myMesh_i->_this() );
4036       SMESH_Mesh_i* mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh_var );
4037       tgtMesh = & mesh_i->GetImpl();
4038     }
4039     groupIds = getEditor().Offset( elements, theValue, tgtMesh,
4040                                    theCopyGroups, theCopyElements, !myIsPreviewMode );
4041
4042     tgtMesh->GetMeshDS()->Modified();
4043   }
4044
4045   if ( myIsPreviewMode )
4046   {
4047     //getPreviewMesh()->Remove( SMESHUtils::elemSetIterator( copyElements ));
4048   }
4049   else
4050   {
4051     if ( *theMeshName && mesh_var->NbFaces() == 0 )
4052     {
4053       // new mesh empty, remove it
4054       SALOMEDS::Study_var          study = SMESH_Gen_i::getStudyServant();
4055       SALOMEDS::StudyBuilder_var builder = study->NewBuilder();
4056       SALOMEDS::SObject_wrap      meshSO = SMESH_Gen_i::ObjectToSObject( mesh_var );
4057       builder->RemoveObjectWithChildren( meshSO );
4058       THROW_SALOME_CORBA_EXCEPTION("Offset failed", SALOME::INTERNAL_ERROR);
4059     }
4060     if ( !groupIds ) // nothing changed in the current mesh
4061       THROW_SALOME_CORBA_EXCEPTION("Offset failed", SALOME::INTERNAL_ERROR);
4062
4063     theGroups = theCopyGroups ? getGroups( groupIds.get() ) : new SMESH::ListOfGroups;
4064
4065     // result of Offset() is a tuple (mesh, groups)
4066     if ( mesh_var->_is_nil() ) pyDump << myMesh_i->_this() << ", ";
4067     else                       pyDump << mesh_var          << ", ";
4068     pyDump << theGroups << " = " << this << ".Offset( "
4069            << theObject << ", "
4070            << theValue << ", "
4071            << theCopyGroups << ", "
4072            << theCopyElements << ", "
4073            << "'" << theMeshName<< "')";
4074   }
4075
4076   return mesh_var._retn();
4077
4078   SMESH_CATCH( SMESH::throwCorbaException );
4079   return SMESH::SMESH_Mesh::_nil();
4080 }
4081
4082 //=======================================================================
4083 //function : findCoincidentNodes
4084 //purpose  :
4085 //=======================================================================
4086
4087 void SMESH_MeshEditor_i::
4088 findCoincidentNodes (TIDSortedNodeSet &             Nodes,
4089                      CORBA::Double                  Tolerance,
4090                      SMESH::array_of_long_array_out GroupsOfNodes,
4091                      CORBA::Boolean                 SeparateCornersAndMedium)
4092 {
4093   ::SMESH_MeshEditor::TListOfListOfNodes aListOfListOfNodes;
4094   getEditor().FindCoincidentNodes( Nodes, Tolerance, aListOfListOfNodes, SeparateCornersAndMedium );
4095
4096   GroupsOfNodes = new SMESH::array_of_long_array;
4097   GroupsOfNodes->length( aListOfListOfNodes.size() );
4098   ::SMESH_MeshEditor::TListOfListOfNodes::iterator llIt = aListOfListOfNodes.begin();
4099   for ( CORBA::Long i = 0; llIt != aListOfListOfNodes.end(); llIt++, i++ )
4100   {
4101     list< const SMDS_MeshNode* >& aListOfNodes = *llIt;
4102     list< const SMDS_MeshNode* >::iterator lIt = aListOfNodes.begin();;
4103     SMESH::long_array& aGroup = (*GroupsOfNodes)[ i ];
4104     aGroup.length( aListOfNodes.size() );
4105     for ( int j = 0; lIt != aListOfNodes.end(); lIt++, j++ )
4106       aGroup[ j ] = (*lIt)->GetID();
4107   }
4108 }
4109
4110 //=======================================================================
4111 //function : FindCoincidentNodes
4112 //purpose  :
4113 //=======================================================================
4114
4115 void SMESH_MeshEditor_i::
4116 FindCoincidentNodes (CORBA::Double                  Tolerance,
4117                      SMESH::array_of_long_array_out GroupsOfNodes,
4118                      CORBA::Boolean                 SeparateCornersAndMedium)
4119 {
4120   SMESH_TRY;
4121   initData();
4122
4123   TIDSortedNodeSet nodes; // no input nodes
4124   findCoincidentNodes( nodes, Tolerance, GroupsOfNodes, SeparateCornersAndMedium );
4125
4126   TPythonDump() << "coincident_nodes = " << this << ".FindCoincidentNodes( "
4127                 << Tolerance << ", "
4128                 << SeparateCornersAndMedium << " )";
4129
4130   SMESH_CATCH( SMESH::throwCorbaException );
4131 }
4132
4133 //=======================================================================
4134 //function : FindCoincidentNodesOnPart
4135 //purpose  :
4136 //=======================================================================
4137
4138 void SMESH_MeshEditor_i::
4139 FindCoincidentNodesOnPart(SMESH::SMESH_IDSource_ptr      theObject,
4140                           CORBA::Double                  Tolerance,
4141                           SMESH::array_of_long_array_out GroupsOfNodes,
4142                           CORBA::Boolean                 SeparateCornersAndMedium)
4143 {
4144   SMESH_TRY;
4145   initData();
4146
4147   TIDSortedNodeSet nodes;
4148   prepareIdSource( theObject );
4149   idSourceToNodeSet( theObject, getMeshDS(), nodes );
4150
4151   findCoincidentNodes( nodes, Tolerance, GroupsOfNodes, SeparateCornersAndMedium );
4152
4153   TPythonDump() << "coincident_nodes_on_part = " << this << ".FindCoincidentNodesOnPart( "
4154                 << theObject <<", "
4155                 << Tolerance << ", "
4156                 << SeparateCornersAndMedium << " )";
4157
4158   SMESH_CATCH( SMESH::throwCorbaException );
4159 }
4160
4161 //================================================================================
4162 /*!
4163  * \brief Finds nodes coincident with Tolerance within Objects excluding nodes within
4164  *        ExceptSubMeshOrGroups
4165  */
4166 //================================================================================
4167
4168 void SMESH_MeshEditor_i::
4169 FindCoincidentNodesOnPartBut(const SMESH::ListOfIDSources&  theObjects,
4170                              CORBA::Double                  theTolerance,
4171                              SMESH::array_of_long_array_out theGroupsOfNodes,
4172                              const SMESH::ListOfIDSources&  theExceptSubMeshOrGroups,
4173                              CORBA::Boolean                 theSeparateCornersAndMedium)
4174 {
4175   SMESH_TRY;
4176   initData();
4177
4178   TIDSortedNodeSet nodes;
4179   for ( CORBA::ULong i = 0; i < theObjects.length(); ++i )
4180   {
4181     prepareIdSource( theObjects[i] );
4182     idSourceToNodeSet( theObjects[i], getMeshDS(), nodes );
4183   }
4184   for ( CORBA::ULong i = 0; i < theExceptSubMeshOrGroups.length(); ++i )
4185   {
4186     if ( SMDS_ElemIteratorPtr nodeIt = myMesh_i->GetElements( theExceptSubMeshOrGroups[i],
4187                                                               SMESH::NODE ))
4188       while ( nodeIt->more() )
4189         nodes.erase( cast2Node( nodeIt->next() ));
4190   }
4191   findCoincidentNodes( nodes, theTolerance, theGroupsOfNodes, theSeparateCornersAndMedium );
4192
4193   TPythonDump() << "coincident_nodes_on_part = " << this << ".FindCoincidentNodesOnPartBut( "
4194                 << theObjects <<", "
4195                 << theTolerance << ", "
4196                 << theExceptSubMeshOrGroups << ", "
4197                 << theSeparateCornersAndMedium << " )";
4198
4199   SMESH_CATCH( SMESH::throwCorbaException );
4200 }
4201
4202 //=======================================================================
4203 //function : MergeNodes
4204 //purpose  :
4205 //=======================================================================
4206
4207 void SMESH_MeshEditor_i::MergeNodes (const SMESH::array_of_long_array& GroupsOfNodes,
4208                                      const SMESH::ListOfIDSources&     NodesToKeep,
4209                                      CORBA::Boolean                    AvoidMakingHoles)
4210 {
4211   SMESH_TRY;
4212   initData();
4213
4214   SMESHDS_Mesh* aMesh = getMeshDS();
4215
4216   TPythonDump aTPythonDump;
4217   aTPythonDump << this << ".MergeNodes([";
4218
4219   TIDSortedNodeSet setOfNodesToKeep;
4220   for ( CORBA::ULong i = 0; i < NodesToKeep.length(); ++i )
4221   {
4222     prepareIdSource( NodesToKeep[i] );
4223     if ( SMDS_ElemIteratorPtr nodeIt = myMesh_i->GetElements( NodesToKeep[i], SMESH::NODE ))
4224       while ( nodeIt->more() )
4225         setOfNodesToKeep.insert( setOfNodesToKeep.end(), cast2Node( nodeIt->next() ));
4226   }
4227
4228   ::SMESH_MeshEditor::TListOfListOfNodes aListOfListOfNodes;
4229   for ( CORBA::ULong i = 0; i < GroupsOfNodes.length(); i++ )
4230   {
4231     const SMESH::long_array& aNodeGroup = GroupsOfNodes[ i ];
4232     aListOfListOfNodes.push_back( list< const SMDS_MeshNode* >() );
4233     list< const SMDS_MeshNode* >& aListOfNodes = aListOfListOfNodes.back();
4234     for ( CORBA::ULong j = 0; j < aNodeGroup.length(); j++ )
4235     {
4236       CORBA::Long index = aNodeGroup[ j ];
4237       if ( const SMDS_MeshNode * node = aMesh->FindNode( index ))
4238       {
4239         if ( setOfNodesToKeep.count( node ))
4240           aListOfNodes.push_front( node );
4241         else
4242           aListOfNodes.push_back( node );
4243       }
4244     }
4245     if ( aListOfNodes.size() < 2 )
4246       aListOfListOfNodes.pop_back();
4247
4248     if ( i > 0 ) aTPythonDump << ", ";
4249     aTPythonDump << aNodeGroup;
4250   }
4251
4252   getEditor().MergeNodes( aListOfListOfNodes, AvoidMakingHoles );
4253
4254   aTPythonDump << "], " << NodesToKeep << ", " << AvoidMakingHoles << ")";
4255
4256   declareMeshModified( /*isReComputeSafe=*/false );
4257
4258   SMESH_CATCH( SMESH::throwCorbaException );
4259 }
4260
4261 //=======================================================================
4262 //function : FindEqualElements
4263 //purpose  :
4264 //=======================================================================
4265
4266 void SMESH_MeshEditor_i::FindEqualElements(const SMESH::ListOfIDSources&  theObjects,
4267                                            const SMESH::ListOfIDSources&  theExceptObjects,
4268                                            SMESH::array_of_long_array_out theGroupsOfElementsID)
4269 {
4270   SMESH_TRY;
4271   initData();
4272
4273   theGroupsOfElementsID = new SMESH::array_of_long_array;
4274
4275   TIDSortedElemSet elems;
4276   bool hasOkObject = false;
4277   bool emptyIfIsMesh= ( theObjects.length() == 1 && theExceptObjects.length() == 0 );
4278
4279   for ( CORBA::ULong i = 0; i < theObjects.length(); ++i )
4280   {
4281     SMESH::SMESH_GroupBase_var group = SMESH::SMESH_GroupBase::_narrow( theObjects[i] );
4282     if ( !( !group->_is_nil() && group->GetType() == SMESH::NODE ))
4283       if ( idSourceToSet( theObjects[i], getMeshDS(), elems, SMDSAbs_All, emptyIfIsMesh ))
4284         hasOkObject = true;
4285   }
4286
4287   if ( hasOkObject )
4288   {
4289     for ( CORBA::ULong i = 0; i < theExceptObjects.length(); ++i )
4290     {
4291       if ( SMDS_ElemIteratorPtr elemIt = myMesh_i->GetElements( theExceptObjects[i], SMESH::ALL ))
4292         while ( elemIt->more() )
4293           elems.erase( elemIt->next() );
4294     }
4295
4296     ::SMESH_MeshEditor::TListOfListOfElementsID aListOfListOfElementsID;
4297     getEditor().FindEqualElements( elems, aListOfListOfElementsID );
4298
4299     theGroupsOfElementsID->length( aListOfListOfElementsID.size() );
4300
4301     ::SMESH_MeshEditor::TListOfListOfElementsID::iterator arraysIt =
4302         aListOfListOfElementsID.begin();
4303     for (CORBA::Long j = 0; arraysIt != aListOfListOfElementsID.end(); ++arraysIt, ++j)
4304     {
4305       SMESH::long_array& aGroup = (*theGroupsOfElementsID)[ j ];
4306       list<int>&      listOfIDs = *arraysIt;
4307       aGroup.length( listOfIDs.size() );
4308       list<int>::iterator idIt = listOfIDs.begin();
4309       for (int k = 0; idIt != listOfIDs.end(); ++idIt, ++k )
4310         aGroup[ k ] = *idIt;
4311     }
4312
4313     TPythonDump() << "equal_elements = " << this << ".FindEqualElements( "
4314                   << theObjects << ", "
4315                   << theExceptObjects << " )";
4316   }
4317
4318   SMESH_CATCH( SMESH::throwCorbaException );
4319 }
4320
4321 //=======================================================================
4322 //function : MergeElements
4323 //purpose  :
4324 //=======================================================================
4325
4326 void SMESH_MeshEditor_i::MergeElements(const SMESH::array_of_long_array& theGroupsOfElementsID,
4327                                        const SMESH::ListOfIDSources&     theElementsToKeep)
4328 {
4329   SMESH_TRY;
4330   initData();
4331
4332   TPythonDump aTPythonDump;
4333   aTPythonDump << this << ".MergeElements( [";
4334
4335   NCollection_Map< int > idsToKeep;
4336   for ( CORBA::ULong i = 0; i < theElementsToKeep.length(); i++ )
4337   {
4338     if ( CORBA::is_nil( theElementsToKeep[i] ))
4339       continue;
4340     SMESH::array_of_ElementType_var elemTypes = theElementsToKeep[i]->GetTypes();
4341     if ( elemTypes->length() == 1 && elemTypes[0] == SMESH::NODE )
4342       continue;
4343     SMESH::long_array_var elementsId = theElementsToKeep[i]->GetIDs();
4344     for ( CORBA::ULong j = 0; j < elementsId->length(); ++j )
4345       idsToKeep.Add( elementsId[ j ]);
4346   }
4347
4348   ::SMESH_MeshEditor::TListOfListOfElementsID aListOfListOfElementsID;
4349
4350   for ( CORBA::ULong i = 0; i < theGroupsOfElementsID.length(); i++ )
4351   {
4352     const SMESH::long_array& anElemsIDGroup = theGroupsOfElementsID[ i ];
4353     aListOfListOfElementsID.push_back( list< int >() );
4354     list< int >& aListOfElemsID = aListOfListOfElementsID.back();
4355     for ( CORBA::ULong j = 0; j < anElemsIDGroup.length(); j++ )
4356     {
4357       CORBA::Long id = anElemsIDGroup[ j ];
4358       if ( idsToKeep.Contains( id )) aListOfElemsID.push_front( id );
4359       else                           aListOfElemsID.push_back( id );
4360     }
4361     if ( aListOfElemsID.size() < 2 )
4362       aListOfListOfElementsID.pop_back();
4363     if ( i > 0 ) aTPythonDump << ", ";
4364     aTPythonDump << anElemsIDGroup;
4365   }
4366
4367   getEditor().MergeElements(aListOfListOfElementsID);
4368
4369   declareMeshModified( /*isReComputeSafe=*/true );
4370
4371   aTPythonDump << "], " << theElementsToKeep << " )";
4372
4373   SMESH_CATCH( SMESH::throwCorbaException );
4374 }
4375
4376 //=======================================================================
4377 //function : MergeEqualElements
4378 //purpose  :
4379 //=======================================================================
4380
4381 void SMESH_MeshEditor_i::MergeEqualElements()
4382 {
4383   SMESH_TRY;
4384   initData();
4385
4386   getEditor().MergeEqualElements();
4387
4388   declareMeshModified( /*isReComputeSafe=*/true );
4389
4390   TPythonDump() << this << ".MergeEqualElements()";
4391
4392   SMESH_CATCH( SMESH::throwCorbaException );
4393 }
4394
4395 //=============================================================================
4396 /*!
4397  * Move the node to a given point
4398  */
4399 //=============================================================================
4400
4401 CORBA::Boolean SMESH_MeshEditor_i::MoveNode(CORBA::Long   NodeID,
4402                                             CORBA::Double x,
4403                                             CORBA::Double y,
4404                                             CORBA::Double z)
4405 {
4406   SMESH_TRY;
4407   initData(/*deleteSearchers=*/false);
4408
4409   const SMDS_MeshNode * node = getMeshDS()->FindNode( NodeID );
4410   if ( !node )
4411     return false;
4412
4413   if ( theNodeSearcher )
4414     theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
4415
4416   if ( myIsPreviewMode ) // make preview data
4417   {
4418     // in a preview mesh, make edges linked to a node
4419     TPreviewMesh& tmpMesh = *getPreviewMesh();
4420     TIDSortedElemSet linkedNodes;
4421     ::SMESH_MeshEditor::GetLinkedNodes( node, linkedNodes );
4422     TIDSortedElemSet::iterator nIt = linkedNodes.begin();
4423     SMDS_MeshNode *nodeCpy1 = tmpMesh.Copy(node);
4424     for ( ; nIt != linkedNodes.end(); ++nIt )
4425     {
4426       SMDS_MeshNode *nodeCpy2 = tmpMesh.Copy ( cast2Node( *nIt ));
4427       tmpMesh.GetMeshDS()->AddEdge(nodeCpy1, nodeCpy2);
4428     }
4429     // move copied node
4430     if ( nodeCpy1 )
4431       tmpMesh.GetMeshDS()->MoveNode(nodeCpy1, x, y, z);
4432     // fill preview data
4433   }
4434   else if ( theNodeSearcher ) // move node and update theNodeSearcher data accordingly
4435     theNodeSearcher->MoveNode(node, gp_Pnt( x,y,z ));
4436   else
4437     getMeshDS()->MoveNode(node, x, y, z);
4438
4439   if ( !myIsPreviewMode )
4440   {
4441     // Update Python script
4442     TPythonDump() << "isDone = " << this << ".MoveNode( "
4443                   << NodeID << ", " << TVar(x) << ", " << TVar(y) << ", " << TVar(z) << " )";
4444     declareMeshModified( /*isReComputeSafe=*/false );
4445   }
4446
4447   SMESH_CATCH( SMESH::throwCorbaException );
4448
4449   return true;
4450 }
4451
4452 //================================================================================
4453 /*!
4454  * \brief Return ID of node closest to a given point
4455  */
4456 //================================================================================
4457
4458 CORBA::Long SMESH_MeshEditor_i::FindNodeClosestTo(CORBA::Double x,
4459                                                   CORBA::Double y,
4460                                                   CORBA::Double z)
4461 {
4462   SMESH_TRY;
4463   theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
4464
4465   if ( !theNodeSearcher ) {
4466     theNodeSearcher = SMESH_MeshAlgos::GetNodeSearcher( *getMeshDS() );
4467   }
4468   gp_Pnt p( x,y,z );
4469   if ( const SMDS_MeshNode* node = theNodeSearcher->FindClosestTo( p ))
4470     return node->GetID();
4471
4472   SMESH_CATCH( SMESH::throwCorbaException );
4473   return 0;
4474 }
4475
4476 //================================================================================
4477 /*!
4478  * \brief If the given ID is a valid node ID (nodeID > 0), just move this node, else
4479  * move the node closest to the point to point's location and return ID of the node
4480  */
4481 //================================================================================
4482
4483 CORBA::Long SMESH_MeshEditor_i::MoveClosestNodeToPoint(CORBA::Double x,
4484                                                        CORBA::Double y,
4485                                                        CORBA::Double z,
4486                                                        CORBA::Long   theNodeID)
4487 {
4488   SMESH_TRY;
4489   // We keep theNodeSearcher until any mesh modification:
4490   // 1) initData() deletes theNodeSearcher at any edition,
4491   // 2) TSearchersDeleter - at any mesh compute event and mesh change
4492
4493   initData(/*deleteSearchers=*/false);
4494
4495   theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
4496
4497   int nodeID = theNodeID;
4498   const SMDS_MeshNode* node = getMeshDS()->FindNode( nodeID );
4499   if ( !node ) // preview moving node
4500   {
4501     if ( !theNodeSearcher ) {
4502       theNodeSearcher = SMESH_MeshAlgos::GetNodeSearcher( *getMeshDS() );
4503     }
4504     gp_Pnt p( x,y,z );
4505     node = theNodeSearcher->FindClosestTo( p );
4506   }
4507   if ( node ) {
4508     nodeID = node->GetID();
4509     if ( myIsPreviewMode ) // make preview data
4510     {
4511       // in a preview mesh, make edges linked to a node
4512       TPreviewMesh tmpMesh = *getPreviewMesh();
4513       TIDSortedElemSet linkedNodes;
4514       ::SMESH_MeshEditor::GetLinkedNodes( node, linkedNodes );
4515       TIDSortedElemSet::iterator nIt = linkedNodes.begin();
4516       for ( ; nIt != linkedNodes.end(); ++nIt )
4517       {
4518         SMDS_LinearEdge edge( node, cast2Node( *nIt ));
4519         tmpMesh.Copy( &edge );
4520       }
4521       // move copied node
4522       node = tmpMesh.GetMeshDS()->FindNode( nodeID );
4523       if ( node )
4524         tmpMesh.GetMeshDS()->MoveNode(node, x, y, z);
4525       // fill preview data
4526     }
4527     else if ( theNodeSearcher ) // move node and update theNodeSearcher data accordingly
4528     {
4529       theNodeSearcher->MoveNode(node, gp_Pnt( x,y,z ));
4530     }
4531     else
4532     {
4533       getMeshDS()->MoveNode(node, x, y, z);
4534     }
4535   }
4536
4537   if ( !myIsPreviewMode )
4538   {
4539     TPythonDump() << "nodeID = " << this
4540                   << ".MoveClosestNodeToPoint( "<< x << ", " << y << ", " << z
4541                   << ", " << nodeID << " )";
4542
4543     declareMeshModified( /*isReComputeSafe=*/false );
4544   }
4545
4546   return nodeID;
4547
4548   SMESH_CATCH( SMESH::throwCorbaException );
4549   return 0;
4550 }
4551
4552 //=======================================================================
4553 /*!
4554  * Return elements of given type where the given point is IN or ON.
4555  *
4556  * 'ALL' type means elements of any type excluding nodes
4557  */
4558 //=======================================================================
4559
4560 SMESH::long_array* SMESH_MeshEditor_i::FindElementsByPoint(CORBA::Double      x,
4561                                                            CORBA::Double      y,
4562                                                            CORBA::Double      z,
4563                                                            SMESH::ElementType type)
4564 {
4565   SMESH_TRY;
4566   SMESH::long_array_var res = new SMESH::long_array;
4567   vector< const SMDS_MeshElement* > foundElems;
4568
4569   theSearchersDeleter.Set( myMesh );
4570   if ( !theElementSearcher ) {
4571     theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() );
4572   }
4573   theElementSearcher->FindElementsByPoint( gp_Pnt( x,y,z ),
4574                                            SMDSAbs_ElementType( type ),
4575                                            foundElems);
4576   res->length( foundElems.size() );
4577   for ( size_t i = 0; i < foundElems.size(); ++i )
4578     res[i] = foundElems[i]->GetID();
4579
4580   return res._retn();
4581
4582   SMESH_CATCH( SMESH::throwCorbaException );
4583   return 0;
4584 }
4585
4586 //=======================================================================
4587 //function : FindAmongElementsByPoint
4588 //purpose  : Searching among the given elements, return elements of given type 
4589 //           where the given point is IN or ON.
4590 //           'ALL' type means elements of any type excluding nodes
4591 //=======================================================================
4592
4593 SMESH::long_array*
4594 SMESH_MeshEditor_i::FindAmongElementsByPoint(SMESH::SMESH_IDSource_ptr elementIDs,
4595                                              CORBA::Double             x,
4596                                              CORBA::Double             y,
4597                                              CORBA::Double             z,
4598                                              SMESH::ElementType        type)
4599 {
4600   SMESH_TRY;
4601   SMESH::long_array_var res = new SMESH::long_array;
4602
4603   prepareIdSource( elementIDs );
4604   if ( type != SMESH::NODE )
4605   {
4606     SMESH::array_of_ElementType_var types = elementIDs->GetTypes();
4607     if ( types->length() == 1 && // a part contains only nodes or 0D elements
4608          ( types[0] == SMESH::NODE || types[0] == SMESH::ELEM0D || types[0] == SMESH::BALL) &&
4609          type != types[0] ) // but search of elements of dim > 0
4610       return res._retn();
4611   }
4612
4613   SMESH::SMESH_Mesh_var mesh = elementIDs->GetMesh();
4614   SMESH_Mesh_i*       mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
4615   if ( mesh_i != myMesh_i )
4616   {
4617     SMESH::SMESH_MeshEditor_var editor=
4618       myIsPreviewMode ? mesh_i->GetMeshEditPreviewer() : mesh_i->GetMeshEditor();
4619     return editor->FindAmongElementsByPoint( elementIDs, x,y,z, type );
4620   }
4621
4622   if ( SMESH::DownCast<SMESH_Mesh_i*>( elementIDs )) // elementIDs is the whole mesh 
4623     return FindElementsByPoint( x,y,z, type );
4624
4625   TIDSortedElemSet elements; // elems should live until FindElementsByPoint() finishes
4626
4627   theSearchersDeleter.Set( myMesh, getPartIOR( elementIDs, type ));
4628   if ( !theElementSearcher )
4629   {
4630     // create a searcher from elementIDs
4631     SMDS_ElemIteratorPtr elemIt;
4632     if ( ! SMESH::DownCast<SMESH_Mesh_i*>( elementIDs ))
4633     {
4634       //prepareIdSource( elementIDs );
4635       elemIt = myMesh_i->GetElements( elementIDs, type );
4636       if ( !elemIt )
4637         return res._retn();
4638     }
4639     theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), elemIt );
4640   }
4641
4642   vector< const SMDS_MeshElement* > foundElems;
4643
4644   theElementSearcher->FindElementsByPoint( gp_Pnt( x,y,z ),
4645                                            SMDSAbs_ElementType( type ),
4646                                            foundElems);
4647   res->length( foundElems.size() );
4648   for ( size_t i = 0; i < foundElems.size(); ++i )
4649     res[i] = foundElems[i]->GetID();
4650
4651   return res._retn();
4652
4653   SMESH_CATCH( SMESH::throwCorbaException );
4654   return 0;
4655 }
4656
4657 //=======================================================================
4658 //function : ProjectPoint
4659 //purpose  : Project a point to a mesh object.
4660 //           Return ID of an element of given type where the given point is projected
4661 //           and coordinates of the projection point.
4662 //           In the case if nothing found, return -1 and []
4663 //=======================================================================
4664
4665 CORBA::Long SMESH_MeshEditor_i::ProjectPoint(CORBA::Double             x,
4666                                              CORBA::Double             y,
4667                                              CORBA::Double             z,
4668                                              SMESH::ElementType        type,
4669                                              SMESH::SMESH_IDSource_ptr meshObject,
4670                                              SMESH::double_array_out   projecton)
4671 {
4672   if ( CORBA::is_nil( meshObject ))
4673     THROW_SALOME_CORBA_EXCEPTION("NULL meshObject", SALOME::BAD_PARAM);
4674
4675   SMESH_TRY;
4676
4677   SMESH::SMESH_Mesh_var mesh = meshObject->GetMesh();
4678   SMESH_Mesh_i*       mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
4679   if ( mesh_i != myMesh_i )
4680   {
4681     SMESH::SMESH_MeshEditor_var editor=
4682       myIsPreviewMode ? mesh_i->GetMeshEditPreviewer() : mesh_i->GetMeshEditor();
4683     return editor->ProjectPoint( x,y,z, type, meshObject, projecton );
4684   }
4685
4686
4687   theSearchersDeleter.Set( myMesh, getPartIOR( meshObject, type ));
4688   if ( !theElementSearcher )
4689   {
4690     // create a searcher from meshObject
4691
4692     SMDS_ElemIteratorPtr elemIt;
4693     if ( ! SMESH::DownCast<SMESH_Mesh_i*>( meshObject ))
4694     {
4695       prepareIdSource( meshObject );
4696       elemIt = myMesh_i->GetElements( meshObject, type );
4697       if ( !elemIt )
4698         return -1;
4699     }
4700     theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), elemIt );
4701   }
4702
4703   const SMDS_MeshElement* elem = 0;
4704   gp_XYZ pProj = theElementSearcher->Project( gp_Pnt( x,y,z ),
4705                                               SMDSAbs_ElementType( type ),
4706                                               &elem );
4707
4708   projecton = new SMESH::double_array();
4709   if ( elem && !elem->IsNull() )
4710   {
4711     projecton->length( 3 );
4712     projecton[0] = pProj.X();
4713     projecton[1] = pProj.Y();
4714     projecton[2] = pProj.Z();
4715     return elem->GetID();
4716   }
4717
4718   SMESH_CATCH( SMESH::throwCorbaException );
4719   return -1;
4720 }
4721
4722 //=======================================================================
4723 //function : GetPointState
4724 //purpose  : Return point state in a closed 2D mesh in terms of TopAbs_State enumeration.
4725 //           TopAbs_UNKNOWN state means that either mesh is wrong or the analysis fails.
4726 //=======================================================================
4727
4728 CORBA::Short SMESH_MeshEditor_i::GetPointState(CORBA::Double x,
4729                                                CORBA::Double y,
4730                                                CORBA::Double z)
4731 {
4732   SMESH_TRY;
4733   theSearchersDeleter.Set( myMesh );
4734   if ( !theElementSearcher ) {
4735     theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() );
4736   }
4737   return CORBA::Short( theElementSearcher->GetPointState( gp_Pnt( x,y,z )));
4738
4739   SMESH_CATCH( SMESH::throwCorbaException );
4740   return 0;
4741 }
4742
4743 //=======================================================================
4744 //function : IsManifold
4745 //purpose  : Check if a 2D mesh is manifold
4746 //=======================================================================
4747
4748 CORBA::Boolean SMESH_MeshEditor_i::IsManifold()
4749 {
4750   bool isManifold = true;
4751
4752   SMESH_TRY;
4753   SMESH_MeshAlgos::TFreeBorderVec foundFreeBordes;
4754   SMESH_MeshAlgos::FindFreeBorders( *getMeshDS(),
4755                                     foundFreeBordes,
4756                                     /*closedOnly=*/true,
4757                                     &isManifold );
4758   SMESH_CATCH( SMESH::throwCorbaException );
4759
4760   return isManifold;
4761 }
4762
4763 //=======================================================================
4764 //function : IsCoherentOrientation2D
4765 //purpose  : Check if orientation of 2D elements is coherent
4766 //=======================================================================
4767
4768 CORBA::Boolean SMESH_MeshEditor_i::IsCoherentOrientation2D()
4769 {
4770   bool isGoodOri = true;
4771
4772   SMESH_TRY;
4773   SMESH_MeshAlgos::TFreeBorderVec foundFreeBordes;
4774   SMESH_MeshAlgos::FindFreeBorders( *getMeshDS(),
4775                                     foundFreeBordes,
4776                                     /*closedOnly=*/true,
4777                                     /*isManifold=*/0,
4778                                     &isGoodOri);
4779   SMESH_CATCH( SMESH::throwCorbaException );
4780
4781   return isGoodOri;
4782 }
4783
4784 //=======================================================================
4785 //function : Get1DBranches
4786 //purpose  : Partition given 1D elements into groups of contiguous edges.
4787 //           A node where number of meeting edges != 2 is a group end.
4788 //           An optional startNode is used to orient groups it belongs to.
4789 //return   : a list of edge groups and a list of corresponding node groups.
4790 //           If a group is closed, the first and last nodes of the group are same.
4791 //=======================================================================
4792
4793 SMESH::array_of_long_array*
4794 SMESH_MeshEditor_i::Get1DBranches( SMESH::SMESH_IDSource_ptr      theEdges,
4795                                    CORBA::Long                    theStartNode,
4796                                    SMESH::array_of_long_array_out theNodeGroups )
4797 {
4798   if ( CORBA::is_nil( theEdges ))
4799     THROW_SALOME_CORBA_EXCEPTION("Get1DBranches(): NULL group given", SALOME::BAD_PARAM);
4800
4801   SMESH::array_of_long_array_var edgeGroupArray = new SMESH::array_of_long_array;
4802   theNodeGroups = new SMESH::array_of_long_array;
4803
4804   SMESH_TRY;
4805
4806   prepareIdSource( theEdges );
4807
4808   SMESH_MeshAlgos::TElemGroupVector edgeBranches;
4809   SMESH_MeshAlgos::TNodeGroupVector nodeBranches;
4810   SMESH_MeshAlgos::Get1DBranches( SMESH_Mesh_i::GetElements( theEdges, SMESH::EDGE ),
4811                                   edgeBranches,
4812                                   nodeBranches,
4813                                   getMeshDS()->FindNode( theStartNode ));
4814
4815   edgeGroupArray->length( edgeBranches.size() );
4816   for ( size_t iG = 0; iG < edgeBranches.size(); ++iG )
4817   {
4818     edgeGroupArray[ iG ].length( edgeBranches[ iG ].size() );
4819     for ( size_t i = 0; i < edgeBranches[ iG ].size(); ++i )
4820       edgeGroupArray[ iG ][ i ] = edgeBranches[ iG ][ i ]->GetID();
4821   }
4822
4823   theNodeGroups->length( nodeBranches.size() );
4824   for ( size_t iG = 0; iG < nodeBranches.size(); ++iG )
4825   {
4826     theNodeGroups[ iG ].length( nodeBranches[ iG ].size() );
4827     for ( size_t i = 0; i < nodeBranches[ iG ].size(); ++i )
4828       theNodeGroups[ iG ][ i ] = nodeBranches[ iG ][ i ]->GetID();
4829   }
4830
4831   SMESH_CATCH( SMESH::throwCorbaException );
4832
4833   return edgeGroupArray._retn();
4834 }
4835
4836 //=======================================================================
4837 //function : FindSharpEdges
4838 //purpose  : Return sharp edges of faces and non-manifold ones. Optionally add existing edges.
4839 //=======================================================================
4840
4841 SMESH::ListOfEdges* SMESH_MeshEditor_i::FindSharpEdges(CORBA::Double  theAngle,
4842                                                        CORBA::Boolean theAddExisting)
4843 {
4844   SMESH::ListOfEdges_var resultEdges = new SMESH::ListOfEdges;
4845   SMESH_TRY;
4846
4847   initData();
4848
4849   std::vector< SMESH_MeshAlgos::Edge > edges =
4850     SMESH_MeshAlgos::FindSharpEdges( getMeshDS(), theAngle, theAddExisting );
4851
4852   if ( myIsPreviewMode ) // fill a preview mesh with edges
4853   {
4854     TPreviewMesh* mesh = getPreviewMesh( SMDSAbs_Edge );
4855     SMDS_Mesh*  meshDS = mesh->GetMeshDS();
4856     for ( size_t i = 0; i < edges.size(); ++i )
4857     {
4858       SMESH_NodeXYZ xyz1( edges[i]._node1), xyz2( edges[i]._node2);
4859       SMDS_MeshNode* n1 = meshDS->AddNode( xyz1.X(), xyz1.Y(), xyz1.Z() );
4860       SMDS_MeshNode* n2 = meshDS->AddNode( xyz2.X(), xyz2.Y(), xyz2.Z() );
4861       if ( edges[i]._medium )
4862       {
4863         xyz1.Set( edges[i]._medium );
4864         SMDS_MeshNode* nm = meshDS->AddNode( xyz1.X(), xyz1.Y(), xyz1.Z() );
4865         mesh->GetMeshDS()->AddEdge( n1, n2, nm );
4866       }
4867       else
4868       {
4869         mesh->GetMeshDS()->AddEdge( n1, n2 );
4870       }
4871     }
4872   }
4873   else
4874   {
4875     resultEdges->length( edges.size() );
4876     for ( size_t i = 0; i < edges.size(); ++i )
4877     {
4878       resultEdges[ i ].node1  = edges[i]._node1->GetID();
4879       resultEdges[ i ].node2  = edges[i]._node2->GetID();
4880       resultEdges[ i ].medium = edges[i]._medium ? edges[i]._medium->GetID() : 0;
4881     }
4882   }
4883   SMESH_CATCH( SMESH::throwCorbaException );
4884   return resultEdges._retn();
4885 }
4886
4887 //=======================================================================
4888 //function : FindFreeBorders
4889 //purpose  : Returns all or only closed FreeBorder's.
4890 //=======================================================================
4891
4892 SMESH::ListOfFreeBorders* SMESH_MeshEditor_i::FindFreeBorders(CORBA::Boolean closedOnly)
4893 {
4894   SMESH::ListOfFreeBorders_var resBorders = new SMESH::ListOfFreeBorders;
4895   SMESH_TRY;
4896
4897   SMESH_MeshAlgos::TFreeBorderVec foundFreeBordes;
4898   SMESH_MeshAlgos::FindFreeBorders( *getMeshDS(), foundFreeBordes, closedOnly );
4899
4900   resBorders->length( foundFreeBordes.size() );
4901   for ( size_t i = 0; i < foundFreeBordes.size(); ++i )
4902   {
4903     const SMESH_MeshAlgos::TFreeBorder& bordNodes = foundFreeBordes[i];
4904     SMESH::FreeBorder&                    bordOut = resBorders[i];
4905     bordOut.nodeIDs.length( bordNodes.size() );
4906     for ( size_t iN = 0; iN < bordNodes.size(); ++iN )
4907       bordOut.nodeIDs[ iN ] = bordNodes[ iN ]->GetID();
4908   }
4909
4910   SMESH_CATCH( SMESH::throwCorbaException );
4911
4912   return resBorders._retn();
4913 }
4914
4915 //=======================================================================
4916 //function : FillHole
4917 //purpose  : Fill with 2D elements a hole defined by a FreeBorder.
4918 //=======================================================================
4919
4920 SMESH::SMESH_Group_ptr 
4921 SMESH_MeshEditor_i::FillHole(const SMESH::FreeBorder& theHole,
4922                              const char*              theGroupName)
4923 {
4924   initData();
4925
4926   if ( theHole.nodeIDs.length() < 4 )
4927     THROW_SALOME_CORBA_EXCEPTION("A hole should be bound by at least 3 nodes", SALOME::BAD_PARAM);
4928   if ( theHole.nodeIDs[0] != theHole.nodeIDs[ theHole.nodeIDs.length()-1 ] )
4929     THROW_SALOME_CORBA_EXCEPTION("Not closed hole boundary. "
4930                                  "First and last nodes must be same", SALOME::BAD_PARAM);
4931
4932   SMESH_MeshAlgos::TFreeBorder bordNodes;
4933   bordNodes.resize( theHole.nodeIDs.length() );
4934   for ( size_t iN = 0; iN < theHole.nodeIDs.length(); ++iN )
4935   {
4936     bordNodes[ iN ] = getMeshDS()->FindNode( theHole.nodeIDs[ iN ]);
4937     if ( !bordNodes[ iN ] )
4938       THROW_SALOME_CORBA_EXCEPTION(SMESH_Comment("Node #") << theHole.nodeIDs[ iN ]
4939                                    << " does not exist", SALOME::BAD_PARAM);
4940   }
4941
4942   SMESH_TRY;
4943
4944   // prepare a preview mesh
4945   MeshEditor_I::TPreviewMesh* previewMesh = 0;
4946   SMDS_Mesh* meshDS = getMeshDS();
4947   if ( myIsPreviewMode )
4948   {
4949     // copy faces sharing nodes of theHole
4950     TIDSortedElemSet holeFaces;
4951     previewMesh = getPreviewMesh( SMDSAbs_Face );
4952     for ( size_t i = 0; i < bordNodes.size(); ++i )
4953     {
4954       SMDS_ElemIteratorPtr fIt = bordNodes[i]->GetInverseElementIterator( SMDSAbs_Face );
4955       while ( fIt->more() )
4956       {
4957         const SMDS_MeshElement* face = fIt->next();
4958         if ( holeFaces.insert( face ).second )
4959           previewMesh->Copy( face );
4960       }
4961       bordNodes[i] = previewMesh->GetMeshDS()->FindNode( bordNodes[i]->GetID() );
4962       ASSERT( bordNodes[i] );
4963     }
4964     meshDS = previewMesh->GetMeshDS();
4965   }
4966
4967   // fill the hole
4968   std::vector<const SMDS_MeshElement*> newFaces;
4969   SMESH_MeshAlgos::FillHole( bordNodes, *meshDS, newFaces );
4970
4971   if ( myIsPreviewMode )
4972   {
4973     // show new faces
4974     previewMesh->Clear();
4975     for ( size_t i = 0; i < newFaces.size(); ++i )
4976       previewMesh->Copy( newFaces[i] );
4977   }
4978   else
4979   {
4980     // return new faces via a group
4981     SMESH::SMESH_Group_var group;
4982     if ( theGroupName && theGroupName[0] && !newFaces.empty() )
4983     {
4984       SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
4985       for ( CORBA::ULong i = 0; i < groups->length(); ++i )
4986       {
4987         SMESH::SMESH_GroupBase_var g = groups[ i ];
4988         if ( g->GetType() != SMESH::FACE ) continue;
4989         SMESH::SMESH_Group_var standalone = SMESH::SMESH_Group::_narrow( g );
4990         if ( standalone->_is_nil() ) continue;
4991         CORBA::String_var name = g->GetName();
4992         if ( strcmp( theGroupName, name.in() ) == 0 )
4993         {
4994           group = standalone;
4995           break;
4996         }
4997       }
4998       if ( group->_is_nil() )
4999         group = myMesh_i->CreateGroup( SMESH::FACE, theGroupName );
5000
5001       if ( !group->_is_nil() )
5002       {
5003         SMESH_GroupBase_i * grpI = SMESH::DownCast< SMESH_GroupBase_i* >( group );
5004         SMESHDS_Group*     grpDS = static_cast< SMESHDS_Group* >( grpI->GetGroupDS() );
5005         for ( size_t i = 0; i < newFaces.size(); ++i )
5006           grpDS->Add( newFaces[ i ]);
5007       }
5008     }
5009
5010     // fill LastCreated
5011     getEditor().ClearLastCreated();
5012     SMESH_SequenceOfElemPtr& aSeq =
5013       const_cast<SMESH_SequenceOfElemPtr&>( getEditor().GetLastCreatedElems() );
5014     aSeq.swap( newFaces );
5015
5016     TPythonDump pyDump;
5017     if ( group->_is_nil() ) pyDump << "_group = ";
5018     else                    pyDump << group << " = ";
5019     pyDump << this << ".FillHole( SMESH.FreeBorder(" << theHole.nodeIDs << " ))";
5020
5021     return group._retn();
5022   }
5023
5024   SMESH_CATCH( SMESH::throwCorbaException );
5025
5026   return SMESH::SMESH_Group::_nil();
5027 }
5028
5029 //=======================================================================
5030 //function : convError
5031 //purpose  :
5032 //=======================================================================
5033
5034 #define RETCASE(enm) case ::SMESH_MeshEditor::enm: return SMESH::SMESH_MeshEditor::enm;
5035
5036 static SMESH::SMESH_MeshEditor::Sew_Error convError( const::SMESH_MeshEditor::Sew_Error e )
5037 {
5038   switch ( e ) {
5039     RETCASE( SEW_OK );
5040     RETCASE( SEW_BORDER1_NOT_FOUND );
5041     RETCASE( SEW_BORDER2_NOT_FOUND );
5042     RETCASE( SEW_BOTH_BORDERS_NOT_FOUND );
5043     RETCASE( SEW_BAD_SIDE_NODES );
5044     RETCASE( SEW_VOLUMES_TO_SPLIT );
5045     RETCASE( SEW_DIFF_NB_OF_ELEMENTS );
5046     RETCASE( SEW_TOPO_DIFF_SETS_OF_ELEMENTS );
5047     RETCASE( SEW_BAD_SIDE1_NODES );
5048     RETCASE( SEW_BAD_SIDE2_NODES );
5049     RETCASE( SEW_INTERNAL_ERROR );
5050   }
5051   return SMESH::SMESH_MeshEditor::SEW_OK;
5052 }
5053
5054 //=======================================================================
5055 /*!
5056  * Returns groups of FreeBorder's coincident within the given tolerance.
5057  * If the tolerance <= 0.0 then one tenth of an average size of elements adjacent
5058  * to free borders being compared is used.
5059  */
5060 //=======================================================================
5061
5062 SMESH::CoincidentFreeBorders*
5063 SMESH_MeshEditor_i::FindCoincidentFreeBorders(CORBA::Double tolerance)
5064 {
5065   SMESH::CoincidentFreeBorders_var aCFB = new SMESH::CoincidentFreeBorders;
5066
5067   SMESH_TRY;
5068
5069   SMESH_MeshAlgos::CoincidentFreeBorders cfb;
5070   SMESH_MeshAlgos::FindCoincidentFreeBorders( *getMeshDS(), tolerance, cfb );
5071
5072   // copy free borders
5073   aCFB->borders.length( cfb._borders.size() );
5074   for ( size_t i = 0; i < cfb._borders.size(); ++i )
5075   {
5076     SMESH_MeshAlgos::TFreeBorder& nodes = cfb._borders[i];
5077     SMESH::FreeBorder&             aBRD = aCFB->borders[i];
5078     aBRD.nodeIDs.length( nodes.size() );
5079     for ( size_t iN = 0; iN < nodes.size(); ++iN )
5080       aBRD.nodeIDs[ iN ] = nodes[ iN ]->GetID();
5081   }
5082
5083   // copy coincident parts
5084   aCFB->coincidentGroups.length( cfb._coincidentGroups.size() );
5085   for ( size_t i = 0; i < cfb._coincidentGroups.size(); ++i )
5086   {
5087     SMESH_MeshAlgos::TCoincidentGroup& grp = cfb._coincidentGroups[i];
5088     SMESH::FreeBordersGroup&          aGRP = aCFB->coincidentGroups[i];
5089     aGRP.length( grp.size() );
5090     for ( size_t iP = 0; iP < grp.size(); ++iP )
5091     {
5092       SMESH_MeshAlgos::TFreeBorderPart& part = grp[ iP ];
5093       SMESH::FreeBorderPart&           aPART = aGRP[ iP ];
5094       aPART.border   = part._border;
5095       aPART.node1    = part._node1;
5096       aPART.node2    = part._node2;
5097       aPART.nodeLast = part._nodeLast;
5098     }
5099   }
5100   SMESH_CATCH( SMESH::doNothing );
5101
5102   TPythonDump() << "CoincidentFreeBorders = "
5103                 << this << ".FindCoincidentFreeBorders( " << tolerance << " )";
5104
5105   return aCFB._retn();
5106 }
5107
5108 //=======================================================================
5109 /*!
5110  * Sew FreeBorder's of each group
5111  */
5112 //=======================================================================
5113
5114 CORBA::Short SMESH_MeshEditor_i::
5115 SewCoincidentFreeBorders(const SMESH::CoincidentFreeBorders& freeBorders,
5116                          CORBA::Boolean                      createPolygons,
5117                          CORBA::Boolean                      createPolyhedra)
5118 {
5119   CORBA::Short nbSewed = 0;
5120
5121   SMESH_MeshAlgos::TFreeBorderVec groups;
5122   SMESH_MeshAlgos::TFreeBorder    borderNodes; // triples of nodes for every FreeBorderPart
5123
5124   // check the input and collect nodes
5125   for ( CORBA::ULong i = 0; i < freeBorders.coincidentGroups.length(); ++i )
5126   {
5127     borderNodes.clear();
5128     const SMESH::FreeBordersGroup& aGRP = freeBorders.coincidentGroups[ i ];
5129     for ( CORBA::ULong iP = 0; iP < aGRP.length(); ++iP )
5130     {
5131       const SMESH::FreeBorderPart& aPART = aGRP[ iP ];
5132       if ( aPART.border < 0 || aPART.border >= (int) freeBorders.borders.length() )
5133         THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::border index", SALOME::BAD_PARAM);
5134
5135       const SMESH::FreeBorder& aBRD = freeBorders.borders[ aPART.border ];
5136
5137       if ( aPART.node1 < 0 || aPART.node1 > (int) aBRD.nodeIDs.length() )
5138         THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::node1", SALOME::BAD_PARAM);
5139       if ( aPART.node2 < 0 || aPART.node2 > (int) aBRD.nodeIDs.length() )
5140         THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::node2", SALOME::BAD_PARAM);
5141       if ( aPART.nodeLast < 0 || aPART.nodeLast > (int) aBRD.nodeIDs.length() )
5142         THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::nodeLast", SALOME::BAD_PARAM);
5143
5144       // do not keep these nodes for further sewing as nodes can be removed by the sewing
5145       const SMDS_MeshNode* n1 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.node1    ]);
5146       const SMDS_MeshNode* n2 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.node2    ]);
5147       const SMDS_MeshNode* n3 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.nodeLast ]);
5148       if ( !n1)
5149         THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::node1", SALOME::BAD_PARAM);
5150       if ( !n2 )
5151         THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::node2", SALOME::BAD_PARAM);
5152       if ( !n3 )
5153         THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::nodeLast", SALOME::BAD_PARAM);
5154
5155       borderNodes.push_back( n1 );
5156       borderNodes.push_back( n2 );
5157       borderNodes.push_back( n3 );
5158     }
5159     groups.push_back( borderNodes );
5160   }
5161
5162   // SewFreeBorder() can merge nodes, thus nodes stored in 'groups' can become dead;
5163   // to get nodes that replace other nodes during merge we create 0D elements
5164   // on each node and MergeNodes() will replace underlying nodes of 0D elements by
5165   // new ones.
5166
5167   vector< const SMDS_MeshElement* > tmp0Delems;
5168   for ( size_t i = 0; i < groups.size(); ++i )
5169   {
5170     SMESH_MeshAlgos::TFreeBorder& nodes = groups[i];
5171     for ( size_t iN = 0; iN < nodes.size(); ++iN )
5172     {
5173       SMDS_ElemIteratorPtr it0D = nodes[iN]->GetInverseElementIterator(SMDSAbs_0DElement);
5174       if ( it0D->more() )
5175         tmp0Delems.push_back( it0D->next() );
5176       else
5177         tmp0Delems.push_back( getMeshDS()->Add0DElement( nodes[iN] ));
5178     }
5179   }
5180
5181   // cout << endl << "INIT" << endl;
5182   // for ( size_t i = 0; i < tmp0Delems.size(); ++i )
5183   // {
5184   //   cout << i << " ";
5185   //   if ( i % 3 == 0 ) cout << "^ ";
5186   //   tmp0Delems[i]->GetNode(0)->Print( cout );
5187   // }
5188
5189   SMESH_TRY;
5190
5191   ::SMESH_MeshEditor::Sew_Error res, ok = ::SMESH_MeshEditor::SEW_OK;
5192   int i0D = 0;
5193   for ( size_t i = 0; i < groups.size(); ++i )
5194   {
5195     bool isBordToBord = true;
5196     bool   groupSewed = false;
5197     SMESH_MeshAlgos::TFreeBorder& nodes = groups[i];
5198     for ( size_t iN = 3; iN+2 < nodes.size(); iN += 3 )
5199     {
5200       const SMDS_MeshNode* n0 = tmp0Delems[ i0D + 0 ]->GetNode( 0 );
5201       const SMDS_MeshNode* n1 = tmp0Delems[ i0D + 1 ]->GetNode( 0 );
5202       const SMDS_MeshNode* n2 = tmp0Delems[ i0D + 2 ]->GetNode( 0 );
5203
5204       const SMDS_MeshNode* n3 = tmp0Delems[ i0D + 0 + iN ]->GetNode( 0 );
5205       const SMDS_MeshNode* n4 = tmp0Delems[ i0D + 1 + iN ]->GetNode( 0 );
5206       const SMDS_MeshNode* n5 = tmp0Delems[ i0D + 2 + iN ]->GetNode( 0 );
5207
5208       if ( !n0 || !n1 || !n2 || !n3 || !n4 || !n5 )
5209         continue;
5210
5211       // TIDSortedElemSet emptySet, avoidSet;
5212       // if ( !SMESH_MeshAlgos::FindFaceInSet( n0, n1, emptySet, avoidSet))
5213       // {
5214       //   cout << "WRONG 2nd 1" << endl;
5215       //   n0->Print( cout );
5216       //   n1->Print( cout );
5217       // }
5218       // if ( !SMESH_MeshAlgos::FindFaceInSet( n3, n4, emptySet, avoidSet))
5219       // {
5220       //   cout << "WRONG 2nd 2" << endl;
5221       //   n3->Print( cout );
5222       //   n4->Print( cout );
5223       // }
5224
5225       if ( !isBordToBord )
5226       {
5227         n1 = n2; // at border-to-side sewing only last side node (n1) is needed
5228         n2 = 0;  //  and n2 is not used
5229       }
5230       // 1st border moves to 2nd
5231       res = getEditor().SewFreeBorder( n3, n4, n5 ,// 1st
5232                                        n0 ,n1 ,n2 ,// 2nd
5233                                        /*2ndIsFreeBorder=*/ isBordToBord,
5234                                        createPolygons, createPolyhedra);
5235       groupSewed = ( res == ok );
5236
5237       isBordToBord = false;
5238       // cout << endl << "SEWED GROUP " << i << " PART " << iN / 3 << endl;
5239       // for ( size_t t = 0; t < tmp0Delems.size(); ++t )
5240       // {
5241       //   cout << t << " ";
5242       //   if ( t % 3 == 0 ) cout << "^ ";
5243       //   tmp0Delems[t]->GetNode(0)->Print( cout );
5244       // }
5245     }
5246     i0D += nodes.size();
5247     nbSewed += groupSewed;
5248   }
5249
5250   TPythonDump() << "nbSewed = " << this << ".SewCoincidentFreeBorders( "
5251                 << freeBorders     << ", "
5252                 << createPolygons  << ", "
5253                 << createPolyhedra << " )";
5254
5255   SMESH_CATCH( SMESH::doNothing );
5256
5257   declareMeshModified( /*isReComputeSafe=*/false );
5258
5259   // remove tmp 0D elements
5260   SMESH_TRY;
5261   set< const SMDS_MeshElement* > removed0D;
5262   for ( size_t i = 0; i < tmp0Delems.size(); ++i )
5263   {
5264     if ( removed0D.insert( tmp0Delems[i] ).second )
5265       getMeshDS()->RemoveFreeElement( tmp0Delems[i], /*sm=*/0, /*fromGroups=*/false );
5266   }
5267   SMESH_CATCH( SMESH::throwCorbaException );
5268
5269   return nbSewed;
5270 }
5271
5272 //=======================================================================
5273 //function : SewFreeBorders
5274 //purpose  :
5275 //=======================================================================
5276
5277 SMESH::SMESH_MeshEditor::Sew_Error
5278 SMESH_MeshEditor_i::SewFreeBorders(CORBA::Long FirstNodeID1,
5279                                    CORBA::Long SecondNodeID1,
5280                                    CORBA::Long LastNodeID1,
5281                                    CORBA::Long FirstNodeID2,
5282                                    CORBA::Long SecondNodeID2,
5283                                    CORBA::Long LastNodeID2,
5284                                    CORBA::Boolean CreatePolygons,
5285                                    CORBA::Boolean CreatePolyedrs)
5286 {
5287   SMESH_TRY;
5288   initData();
5289
5290   SMESHDS_Mesh* aMesh = getMeshDS();
5291
5292   const SMDS_MeshNode* aBorderFirstNode  = aMesh->FindNode( FirstNodeID1  );
5293   const SMDS_MeshNode* aBorderSecondNode = aMesh->FindNode( SecondNodeID1 );
5294   const SMDS_MeshNode* aBorderLastNode   = aMesh->FindNode( LastNodeID1   );
5295   const SMDS_MeshNode* aSide2FirstNode   = aMesh->FindNode( FirstNodeID2  );
5296   const SMDS_MeshNode* aSide2SecondNode  = aMesh->FindNode( SecondNodeID2 );
5297   const SMDS_MeshNode* aSide2ThirdNode   = aMesh->FindNode( LastNodeID2   );
5298
5299   if (!aBorderFirstNode ||
5300       !aBorderSecondNode||
5301       !aBorderLastNode)
5302     return SMESH::SMESH_MeshEditor::SEW_BORDER1_NOT_FOUND;
5303   if (!aSide2FirstNode  ||
5304       !aSide2SecondNode ||
5305       !aSide2ThirdNode)
5306     return SMESH::SMESH_MeshEditor::SEW_BORDER2_NOT_FOUND;
5307
5308   TPythonDump() << "error = " << this << ".SewFreeBorders( "
5309                 << FirstNodeID1  << ", "
5310                 << SecondNodeID1 << ", "
5311                 << LastNodeID1   << ", "
5312                 << FirstNodeID2  << ", "
5313                 << SecondNodeID2 << ", "
5314                 << LastNodeID2   << ", "
5315                 << CreatePolygons<< ", "
5316                 << CreatePolyedrs<< " )";
5317
5318   SMESH::SMESH_MeshEditor::Sew_Error error =
5319     convError( getEditor().SewFreeBorder (aBorderFirstNode,
5320                                           aBorderSecondNode,
5321                                           aBorderLastNode,
5322                                           aSide2FirstNode,
5323                                           aSide2SecondNode,
5324                                           aSide2ThirdNode,
5325                                           true,
5326                                           CreatePolygons,
5327                                           CreatePolyedrs) );
5328
5329
5330   declareMeshModified( /*isReComputeSafe=*/false );
5331   return error;
5332
5333   SMESH_CATCH( SMESH::throwCorbaException );
5334   return SMESH::SMESH_MeshEditor::Sew_Error(0);
5335 }
5336
5337
5338 //=======================================================================
5339 //function : SewConformFreeBorders
5340 //purpose  :
5341 //=======================================================================
5342
5343 SMESH::SMESH_MeshEditor::Sew_Error
5344 SMESH_MeshEditor_i::SewConformFreeBorders(CORBA::Long FirstNodeID1,
5345                                           CORBA::Long SecondNodeID1,
5346                                           CORBA::Long LastNodeID1,
5347                                           CORBA::Long FirstNodeID2,
5348                                           CORBA::Long SecondNodeID2)
5349 {
5350   SMESH_TRY;
5351   initData();
5352
5353   SMESHDS_Mesh* aMesh = getMeshDS();
5354
5355   const SMDS_MeshNode* aBorderFirstNode  = aMesh->FindNode( FirstNodeID1  );
5356   const SMDS_MeshNode* aBorderSecondNode = aMesh->FindNode( SecondNodeID1 );
5357   const SMDS_MeshNode* aBorderLastNode   = aMesh->FindNode( LastNodeID1   );
5358   const SMDS_MeshNode* aSide2FirstNode   = aMesh->FindNode( FirstNodeID2  );
5359   const SMDS_MeshNode* aSide2SecondNode  = aMesh->FindNode( SecondNodeID2 );
5360   const SMDS_MeshNode* aSide2ThirdNode   = 0;
5361
5362   if (!aBorderFirstNode ||
5363       !aBorderSecondNode||
5364       !aBorderLastNode )
5365     return SMESH::SMESH_MeshEditor::SEW_BORDER1_NOT_FOUND;
5366   if (!aSide2FirstNode  ||
5367       !aSide2SecondNode)
5368     return SMESH::SMESH_MeshEditor::SEW_BORDER2_NOT_FOUND;
5369
5370   TPythonDump() << "error = " << this << ".SewConformFreeBorders( "
5371                 << FirstNodeID1  << ", "
5372                 << SecondNodeID1 << ", "
5373                 << LastNodeID1   << ", "
5374                 << FirstNodeID2  << ", "
5375                 << SecondNodeID2 << " )";
5376
5377   SMESH::SMESH_MeshEditor::Sew_Error error =
5378     convError( getEditor().SewFreeBorder (aBorderFirstNode,
5379                                           aBorderSecondNode,
5380                                           aBorderLastNode,
5381                                           aSide2FirstNode,
5382                                           aSide2SecondNode,
5383                                           aSide2ThirdNode,
5384                                           true,
5385                                           false, false) );
5386
5387   declareMeshModified( /*isReComputeSafe=*/false );
5388   return error;
5389
5390   SMESH_CATCH( SMESH::throwCorbaException );
5391   return SMESH::SMESH_MeshEditor::Sew_Error(0);
5392 }
5393
5394
5395 //=======================================================================
5396 //function : SewBorderToSide
5397 //purpose  :
5398 //=======================================================================
5399
5400 SMESH::SMESH_MeshEditor::Sew_Error
5401 SMESH_MeshEditor_i::SewBorderToSide(CORBA::Long FirstNodeIDOnFreeBorder,
5402                                     CORBA::Long SecondNodeIDOnFreeBorder,
5403                                     CORBA::Long LastNodeIDOnFreeBorder,
5404                                     CORBA::Long FirstNodeIDOnSide,
5405                                     CORBA::Long LastNodeIDOnSide,
5406                                     CORBA::Boolean CreatePolygons,
5407                                     CORBA::Boolean CreatePolyedrs)
5408 {
5409   SMESH_TRY;
5410   initData();
5411
5412   SMESHDS_Mesh* aMesh = getMeshDS();
5413
5414   const SMDS_MeshNode* aBorderFirstNode  = aMesh->FindNode( FirstNodeIDOnFreeBorder  );
5415   const SMDS_MeshNode* aBorderSecondNode = aMesh->FindNode( SecondNodeIDOnFreeBorder );
5416   const SMDS_MeshNode* aBorderLastNode   = aMesh->FindNode( LastNodeIDOnFreeBorder   );
5417   const SMDS_MeshNode* aSide2FirstNode   = aMesh->FindNode( FirstNodeIDOnSide  );
5418   const SMDS_MeshNode* aSide2SecondNode  = aMesh->FindNode( LastNodeIDOnSide );
5419   const SMDS_MeshNode* aSide2ThirdNode   = 0;
5420
5421   if (!aBorderFirstNode ||
5422       !aBorderSecondNode||
5423       !aBorderLastNode  )
5424     return SMESH::SMESH_MeshEditor::SEW_BORDER1_NOT_FOUND;
5425   if (!aSide2FirstNode  ||
5426       !aSide2SecondNode)
5427     return SMESH::SMESH_MeshEditor::SEW_BAD_SIDE_NODES;
5428
5429   TPythonDump() << "error = " << this << ".SewBorderToSide( "
5430                 << FirstNodeIDOnFreeBorder  << ", "
5431                 << SecondNodeIDOnFreeBorder << ", "
5432                 << LastNodeIDOnFreeBorder   << ", "
5433                 << FirstNodeIDOnSide        << ", "
5434                 << LastNodeIDOnSide         << ", "
5435                 << CreatePolygons           << ", "
5436                 << CreatePolyedrs           << ") ";
5437
5438   SMESH::SMESH_MeshEditor::Sew_Error error =
5439     convError( getEditor().SewFreeBorder (aBorderFirstNode,
5440                                           aBorderSecondNode,
5441                                           aBorderLastNode,
5442                                           aSide2FirstNode,
5443                                           aSide2SecondNode,
5444                                           aSide2ThirdNode,
5445                                           false,
5446                                           CreatePolygons,
5447                                           CreatePolyedrs) );
5448
5449   declareMeshModified( /*isReComputeSafe=*/false );
5450   return error;
5451
5452   SMESH_CATCH( SMESH::throwCorbaException );
5453   return SMESH::SMESH_MeshEditor::Sew_Error(0);
5454 }
5455
5456
5457 //=======================================================================
5458 //function : SewSideElements
5459 //purpose  :
5460 //=======================================================================
5461
5462 SMESH::SMESH_MeshEditor::Sew_Error
5463 SMESH_MeshEditor_i::SewSideElements(const SMESH::long_array& IDsOfSide1Elements,
5464                                     const SMESH::long_array& IDsOfSide2Elements,
5465                                     CORBA::Long NodeID1OfSide1ToMerge,
5466                                     CORBA::Long NodeID1OfSide2ToMerge,
5467                                     CORBA::Long NodeID2OfSide1ToMerge,
5468                                     CORBA::Long NodeID2OfSide2ToMerge)
5469 {
5470   SMESH_TRY;
5471   initData();
5472
5473   SMESHDS_Mesh* aMesh = getMeshDS();
5474
5475   const SMDS_MeshNode* aFirstNode1ToMerge  = aMesh->FindNode( NodeID1OfSide1ToMerge );
5476   const SMDS_MeshNode* aFirstNode2ToMerge  = aMesh->FindNode( NodeID1OfSide2ToMerge );
5477   const SMDS_MeshNode* aSecondNode1ToMerge = aMesh->FindNode( NodeID2OfSide1ToMerge );
5478   const SMDS_MeshNode* aSecondNode2ToMerge = aMesh->FindNode( NodeID2OfSide2ToMerge );
5479
5480   if (!aFirstNode1ToMerge ||
5481       !aFirstNode2ToMerge )
5482     return SMESH::SMESH_MeshEditor::SEW_BAD_SIDE1_NODES;
5483   if (!aSecondNode1ToMerge||
5484       !aSecondNode2ToMerge)
5485     return SMESH::SMESH_MeshEditor::SEW_BAD_SIDE2_NODES;
5486
5487   TIDSortedElemSet aSide1Elems, aSide2Elems;
5488   arrayToSet(IDsOfSide1Elements, aMesh, aSide1Elems);
5489   arrayToSet(IDsOfSide2Elements, aMesh, aSide2Elems);
5490
5491   TPythonDump() << "error = " << this << ".SewSideElements( "
5492                 << IDsOfSide1Elements << ", "
5493                 << IDsOfSide2Elements << ", "
5494                 << NodeID1OfSide1ToMerge << ", "
5495                 << NodeID1OfSide2ToMerge << ", "
5496                 << NodeID2OfSide1ToMerge << ", "
5497                 << NodeID2OfSide2ToMerge << ")";
5498
5499   SMESH::SMESH_MeshEditor::Sew_Error error =
5500     convError( getEditor().SewSideElements (aSide1Elems, aSide2Elems,
5501                                          aFirstNode1ToMerge,
5502                                          aFirstNode2ToMerge,
5503                                          aSecondNode1ToMerge,
5504                                          aSecondNode2ToMerge));
5505
5506   declareMeshModified( /*isReComputeSafe=*/false );
5507   return error;
5508
5509   SMESH_CATCH( SMESH::throwCorbaException );
5510   return SMESH::SMESH_MeshEditor::Sew_Error(0);
5511 }
5512
5513 //================================================================================
5514 /*!
5515  * \brief Set new nodes for given element
5516  * \param ide - element id
5517  * \param newIDs - new node ids
5518  * \retval CORBA::Boolean - true if result is OK
5519  */
5520 //================================================================================
5521
5522 CORBA::Boolean SMESH_MeshEditor_i::ChangeElemNodes(CORBA::Long ide,
5523                                                    const SMESH::long_array& newIDs)
5524 {
5525   SMESH_TRY;
5526   initData();
5527
5528   const SMDS_MeshElement* elem = getMeshDS()->FindElement(ide);
5529   if ( !elem ) return false;
5530
5531   int nbn = newIDs.length();
5532   vector<const SMDS_MeshNode*> aNodes(nbn);
5533   for ( int i = 0; i < nbn; i++ ) {
5534     const SMDS_MeshNode* aNode = getMeshDS()->FindNode( newIDs[ i ]);
5535     if ( !aNode )
5536       return false;
5537     aNodes[ i ] = aNode;
5538   }
5539   TPythonDump() << "isDone = " << this << ".ChangeElemNodes( "
5540                 << ide << ", " << newIDs << " )";
5541
5542   bool res = getMeshDS()->ChangeElementNodes( elem, & aNodes[0], aNodes.size() );
5543
5544   declareMeshModified( /*isReComputeSafe=*/ !res );
5545
5546   return res;
5547
5548   SMESH_CATCH( SMESH::throwCorbaException );
5549   return 0;
5550 }
5551
5552 //=======================================================================
5553 /*!
5554  * \brief Makes a part of the mesh quadratic or bi-quadratic
5555  */
5556 //=======================================================================
5557
5558 void SMESH_MeshEditor_i::convertToQuadratic(CORBA::Boolean            theForce3d,
5559                                             CORBA::Boolean            theToBiQuad,
5560                                             SMESH::SMESH_IDSource_ptr theObject)
5561 {
5562   SMESH_TRY;
5563   initData();
5564
5565   TIDSortedElemSet elems;
5566   bool elemsOK;
5567   if ( !( elemsOK = CORBA::is_nil( theObject )))
5568   {
5569     elemsOK = idSourceToSet( theObject, getMeshDS(), elems,
5570                              SMDSAbs_All, /*emptyIfIsMesh=*/true );
5571   }
5572   if ( elemsOK )
5573   {
5574     if ( !elems.empty() && (*elems.begin())->GetType() == SMDSAbs_Node )
5575       THROW_SALOME_CORBA_EXCEPTION("Group of nodes is not allowed", SALOME::BAD_PARAM);
5576
5577     if ( elems.empty() ) getEditor().ConvertToQuadratic(theForce3d, theToBiQuad);
5578     else                 getEditor().ConvertToQuadratic(theForce3d, elems, theToBiQuad);
5579
5580     declareMeshModified( /*isReComputeSafe=*/false );
5581   }
5582
5583   SMESH_CATCH( SMESH::throwCorbaException );
5584 }
5585
5586 //=======================================================================
5587 //function : ConvertFromQuadratic
5588 //purpose  :
5589 //=======================================================================
5590
5591 CORBA::Boolean SMESH_MeshEditor_i::ConvertFromQuadratic()
5592 {
5593   SMESH_TRY;
5594   initData();
5595
5596   CORBA::Boolean isDone = getEditor().ConvertFromQuadratic();
5597   TPythonDump() << this << ".ConvertFromQuadratic()";
5598   declareMeshModified( /*isReComputeSafe=*/!isDone );
5599   return isDone;
5600
5601   SMESH_CATCH( SMESH::throwCorbaException );
5602   return false;
5603 }
5604
5605 //=======================================================================
5606 //function : ConvertToQuadratic
5607 //purpose  :
5608 //=======================================================================
5609
5610 void SMESH_MeshEditor_i::ConvertToQuadratic(CORBA::Boolean theForce3d)
5611 {
5612   convertToQuadratic( theForce3d, false );
5613   TPythonDump() << this << ".ConvertToQuadratic("<<theForce3d<<")";
5614 }
5615
5616 //================================================================================
5617 /*!
5618  * \brief Makes a part of the mesh quadratic
5619  */
5620 //================================================================================
5621
5622 void SMESH_MeshEditor_i::ConvertToQuadraticObject(CORBA::Boolean            theForce3d,
5623                                                   SMESH::SMESH_IDSource_ptr theObject)
5624 {
5625   convertToQuadratic( theForce3d, false, theObject );
5626   TPythonDump() << this << ".ConvertToQuadraticObject("<<theForce3d<<", "<<theObject<<")";
5627 }
5628
5629 //================================================================================
5630 /*!
5631  * \brief Makes a part of the mesh bi-quadratic
5632  */
5633 //================================================================================
5634
5635 void SMESH_MeshEditor_i::ConvertToBiQuadratic(CORBA::Boolean            theForce3d,
5636                                               SMESH::SMESH_IDSource_ptr theObject)
5637 {
5638   convertToQuadratic( theForce3d, true, theObject );
5639   TPythonDump() << this << ".ConvertToBiQuadratic("<<theForce3d<<", "<<theObject<<")";
5640 }
5641
5642 //================================================================================
5643 /*!
5644  * \brief Makes a part of the mesh linear
5645  */
5646 //================================================================================
5647
5648 void SMESH_MeshEditor_i::ConvertFromQuadraticObject(SMESH::SMESH_IDSource_ptr theObject)
5649 {
5650   SMESH_TRY;
5651   initData();
5652
5653   TPythonDump pyDump;
5654
5655   TIDSortedElemSet elems;
5656   if ( idSourceToSet( theObject, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true ))
5657   {
5658     if ( elems.empty() )
5659     {
5660       ConvertFromQuadratic();
5661     }
5662     else if ( (*elems.begin())->GetType() == SMDSAbs_Node )
5663     {
5664       THROW_SALOME_CORBA_EXCEPTION("Group of nodes is not allowed", SALOME::BAD_PARAM);
5665     }
5666     else
5667     {
5668       getEditor().ConvertFromQuadratic(elems);
5669     }
5670   }
5671   declareMeshModified( /*isReComputeSafe=*/false );
5672
5673   pyDump << this << ".ConvertFromQuadraticObject( "<<theObject<<" )";
5674
5675   SMESH_CATCH( SMESH::throwCorbaException );
5676 }
5677
5678 //=======================================================================
5679 //function : makeMesh
5680 //purpose  : create a named imported mesh
5681 //=======================================================================
5682
5683 SMESH::SMESH_Mesh_ptr SMESH_MeshEditor_i::makeMesh(const char* theMeshName)
5684 {
5685   SMESH_Gen_i*              gen = SMESH_Gen_i::GetSMESHGen();
5686   SMESH::SMESH_Mesh_var    mesh = gen->CreateEmptyMesh();
5687   SALOMEDS::SObject_wrap meshSO = gen->ObjectToSObject( mesh );
5688   gen->SetName( meshSO, theMeshName, "Mesh" );
5689   gen->SetPixMap( meshSO, "ICON_SMESH_TREE_MESH_IMPORTED");
5690
5691   return mesh._retn();
5692 }
5693
5694 //=======================================================================
5695 //function : dumpGroupsList
5696 //purpose  :
5697 //=======================================================================
5698
5699 void SMESH_MeshEditor_i::dumpGroupsList(TPythonDump &               theDumpPython,
5700                                         const SMESH::ListOfGroups * theGroupList)
5701 {
5702   bool isDumpGroupList = ( theGroupList && theGroupList->length() > 0 );
5703   if ( isDumpGroupList )
5704     theDumpPython << theGroupList << " = ";
5705 }
5706
5707 //================================================================================
5708 /*!
5709   \brief Generates the unique group name.
5710   \param thePrefix name prefix
5711   \return unique name
5712 */
5713 //================================================================================
5714
5715 std::string SMESH_MeshEditor_i::GenerateGroupName(const std::string& thePrefix)
5716 {
5717   SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
5718   set<std::string> groupNames;
5719
5720   // Get existing group names
5721   for (int i = 0, nbGroups = groups->length(); i < nbGroups; i++ ) {
5722     SMESH::SMESH_GroupBase_var aGroup = groups[i];
5723     if (CORBA::is_nil(aGroup))
5724       continue;
5725
5726     CORBA::String_var name = aGroup->GetName();
5727     groupNames.insert( name.in() );
5728   }
5729
5730   // Find new name
5731   std::string name = thePrefix;
5732   int index = 0;
5733
5734   while (!groupNames.insert(name).second)
5735     name = SMESH_Comment( thePrefix ) << "_" << index++;
5736
5737   return name;
5738 }
5739
5740 //================================================================================
5741 /*!
5742  * \brief Prepare SMESH_IDSource for work
5743  */
5744 //================================================================================
5745
5746 void SMESH_MeshEditor_i::prepareIdSource(SMESH::SMESH_IDSource_ptr theObject)
5747 {
5748   if ( SMESH::Filter_i* filter = SMESH::DownCast<SMESH::Filter_i*>( theObject ))
5749   {
5750     SMESH::SMESH_Mesh_var mesh = myMesh_i->_this();
5751     filter->SetMesh( mesh );
5752   }
5753 }
5754 //================================================================================
5755 /*!
5756  * \brief Retrieve elements of given type from SMESH_IDSource
5757  */
5758 //================================================================================
5759
5760 bool SMESH_MeshEditor_i::idSourceToSet(SMESH::SMESH_IDSource_ptr  theIDSource,
5761                                        const SMESHDS_Mesh*        theMeshDS,
5762                                        TIDSortedElemSet&          theElemSet,
5763                                        const SMDSAbs_ElementType  theType,
5764                                        const bool                 emptyIfIsMesh,
5765                                        IDSource_Error*            error)
5766
5767 {
5768   if ( error ) *error = IDSource_OK;
5769
5770   if ( CORBA::is_nil( theIDSource ))
5771   {
5772     if ( error ) *error = IDSource_INVALID;
5773     return false;
5774   }
5775   if ( emptyIfIsMesh && SMESH::DownCast<SMESH_Mesh_i*>( theIDSource ))
5776   {
5777     if ( error && theMeshDS->GetMeshInfo().NbElements( theType ) == 0 )
5778       *error = IDSource_EMPTY;
5779     return true;
5780   }
5781   if ( getMeshDS() == theMeshDS ) // check if theIDSource belongs to myMesh
5782   {
5783     SMESH::SMESH_Mesh_var mesh = theIDSource->GetMesh();
5784     SMESH_Mesh_i*       mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
5785     if ( mesh_i && mesh_i != myMesh_i )
5786     {
5787       if ( error )
5788         *error = IDSource_INVALID;
5789       return false;
5790     }
5791   }
5792   prepareIdSource( theIDSource );
5793   SMESH::long_array_var anIDs = theIDSource->GetIDs();
5794   if ( anIDs->length() == 0 )
5795   {
5796     if ( error ) *error = IDSource_EMPTY;
5797     return false;
5798   }
5799   SMESH::array_of_ElementType_var types = theIDSource->GetTypes();
5800   if ( types->length() == 1 && types[0] == SMESH::NODE ) // group of nodes
5801   {
5802     if ( theType == SMDSAbs_All || theType == SMDSAbs_Node )
5803     {
5804       arrayToSet( anIDs, getMeshDS(), theElemSet, SMDSAbs_Node );
5805     }
5806     else
5807     {
5808       if ( error ) *error = IDSource_INVALID;
5809       return false;
5810     }
5811   }
5812   else
5813   {
5814     arrayToSet( anIDs, getMeshDS(), theElemSet, theType);
5815     if ( bool(anIDs->length()) != bool(theElemSet.size()))
5816     {
5817       if ( error ) *error = IDSource_INVALID;
5818       return false;
5819     }
5820   }
5821   return true;
5822 }
5823
5824 //================================================================================
5825 /*!
5826  * \brief Duplicates given elements, i.e. creates new elements based on the
5827  *        same nodes as the given ones.
5828  * \param theElements - container of elements to duplicate.
5829  * \param theGroupName - a name of group to contain the generated elements.
5830  *                    If a group with such a name already exists, the new elements
5831  *                    are added to the existing group, else a new group is created.
5832  *                    If \a theGroupName is empty, new elements are not added 
5833  *                    in any group.
5834  * \return a group where the new elements are added. NULL if theGroupName == "".
5835  * \sa DoubleNode()
5836  */
5837 //================================================================================
5838
5839 SMESH::SMESH_Group_ptr
5840 SMESH_MeshEditor_i::DoubleElements(SMESH::SMESH_IDSource_ptr theElements,
5841                                    const char*               theGroupName)
5842 {
5843   SMESH::SMESH_Group_var newGroup;
5844
5845   SMESH_TRY;
5846   initData();
5847
5848   TPythonDump pyDump;
5849
5850   TIDSortedElemSet elems;
5851   if ( idSourceToSet( theElements, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true))
5852   {
5853     getEditor().DoubleElements( elems );
5854
5855     if ( strlen( theGroupName ) && !getEditor().GetLastCreatedElems().empty() )
5856     {
5857       // group type
5858       SMESH::ElementType type =
5859         SMESH::ElementType( getEditor().GetLastCreatedElems()[0]->GetType() );
5860       // find existing group
5861       SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
5862       for ( size_t i = 0; i < groups->length(); ++i )
5863         if ( groups[i]->GetType() == type )
5864         {
5865           CORBA::String_var name = groups[i]->GetName();
5866           if ( strcmp( name, theGroupName ) == 0 ) {
5867             newGroup = SMESH::SMESH_Group::_narrow( groups[i] );
5868             break;
5869           }
5870         }
5871       // create a new group
5872       if ( newGroup->_is_nil() )
5873         newGroup = myMesh_i->CreateGroup( type, theGroupName );
5874       // fill newGroup
5875       if ( SMESH_Group_i* group_i = SMESH::DownCast< SMESH_Group_i* >( newGroup ))
5876       {
5877         SMESHDS_Group* groupDS = static_cast< SMESHDS_Group* >( group_i->GetGroupDS() );
5878         const SMESH_SequenceOfElemPtr& aSeq = getEditor().GetLastCreatedElems();
5879         for ( size_t i = 0; i < aSeq.size(); i++ )
5880           groupDS->SMDSGroup().Add( aSeq[i] );
5881       }
5882     }
5883   }
5884   // python dump
5885   if ( !newGroup->_is_nil() )
5886     pyDump << newGroup << " = ";
5887   pyDump << this << ".DoubleElements( "
5888          << theElements << ", " << "'" << theGroupName <<"')";
5889
5890   SMESH_CATCH( SMESH::throwCorbaException );
5891
5892   return newGroup._retn();
5893 }
5894
5895 //================================================================================
5896 /*!
5897   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5898   \param theNodes - identifiers of nodes to be doubled
5899   \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
5900          nodes. If list of element identifiers is empty then nodes are doubled but
5901          they not assigned to elements
5902   \return TRUE if operation has been completed successfully, FALSE otherwise
5903   \sa DoubleNode(), DoubleNodeGroup(), DoubleNodeGroups()
5904 */
5905 //================================================================================
5906
5907 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodes( const SMESH::long_array& theNodes,
5908                                                 const SMESH::long_array& theModifiedElems )
5909 {
5910   SMESH_TRY;
5911   initData();
5912
5913   list< int > aListOfNodes;
5914   int i, n;
5915   for ( i = 0, n = theNodes.length(); i < n; i++ )
5916     aListOfNodes.push_back( theNodes[ i ] );
5917
5918   list< int > aListOfElems;
5919   for ( i = 0, n = theModifiedElems.length(); i < n; i++ )
5920     aListOfElems.push_back( theModifiedElems[ i ] );
5921
5922   bool aResult = getEditor().DoubleNodes( aListOfNodes, aListOfElems );
5923
5924   declareMeshModified( /*isReComputeSafe=*/ !aResult );
5925
5926   // Update Python script
5927   TPythonDump() << this << ".DoubleNodes( " << theNodes << ", "<< theModifiedElems << " )";
5928
5929   return aResult;
5930
5931   SMESH_CATCH( SMESH::throwCorbaException );
5932   return 0;
5933 }
5934
5935 //================================================================================
5936 /*!
5937   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5938   This method provided for convenience works as DoubleNodes() described above.
5939   \param theNodeId - identifier of node to be doubled.
5940   \param theModifiedElems - identifiers of elements to be updated.
5941   \return TRUE if operation has been completed successfully, FALSE otherwise
5942   \sa DoubleNodes(), DoubleNodeGroup(), DoubleNodeGroups()
5943 */
5944 //================================================================================
5945
5946 CORBA::Boolean SMESH_MeshEditor_i::DoubleNode( CORBA::Long              theNodeId,
5947                                                const SMESH::long_array& theModifiedElems )
5948 {
5949   SMESH_TRY;
5950   SMESH::long_array_var aNodes = new SMESH::long_array;
5951   aNodes->length( 1 );
5952   aNodes[ 0 ] = theNodeId;
5953
5954   TPythonDump pyDump; // suppress dump by the next line
5955
5956   CORBA::Boolean done = DoubleNodes( aNodes, theModifiedElems );
5957
5958   pyDump << this << ".DoubleNode( " << theNodeId << ", " << theModifiedElems << " )";
5959
5960   return done;
5961
5962   SMESH_CATCH( SMESH::throwCorbaException );
5963   return 0;
5964 }
5965
5966 //================================================================================
5967 /*!
5968   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5969   This method provided for convenience works as DoubleNodes() described above.
5970   \param theNodes - group of nodes to be doubled.
5971   \param theModifiedElems - group of elements to be updated.
5972   \return TRUE if operation has been completed successfully, FALSE otherwise
5973   \sa DoubleNode(), DoubleNodes(), DoubleNodeGroups()
5974 */
5975 //================================================================================
5976
5977 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroup(SMESH::SMESH_GroupBase_ptr theNodes,
5978                                                    SMESH::SMESH_GroupBase_ptr theModifiedElems )
5979 {
5980   SMESH_TRY;
5981   if ( CORBA::is_nil( theNodes ) && theNodes->GetType() != SMESH::NODE )
5982     return false;
5983
5984   SMESH::long_array_var aNodes = theNodes->GetListOfID();
5985   SMESH::long_array_var aModifiedElems;
5986   if ( !CORBA::is_nil( theModifiedElems ) )
5987     aModifiedElems = theModifiedElems->GetListOfID();
5988   else
5989     aModifiedElems = new SMESH::long_array;
5990
5991   TPythonDump pyDump; // suppress dump by the next line
5992
5993   bool done = DoubleNodes( aNodes, aModifiedElems );
5994
5995   pyDump << this << ".DoubleNodeGroup( " << theNodes << ", " << theModifiedElems << " )";
5996
5997   return done;
5998
5999   SMESH_CATCH( SMESH::throwCorbaException );
6000   return 0;
6001 }
6002
6003 //================================================================================
6004 /*!
6005  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
6006  * Works as DoubleNodeGroup(), but returns a new group with newly created nodes.
6007  * \param theNodes - group of nodes to be doubled.
6008  * \param theModifiedElems - group of elements to be updated.
6009  * \return a new group with newly created nodes
6010  * \sa DoubleNodeGroup()
6011  */
6012 //================================================================================
6013
6014 SMESH::SMESH_Group_ptr
6015 SMESH_MeshEditor_i::DoubleNodeGroupNew( SMESH::SMESH_GroupBase_ptr theNodes,
6016                                         SMESH::SMESH_GroupBase_ptr theModifiedElems )
6017 {
6018   SMESH_TRY;
6019   SMESH::SMESH_Group_var aNewGroup;
6020
6021   if ( CORBA::is_nil( theNodes ) && theNodes->GetType() != SMESH::NODE )
6022     return aNewGroup._retn();
6023
6024   // Duplicate nodes
6025   SMESH::long_array_var aNodes = theNodes->GetListOfID();
6026   SMESH::long_array_var aModifiedElems;
6027   if ( !CORBA::is_nil( theModifiedElems ) )
6028     aModifiedElems = theModifiedElems->GetListOfID();
6029   else {
6030     aModifiedElems = new SMESH::long_array;
6031     aModifiedElems->length( 0 );
6032   }
6033
6034   TPythonDump pyDump; // suppress dump by the next line
6035
6036   bool aResult = DoubleNodes( aNodes, aModifiedElems );
6037   if ( aResult )
6038   {
6039     // Create group with newly created nodes
6040     SMESH::long_array_var anIds = GetLastCreatedNodes();
6041     if (anIds->length() > 0) {
6042       std::string anUnindexedName (theNodes->GetName());
6043       std::string aNewName = GenerateGroupName(anUnindexedName + "_double");
6044       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
6045       aNewGroup->Add(anIds);
6046       pyDump << aNewGroup << " = ";
6047     }
6048   }
6049
6050   pyDump << this << ".DoubleNodeGroupNew( " << theNodes << ", "
6051          << theModifiedElems << " )";
6052
6053   return aNewGroup._retn();
6054
6055   SMESH_CATCH( SMESH::throwCorbaException );
6056   return 0;
6057 }
6058
6059 //================================================================================
6060 /*!
6061   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6062   This method provided for convenience works as DoubleNodes() described above.
6063   \param theNodes - list of groups of nodes to be doubled
6064   \param theModifiedElems - list of groups of elements to be updated.
6065   \return TRUE if operation has been completed successfully, FALSE otherwise
6066   \sa DoubleNode(), DoubleNodeGroup(), DoubleNodes()
6067 */
6068 //================================================================================
6069
6070 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroups(const SMESH::ListOfGroups& theNodes,
6071                                                     const SMESH::ListOfGroups& theModifiedElems )
6072 {
6073   SMESH_TRY;
6074   initData();
6075
6076   std::list< int > aNodes;
6077   int i, n, j, m;
6078   for ( i = 0, n = theNodes.length(); i < n; i++ )
6079   {
6080     SMESH::SMESH_GroupBase_var aGrp = theNodes[ i ];
6081     if ( !CORBA::is_nil( aGrp ) && aGrp->GetType() == SMESH::NODE )
6082     {
6083       SMESH::long_array_var aCurr = aGrp->GetListOfID();
6084       for ( j = 0, m = aCurr->length(); j < m; j++ )
6085         aNodes.push_back( aCurr[ j ] );
6086     }
6087   }
6088
6089   std::list< int > anElems;
6090   for ( i = 0, n = theModifiedElems.length(); i < n; i++ )
6091   {
6092     SMESH::SMESH_GroupBase_var aGrp = theModifiedElems[ i ];
6093     if ( !CORBA::is_nil( aGrp ) && aGrp->GetType() != SMESH::NODE )
6094     {
6095       SMESH::long_array_var aCurr = aGrp->GetListOfID();
6096       for ( j = 0, m = aCurr->length(); j < m; j++ )
6097         anElems.push_back( aCurr[ j ] );
6098     }
6099   }
6100
6101   bool aResult = getEditor().DoubleNodes( aNodes, anElems );
6102
6103   declareMeshModified( /*isReComputeSafe=*/false );
6104
6105   TPythonDump() << this << ".DoubleNodeGroups( " << theNodes << ", " << theModifiedElems << " )";
6106
6107   return aResult;
6108
6109   SMESH_CATCH( SMESH::throwCorbaException );
6110   return 0;
6111 }
6112
6113 //================================================================================
6114 /*!
6115  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
6116  * Works as DoubleNodeGroups(), but returns a new group with newly created nodes.
6117  * \param theNodes - group of nodes to be doubled.
6118  * \param theModifiedElems - group of elements to be updated.
6119  * \return a new group with newly created nodes
6120  * \sa DoubleNodeGroups()
6121  */
6122 //================================================================================
6123
6124 SMESH::SMESH_Group_ptr
6125 SMESH_MeshEditor_i::DoubleNodeGroupsNew( const SMESH::ListOfGroups& theNodes,
6126                                          const SMESH::ListOfGroups& theModifiedElems )
6127 {
6128   SMESH::SMESH_Group_var aNewGroup;
6129
6130   TPythonDump pyDump; // suppress dump by the next line
6131
6132   bool aResult = DoubleNodeGroups( theNodes, theModifiedElems );
6133
6134   if ( aResult )
6135   {
6136     // Create group with newly created nodes
6137     SMESH::long_array_var anIds = GetLastCreatedNodes();
6138     if (anIds->length() > 0) {
6139       std::string anUnindexedName (theNodes[0]->GetName());
6140       std::string aNewName = GenerateGroupName(anUnindexedName + "_double");
6141       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
6142       aNewGroup->Add(anIds);
6143       pyDump << aNewGroup << " = ";
6144     }
6145   }
6146
6147   pyDump << this << ".DoubleNodeGroupsNew( " << theNodes << ", "
6148          << theModifiedElems << " )";
6149
6150   return aNewGroup._retn();
6151 }
6152
6153
6154 //================================================================================
6155 /*!
6156   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6157   \param theElems - the list of elements (edges or faces) to be replicated
6158   The nodes for duplication could be found from these elements
6159   \param theNodesNot - list of nodes to NOT replicate
6160   \param theAffectedElems - the list of elements (cells and edges) to which the
6161   replicated nodes should be associated to.
6162   \return TRUE if operation has been completed successfully, FALSE otherwise
6163   \sa DoubleNodeGroup(), DoubleNodeGroups()
6164 */
6165 //================================================================================
6166
6167 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElem( const SMESH::long_array& theElems,
6168                                                    const SMESH::long_array& theNodesNot,
6169                                                    const SMESH::long_array& theAffectedElems )
6170 {
6171   SMESH_TRY;
6172   initData();
6173
6174   SMESHDS_Mesh* aMeshDS = getMeshDS();
6175   TIDSortedElemSet anElems, aNodes, anAffected;
6176   arrayToSet(theElems, aMeshDS, anElems, SMDSAbs_All);
6177   arrayToSet(theNodesNot, aMeshDS, aNodes, SMDSAbs_Node);
6178   arrayToSet(theAffectedElems, aMeshDS, anAffected, SMDSAbs_All);
6179
6180   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
6181
6182   // Update Python script
6183   TPythonDump() << this << ".DoubleNodeElem( " << theElems << ", "
6184                 << theNodesNot << ", " << theAffectedElems << " )";
6185
6186   declareMeshModified( /*isReComputeSafe=*/false );
6187   return aResult;
6188
6189   SMESH_CATCH( SMESH::throwCorbaException );
6190   return 0;
6191 }
6192
6193 //================================================================================
6194 /*!
6195   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6196   \param theElems - the list of elements (edges or faces) to be replicated
6197   The nodes for duplication could be found from these elements
6198   \param theNodesNot - list of nodes to NOT replicate
6199   \param theShape - shape to detect affected elements (element which geometric center
6200   located on or inside shape).
6201   The replicated nodes should be associated to affected elements.
6202   \return TRUE if operation has been completed successfully, FALSE otherwise
6203   \sa DoubleNodeGroupInRegion(), DoubleNodeGroupsInRegion()
6204 */
6205 //================================================================================
6206
6207 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemInRegion ( const SMESH::long_array& theElems,
6208                                                             const SMESH::long_array& theNodesNot,
6209                                                             GEOM::GEOM_Object_ptr    theShape )
6210 {
6211   SMESH_TRY;
6212   initData();
6213
6214
6215   SMESHDS_Mesh* aMeshDS = getMeshDS();
6216   TIDSortedElemSet anElems, aNodes;
6217   arrayToSet(theElems, aMeshDS, anElems, SMDSAbs_All);
6218   arrayToSet(theNodesNot, aMeshDS, aNodes, SMDSAbs_Node);
6219
6220   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
6221   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
6222
6223   // Update Python script
6224   TPythonDump() << "isDone = " << this << ".DoubleNodeElemInRegion( " << theElems << ", "
6225                 << theNodesNot << ", " << theShape << " )";
6226
6227   declareMeshModified( /*isReComputeSafe=*/false );
6228   return aResult;
6229
6230   SMESH_CATCH( SMESH::throwCorbaException );
6231   return 0;
6232 }
6233
6234 //================================================================================
6235 /*!
6236   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6237   \param theElems - group of of elements (edges or faces) to be replicated
6238   \param theNodesNot - group of nodes not to replicated
6239   \param theAffectedElems - group of elements to which the replicated nodes
6240   should be associated to.
6241   \return TRUE if operation has been completed successfully, FALSE otherwise
6242   \sa DoubleNodes(), DoubleNodeGroups()
6243 */
6244 //================================================================================
6245
6246 CORBA::Boolean
6247 SMESH_MeshEditor_i::DoubleNodeElemGroup(SMESH::SMESH_GroupBase_ptr theElems,
6248                                         SMESH::SMESH_GroupBase_ptr theNodesNot,
6249                                         SMESH::SMESH_GroupBase_ptr theAffectedElems)
6250 {
6251   SMESH_TRY;
6252   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
6253     return false;
6254
6255   initData();
6256
6257
6258   SMESHDS_Mesh* aMeshDS = getMeshDS();
6259   TIDSortedElemSet anElems, aNodes, anAffected;
6260   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
6261   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
6262   idSourceToSet( theAffectedElems, aMeshDS, anAffected, SMDSAbs_All );
6263
6264   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
6265
6266   // Update Python script
6267   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroup( " << theElems << ", "
6268                 << theNodesNot << ", " << theAffectedElems << " )";
6269
6270   declareMeshModified( /*isReComputeSafe=*/false );
6271   return aResult;
6272
6273   SMESH_CATCH( SMESH::throwCorbaException );
6274   return 0;
6275 }
6276
6277 //================================================================================
6278 /*!
6279  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6280  * Works as DoubleNodeElemGroup(), but returns a new group with newly created elements.
6281  * \param theElems - group of of elements (edges or faces) to be replicated
6282  * \param theNodesNot - group of nodes not to replicated
6283  * \param theAffectedElems - group of elements to which the replicated nodes
6284  *        should be associated to.
6285  * \return a new group with newly created elements
6286  * \sa DoubleNodeElemGroup()
6287  */
6288 //================================================================================
6289
6290 SMESH::SMESH_Group_ptr
6291 SMESH_MeshEditor_i::DoubleNodeElemGroupNew(SMESH::SMESH_GroupBase_ptr theElems,
6292                                            SMESH::SMESH_GroupBase_ptr theNodesNot,
6293                                            SMESH::SMESH_GroupBase_ptr theAffectedElems)
6294 {
6295   TPythonDump pyDump;
6296   SMESH::ListOfGroups_var twoGroups = DoubleNodeElemGroup2New( theElems,
6297                                                                theNodesNot,
6298                                                                theAffectedElems,
6299                                                                true, false );
6300   SMESH::SMESH_GroupBase_var baseGroup = twoGroups[0].in();
6301   SMESH::SMESH_Group_var     elemGroup = SMESH::SMESH_Group::_narrow( baseGroup );
6302
6303   pyDump << elemGroup << " = " << this << ".DoubleNodeElemGroupNew( "
6304          << theElems         << ", "
6305          << theNodesNot      << ", "
6306          << theAffectedElems << " )";
6307
6308   return elemGroup._retn();
6309 }
6310
6311 //================================================================================
6312 /*!
6313  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6314  * Works as DoubleNodeElemGroup(), but returns a new group with newly created elements.
6315  * \param theElems - group of of elements (edges or faces) to be replicated
6316  * \param theNodesNot - group of nodes not to replicated
6317  * \param theAffectedElems - group of elements to which the replicated nodes
6318  *        should be associated to.
6319  * \return a new group with newly created elements
6320  * \sa DoubleNodeElemGroup()
6321  */
6322 //================================================================================
6323
6324 SMESH::ListOfGroups*
6325 SMESH_MeshEditor_i::DoubleNodeElemGroup2New(SMESH::SMESH_GroupBase_ptr theElems,
6326                                             SMESH::SMESH_GroupBase_ptr theNodesNot,
6327                                             SMESH::SMESH_GroupBase_ptr theAffectedElems,
6328                                             CORBA::Boolean             theElemGroupNeeded,
6329                                             CORBA::Boolean             theNodeGroupNeeded)
6330 {
6331   SMESH_TRY;
6332   SMESH::SMESH_Group_var aNewElemGroup, aNewNodeGroup;
6333   SMESH::ListOfGroups_var aTwoGroups = new SMESH::ListOfGroups();
6334   aTwoGroups->length( 2 );
6335
6336   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
6337     return aTwoGroups._retn();
6338
6339   initData();
6340
6341
6342   SMESHDS_Mesh* aMeshDS = getMeshDS();
6343   TIDSortedElemSet anElems, aNodes, anAffected;
6344   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
6345   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
6346   idSourceToSet( theAffectedElems, aMeshDS, anAffected, SMDSAbs_All );
6347
6348
6349   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
6350
6351   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6352
6353   TPythonDump pyDump;
6354
6355   if ( aResult )
6356   {
6357     // Create group with newly created elements
6358     CORBA::String_var elemGroupName = theElems->GetName();
6359     std::string aNewName = GenerateGroupName( std::string(elemGroupName.in()) + "_double");
6360     if ( !getEditor().GetLastCreatedElems().empty() && theElemGroupNeeded )
6361     {
6362       SMESH::long_array_var anIds = GetLastCreatedElems();
6363       SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true);
6364       aNewElemGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str());
6365       aNewElemGroup->Add(anIds);
6366     }
6367     if ( !getEditor().GetLastCreatedNodes().empty() && theNodeGroupNeeded )
6368     {
6369       SMESH::long_array_var anIds = GetLastCreatedNodes();
6370       aNewNodeGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
6371       aNewNodeGroup->Add(anIds);
6372     }
6373   }
6374
6375   // Update Python script
6376
6377   pyDump << "[ ";
6378   if ( aNewElemGroup->_is_nil() ) pyDump << "nothing, ";
6379   else                            pyDump << aNewElemGroup << ", ";
6380   if ( aNewNodeGroup->_is_nil() ) pyDump << "nothing ] = ";
6381   else                            pyDump << aNewNodeGroup << " ] = ";
6382
6383   pyDump << this << ".DoubleNodeElemGroup2New( " << theElems << ", "
6384          << theNodesNot        << ", "
6385          << theAffectedElems   << ", "
6386          << theElemGroupNeeded << ", "
6387          << theNodeGroupNeeded <<" )";
6388
6389   aTwoGroups[0] = aNewElemGroup._retn();
6390   aTwoGroups[1] = aNewNodeGroup._retn();
6391   return aTwoGroups._retn();
6392
6393   SMESH_CATCH( SMESH::throwCorbaException );
6394   return 0;
6395 }
6396
6397 //================================================================================
6398 /*!
6399   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6400   \param theElems - group of of elements (edges or faces) to be replicated
6401   \param theNodesNot - group of nodes not to replicated
6402   \param theShape - shape to detect affected elements (element which geometric center
6403   located on or inside shape).
6404   The replicated nodes should be associated to affected elements.
6405   \return TRUE if operation has been completed successfully, FALSE otherwise
6406   \sa DoubleNodesInRegion(), DoubleNodeGroupsInRegion()
6407 */
6408 //================================================================================
6409
6410 CORBA::Boolean
6411 SMESH_MeshEditor_i::DoubleNodeElemGroupInRegion(SMESH::SMESH_GroupBase_ptr theElems,
6412                                                 SMESH::SMESH_GroupBase_ptr theNodesNot,
6413                                                 GEOM::GEOM_Object_ptr      theShape )
6414 {
6415   SMESH_TRY;
6416   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
6417     return false;
6418
6419   initData();
6420
6421
6422   SMESHDS_Mesh* aMeshDS = getMeshDS();
6423   TIDSortedElemSet anElems, aNodes, anAffected;
6424   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
6425   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
6426
6427   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
6428   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
6429
6430
6431   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6432
6433   // Update Python script
6434   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroupInRegion( " << theElems << ", "
6435                 << theNodesNot << ", " << theShape << " )";
6436   return aResult;
6437
6438   SMESH_CATCH( SMESH::throwCorbaException );
6439   return 0;
6440 }
6441
6442 //================================================================================
6443 /*!
6444  * \brief Re-load elements from a list of groups into a TIDSortedElemSet
6445  *  \param [in] theGrpList - groups
6446  *  \param [in] theMeshDS -  mesh
6447  *  \param [out] theElemSet - set of elements
6448  *  \param [in] theIsNodeGrp - is \a theGrpList includes goups of nodes
6449  */
6450 //================================================================================
6451
6452 static void listOfGroupToSet(const SMESH::ListOfGroups& theGrpList,
6453                              SMESHDS_Mesh*              theMeshDS,
6454                              TIDSortedElemSet&          theElemSet,
6455                              const bool                 theIsNodeGrp)
6456 {
6457   for ( int i = 0, n = theGrpList.length(); i < n; i++ )
6458   {
6459     SMESH::SMESH_GroupBase_var aGrp = theGrpList[ i ];
6460     if ( !CORBA::is_nil( aGrp ) && (theIsNodeGrp ? aGrp->GetType() == SMESH::NODE
6461                                     : aGrp->GetType() != SMESH::NODE ) )
6462     {
6463       SMESH::long_array_var anIDs = aGrp->GetIDs();
6464       arrayToSet( anIDs, theMeshDS, theElemSet, theIsNodeGrp ? SMDSAbs_Node : SMDSAbs_All );
6465     }
6466   }
6467 }
6468
6469 //================================================================================
6470 /*!
6471   \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
6472   This method provided for convenience works as DoubleNodes() described above.
6473   \param theElems - list of groups of elements (edges or faces) to be replicated
6474   \param theNodesNot - list of groups of nodes not to replicated
6475   \param theAffectedElems - group of elements to which the replicated nodes
6476   should be associated to.
6477   \return TRUE if operation has been completed successfully, FALSE otherwise
6478   \sa DoubleNodeGroup(), DoubleNodes(), DoubleNodeElemGroupsNew()
6479 */
6480 //================================================================================
6481
6482 CORBA::Boolean
6483 SMESH_MeshEditor_i::DoubleNodeElemGroups(const SMESH::ListOfGroups& theElems,
6484                                          const SMESH::ListOfGroups& theNodesNot,
6485                                          const SMESH::ListOfGroups& theAffectedElems)
6486 {
6487   SMESH_TRY;
6488   initData();
6489
6490
6491   SMESHDS_Mesh* aMeshDS = getMeshDS();
6492   TIDSortedElemSet anElems, aNodes, anAffected;
6493   listOfGroupToSet(theElems, aMeshDS, anElems, false );
6494   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
6495   listOfGroupToSet(theAffectedElems, aMeshDS, anAffected, false );
6496
6497   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
6498
6499   // Update Python script
6500   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroups( " << &theElems << ", "
6501                 << &theNodesNot << ", " << &theAffectedElems << " )";
6502
6503   declareMeshModified( /*isReComputeSafe=*/false );
6504   return aResult;
6505
6506   SMESH_CATCH( SMESH::throwCorbaException );
6507   return 0;
6508 }
6509
6510 //================================================================================
6511 /*!
6512  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6513  * Works as DoubleNodeElemGroups(), but returns a new group with newly created elements.
6514   \param theElems - list of groups of elements (edges or faces) to be replicated
6515   \param theNodesNot - list of groups of nodes not to replicated
6516   \param theAffectedElems - group of elements to which the replicated nodes
6517   should be associated to.
6518  * \return a new group with newly created elements
6519  * \sa DoubleNodeElemGroups()
6520  */
6521 //================================================================================
6522
6523 SMESH::SMESH_Group_ptr
6524 SMESH_MeshEditor_i::DoubleNodeElemGroupsNew(const SMESH::ListOfGroups& theElems,
6525                                             const SMESH::ListOfGroups& theNodesNot,
6526                                             const SMESH::ListOfGroups& theAffectedElems)
6527 {
6528   TPythonDump pyDump;
6529   SMESH::ListOfGroups_var twoGroups = DoubleNodeElemGroups2New( theElems,
6530                                                                 theNodesNot,
6531                                                                 theAffectedElems,
6532                                                                 true, false );
6533   SMESH::SMESH_GroupBase_var baseGroup = twoGroups[0].in();
6534   SMESH::SMESH_Group_var     elemGroup = SMESH::SMESH_Group::_narrow( baseGroup );
6535
6536   pyDump << elemGroup << " = " << this << ".DoubleNodeElemGroupsNew( "
6537          << theElems         << ", "
6538          << theNodesNot      << ", "
6539          << theAffectedElems << " )";
6540
6541   return elemGroup._retn();
6542 }
6543
6544 //================================================================================
6545 /*!
6546  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6547  * Works as DoubleNodeElemGroups(), but returns a new group with newly created elements.
6548   \param theElems - list of groups of elements (edges or faces) to be replicated
6549   \param theNodesNot - list of groups of nodes not to replicated
6550   \param theAffectedElems - group of elements to which the replicated nodes
6551   should be associated to.
6552  * \return a new group with newly created elements
6553  * \sa DoubleNodeElemGroups()
6554  */
6555 //================================================================================
6556
6557 SMESH::ListOfGroups*
6558 SMESH_MeshEditor_i::DoubleNodeElemGroups2New(const SMESH::ListOfGroups& theElems,
6559                                              const SMESH::ListOfGroups& theNodesNot,
6560                                              const SMESH::ListOfGroups& theAffectedElems,
6561                                              CORBA::Boolean             theElemGroupNeeded,
6562                                              CORBA::Boolean             theNodeGroupNeeded)
6563 {
6564   SMESH_TRY;
6565   SMESH::SMESH_Group_var aNewElemGroup, aNewNodeGroup;
6566   SMESH::ListOfGroups_var aTwoGroups = new SMESH::ListOfGroups();
6567   aTwoGroups->length( 2 );
6568   
6569   initData();
6570
6571
6572   SMESHDS_Mesh* aMeshDS = getMeshDS();
6573   TIDSortedElemSet anElems, aNodes, anAffected;
6574   listOfGroupToSet(theElems, aMeshDS, anElems, false );
6575   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
6576   listOfGroupToSet(theAffectedElems, aMeshDS, anAffected, false );
6577
6578   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
6579
6580   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6581
6582   TPythonDump pyDump;
6583   if ( aResult )
6584   {
6585     // Create group with newly created elements
6586     CORBA::String_var elemGroupName = theElems[0]->GetName();
6587     std::string aNewName = GenerateGroupName( std::string(elemGroupName.in()) + "_double");
6588     if ( !getEditor().GetLastCreatedElems().empty() && theElemGroupNeeded )
6589     {
6590       SMESH::long_array_var anIds = GetLastCreatedElems();
6591       SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true);
6592       aNewElemGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str());
6593       aNewElemGroup->Add(anIds);
6594     }
6595     if ( !getEditor().GetLastCreatedNodes().empty() && theNodeGroupNeeded )
6596     {
6597       SMESH::long_array_var anIds = GetLastCreatedNodes();
6598       aNewNodeGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
6599       aNewNodeGroup->Add(anIds);
6600     }
6601   }
6602
6603   // Update Python script
6604
6605   pyDump << "[ ";
6606   if ( aNewElemGroup->_is_nil() ) pyDump << "nothing, ";
6607   else                            pyDump << aNewElemGroup << ", ";
6608   if ( aNewNodeGroup->_is_nil() ) pyDump << "nothing ] = ";
6609   else                            pyDump << aNewNodeGroup << " ] = ";
6610
6611   pyDump << this << ".DoubleNodeElemGroups2New( " << &theElems << ", "
6612          << &theNodesNot       << ", "
6613          << &theAffectedElems  << ", "
6614          << theElemGroupNeeded << ", "
6615          << theNodeGroupNeeded << " )";
6616
6617   aTwoGroups[0] = aNewElemGroup._retn();
6618   aTwoGroups[1] = aNewNodeGroup._retn();
6619   return aTwoGroups._retn();
6620
6621   SMESH_CATCH( SMESH::throwCorbaException );
6622   return 0;
6623 }
6624
6625 //================================================================================
6626 /*!
6627   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6628   This method provided for convenience works as DoubleNodes() described above.
6629   \param theElems - list of groups of elements (edges or faces) to be replicated
6630   \param theNodesNot - list of groups of nodes not to replicated
6631   \param theShape - shape to detect affected elements (element which geometric center
6632   located on or inside shape).
6633   The replicated nodes should be associated to affected elements.
6634   \return TRUE if operation has been completed successfully, FALSE otherwise
6635   \sa DoubleNodeGroupInRegion(), DoubleNodesInRegion()
6636 */
6637 //================================================================================
6638
6639 CORBA::Boolean
6640 SMESH_MeshEditor_i::DoubleNodeElemGroupsInRegion(const SMESH::ListOfGroups& theElems,
6641                                                  const SMESH::ListOfGroups& theNodesNot,
6642                                                  GEOM::GEOM_Object_ptr      theShape )
6643 {
6644   SMESH_TRY;
6645   initData();
6646
6647
6648   SMESHDS_Mesh* aMeshDS = getMeshDS();
6649   TIDSortedElemSet anElems, aNodes;
6650   listOfGroupToSet(theElems, aMeshDS, anElems,false );
6651   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
6652
6653   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
6654   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
6655
6656   // Update Python script
6657   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroupsInRegion( " << &theElems << ", "
6658                 << &theNodesNot << ", " << theShape << " )";
6659
6660   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6661   return aResult;
6662
6663   SMESH_CATCH( SMESH::throwCorbaException );
6664   return 0;
6665 }
6666
6667 //================================================================================
6668 /*!
6669   \brief Identify the elements that will be affected by node duplication (actual
6670          duplication is not performed.
6671   This method is the first step of DoubleNodeElemGroupsInRegion.
6672   \param theElems - list of groups of elements (edges or faces) to be replicated
6673   \param theNodesNot - list of groups of nodes not to replicated
6674   \param theShape - shape to detect affected elements (element which geometric center
6675          located on or inside shape).
6676          The replicated nodes should be associated to affected elements.
6677   \return groups of affected elements
6678   \sa DoubleNodeElemGroupsInRegion()
6679 */
6680 //================================================================================
6681 SMESH::ListOfGroups*
6682 SMESH_MeshEditor_i::AffectedElemGroupsInRegion( const SMESH::ListOfGroups& theElems,
6683                                                 const SMESH::ListOfGroups& theNodesNot,
6684                                                 GEOM::GEOM_Object_ptr      theShape )
6685 {
6686   SMESH_TRY;
6687   SMESH::ListOfGroups_var aListOfGroups = new SMESH::ListOfGroups();
6688   SMESH::SMESH_Group_var aNewEdgeGroup   = SMESH::SMESH_Group::_nil();
6689   SMESH::SMESH_Group_var aNewFaceGroup   = SMESH::SMESH_Group::_nil();
6690   SMESH::SMESH_Group_var aNewVolumeGroup = SMESH::SMESH_Group::_nil();
6691
6692   initData();
6693
6694   ::SMESH_MeshEditor aMeshEditor(myMesh);
6695
6696   SMESHDS_Mesh* aMeshDS = getMeshDS();
6697   TIDSortedElemSet anElems, aNodes;
6698   bool isNodeGrp = theElems.length() ? theElems[0]->GetType() == SMESH::NODE : false;
6699   listOfGroupToSet(theElems, aMeshDS, anElems, isNodeGrp);
6700   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true);
6701
6702   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape(theShape);
6703   TIDSortedElemSet anAffected;
6704   bool aResult = aMeshEditor.AffectedElemGroupsInRegion(anElems, aNodes, aShape, anAffected);
6705
6706   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6707
6708   TPythonDump pyDump;
6709   if ( aResult && anAffected.size() > 0 )
6710   {
6711     SMESH::long_array_var volumeIds = new SMESH::long_array;
6712     SMESH::long_array_var   faceIds = new SMESH::long_array;
6713     SMESH::long_array_var   edgeIds = new SMESH::long_array;
6714     volumeIds->length( anAffected.size() );
6715     faceIds  ->length( anAffected.size() );
6716     edgeIds  ->length( anAffected.size() );
6717
6718     int ivol = 0;
6719     int iface = 0;
6720     int iedge = 0;
6721     TIDSortedElemSet::const_iterator eIt = anAffected.begin();
6722     for (; eIt != anAffected.end(); ++eIt)
6723     {
6724       const SMDS_MeshElement* anElem = *eIt;
6725       int elemId = anElem->GetID();
6726       switch ( anElem->GetType() ) {
6727       case SMDSAbs_Volume: volumeIds[ivol++] = elemId; break;
6728       case SMDSAbs_Face:    faceIds[iface++] = elemId; break;
6729       case SMDSAbs_Edge:    edgeIds[iedge++] = elemId; break;
6730       default:;
6731       }
6732     }
6733     volumeIds->length(ivol);
6734     faceIds->length(iface);
6735     edgeIds->length(iedge);
6736
6737     int nbGroups = 0;
6738     if ( ivol > 0 )
6739     {
6740       aNewVolumeGroup = myMesh_i->CreateGroup(SMESH::VOLUME,
6741                                               GenerateGroupName("affectedVolumes").c_str());
6742       aNewVolumeGroup->Add(volumeIds);
6743       aListOfGroups->length( nbGroups+1 );
6744       aListOfGroups[ nbGroups++ ] = aNewVolumeGroup._retn();
6745     }
6746     if ( iface > 0 )
6747     {
6748       aNewFaceGroup = myMesh_i->CreateGroup(SMESH::FACE,
6749                                             GenerateGroupName("affectedFaces").c_str());
6750       aNewFaceGroup->Add(faceIds);
6751       aListOfGroups->length( nbGroups+1 );
6752       aListOfGroups[ nbGroups++ ] = aNewFaceGroup._retn();
6753     }
6754     if ( iedge > 0 )
6755     {
6756       aNewEdgeGroup = myMesh_i->CreateGroup(SMESH::EDGE,
6757                                             GenerateGroupName("affectedEdges").c_str());
6758       aNewEdgeGroup->Add(edgeIds);
6759       aListOfGroups->length( nbGroups+1 );
6760       aListOfGroups[ nbGroups++ ] = aNewEdgeGroup._retn();
6761     }
6762   }
6763
6764   // Update Python script
6765
6766   pyDump << aListOfGroups << " = " << this << ".AffectedElemGroupsInRegion( "
6767          << &theElems << ", " << &theNodesNot << ", " << theShape << " )";
6768
6769   return aListOfGroups._retn();
6770
6771   SMESH_CATCH( SMESH::throwCorbaException );
6772   return 0;
6773 }
6774
6775 //================================================================================
6776 /*!
6777   \brief Generated skin mesh (containing 2D cells) from 3D mesh
6778   The created 2D mesh elements based on nodes of free faces of boundary volumes
6779   \return TRUE if operation has been completed successfully, FALSE otherwise
6780 */
6781 //================================================================================
6782
6783 CORBA::Boolean SMESH_MeshEditor_i::Make2DMeshFrom3D()
6784 {
6785   SMESH_TRY;
6786   initData();
6787
6788   bool aResult = getEditor().Make2DMeshFrom3D();
6789
6790   TPythonDump() << "isDone = " << this << ".Make2DMeshFrom3D()";
6791
6792   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6793   return aResult;
6794
6795   SMESH_CATCH( SMESH::throwCorbaException );
6796   return false;
6797 }
6798
6799 //================================================================================
6800 /*!
6801  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
6802  * The list of groups must contain at least two groups. The groups have to be disjoint:
6803  * no common element into two different groups.
6804  * The nodes of the internal faces at the boundaries of the groups are doubled.
6805  * Optionally, the internal faces are replaced by flat elements.
6806  * Triangles are transformed into prisms, and quadrangles into hexahedrons.
6807  * The flat elements are stored in groups of volumes.
6808  * These groups are named according to the position of the group in the list:
6809  * the group j_n_p is the group of the flat elements that are built between the group #n and the group #p in the list.
6810  * If there is no shared faces between the group #n and the group #p in the list, the group j_n_p is not created.
6811  * All the flat elements are gathered into the group named "joints3D" (or "joints2D" in 2D situation).
6812  * The flat element of the multiple junctions between the simple junction are stored in a group named "jointsMultiples".
6813  * \param theDomains - list of groups of volumes
6814  * \param createJointElems - if TRUE, create the elements
6815  * \param onAllBoundaries - if TRUE, the nodes and elements are also created on
6816  *        the boundary between \a theDomains and the rest mesh
6817  * \return TRUE if operation has been completed successfully, FALSE otherwise
6818  */
6819 //================================================================================
6820
6821 CORBA::Boolean
6822 SMESH_MeshEditor_i::DoubleNodesOnGroupBoundaries( const SMESH::ListOfGroups& theDomains,
6823                                                   CORBA::Boolean             createJointElems,
6824                                                   CORBA::Boolean             onAllBoundaries )
6825 {
6826   bool isOK = false;
6827
6828   SMESH_TRY;
6829   initData();
6830
6831   SMESHDS_Mesh* aMeshDS = getMeshDS();
6832
6833   // MESSAGE("theDomains.length = "<<theDomains.length());
6834   if ( theDomains.length() <= 1 && !onAllBoundaries )
6835     THROW_SALOME_CORBA_EXCEPTION("At least 2 groups are required.", SALOME::BAD_PARAM);
6836
6837   vector<TIDSortedElemSet> domains;
6838   domains.resize( theDomains.length() );
6839
6840   for ( int i = 0, n = theDomains.length(); i < n; i++ )
6841   {
6842     SMESH::SMESH_GroupBase_var aGrp = theDomains[ i ];
6843     if ( !CORBA::is_nil( aGrp ) /*&& ( aGrp->GetType() != SMESH::NODE )*/ )
6844     {
6845 //      if ( aGrp->GetType() != SMESH::VOLUME )
6846 //        THROW_SALOME_CORBA_EXCEPTION("Not a volume group", SALOME::BAD_PARAM);
6847       SMESH::long_array_var anIDs = aGrp->GetIDs();
6848       arrayToSet( anIDs, aMeshDS, domains[ i ], SMDSAbs_All );
6849     }
6850   }
6851
6852   isOK = getEditor().DoubleNodesOnGroupBoundaries( domains, createJointElems, onAllBoundaries );
6853   // TODO publish the groups of flat elements in study
6854
6855   declareMeshModified( /*isReComputeSafe=*/ !isOK );
6856
6857   // Update Python script
6858   TPythonDump() << "isDone = " << this << ".DoubleNodesOnGroupBoundaries( " << &theDomains
6859                 << ", " << createJointElems << ", " << onAllBoundaries << " )";
6860
6861   SMESH_CATCH( SMESH::throwCorbaException );
6862
6863   myMesh_i->CreateGroupServants(); // publish created groups if any
6864
6865   return isOK;
6866 }
6867
6868 //================================================================================
6869 /*!
6870  * \brief Double nodes on some external faces and create flat elements.
6871  * Flat elements are mainly used by some types of mechanic calculations.
6872  *
6873  * Each group of the list must be constituted of faces.
6874  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
6875  * @param theGroupsOfFaces - list of groups of faces
6876  * @return TRUE if operation has been completed successfully, FALSE otherwise
6877  */
6878 //================================================================================
6879
6880 CORBA::Boolean
6881 SMESH_MeshEditor_i::CreateFlatElementsOnFacesGroups( const SMESH::ListOfGroups& theGroupsOfFaces )
6882 {
6883   SMESH_TRY;
6884   initData();
6885
6886   SMESHDS_Mesh* aMeshDS = getMeshDS();
6887
6888   vector<TIDSortedElemSet> faceGroups;
6889   faceGroups.clear();
6890
6891   for ( int i = 0, n = theGroupsOfFaces.length(); i < n; i++ )
6892   {
6893     SMESH::SMESH_GroupBase_var aGrp = theGroupsOfFaces[ i ];
6894     if ( !CORBA::is_nil( aGrp ) && ( aGrp->GetType() != SMESH::NODE ) )
6895     {
6896       TIDSortedElemSet faceGroup;
6897       faceGroup.clear();
6898       faceGroups.push_back(faceGroup);
6899       SMESH::long_array_var anIDs = aGrp->GetIDs();
6900       arrayToSet( anIDs, aMeshDS, faceGroups[ i ], SMDSAbs_All );
6901     }
6902   }
6903
6904   bool aResult = getEditor().CreateFlatElementsOnFacesGroups( faceGroups );
6905   // TODO publish the groups of flat elements in study
6906
6907   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6908
6909   // Update Python script
6910   TPythonDump() << this << ".CreateFlatElementsOnFacesGroups( " << &theGroupsOfFaces << " )";
6911   return aResult;
6912
6913   SMESH_CATCH( SMESH::throwCorbaException );
6914   return false;
6915 }
6916
6917 //================================================================================
6918 /*!
6919  *  \brief Identify all the elements around a geom shape, get the faces delimiting
6920  *         the hole.
6921  *
6922  *  Build groups of volume to remove, groups of faces to replace on the skin of the
6923  *  object, groups of faces to remove inside the object, (idem edges).
6924  *  Build ordered list of nodes at the border of each group of faces to replace
6925  *  (to be used to build a geom subshape).
6926  */
6927 //================================================================================
6928
6929 void SMESH_MeshEditor_i::CreateHoleSkin(CORBA::Double                  radius,
6930                                         GEOM::GEOM_Object_ptr          theShape,
6931                                         const char*                    groupName,
6932                                         const SMESH::double_array&     theNodesCoords,
6933                                         SMESH::array_of_long_array_out GroupsOfNodes)
6934 {
6935   SMESH_TRY;
6936
6937   initData();
6938   std::vector<std::vector<int> > aListOfListOfNodes;
6939   ::SMESH_MeshEditor aMeshEditor( myMesh );
6940
6941   theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
6942   if ( !theNodeSearcher )
6943     theNodeSearcher = SMESH_MeshAlgos::GetNodeSearcher( *getMeshDS() );
6944
6945   vector<double> nodesCoords;
6946   for ( CORBA::ULong i = 0; i < theNodesCoords.length(); i++)
6947   {
6948     nodesCoords.push_back( theNodesCoords[i] );
6949   }
6950
6951   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
6952   aMeshEditor.CreateHoleSkin(radius, aShape, theNodeSearcher, groupName,
6953                              nodesCoords, aListOfListOfNodes);
6954
6955   GroupsOfNodes = new SMESH::array_of_long_array;
6956   GroupsOfNodes->length( aListOfListOfNodes.size() );
6957   std::vector<std::vector<int> >::iterator llIt = aListOfListOfNodes.begin();
6958   for ( CORBA::Long i = 0; llIt != aListOfListOfNodes.end(); llIt++, i++ )
6959   {
6960     vector<int>& aListOfNodes = *llIt;
6961     vector<int>::iterator lIt = aListOfNodes.begin();;
6962     SMESH::long_array& aGroup = (*GroupsOfNodes)[ i ];
6963     aGroup.length( aListOfNodes.size() );
6964     for ( int j = 0; lIt != aListOfNodes.end(); lIt++, j++ )
6965       aGroup[ j ] = (*lIt);
6966   }
6967   TPythonDump() << "lists_nodes = " << this << ".CreateHoleSkin( "
6968                 << radius << ", "
6969                 << theShape
6970                 << ", '" << groupName << "', "
6971                 << theNodesCoords << " )";
6972
6973   SMESH_CATCH( SMESH::throwCorbaException );
6974 }
6975
6976 // issue 20749 ===================================================================
6977 /*!
6978  * \brief Creates missing boundary elements
6979  *  \param elements - elements whose boundary is to be checked
6980  *  \param dimension - defines type of boundary elements to create
6981  *  \param groupName - a name of group to store created boundary elements in,
6982  *                     "" means not to create the group
6983  *  \param meshName - a name of new mesh to store created boundary elements in,
6984  *                     "" means not to create the new mesh
6985  *  \param toCopyElements - if true, the checked elements will be copied into the new mesh
6986  *  \param toCopyExistingBondary - if true, not only new but also pre-existing
6987  *                                boundary elements will be copied into the new mesh
6988  *  \param group - returns the create group, if any
6989  *  \retval SMESH::SMESH_Mesh - the mesh where elements were added to
6990  */
6991 // ================================================================================
6992
6993 SMESH::SMESH_Mesh_ptr
6994 SMESH_MeshEditor_i::MakeBoundaryMesh(SMESH::SMESH_IDSource_ptr idSource,
6995                                      SMESH::Bnd_Dimension      dim,
6996                                      const char*               groupName,
6997                                      const char*               meshName,
6998                                      CORBA::Boolean            toCopyElements,
6999                                      CORBA::Boolean            toCopyExistingBondary,
7000                                      SMESH::SMESH_Group_out    group)
7001 {
7002   SMESH_TRY;
7003   initData();
7004
7005   if ( dim > SMESH::BND_1DFROM2D )
7006     THROW_SALOME_CORBA_EXCEPTION("Invalid boundary dimension", SALOME::BAD_PARAM);
7007
7008   SMESHDS_Mesh* aMeshDS = getMeshDS();
7009
7010   SMESH::SMESH_Mesh_var mesh_var;
7011   SMESH::SMESH_Group_var group_var;
7012
7013   TPythonDump pyDump;
7014
7015   TIDSortedElemSet elements;
7016   SMDSAbs_ElementType elemType = (dim == SMESH::BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
7017   if ( idSourceToSet( idSource, aMeshDS, elements, elemType,/*emptyIfIsMesh=*/true ))
7018   {
7019     // mesh to fill in
7020     mesh_var =
7021       strlen(meshName) ? makeMesh(meshName) : SMESH::SMESH_Mesh::_duplicate(myMesh_i->_this());
7022     SMESH_Mesh_i* mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh_var );
7023     // other mesh
7024     SMESH_Mesh* smesh_mesh = (mesh_i==myMesh_i) ? (SMESH_Mesh*)0 : &mesh_i->GetImpl();
7025
7026     // group of new boundary elements
7027     SMESH_Group* smesh_group = 0;
7028     if ( strlen(groupName) )
7029     {
7030       group_var = mesh_i->CreateGroup( SMESH::ElementType(int(elemType)-1),groupName);
7031       if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( group_var ))
7032         smesh_group = group_i->GetSmeshGroup();
7033     }
7034
7035     // do it
7036     getEditor().MakeBoundaryMesh( elements,
7037                                   ::SMESH_MeshEditor::Bnd_Dimension(dim),
7038                                   smesh_group,
7039                                   smesh_mesh,
7040                                   toCopyElements,
7041                                   toCopyExistingBondary);
7042
7043     if ( smesh_mesh )
7044       smesh_mesh->GetMeshDS()->Modified();
7045   }
7046
7047   const char* dimName[] = { "BND_2DFROM3D", "BND_1DFROM3D", "BND_1DFROM2D" };
7048
7049   // result of MakeBoundaryMesh() is a tuple (mesh, group)
7050   if ( mesh_var->_is_nil() )
7051     pyDump << myMesh_i->_this() << ", ";
7052   else
7053     pyDump << mesh_var << ", ";
7054   if ( group_var->_is_nil() )
7055     pyDump << "_NoneGroup = "; // assignment to None is forbidden
7056   else
7057     pyDump << group_var << " = ";
7058   pyDump << this << ".MakeBoundaryMesh( "
7059          << idSource << ", "
7060          << "SMESH." << dimName[int(dim)] << ", "
7061          << "'" << groupName << "', "
7062          << "'" << meshName<< "', "
7063          << toCopyElements << ", "
7064          << toCopyExistingBondary << ")";
7065
7066   group = group_var._retn();
7067   return mesh_var._retn();
7068
7069   SMESH_CATCH( SMESH::throwCorbaException );
7070   return SMESH::SMESH_Mesh::_nil();
7071 }
7072
7073 //================================================================================
7074 /*!
7075  * \brief Creates missing boundary elements
7076  *  \param dimension - defines type of boundary elements to create
7077  *  \param groupName - a name of group to store all boundary elements in,
7078  *    "" means not to create the group
7079  *  \param meshName - a name of a new mesh, which is a copy of the initial 
7080  *    mesh + created boundary elements; "" means not to create the new mesh
7081  *  \param toCopyAll - if true, the whole initial mesh will be copied into
7082  *    the new mesh else only boundary elements will be copied into the new mesh
7083  *  \param groups - optional groups of elements to make boundary around
7084  *  \param mesh - returns the mesh where elements were added to
7085  *  \param group - returns the created group, if any
7086  *  \retval long - number of added boundary elements
7087  */
7088 //================================================================================
7089
7090 CORBA::Long SMESH_MeshEditor_i::MakeBoundaryElements(SMESH::Bnd_Dimension dim,
7091                                                      const char* groupName,
7092                                                      const char* meshName,
7093                                                      CORBA::Boolean toCopyAll,
7094                                                      const SMESH::ListOfIDSources& groups,
7095                                                      SMESH::SMESH_Mesh_out mesh,
7096                                                      SMESH::SMESH_Group_out group)
7097 {
7098   SMESH_TRY;
7099   initData();
7100
7101   if ( dim > SMESH::BND_1DFROM2D )
7102     THROW_SALOME_CORBA_EXCEPTION("Invalid boundary dimension", SALOME::BAD_PARAM);
7103
7104   // separate groups belonging to this and other mesh
7105   SMESH::ListOfIDSources_var groupsOfThisMesh  = new SMESH::ListOfIDSources;
7106   SMESH::ListOfIDSources_var groupsOfOtherMesh = new SMESH::ListOfIDSources;
7107   groupsOfThisMesh ->length( groups.length() );
7108   groupsOfOtherMesh->length( groups.length() );
7109   int nbGroups = 0, nbGroupsOfOtherMesh = 0;
7110   for ( CORBA::ULong i = 0; i < groups.length(); ++i )
7111   {
7112     SMESH::SMESH_Mesh_var m = groups[i]->GetMesh();
7113     if ( !m->_is_nil() && myMesh_i != SMESH::DownCast<SMESH_Mesh_i*>( m ))
7114       groupsOfOtherMesh[ nbGroupsOfOtherMesh++ ] = groups[i];
7115     else
7116       groupsOfThisMesh[ nbGroups++ ] = groups[i];
7117     if ( SMESH::DownCast<SMESH_Mesh_i*>( groups[i] ))
7118       THROW_SALOME_CORBA_EXCEPTION("expected a group but received a mesh", SALOME::BAD_PARAM);
7119   }
7120   groupsOfThisMesh->length( nbGroups );
7121   groupsOfOtherMesh->length( nbGroupsOfOtherMesh );
7122
7123   int nbAdded = 0;
7124   TPythonDump pyDump;
7125
7126   if ( nbGroupsOfOtherMesh > 0 )
7127   {
7128     // process groups belonging to another mesh
7129     SMESH::SMESH_Mesh_var    otherMesh = groupsOfOtherMesh[0]->GetMesh();
7130     SMESH::SMESH_MeshEditor_var editor = otherMesh->GetMeshEditor();
7131     nbAdded += editor->MakeBoundaryElements( dim, groupName, meshName, toCopyAll,
7132                                              groupsOfOtherMesh, mesh, group );
7133   }
7134
7135   SMESH::SMESH_Mesh_var mesh_var;
7136   SMESH::SMESH_Group_var group_var;
7137
7138   // get mesh to fill
7139   mesh_var = SMESH::SMESH_Mesh::_duplicate( myMesh_i->_this() );
7140   const bool toCopyMesh = ( strlen( meshName ) > 0 );
7141   if ( toCopyMesh )
7142   {
7143     if ( toCopyAll )
7144       mesh_var = SMESH_Gen_i::GetSMESHGen()->CopyMesh(mesh_var,
7145                                                       meshName,
7146                                                       /*toCopyGroups=*/false,
7147                                                       /*toKeepIDs=*/true);
7148     else
7149       mesh_var = makeMesh(meshName);
7150   }
7151   SMESH_Mesh_i* mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh_var );
7152   SMESH_Mesh*  tgtMesh = &mesh_i->GetImpl();
7153
7154   // source mesh
7155   SMESH_Mesh*     srcMesh = ( toCopyMesh && !toCopyAll ) ? myMesh : tgtMesh;
7156   SMESHDS_Mesh* srcMeshDS = srcMesh->GetMeshDS();
7157
7158   // group of boundary elements
7159   SMESH_Group* smesh_group = 0;
7160   SMDSAbs_ElementType elemType = (dim == SMESH::BND_2DFROM3D) ? SMDSAbs_Volume : SMDSAbs_Face;
7161   if ( strlen( groupName ))
7162   {
7163     SMESH::ElementType groupType = SMESH::ElementType( int(elemType)-1 );
7164     group_var = mesh_i->CreateGroup( groupType, groupName );
7165     if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( group_var ))
7166       smesh_group = group_i->GetSmeshGroup();
7167   }
7168
7169   TIDSortedElemSet elements;
7170
7171   if ( groups.length() > 0 )
7172   {
7173     for ( int i = 0; i < nbGroups; ++i )
7174     {
7175       elements.clear();
7176       if ( idSourceToSet( groupsOfThisMesh[i], srcMeshDS, elements, elemType,/*emptyIfIsMesh=*/0 ))
7177       {
7178         SMESH::Bnd_Dimension bdim = 
7179           ( elemType == SMDSAbs_Volume ) ? SMESH::BND_2DFROM3D : SMESH::BND_1DFROM2D;
7180         nbAdded += getEditor().MakeBoundaryMesh( elements,
7181                                                  ::SMESH_MeshEditor::Bnd_Dimension(bdim),
7182                                                  smesh_group,
7183                                                  tgtMesh,
7184                                                  /*toCopyElements=*/false,
7185                                                  /*toCopyExistingBondary=*/srcMesh != tgtMesh,
7186                                                  /*toAddExistingBondary=*/true,
7187                                                  /*aroundElements=*/true);
7188       }
7189     }
7190   }
7191   else
7192   {
7193     nbAdded += getEditor().MakeBoundaryMesh( elements,
7194                                              ::SMESH_MeshEditor::Bnd_Dimension(dim),
7195                                              smesh_group,
7196                                              tgtMesh,
7197                                              /*toCopyElements=*/false,
7198                                              /*toCopyExistingBondary=*/srcMesh != tgtMesh,
7199                                              /*toAddExistingBondary=*/true);
7200   }
7201   tgtMesh->GetMeshDS()->Modified();
7202
7203   const char* dimName[] = { "BND_2DFROM3D", "BND_1DFROM3D", "BND_1DFROM2D" };
7204
7205   // result of MakeBoundaryElements() is a tuple (nb, mesh, group)
7206   pyDump << "nbAdded, ";
7207   if ( mesh_var->_is_nil() )
7208     pyDump << myMesh_i->_this() << ", ";
7209   else
7210     pyDump << mesh_var << ", ";
7211   if ( group_var->_is_nil() )
7212     pyDump << "_NoneGroup = "; // assignment to None is forbidden
7213   else
7214     pyDump << group_var << " = ";
7215   pyDump << this << ".MakeBoundaryElements( "
7216          << "SMESH." << dimName[int(dim)] << ", "
7217          << "'" << groupName << "', "
7218          << "'" << meshName<< "', "
7219          << toCopyAll << ", "
7220          << groups << ")";
7221
7222   mesh  = mesh_var._retn();
7223   group = group_var._retn();
7224   return nbAdded;
7225
7226   SMESH_CATCH( SMESH::throwCorbaException );
7227   return 0;
7228 }
7229
7230 //================================================================================
7231 /*!
7232  * \brief Create a polyline consisting of 1D mesh elements each lying on a 2D element of
7233  *        the initial mesh. Positions of new nodes are found by cutting the mesh by the
7234  *        plane passing through pairs of points specified by each PolySegment structure.
7235  *        If there are several paths connecting a pair of points, the shortest path is
7236  *        selected by the module. Position of the cutting plane is defined by the two
7237  *        points and an optional vector lying on the plane specified by a PolySegment.
7238  *        By default the vector is defined by Mesh module as following. A middle point
7239  *        of the two given points is computed. The middle point is projected to the mesh.
7240  *        The vector goes from the middle point to the projection point. In case of planar
7241  *        mesh, the vector is normal to the mesh.
7242  *  \param [inout] segments - PolySegment's defining positions of cutting planes.
7243  *        Return the used vector and position of the middle point.
7244  *  \param [in] groupName - optional name of a group where created mesh segments will
7245  *        be added.
7246  */
7247 //================================================================================
7248
7249 void SMESH_MeshEditor_i::MakePolyLine(SMESH::ListOfPolySegments& theSegments,
7250                                       const char*                theGroupName)
7251 {
7252   if ( theSegments.length() == 0 )
7253     THROW_SALOME_CORBA_EXCEPTION("No segments given", SALOME::BAD_PARAM );
7254   if ( myMesh->NbFaces() == 0 )
7255     THROW_SALOME_CORBA_EXCEPTION("No faces in the mesh", SALOME::BAD_PARAM );
7256
7257   SMESH_TRY;
7258   initData(/*deleteSearchers=*/false);
7259
7260   SMESHDS_Group* groupDS = 0;
7261   SMESHDS_Mesh*   meshDS = getMeshDS();
7262   if ( myIsPreviewMode ) // copy faces to the tmp mesh
7263   {
7264     TPreviewMesh * tmpMesh = getPreviewMesh( SMDSAbs_Edge );
7265     SMDS_ElemIteratorPtr faceIt = getMeshDS()->elementsIterator( SMDSAbs_Face );
7266     while ( faceIt->more() )
7267       tmpMesh->Copy( faceIt->next() );
7268     meshDS = tmpMesh->GetMeshDS();
7269   }
7270   else if ( theGroupName[0] ) // find/create a group of segments
7271   {
7272     // SMESH_Mesh::GroupIteratorPtr grpIt = myMesh->GetGroups();
7273     // while ( !groupDS && grpIt->more() )
7274     // {
7275     //   SMESH_Group* group = grpIt->next();
7276     //   if ( group->GetGroupDS()->GetType() == SMDSAbs_Edge &&
7277     //        strcmp( group->GetName(), theGroupName ) == 0 )
7278     //   {
7279     //     groupDS = dynamic_cast< SMESHDS_Group* >( group->GetGroupDS() );
7280     //   }
7281     // }
7282     if ( !groupDS )
7283     {
7284       SMESH::SMESH_Group_var groupVar = myMesh_i->CreateGroup( SMESH::EDGE, theGroupName );
7285
7286       if ( SMESH_Group_i* groupImpl = SMESH::DownCast<SMESH_Group_i*>( groupVar ))
7287         groupDS = dynamic_cast< SMESHDS_Group* >( groupImpl->GetGroupDS() );
7288     }
7289   }
7290
7291   // convert input polySegments
7292   SMESH_MeshAlgos::TListOfPolySegments segments( theSegments.length() );
7293   for ( CORBA::ULong i = 0; i < theSegments.length(); ++i )
7294   {
7295     SMESH::PolySegment&            segIn = theSegments[ i ];
7296     SMESH_MeshAlgos::PolySegment& segOut = segments[ i ];
7297     segOut.myNode1[0] = meshDS->FindNode( segIn.node1ID1 );
7298     segOut.myNode2[0] = meshDS->FindNode( segIn.node1ID2 );
7299     segOut.myNode1[1] = meshDS->FindNode( segIn.node2ID1 );
7300     segOut.myNode2[1] = meshDS->FindNode( segIn.node2ID2 );
7301     segOut.myXYZ[0].SetCoord( segIn.xyz1.x,
7302                               segIn.xyz1.y,
7303                               segIn.xyz1.z);
7304     segOut.myXYZ[1].SetCoord( segIn.xyz2.x,
7305                               segIn.xyz2.y,
7306                               segIn.xyz2.z);
7307     segOut.myVector.SetCoord( segIn.vector.PS.x,
7308                               segIn.vector.PS.y,
7309                               segIn.vector.PS.z );
7310   }
7311
7312   // get a static ElementSearcher
7313   SMESH::SMESH_IDSource_var idSource = SMESH::SMESH_IDSource::_narrow( myMesh_i->_this() );
7314   theSearchersDeleter.Set( myMesh, getPartIOR( idSource, SMESH::FACE ));
7315   if ( !theElementSearcher )
7316     theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() );
7317
7318   // compute
7319   std::vector<const SMDS_MeshElement*> newEdges;
7320   std::vector<const SMDS_MeshNode*>    newNodes;
7321   SMESH_MeshAlgos::MakePolyLine( meshDS, segments, newEdges, newNodes,
7322                                  groupDS ? &groupDS->SMDSGroup() : 0,
7323                                  theElementSearcher );
7324
7325   const_cast< SMESH_SequenceOfElemPtr& >( getEditor().GetLastCreatedElems() ).
7326     swap( newEdges );
7327   const_cast< SMESH_SequenceOfElemPtr& >( getEditor().GetLastCreatedNodes() ).
7328     assign( newNodes.begin(), newNodes.end() );
7329
7330   // return vectors
7331   if ( myIsPreviewMode )
7332   {
7333     for ( CORBA::ULong i = 0; i < theSegments.length(); ++i )
7334     {
7335       SMESH::PolySegment&           segOut = theSegments[ i ];
7336       SMESH_MeshAlgos::PolySegment& segIn = segments[ i ];
7337       segOut.vector.PS.x = segIn.myVector.X();
7338       segOut.vector.PS.y = segIn.myVector.Y();
7339       segOut.vector.PS.z = segIn.myVector.Z();
7340     }
7341   }
7342   else
7343   {
7344     TPythonDump() << "_segments = []";
7345     for ( CORBA::ULong i = 0; i < theSegments.length(); ++i )
7346     {
7347       SMESH::PolySegment& segIn = theSegments[ i ];
7348       TPythonDump() << "_segments.append( SMESH.PolySegment( "
7349                     << segIn.node1ID1 << ", "
7350                     << segIn.node1ID2 << ", "
7351                     << segIn.node2ID1 << ", "
7352                     << segIn.node2ID2 << ", "
7353                     << "smeshBuilder.MakeDirStruct( "
7354                     << segIn.vector.PS.x << ", "
7355                     << segIn.vector.PS.y << ", "
7356                     << segIn.vector.PS.z << ")))";
7357     }
7358     TPythonDump() << this << ".MakePolyLine( _segments, '" << theGroupName << "')";
7359   }
7360   meshDS->Modified();
7361   SMESH_CATCH( SMESH::throwCorbaException );
7362   return;
7363 }
7364
7365 //================================================================================
7366 /*!
7367  * \brief Create a slot of given width around given 1D elements lying on a triangle mesh.
7368  *        The slot is constructed by cutting faces by cylindrical surfaces made
7369  *        around each segment. Segments are expected to be created by MakePolyLine().
7370  * \return Edges located at the slot boundary
7371  */
7372 //================================================================================
7373
7374 SMESH::ListOfEdges* SMESH_MeshEditor_i::MakeSlot(SMESH::SMESH_GroupBase_ptr theSegments,
7375                                                  CORBA::Double              theWidth)
7376 {
7377   if ( CORBA::is_nil( theSegments ) ||
7378        theSegments->GetType() != SMESH::EDGE )
7379     THROW_SALOME_CORBA_EXCEPTION("No segments given", SALOME::BAD_PARAM );
7380   if ( myMesh->NbFaces() == 0 )
7381     THROW_SALOME_CORBA_EXCEPTION("No faces in the mesh", SALOME::BAD_PARAM );
7382
7383   SMESH::ListOfEdges_var resultEdges = new SMESH::ListOfEdges;
7384
7385   SMESH_TRY;
7386   initData(/*deleteSearchers=*/false);
7387
7388   SMESHDS_Mesh* meshDS = getMeshDS();
7389
7390   // get standalone face groups to be updated
7391   std::vector< SMDS_MeshGroup* > faceGroups;
7392   const std::set<SMESHDS_GroupBase*>& allGroups = meshDS->GetGroups();
7393   std::set<SMESHDS_GroupBase*>::const_iterator grIt = allGroups.begin();
7394   for ( ; grIt != allGroups.end(); ++grIt )
7395     if ( const SMESHDS_Group* gr = dynamic_cast< const SMESHDS_Group* >( *grIt ))
7396       if ( gr->GetType() == SMDSAbs_Face )
7397         faceGroups.push_back( & const_cast< SMESHDS_Group* >( gr )->SMDSGroup() );
7398
7399   std::vector< SMESH_MeshAlgos::Edge > edges =
7400     SMESH_MeshAlgos::MakeSlot( SMESH_Mesh_i::GetElements( theSegments, SMESH::EDGE ),
7401                                theWidth, meshDS, faceGroups );
7402
7403   resultEdges->length( edges.size() );
7404   for ( size_t i = 0; i < edges.size(); ++i )
7405   {
7406     resultEdges[ i ].node1  = edges[i]._node1->GetID();
7407     resultEdges[ i ].node2  = edges[i]._node2->GetID();
7408     resultEdges[ i ].medium = edges[i]._medium ? edges[i]._medium->GetID() : 0;
7409   }
7410
7411   meshDS->Modified();
7412   SMESH_CATCH( SMESH::throwCorbaException );
7413
7414   TSearchersDeleter::Delete(); // face searcher becomes invalid as some faces were removed
7415
7416   return resultEdges._retn();
7417 }