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