Salome HOME
5ae3c6a6e0cef61d72acfa2773dd632497943ff9
[modules/smesh.git] / src / SMESH_I / SMESH_MeshEditor_i.cxx
1 // Copyright (C) 2007-2020  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //  File   : SMESH_MeshEditor_i.cxx
23 //  Author : Nicolas REJNERI
24 //  Module : SMESH
25
26 #ifdef WIN32
27 #define NOMINMAX
28 #endif
29
30 // A macro used in SMESH_TryCatch.hxx,
31 // it re-raises a CORBA SALOME exception thrown by SMESH_MeshEditor_i and caught by SMESH_CATCH
32 #define SMY_OWN_CATCH \
33   catch ( SALOME::SALOME_Exception & e ) { throw e; }
34
35 #include "SMESH_MeshEditor_i.hxx"
36
37 #include "SMDS_EdgePosition.hxx"
38 #include "SMDS_ElemIterator.hxx"
39 #include "SMDS_FacePosition.hxx"
40 #include "SMDS_IteratorOnIterators.hxx"
41 #include "SMDS_LinearEdge.hxx"
42 #include "SMDS_Mesh0DElement.hxx"
43 #include "SMDS_MeshFace.hxx"
44 #include "SMDS_MeshVolume.hxx"
45 #include "SMDS_SetIterator.hxx"
46 #include "SMDS_VolumeTool.hxx"
47 #include "SMESHDS_Group.hxx"
48 #include "SMESHDS_GroupOnGeom.hxx"
49 #include "SMESH_ControlsDef.hxx"
50 #include "SMESH_Filter_i.hxx"
51 #include "SMESH_Gen_i.hxx"
52 #include "SMESH_Group.hxx"
53 #include "SMESH_Group_i.hxx"
54 #include "SMESH_MeshAlgos.hxx"
55 #include "SMESH_MeshPartDS.hxx"
56 #include "SMESH_MesherHelper.hxx"
57 #include "SMESH_PythonDump.hxx"
58 #include "SMESH_subMeshEventListener.hxx"
59 #include "SMESH_subMesh_i.hxx"
60
61 #include <utilities.h>
62 #include <Utils_ExceptHandlers.hxx>
63 #include <Utils_CorbaException.hxx>
64 #include <SALOMEDS_wrap.hxx>
65 #include <SALOME_GenericObj_i.hh>
66
67 #include <BRepAdaptor_Surface.hxx>
68 #include <BRep_Tool.hxx>
69 #include <TopExp_Explorer.hxx>
70 #include <TopoDS.hxx>
71 #include <TopoDS_Edge.hxx>
72 #include <TopoDS_Face.hxx>
73 #include <gp_Ax1.hxx>
74 #include <gp_Ax2.hxx>
75 #include <gp_Vec.hxx>
76
77 #include <Standard_Failure.hxx>
78 #include <Standard_ErrorHandler.hxx>
79
80 #include <sstream>
81 #include <limits>
82
83 #include "SMESH_TryCatch.hxx" // include after OCCT headers!
84
85 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
86
87 using namespace std;
88 using SMESH::TPythonDump;
89 using SMESH::TVar;
90
91 namespace MeshEditor_I {
92
93   //=============================================================================
94   /*!
95    * \brief Mesh to apply modifications for preview purposes
96    */
97   //=============================================================================
98
99   struct TPreviewMesh: public SMESH_Mesh
100   {
101     SMDSAbs_ElementType myPreviewType; // type to show
102     //!< Constructor
103     TPreviewMesh(SMDSAbs_ElementType previewElements = SMDSAbs_All) {
104       _isShapeToMesh = (_id = 0);
105       _myMeshDS  = new SMESHDS_Mesh( _id, true );
106       myPreviewType = previewElements;
107     }
108     //!< Copy a set of elements
109     void Copy(const TIDSortedElemSet & theElements,
110               TIDSortedElemSet&        theCopyElements,
111               SMDSAbs_ElementType      theSelectType = SMDSAbs_All,
112               SMDSAbs_ElementType      theAvoidType = SMDSAbs_All)
113     {
114       // loop on theIDsOfElements
115       TIDSortedElemSet::const_iterator eIt = theElements.begin();
116       for ( ; eIt != theElements.end(); ++eIt )
117       {
118         const SMDS_MeshElement* anElem = *eIt;
119         if ( !anElem ) continue;
120         SMDSAbs_ElementType type = anElem->GetType();
121         if ( type == theAvoidType ||
122              ( theSelectType != SMDSAbs_All && type != theSelectType ))
123           continue;
124         const SMDS_MeshElement* anElemCopy;
125         if ( type == SMDSAbs_Node)
126           anElemCopy = Copy( cast2Node(anElem) );
127         else
128           anElemCopy = Copy( anElem );
129         if ( anElemCopy )
130           theCopyElements.insert( theCopyElements.end(), anElemCopy );
131       }
132     }
133     //!< Copy an element
134     SMDS_MeshElement* Copy( const SMDS_MeshElement* anElem )
135     {
136       // copy element nodes
137       int anElemNbNodes = anElem->NbNodes();
138       vector< int > anElemNodesID( anElemNbNodes ) ;
139       SMDS_ElemIteratorPtr itElemNodes = anElem->nodesIterator();
140       for ( int i = 0; itElemNodes->more(); i++)
141       {
142         const SMDS_MeshNode* anElemNode = cast2Node( itElemNodes->next() );
143         Copy( anElemNode );
144         anElemNodesID[i] = anElemNode->GetID();
145       }
146
147       // creates a corresponding element on copied nodes
148       ::SMESH_MeshEditor::ElemFeatures elemType;
149       elemType.Init( anElem, /*basicOnly=*/false );
150       elemType.SetID( anElem->GetID() );
151       SMDS_MeshElement* anElemCopy =
152         ::SMESH_MeshEditor(this).AddElement( anElemNodesID, elemType );
153       return anElemCopy;
154     }
155     //!< Copy a node
156     SMDS_MeshNode* Copy( const SMDS_MeshNode* anElemNode )
157     {
158       return _myMeshDS->AddNodeWithID(anElemNode->X(), anElemNode->Y(), anElemNode->Z(),
159                                       anElemNode->GetID());
160     }
161     void RemoveAll()
162     {
163       GetMeshDS()->ClearMesh();
164     }
165     void Remove( SMDSAbs_ElementType type )
166     {
167       Remove( GetMeshDS()->elementsIterator( type ));
168     }
169     void Remove( SMDS_ElemIteratorPtr eIt )
170     {
171       while ( eIt->more() )
172         GetMeshDS()->RemoveFreeElement( eIt->next(), /*sm=*/0, /*fromGroups=*/false );
173     }
174   };// struct TPreviewMesh
175
176   static SMESH_NodeSearcher *    theNodeSearcher    = 0;
177   static SMESH_ElementSearcher * theElementSearcher = 0;
178
179   //=============================================================================
180   /*!
181    * \brief Deleter of theNodeSearcher and theElementSearcher at any compute event occurred
182    */
183   //=============================================================================
184
185   struct TSearchersDeleter : public SMESH_subMeshEventListener
186   {
187     SMESH_Mesh* myMesh;
188     string      myMeshPartIOR;
189     //!< Constructor
190     TSearchersDeleter(): SMESH_subMeshEventListener( false, // won't be deleted by submesh
191                                                      "SMESH_MeshEditor_i::TSearchersDeleter"),
192                          myMesh(0) {}
193     //!< Delete theNodeSearcher
194     static void Delete()
195     {
196       if ( theNodeSearcher )    delete theNodeSearcher;    theNodeSearcher    = 0;
197       if ( theElementSearcher ) delete theElementSearcher; theElementSearcher = 0;
198     }
199     typedef map < int, SMESH_subMesh * > TDependsOnMap;
200     //!< The meshod called by submesh: do my main job
201     void ProcessEvent(const int, const int eventType, SMESH_subMesh* sm,
202                       SMESH_subMeshEventListenerData*,const SMESH_Hypothesis*)
203     {
204       if ( eventType == SMESH_subMesh::COMPUTE_EVENT ) {
205         Delete();
206         Unset( sm->GetFather() );
207       }
208     }
209     //!< set self on all submeshes and delete theNodeSearcher if other mesh is set
210     void Set(SMESH_Mesh* mesh, const string& meshPartIOR = string())
211     {
212       if ( myMesh != mesh || myMeshPartIOR != meshPartIOR)
213       {
214         if ( myMesh ) {
215           Delete();
216           Unset( myMesh );
217         }
218         myMesh = mesh;
219         myMeshPartIOR = meshPartIOR;
220         SMESH_subMesh* sm = mesh->GetSubMesh( mesh->GetShapeToMesh() );
221         SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator( /*includeSelf=*/true );
222         while ( smIt->more() )
223         {
224           sm = smIt->next();
225           sm->SetEventListener( this, 0, sm );
226         }
227       }
228     }
229     //!<  delete self from all submeshes
230     void Unset(SMESH_Mesh* mesh)
231     {
232       if ( SMESH_subMesh* sm = mesh->GetSubMeshContaining(1) ) {
233         SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator( /*includeSelf=*/true );
234         while ( smIt->more() )
235           smIt->next()->DeleteEventListener( this );
236       }
237       myMesh = 0;
238     }
239
240   } theSearchersDeleter;
241
242   TCollection_AsciiString mirrorTypeName( SMESH::SMESH_MeshEditor::MirrorType theMirrorType )
243   {
244     TCollection_AsciiString typeStr;
245     switch ( theMirrorType ) {
246     case  SMESH::SMESH_MeshEditor::POINT:
247       typeStr = "SMESH.SMESH_MeshEditor.POINT";
248       break;
249     case  SMESH::SMESH_MeshEditor::AXIS:
250       typeStr = "SMESH.SMESH_MeshEditor.AXIS";
251       break;
252     default:
253       typeStr = "SMESH.SMESH_MeshEditor.PLANE";
254     }
255     return typeStr;
256   }
257   //================================================================================
258   /*!
259    * \brief function for conversion of long_array to TIDSortedElemSet
260    * \param IDs - array of IDs
261    * \param aMesh - mesh
262    * \param aMap - collection to fill
263    * \param aType - element type
264    */
265   //================================================================================
266
267   void arrayToSet(const SMESH::long_array & IDs,
268                   const SMESHDS_Mesh*       aMesh,
269                   TIDSortedElemSet&         aMap,
270                   const SMDSAbs_ElementType aType = SMDSAbs_All,
271                   SMDS_MeshElement::Filter* aFilter = NULL)
272   {
273     SMDS_MeshElement::NonNullFilter filter1;
274     SMDS_MeshElement::TypeFilter    filter2( aType );
275
276     if ( aFilter == NULL )
277       aFilter = ( aType == SMDSAbs_All ) ? (SMDS_MeshElement::Filter*) &filter1 : (SMDS_MeshElement::Filter*) &filter2;
278     
279     SMDS_MeshElement::Filter & filter = *aFilter;
280
281     if ( aType == SMDSAbs_Node )
282       for ( CORBA::ULong i = 0; i < IDs.length(); i++ ) {
283         const SMDS_MeshElement * elem = aMesh->FindNode( IDs[i] );
284         if ( filter( elem ))
285           aMap.insert( aMap.end(), elem );
286       }
287     else
288       for ( CORBA::ULong i = 0; i<IDs.length(); i++) {
289         const SMDS_MeshElement * elem = aMesh->FindElement( IDs[i] );
290         if ( filter( elem ))
291           aMap.insert( aMap.end(), elem );
292       }
293   }
294
295   //================================================================================
296   /*!
297    * \brief Retrieve nodes from SMESH_IDSource
298    */
299   //================================================================================
300
301   void idSourceToNodeSet(SMESH::SMESH_IDSource_ptr theObject,
302                          const SMESHDS_Mesh*       theMeshDS,
303                          TIDSortedNodeSet&         theNodeSet)
304
305   {
306     if ( CORBA::is_nil( theObject ) )
307       return;
308     if ( SMESH::DownCast<SMESH_Mesh_i*>( theObject ))
309     {
310       for ( SMDS_NodeIteratorPtr nIt = theMeshDS->nodesIterator(); nIt->more(); )
311         if ( const SMDS_MeshElement * elem = nIt->next() )
312           theNodeSet.insert( elem->begin_nodes(), elem->end_nodes());
313     }
314     else
315     {
316       SMESH::array_of_ElementType_var types = theObject->GetTypes();
317       SMESH::long_array_var     aElementsId = theObject->GetIDs();
318       if ( types->length() == 1 && types[0] == SMESH::NODE)
319       {
320         for ( CORBA::ULong i = 0; i < aElementsId->length(); i++ )
321           if ( const SMDS_MeshNode * n = theMeshDS->FindNode( aElementsId[i] ))
322             theNodeSet.insert( theNodeSet.end(), n);
323       }
324       else
325       {
326         for ( CORBA::ULong i = 0; i < aElementsId->length(); i++ )
327           if ( const SMDS_MeshElement * elem = theMeshDS->FindElement( aElementsId[i] ))
328             theNodeSet.insert( elem->begin_nodes(), elem->end_nodes());
329       }
330     }
331   }
332
333   //================================================================================
334   /*!
335    * \brief Returns elements connected to the given elements
336    */
337   //================================================================================
338
339   void getElementsAround(const TIDSortedElemSet& theElements,
340                          const SMESHDS_Mesh*     theMeshDS,
341                          TIDSortedElemSet&       theElementsAround)
342   {
343     if ( theElements.empty() ) return;
344
345     SMDSAbs_ElementType elemType    = (*theElements.begin())->GetType();
346     bool sameElemType = ( elemType == (*theElements.rbegin())->GetType() );
347     if ( sameElemType &&
348          theMeshDS->GetMeshInfo().NbElements( elemType ) == (int) theElements.size() )
349       return; // all the elements are in theElements
350
351     if ( !sameElemType )
352       elemType = SMDSAbs_All;
353
354     vector<bool> isNodeChecked( theMeshDS->NbNodes(), false );
355
356     TIDSortedElemSet::const_iterator elemIt = theElements.begin();
357     for ( ; elemIt != theElements.end(); ++elemIt )
358     {
359       const SMDS_MeshElement* e = *elemIt;
360       int i = e->NbCornerNodes();
361       while ( --i != -1 )
362       {
363         const SMDS_MeshNode* n = e->GetNode( i );
364         if ( !isNodeChecked[ n->GetID() ])
365         {
366           isNodeChecked[ n->GetID() ] = true;
367           SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator(elemType);
368           while ( invIt->more() )
369           {
370             const SMDS_MeshElement* elemAround = invIt->next();
371             if ( !theElements.count( elemAround ))
372               theElementsAround.insert( elemAround );
373           }
374         }
375       }
376     }
377   }
378
379   //================================================================================
380   /*!
381    * \brief Return a string used to detect change of mesh part on which theElementSearcher
382    * is going to be used
383    */
384   //================================================================================
385
386   string getPartIOR( SMESH::SMESH_IDSource_ptr theMeshPart, SMESH::ElementType type = SMESH::ALL )
387   {
388     if ( SMESH::DownCast<SMESH_Mesh_i*>( theMeshPart ))
389       return "";
390     string partIOR = SMESH_Gen_i::GetORB()->object_to_string( theMeshPart );
391     if ( SMESH_Group_i* group_i = SMESH::DownCast<SMESH_Group_i*>( theMeshPart ))
392       // take into account passible group modification
393       partIOR += SMESH_Comment( ((SMESHDS_Group*)group_i->GetGroupDS())->SMDSGroup().Tic() );
394     partIOR += SMESH_Comment( type );
395     return partIOR;
396   }
397
398 } // namespace MeshEditor_I
399
400 using namespace MeshEditor_I;
401
402 //=============================================================================
403 /*!
404  *
405  */
406 //=============================================================================
407
408 SMESH_MeshEditor_i::SMESH_MeshEditor_i(SMESH_Mesh_i* theMesh, bool isPreview):
409   myMesh_i( theMesh ),
410   myMesh( &theMesh->GetImpl() ),
411   myEditor( myMesh ),
412   myIsPreviewMode ( isPreview ),
413   myPreviewMesh( 0 ),
414   myPreviewEditor( 0 )
415 {
416 }
417
418 //================================================================================
419 /*!
420  * \brief Destructor
421  */
422 //================================================================================
423
424 SMESH_MeshEditor_i::~SMESH_MeshEditor_i()
425 {
426   PortableServer::POA_var poa = SMESH_Gen_i::GetPOA();
427   PortableServer::ObjectId_var anObjectId = poa->servant_to_id(this);
428   poa->deactivate_object(anObjectId.in());
429
430   //deleteAuxIDSources();
431   delete myPreviewMesh;   myPreviewMesh = 0;
432   delete myPreviewEditor; myPreviewEditor = 0;
433 }
434
435 //================================================================================
436 /*!
437  * \brief Returns the mesh
438  */
439 //================================================================================
440
441 SMESH::SMESH_Mesh_ptr SMESH_MeshEditor_i::GetMesh()
442 {
443   return myMesh_i->_this();
444 }
445
446 //================================================================================
447 /*!
448  * \brief Clear members
449  */
450 //================================================================================
451
452 void SMESH_MeshEditor_i::initData(bool deleteSearchers)
453 {
454   if ( myIsPreviewMode ) {
455     if ( myPreviewMesh ) myPreviewMesh->RemoveAll();
456   }
457   else {
458     if ( deleteSearchers )
459       TSearchersDeleter::Delete();
460   }
461   getEditor().GetError().reset();
462   getEditor().ClearLastCreated();
463 }
464
465 //================================================================================
466 /*!
467  * \brief Increment mesh modif time and optionally record that the performed
468  *        modification may influence further mesh re-compute.
469  *  \param [in] isReComputeSafe - true if the modification does not influence
470  *              further mesh re-compute
471  */
472 //================================================================================
473
474 void SMESH_MeshEditor_i::declareMeshModified( bool isReComputeSafe )
475 {
476   myMesh->GetMeshDS()->Modified();
477   if ( !isReComputeSafe )
478     myMesh->SetIsModified( true );
479 }
480
481 //================================================================================
482 /*!
483  * \brief Return either myEditor or myPreviewEditor depending on myIsPreviewMode.
484  *        WARNING: in preview mode call getPreviewMesh() before getEditor()!
485  */
486 //================================================================================
487
488 ::SMESH_MeshEditor& SMESH_MeshEditor_i::getEditor()
489 {
490   if ( myIsPreviewMode && !myPreviewEditor ) {
491     if ( !myPreviewMesh ) getPreviewMesh();
492     myPreviewEditor = new ::SMESH_MeshEditor( myPreviewMesh );
493   }
494   return myIsPreviewMode ? *myPreviewEditor : myEditor;
495 }
496
497 //================================================================================
498 /*!
499  * \brief Initialize and return myPreviewMesh
500  *  \param previewElements - type of elements to show in preview
501  *
502  *  WARNING: call it once per method!
503  */
504 //================================================================================
505
506 TPreviewMesh * SMESH_MeshEditor_i::getPreviewMesh(SMDSAbs_ElementType previewElements)
507 {
508   if ( !myPreviewMesh || myPreviewMesh->myPreviewType != previewElements )
509   {
510     delete myPreviewEditor;
511     myPreviewEditor = 0;
512     delete myPreviewMesh;
513     myPreviewMesh = new TPreviewMesh( previewElements );
514   }
515   myPreviewMesh->Clear();
516   return myPreviewMesh;
517 }
518
519 //================================================================================
520 /*!
521  * Return data of mesh edition preview
522  */
523 //================================================================================
524
525 SMESH::MeshPreviewStruct* SMESH_MeshEditor_i::GetPreviewData()
526   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   {
1394     SMESH_Comment txt("Invalid paramOnEdge. It must vary in range [ ");
1395     txt << f << ", " << l << " ]";
1396     THROW_SALOME_CORBA_EXCEPTION(txt.c_str(), SALOME::BAD_PARAM);
1397   }
1398   mesh->SetNodeOnEdge( node, EdgeID, paramOnEdge );
1399
1400   myMesh->SetIsModified( true );
1401
1402   SMESH_CATCH( SMESH::throwCorbaException );
1403 }
1404
1405 //=============================================================================
1406 /*!
1407  * \brief Store node position on a face
1408  * \param NodeID - node ID
1409  * \param FaceID - face ID available through GEOM_Object.GetSubShapeIndices()[0]
1410  * \param u - U parameter on face where the node is located
1411  * \param v - V parameter on face where the node is located
1412  * \retval boolean - false if any parameter is invalid
1413  */
1414 //=============================================================================
1415
1416 void SMESH_MeshEditor_i::SetNodeOnFace(CORBA::Long NodeID, CORBA::Long FaceID,
1417                                        CORBA::Double u, CORBA::Double v)
1418   throw (SALOME::SALOME_Exception)
1419 {
1420   SMESH_TRY;
1421   SMESHDS_Mesh * mesh = getMeshDS();
1422   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
1423   if ( !node )
1424     THROW_SALOME_CORBA_EXCEPTION("Invalid NodeID", SALOME::BAD_PARAM);
1425
1426   if ( mesh->MaxShapeIndex() < FaceID )
1427     THROW_SALOME_CORBA_EXCEPTION("Invalid FaceID", SALOME::BAD_PARAM);
1428
1429   TopoDS_Shape shape = mesh->IndexToShape( FaceID );
1430   if ( shape.ShapeType() != TopAbs_FACE )
1431     THROW_SALOME_CORBA_EXCEPTION("Invalid FaceID", SALOME::BAD_PARAM);
1432
1433   BRepAdaptor_Surface surf( TopoDS::Face( shape ));
1434   bool isOut = ( u < surf.FirstUParameter() ||
1435                  u > surf.LastUParameter()  ||
1436                  v < surf.FirstVParameter() ||
1437                  v > surf.LastVParameter() );
1438
1439   if ( isOut ) {
1440     SMESH_Comment txt("Invalid UV. U must vary in range [ ");
1441     txt << surf.FirstUParameter() << ", " << surf.LastUParameter() << " ], ";
1442     txt << "V must vary in range [ ";
1443     txt << surf.FirstVParameter() << ", " << surf.LastVParameter() << " ]";
1444     THROW_SALOME_CORBA_EXCEPTION(txt.c_str(), 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     if ( *theMeshName && mesh_var->NbFaces() == 0 )
4119     {
4120       // new mesh empty, remove it
4121       SALOMEDS::Study_var          study = SMESH_Gen_i::getStudyServant();
4122       SALOMEDS::StudyBuilder_var builder = study->NewBuilder();
4123       SALOMEDS::SObject_wrap      meshSO = SMESH_Gen_i::ObjectToSObject( mesh_var );
4124       builder->RemoveObjectWithChildren( meshSO );
4125       THROW_SALOME_CORBA_EXCEPTION("Offset failed", SALOME::INTERNAL_ERROR);
4126     }
4127     if ( !groupIds ) // nothing changed in the current mesh
4128       THROW_SALOME_CORBA_EXCEPTION("Offset failed", SALOME::INTERNAL_ERROR);
4129
4130     theGroups = theCopyGroups ? getGroups( groupIds.get() ) : new SMESH::ListOfGroups;
4131
4132     // result of Offset() is a tuple (mesh, groups)
4133     if ( mesh_var->_is_nil() ) pyDump << myMesh_i->_this() << ", ";
4134     else                       pyDump << mesh_var          << ", ";
4135     pyDump << theGroups << " = " << this << ".Offset( "
4136            << theObject << ", "
4137            << theValue << ", "
4138            << theCopyGroups << ", "
4139            << theCopyElements << ", "
4140            << "'" << theMeshName<< "')";
4141   }
4142
4143   return mesh_var._retn();
4144
4145   SMESH_CATCH( SMESH::throwCorbaException );
4146   return SMESH::SMESH_Mesh::_nil();
4147 }
4148
4149 //=======================================================================
4150 //function : findCoincidentNodes
4151 //purpose  :
4152 //=======================================================================
4153
4154 void SMESH_MeshEditor_i::
4155 findCoincidentNodes (TIDSortedNodeSet &             Nodes,
4156                      CORBA::Double                  Tolerance,
4157                      SMESH::array_of_long_array_out GroupsOfNodes,
4158                      CORBA::Boolean                 SeparateCornersAndMedium)
4159 {
4160   ::SMESH_MeshEditor::TListOfListOfNodes aListOfListOfNodes;
4161   getEditor().FindCoincidentNodes( Nodes, Tolerance, aListOfListOfNodes, SeparateCornersAndMedium );
4162
4163   GroupsOfNodes = new SMESH::array_of_long_array;
4164   GroupsOfNodes->length( aListOfListOfNodes.size() );
4165   ::SMESH_MeshEditor::TListOfListOfNodes::iterator llIt = aListOfListOfNodes.begin();
4166   for ( CORBA::Long i = 0; llIt != aListOfListOfNodes.end(); llIt++, i++ )
4167   {
4168     list< const SMDS_MeshNode* >& aListOfNodes = *llIt;
4169     list< const SMDS_MeshNode* >::iterator lIt = aListOfNodes.begin();;
4170     SMESH::long_array& aGroup = (*GroupsOfNodes)[ i ];
4171     aGroup.length( aListOfNodes.size() );
4172     for ( int j = 0; lIt != aListOfNodes.end(); lIt++, j++ )
4173       aGroup[ j ] = (*lIt)->GetID();
4174   }
4175 }
4176
4177 //=======================================================================
4178 //function : FindCoincidentNodes
4179 //purpose  :
4180 //=======================================================================
4181
4182 void SMESH_MeshEditor_i::
4183 FindCoincidentNodes (CORBA::Double                  Tolerance,
4184                      SMESH::array_of_long_array_out GroupsOfNodes,
4185                      CORBA::Boolean                 SeparateCornersAndMedium)
4186   throw (SALOME::SALOME_Exception)
4187 {
4188   SMESH_TRY;
4189   initData();
4190
4191   TIDSortedNodeSet nodes; // no input nodes
4192   findCoincidentNodes( nodes, Tolerance, GroupsOfNodes, SeparateCornersAndMedium );
4193
4194   TPythonDump() << "coincident_nodes = " << this << ".FindCoincidentNodes( "
4195                 << Tolerance << ", "
4196                 << SeparateCornersAndMedium << " )";
4197
4198   SMESH_CATCH( SMESH::throwCorbaException );
4199 }
4200
4201 //=======================================================================
4202 //function : FindCoincidentNodesOnPart
4203 //purpose  :
4204 //=======================================================================
4205
4206 void SMESH_MeshEditor_i::
4207 FindCoincidentNodesOnPart(SMESH::SMESH_IDSource_ptr      theObject,
4208                           CORBA::Double                  Tolerance,
4209                           SMESH::array_of_long_array_out GroupsOfNodes,
4210                           CORBA::Boolean                 SeparateCornersAndMedium)
4211   throw (SALOME::SALOME_Exception)
4212 {
4213   SMESH_TRY;
4214   initData();
4215
4216   TIDSortedNodeSet nodes;
4217   prepareIdSource( theObject );
4218   idSourceToNodeSet( theObject, getMeshDS(), nodes );
4219
4220   findCoincidentNodes( nodes, Tolerance, GroupsOfNodes, SeparateCornersAndMedium );
4221
4222   TPythonDump() << "coincident_nodes_on_part = " << this << ".FindCoincidentNodesOnPart( "
4223                 << theObject <<", "
4224                 << Tolerance << ", "
4225                 << SeparateCornersAndMedium << " )";
4226
4227   SMESH_CATCH( SMESH::throwCorbaException );
4228 }
4229
4230 //================================================================================
4231 /*!
4232  * \brief Finds nodes coincident with Tolerance within Objects excluding nodes within
4233  *        ExceptSubMeshOrGroups
4234  */
4235 //================================================================================
4236
4237 void SMESH_MeshEditor_i::
4238 FindCoincidentNodesOnPartBut(const SMESH::ListOfIDSources&  theObjects,
4239                              CORBA::Double                  theTolerance,
4240                              SMESH::array_of_long_array_out theGroupsOfNodes,
4241                              const SMESH::ListOfIDSources&  theExceptSubMeshOrGroups,
4242                              CORBA::Boolean                 theSeparateCornersAndMedium)
4243   throw (SALOME::SALOME_Exception)
4244 {
4245   SMESH_TRY;
4246   initData();
4247
4248   TIDSortedNodeSet nodes;
4249   for ( CORBA::ULong i = 0; i < theObjects.length(); ++i )
4250   {
4251     prepareIdSource( theObjects[i] );
4252     idSourceToNodeSet( theObjects[i], getMeshDS(), nodes );
4253   }
4254   for ( CORBA::ULong i = 0; i < theExceptSubMeshOrGroups.length(); ++i )
4255   {
4256     if ( SMDS_ElemIteratorPtr nodeIt = myMesh_i->GetElements( theExceptSubMeshOrGroups[i],
4257                                                               SMESH::NODE ))
4258       while ( nodeIt->more() )
4259         nodes.erase( cast2Node( nodeIt->next() ));
4260   }
4261   findCoincidentNodes( nodes, theTolerance, theGroupsOfNodes, theSeparateCornersAndMedium );
4262
4263   TPythonDump() << "coincident_nodes_on_part = " << this << ".FindCoincidentNodesOnPartBut( "
4264                 << theObjects <<", "
4265                 << theTolerance << ", "
4266                 << theExceptSubMeshOrGroups << ", "
4267                 << theSeparateCornersAndMedium << " )";
4268
4269   SMESH_CATCH( SMESH::throwCorbaException );
4270 }
4271
4272 //=======================================================================
4273 //function : MergeNodes
4274 //purpose  :
4275 //=======================================================================
4276
4277 void SMESH_MeshEditor_i::MergeNodes (const SMESH::array_of_long_array& GroupsOfNodes,
4278                                      const SMESH::ListOfIDSources&     NodesToKeep,
4279                                      CORBA::Boolean                    AvoidMakingHoles)
4280   throw (SALOME::SALOME_Exception)
4281 {
4282   SMESH_TRY;
4283   initData();
4284
4285   SMESHDS_Mesh* aMesh = getMeshDS();
4286
4287   TPythonDump aTPythonDump;
4288   aTPythonDump << this << ".MergeNodes([";
4289
4290   TIDSortedNodeSet setOfNodesToKeep;
4291   for ( CORBA::ULong i = 0; i < NodesToKeep.length(); ++i )
4292   {
4293     prepareIdSource( NodesToKeep[i] );
4294     if ( SMDS_ElemIteratorPtr nodeIt = myMesh_i->GetElements( NodesToKeep[i], SMESH::NODE ))
4295       while ( nodeIt->more() )
4296         setOfNodesToKeep.insert( setOfNodesToKeep.end(), cast2Node( nodeIt->next() ));
4297   }
4298
4299   ::SMESH_MeshEditor::TListOfListOfNodes aListOfListOfNodes;
4300   for ( CORBA::ULong i = 0; i < GroupsOfNodes.length(); i++ )
4301   {
4302     const SMESH::long_array& aNodeGroup = GroupsOfNodes[ i ];
4303     aListOfListOfNodes.push_back( list< const SMDS_MeshNode* >() );
4304     list< const SMDS_MeshNode* >& aListOfNodes = aListOfListOfNodes.back();
4305     for ( CORBA::ULong j = 0; j < aNodeGroup.length(); j++ )
4306     {
4307       CORBA::Long index = aNodeGroup[ j ];
4308       if ( const SMDS_MeshNode * node = aMesh->FindNode( index ))
4309       {
4310         if ( setOfNodesToKeep.count( node ))
4311           aListOfNodes.push_front( node );
4312         else
4313           aListOfNodes.push_back( node );
4314       }
4315     }
4316     if ( aListOfNodes.size() < 2 )
4317       aListOfListOfNodes.pop_back();
4318
4319     if ( i > 0 ) aTPythonDump << ", ";
4320     aTPythonDump << aNodeGroup;
4321   }
4322
4323   getEditor().MergeNodes( aListOfListOfNodes, AvoidMakingHoles );
4324
4325   aTPythonDump << "], " << NodesToKeep << ", " << AvoidMakingHoles << ")";
4326
4327   declareMeshModified( /*isReComputeSafe=*/false );
4328
4329   SMESH_CATCH( SMESH::throwCorbaException );
4330 }
4331
4332 //=======================================================================
4333 //function : FindEqualElements
4334 //purpose  :
4335 //=======================================================================
4336
4337 void SMESH_MeshEditor_i::FindEqualElements(const SMESH::ListOfIDSources&  theObjects,
4338                                            const SMESH::ListOfIDSources&  theExceptObjects,
4339                                            SMESH::array_of_long_array_out theGroupsOfElementsID)
4340   throw (SALOME::SALOME_Exception)
4341 {
4342   SMESH_TRY;
4343   initData();
4344
4345   theGroupsOfElementsID = new SMESH::array_of_long_array;
4346
4347   TIDSortedElemSet elems;
4348   bool hasOkObject = false;
4349   bool emptyIfIsMesh= ( theObjects.length() == 1 && theExceptObjects.length() == 0 );
4350
4351   for ( CORBA::ULong i = 0; i < theObjects.length(); ++i )
4352   {
4353     SMESH::SMESH_GroupBase_var group = SMESH::SMESH_GroupBase::_narrow( theObjects[i] );
4354     if ( !( !group->_is_nil() && group->GetType() == SMESH::NODE ))
4355       if ( idSourceToSet( theObjects[i], getMeshDS(), elems, SMDSAbs_All, emptyIfIsMesh ))
4356         hasOkObject = true;
4357   }
4358
4359   if ( hasOkObject )
4360   {
4361     for ( CORBA::ULong i = 0; i < theExceptObjects.length(); ++i )
4362     {
4363       if ( SMDS_ElemIteratorPtr elemIt = myMesh_i->GetElements( theExceptObjects[i], SMESH::ALL ))
4364         while ( elemIt->more() )
4365           elems.erase( elemIt->next() );
4366     }
4367
4368     ::SMESH_MeshEditor::TListOfListOfElementsID aListOfListOfElementsID;
4369     getEditor().FindEqualElements( elems, aListOfListOfElementsID );
4370
4371     theGroupsOfElementsID->length( aListOfListOfElementsID.size() );
4372
4373     ::SMESH_MeshEditor::TListOfListOfElementsID::iterator arraysIt =
4374         aListOfListOfElementsID.begin();
4375     for (CORBA::Long j = 0; arraysIt != aListOfListOfElementsID.end(); ++arraysIt, ++j)
4376     {
4377       SMESH::long_array& aGroup = (*theGroupsOfElementsID)[ j ];
4378       list<int>&      listOfIDs = *arraysIt;
4379       aGroup.length( listOfIDs.size() );
4380       list<int>::iterator idIt = listOfIDs.begin();
4381       for (int k = 0; idIt != listOfIDs.end(); ++idIt, ++k )
4382         aGroup[ k ] = *idIt;
4383     }
4384
4385     TPythonDump() << "equal_elements = " << this << ".FindEqualElements( "
4386                   << theObjects << ", "
4387                   << theExceptObjects << " )";
4388   }
4389
4390   SMESH_CATCH( SMESH::throwCorbaException );
4391 }
4392
4393 //=======================================================================
4394 //function : MergeElements
4395 //purpose  :
4396 //=======================================================================
4397
4398 void SMESH_MeshEditor_i::MergeElements(const SMESH::array_of_long_array& theGroupsOfElementsID,
4399                                        const SMESH::ListOfIDSources&     theElementsToKeep)
4400   throw (SALOME::SALOME_Exception)
4401 {
4402   SMESH_TRY;
4403   initData();
4404
4405   TPythonDump aTPythonDump;
4406   aTPythonDump << this << ".MergeElements( [";
4407
4408   NCollection_Map< int > idsToKeep;
4409   for ( CORBA::ULong i = 0; i < theElementsToKeep.length(); i++ )
4410   {
4411     if ( CORBA::is_nil( theElementsToKeep[i] ))
4412       continue;
4413     SMESH::array_of_ElementType_var elemTypes = theElementsToKeep[i]->GetTypes();
4414     if ( elemTypes->length() == 1 && elemTypes[0] == SMESH::NODE )
4415       continue;
4416     SMESH::long_array_var elementsId = theElementsToKeep[i]->GetIDs();
4417     for ( CORBA::ULong j = 0; j < elementsId->length(); ++j )
4418       idsToKeep.Add( elementsId[ j ]);
4419   }
4420
4421   ::SMESH_MeshEditor::TListOfListOfElementsID aListOfListOfElementsID;
4422
4423   for ( CORBA::ULong i = 0; i < theGroupsOfElementsID.length(); i++ )
4424   {
4425     const SMESH::long_array& anElemsIDGroup = theGroupsOfElementsID[ i ];
4426     aListOfListOfElementsID.push_back( list< int >() );
4427     list< int >& aListOfElemsID = aListOfListOfElementsID.back();
4428     for ( CORBA::ULong j = 0; j < anElemsIDGroup.length(); j++ )
4429     {
4430       CORBA::Long id = anElemsIDGroup[ j ];
4431       if ( idsToKeep.Contains( id )) aListOfElemsID.push_front( id );
4432       else                           aListOfElemsID.push_back( id );
4433     }
4434     if ( aListOfElemsID.size() < 2 )
4435       aListOfListOfElementsID.pop_back();
4436     if ( i > 0 ) aTPythonDump << ", ";
4437     aTPythonDump << anElemsIDGroup;
4438   }
4439
4440   getEditor().MergeElements(aListOfListOfElementsID);
4441
4442   declareMeshModified( /*isReComputeSafe=*/true );
4443
4444   aTPythonDump << "], " << theElementsToKeep << " )";
4445
4446   SMESH_CATCH( SMESH::throwCorbaException );
4447 }
4448
4449 //=======================================================================
4450 //function : MergeEqualElements
4451 //purpose  :
4452 //=======================================================================
4453
4454 void SMESH_MeshEditor_i::MergeEqualElements()
4455   throw (SALOME::SALOME_Exception)
4456 {
4457   SMESH_TRY;
4458   initData();
4459
4460   getEditor().MergeEqualElements();
4461
4462   declareMeshModified( /*isReComputeSafe=*/true );
4463
4464   TPythonDump() << this << ".MergeEqualElements()";
4465
4466   SMESH_CATCH( SMESH::throwCorbaException );
4467 }
4468
4469 //=============================================================================
4470 /*!
4471  * Move the node to a given point
4472  */
4473 //=============================================================================
4474
4475 CORBA::Boolean SMESH_MeshEditor_i::MoveNode(CORBA::Long   NodeID,
4476                                             CORBA::Double x,
4477                                             CORBA::Double y,
4478                                             CORBA::Double z)
4479   throw (SALOME::SALOME_Exception)
4480 {
4481   SMESH_TRY;
4482   initData(/*deleteSearchers=*/false);
4483
4484   const SMDS_MeshNode * node = getMeshDS()->FindNode( NodeID );
4485   if ( !node )
4486     return false;
4487
4488   if ( theNodeSearcher )
4489     theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
4490
4491   if ( myIsPreviewMode ) // make preview data
4492   {
4493     // in a preview mesh, make edges linked to a node
4494     TPreviewMesh& tmpMesh = *getPreviewMesh();
4495     TIDSortedElemSet linkedNodes;
4496     ::SMESH_MeshEditor::GetLinkedNodes( node, linkedNodes );
4497     TIDSortedElemSet::iterator nIt = linkedNodes.begin();
4498     SMDS_MeshNode *nodeCpy1 = tmpMesh.Copy(node);
4499     for ( ; nIt != linkedNodes.end(); ++nIt )
4500     {
4501       SMDS_MeshNode *nodeCpy2 = tmpMesh.Copy ( cast2Node( *nIt ));
4502       tmpMesh.GetMeshDS()->AddEdge(nodeCpy1, nodeCpy2);
4503     }
4504     // move copied node
4505     if ( nodeCpy1 )
4506       tmpMesh.GetMeshDS()->MoveNode(nodeCpy1, x, y, z);
4507     // fill preview data
4508   }
4509   else if ( theNodeSearcher ) // move node and update theNodeSearcher data accordingly
4510     theNodeSearcher->MoveNode(node, gp_Pnt( x,y,z ));
4511   else
4512     getMeshDS()->MoveNode(node, x, y, z);
4513
4514   if ( !myIsPreviewMode )
4515   {
4516     // Update Python script
4517     TPythonDump() << "isDone = " << this << ".MoveNode( "
4518                   << NodeID << ", " << TVar(x) << ", " << TVar(y) << ", " << TVar(z) << " )";
4519     declareMeshModified( /*isReComputeSafe=*/false );
4520   }
4521
4522   SMESH_CATCH( SMESH::throwCorbaException );
4523
4524   return true;
4525 }
4526
4527 //================================================================================
4528 /*!
4529  * \brief Return ID of node closest to a given point
4530  */
4531 //================================================================================
4532
4533 CORBA::Long SMESH_MeshEditor_i::FindNodeClosestTo(CORBA::Double x,
4534                                                   CORBA::Double y,
4535                                                   CORBA::Double z)
4536   throw (SALOME::SALOME_Exception)
4537 {
4538   SMESH_TRY;
4539   theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
4540
4541   if ( !theNodeSearcher ) {
4542     theNodeSearcher = SMESH_MeshAlgos::GetNodeSearcher( *getMeshDS() );
4543   }
4544   gp_Pnt p( x,y,z );
4545   if ( const SMDS_MeshNode* node = theNodeSearcher->FindClosestTo( p ))
4546     return node->GetID();
4547
4548   SMESH_CATCH( SMESH::throwCorbaException );
4549   return 0;
4550 }
4551
4552 //================================================================================
4553 /*!
4554  * \brief If the given ID is a valid node ID (nodeID > 0), just move this node, else
4555  * move the node closest to the point to point's location and return ID of the node
4556  */
4557 //================================================================================
4558
4559 CORBA::Long SMESH_MeshEditor_i::MoveClosestNodeToPoint(CORBA::Double x,
4560                                                        CORBA::Double y,
4561                                                        CORBA::Double z,
4562                                                        CORBA::Long   theNodeID)
4563   throw (SALOME::SALOME_Exception)
4564 {
4565   SMESH_TRY;
4566   // We keep theNodeSearcher until any mesh modification:
4567   // 1) initData() deletes theNodeSearcher at any edition,
4568   // 2) TSearchersDeleter - at any mesh compute event and mesh change
4569
4570   initData(/*deleteSearchers=*/false);
4571
4572   theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
4573
4574   int nodeID = theNodeID;
4575   const SMDS_MeshNode* node = getMeshDS()->FindNode( nodeID );
4576   if ( !node ) // preview moving node
4577   {
4578     if ( !theNodeSearcher ) {
4579       theNodeSearcher = SMESH_MeshAlgos::GetNodeSearcher( *getMeshDS() );
4580     }
4581     gp_Pnt p( x,y,z );
4582     node = theNodeSearcher->FindClosestTo( p );
4583   }
4584   if ( node ) {
4585     nodeID = node->GetID();
4586     if ( myIsPreviewMode ) // make preview data
4587     {
4588       // in a preview mesh, make edges linked to a node
4589       TPreviewMesh tmpMesh = *getPreviewMesh();
4590       TIDSortedElemSet linkedNodes;
4591       ::SMESH_MeshEditor::GetLinkedNodes( node, linkedNodes );
4592       TIDSortedElemSet::iterator nIt = linkedNodes.begin();
4593       for ( ; nIt != linkedNodes.end(); ++nIt )
4594       {
4595         SMDS_LinearEdge edge( node, cast2Node( *nIt ));
4596         tmpMesh.Copy( &edge );
4597       }
4598       // move copied node
4599       node = tmpMesh.GetMeshDS()->FindNode( nodeID );
4600       if ( node )
4601         tmpMesh.GetMeshDS()->MoveNode(node, x, y, z);
4602       // fill preview data
4603     }
4604     else if ( theNodeSearcher ) // move node and update theNodeSearcher data accordingly
4605     {
4606       theNodeSearcher->MoveNode(node, gp_Pnt( x,y,z ));
4607     }
4608     else
4609     {
4610       getMeshDS()->MoveNode(node, x, y, z);
4611     }
4612   }
4613
4614   if ( !myIsPreviewMode )
4615   {
4616     TPythonDump() << "nodeID = " << this
4617                   << ".MoveClosestNodeToPoint( "<< x << ", " << y << ", " << z
4618                   << ", " << nodeID << " )";
4619
4620     declareMeshModified( /*isReComputeSafe=*/false );
4621   }
4622
4623   return nodeID;
4624
4625   SMESH_CATCH( SMESH::throwCorbaException );
4626   return 0;
4627 }
4628
4629 //=======================================================================
4630 /*!
4631  * Return elements of given type where the given point is IN or ON.
4632  *
4633  * 'ALL' type means elements of any type excluding nodes
4634  */
4635 //=======================================================================
4636
4637 SMESH::long_array* SMESH_MeshEditor_i::FindElementsByPoint(CORBA::Double      x,
4638                                                            CORBA::Double      y,
4639                                                            CORBA::Double      z,
4640                                                            SMESH::ElementType type)
4641   throw (SALOME::SALOME_Exception)
4642 {
4643   SMESH_TRY;
4644   SMESH::long_array_var res = new SMESH::long_array;
4645   vector< const SMDS_MeshElement* > foundElems;
4646
4647   theSearchersDeleter.Set( myMesh );
4648   if ( !theElementSearcher ) {
4649     theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() );
4650   }
4651   theElementSearcher->FindElementsByPoint( gp_Pnt( x,y,z ),
4652                                            SMDSAbs_ElementType( type ),
4653                                            foundElems);
4654   res->length( foundElems.size() );
4655   for ( size_t i = 0; i < foundElems.size(); ++i )
4656     res[i] = foundElems[i]->GetID();
4657
4658   return res._retn();
4659
4660   SMESH_CATCH( SMESH::throwCorbaException );
4661   return 0;
4662 }
4663
4664 //=======================================================================
4665 //function : FindAmongElementsByPoint
4666 //purpose  : Searching among the given elements, return elements of given type 
4667 //           where the given point is IN or ON.
4668 //           'ALL' type means elements of any type excluding nodes
4669 //=======================================================================
4670
4671 SMESH::long_array*
4672 SMESH_MeshEditor_i::FindAmongElementsByPoint(SMESH::SMESH_IDSource_ptr elementIDs,
4673                                              CORBA::Double             x,
4674                                              CORBA::Double             y,
4675                                              CORBA::Double             z,
4676                                              SMESH::ElementType        type)
4677   throw (SALOME::SALOME_Exception)
4678 {
4679   SMESH_TRY;
4680   SMESH::long_array_var res = new SMESH::long_array;
4681
4682   prepareIdSource( elementIDs );
4683   if ( type != SMESH::NODE )
4684   {
4685     SMESH::array_of_ElementType_var types = elementIDs->GetTypes();
4686     if ( types->length() == 1 && // a part contains only nodes or 0D elements
4687          ( types[0] == SMESH::NODE || types[0] == SMESH::ELEM0D || types[0] == SMESH::BALL) &&
4688          type != types[0] ) // but search of elements of dim > 0
4689       return res._retn();
4690   }
4691
4692   SMESH::SMESH_Mesh_var mesh = elementIDs->GetMesh();
4693   SMESH_Mesh_i*       mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
4694   if ( mesh_i != myMesh_i )
4695   {
4696     SMESH::SMESH_MeshEditor_var editor=
4697       myIsPreviewMode ? mesh_i->GetMeshEditPreviewer() : mesh_i->GetMeshEditor();
4698     return editor->FindAmongElementsByPoint( elementIDs, x,y,z, type );
4699   }
4700
4701   if ( SMESH::DownCast<SMESH_Mesh_i*>( elementIDs )) // elementIDs is the whole mesh 
4702     return FindElementsByPoint( x,y,z, type );
4703
4704   TIDSortedElemSet elements; // elems should live until FindElementsByPoint() finishes
4705
4706   theSearchersDeleter.Set( myMesh, getPartIOR( elementIDs, type ));
4707   if ( !theElementSearcher )
4708   {
4709     // create a searcher from elementIDs
4710     SMDS_ElemIteratorPtr elemIt;
4711     if ( ! SMESH::DownCast<SMESH_Mesh_i*>( elementIDs ))
4712     {
4713       //prepareIdSource( elementIDs );
4714       elemIt = myMesh_i->GetElements( elementIDs, type );
4715       if ( !elemIt )
4716         return res._retn();
4717     }
4718     theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), elemIt );
4719   }
4720
4721   vector< const SMDS_MeshElement* > foundElems;
4722
4723   theElementSearcher->FindElementsByPoint( gp_Pnt( x,y,z ),
4724                                            SMDSAbs_ElementType( type ),
4725                                            foundElems);
4726   res->length( foundElems.size() );
4727   for ( size_t i = 0; i < foundElems.size(); ++i )
4728     res[i] = foundElems[i]->GetID();
4729
4730   return res._retn();
4731
4732   SMESH_CATCH( SMESH::throwCorbaException );
4733   return 0;
4734 }
4735
4736 //=======================================================================
4737 //function : ProjectPoint
4738 //purpose  : Project a point to a mesh object.
4739 //           Return ID of an element of given type where the given point is projected
4740 //           and coordinates of the projection point.
4741 //           In the case if nothing found, return -1 and []
4742 //=======================================================================
4743
4744 CORBA::Long SMESH_MeshEditor_i::ProjectPoint(CORBA::Double             x,
4745                                              CORBA::Double             y,
4746                                              CORBA::Double             z,
4747                                              SMESH::ElementType        type,
4748                                              SMESH::SMESH_IDSource_ptr meshObject,
4749                                              SMESH::double_array_out   projecton)
4750   throw (SALOME::SALOME_Exception)
4751 {
4752   if ( CORBA::is_nil( meshObject ))
4753     THROW_SALOME_CORBA_EXCEPTION("NULL meshObject", SALOME::BAD_PARAM);
4754
4755   SMESH_TRY;
4756
4757   SMESH::SMESH_Mesh_var mesh = meshObject->GetMesh();
4758   SMESH_Mesh_i*       mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
4759   if ( mesh_i != myMesh_i )
4760   {
4761     SMESH::SMESH_MeshEditor_var editor=
4762       myIsPreviewMode ? mesh_i->GetMeshEditPreviewer() : mesh_i->GetMeshEditor();
4763     return editor->ProjectPoint( x,y,z, type, meshObject, projecton );
4764   }
4765
4766
4767   theSearchersDeleter.Set( myMesh, getPartIOR( meshObject, type ));
4768   if ( !theElementSearcher )
4769   {
4770     // create a searcher from meshObject
4771
4772     SMDS_ElemIteratorPtr elemIt;
4773     if ( ! SMESH::DownCast<SMESH_Mesh_i*>( meshObject ))
4774     {
4775       prepareIdSource( meshObject );
4776       elemIt = myMesh_i->GetElements( meshObject, type );
4777       if ( !elemIt )
4778         return -1;
4779     }
4780     theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), elemIt );
4781   }
4782
4783   const SMDS_MeshElement* elem = 0;
4784   gp_XYZ pProj = theElementSearcher->Project( gp_Pnt( x,y,z ),
4785                                               SMDSAbs_ElementType( type ),
4786                                               &elem );
4787
4788   projecton = new SMESH::double_array();
4789   if ( elem && !elem->IsNull() )
4790   {
4791     projecton->length( 3 );
4792     projecton[0] = pProj.X();
4793     projecton[1] = pProj.Y();
4794     projecton[2] = pProj.Z();
4795     return elem->GetID();
4796   }
4797
4798   SMESH_CATCH( SMESH::throwCorbaException );
4799   return -1;
4800 }
4801
4802 //=======================================================================
4803 //function : GetPointState
4804 //purpose  : Return point state in a closed 2D mesh in terms of TopAbs_State enumeration.
4805 //           TopAbs_UNKNOWN state means that either mesh is wrong or the analysis fails.
4806 //=======================================================================
4807
4808 CORBA::Short SMESH_MeshEditor_i::GetPointState(CORBA::Double x,
4809                                                CORBA::Double y,
4810                                                CORBA::Double z)
4811   throw (SALOME::SALOME_Exception)
4812 {
4813   SMESH_TRY;
4814   theSearchersDeleter.Set( myMesh );
4815   if ( !theElementSearcher ) {
4816     theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() );
4817   }
4818   return CORBA::Short( theElementSearcher->GetPointState( gp_Pnt( x,y,z )));
4819
4820   SMESH_CATCH( SMESH::throwCorbaException );
4821   return 0;
4822 }
4823
4824 //=======================================================================
4825 //function : IsManifold
4826 //purpose  : Check if a 2D mesh is manifold
4827 //=======================================================================
4828
4829 CORBA::Boolean SMESH_MeshEditor_i::IsManifold()
4830   throw (SALOME::SALOME_Exception)
4831 {
4832   bool isManifold = true;
4833
4834   SMESH_TRY;
4835   SMESH_MeshAlgos::TFreeBorderVec foundFreeBordes;
4836   SMESH_MeshAlgos::FindFreeBorders( *getMeshDS(),
4837                                     foundFreeBordes,
4838                                     /*closedOnly=*/true,
4839                                     &isManifold );
4840   SMESH_CATCH( SMESH::throwCorbaException );
4841
4842   return isManifold;
4843 }
4844
4845 //=======================================================================
4846 //function : IsCoherentOrientation2D
4847 //purpose  : Check if orientation of 2D elements is coherent
4848 //=======================================================================
4849
4850 CORBA::Boolean SMESH_MeshEditor_i::IsCoherentOrientation2D()
4851   throw (SALOME::SALOME_Exception)
4852 {
4853   bool isGoodOri = true;
4854
4855   SMESH_TRY;
4856   SMESH_MeshAlgos::TFreeBorderVec foundFreeBordes;
4857   SMESH_MeshAlgos::FindFreeBorders( *getMeshDS(),
4858                                     foundFreeBordes,
4859                                     /*closedOnly=*/true,
4860                                     /*isManifold=*/0,
4861                                     &isGoodOri);
4862   SMESH_CATCH( SMESH::throwCorbaException );
4863
4864   return isGoodOri;
4865 }
4866
4867 //=======================================================================
4868 //function : Get1DBranches
4869 //purpose  : Partition given 1D elements into groups of contiguous edges.
4870 //           A node where number of meeting edges != 2 is a group end.
4871 //           An optional startNode is used to orient groups it belongs to.
4872 //return   : a list of edge groups and a list of corresponding node groups.
4873 //           If a group is closed, the first and last nodes of the group are same.
4874 //=======================================================================
4875
4876 SMESH::array_of_long_array*
4877 SMESH_MeshEditor_i::Get1DBranches( SMESH::SMESH_IDSource_ptr      theEdges,
4878                                    CORBA::Long                    theStartNode,
4879                                    SMESH::array_of_long_array_out theNodeGroups )
4880   throw (SALOME::SALOME_Exception)
4881 {
4882   if ( CORBA::is_nil( theEdges ))
4883     THROW_SALOME_CORBA_EXCEPTION("Get1DBranches(): NULL group given", SALOME::BAD_PARAM);
4884
4885   SMESH::array_of_long_array_var edgeGroupArray = new SMESH::array_of_long_array;
4886   theNodeGroups = new SMESH::array_of_long_array;
4887
4888   SMESH_TRY;
4889
4890   prepareIdSource( theEdges );
4891
4892   SMESH_MeshAlgos::TElemGroupVector edgeBranches;
4893   SMESH_MeshAlgos::TNodeGroupVector nodeBranches;
4894   SMESH_MeshAlgos::Get1DBranches( SMESH_Mesh_i::GetElements( theEdges, SMESH::EDGE ),
4895                                   edgeBranches,
4896                                   nodeBranches,
4897                                   getMeshDS()->FindNode( theStartNode ));
4898
4899   edgeGroupArray->length( edgeBranches.size() );
4900   for ( size_t iG = 0; iG < edgeBranches.size(); ++iG )
4901   {
4902     edgeGroupArray[ iG ].length( edgeBranches[ iG ].size() );
4903     for ( size_t i = 0; i < edgeBranches[ iG ].size(); ++i )
4904       edgeGroupArray[ iG ][ i ] = edgeBranches[ iG ][ i ]->GetID();
4905   }
4906
4907   theNodeGroups->length( nodeBranches.size() );
4908   for ( size_t iG = 0; iG < nodeBranches.size(); ++iG )
4909   {
4910     theNodeGroups[ iG ].length( nodeBranches[ iG ].size() );
4911     for ( size_t i = 0; i < nodeBranches[ iG ].size(); ++i )
4912       theNodeGroups[ iG ][ i ] = nodeBranches[ iG ][ i ]->GetID();
4913   }
4914
4915   SMESH_CATCH( SMESH::throwCorbaException );
4916
4917   return edgeGroupArray._retn();
4918 }
4919
4920 //=======================================================================
4921 //function : FindSharpEdges
4922 //purpose  : Return sharp edges of faces and non-manifold ones. Optionally add existing edges.
4923 //=======================================================================
4924
4925 SMESH::ListOfEdges* SMESH_MeshEditor_i::FindSharpEdges(CORBA::Double  theAngle,
4926                                                        CORBA::Boolean theAddExisting)
4927   throw (SALOME::SALOME_Exception)
4928 {
4929   SMESH::ListOfEdges_var resultEdges = new SMESH::ListOfEdges;
4930   SMESH_TRY;
4931
4932   initData();
4933
4934   std::vector< SMESH_MeshAlgos::Edge > edges =
4935     SMESH_MeshAlgos::FindSharpEdges( getMeshDS(), theAngle, theAddExisting );
4936
4937   if ( myIsPreviewMode ) // fill a preview mesh with edges
4938   {
4939     TPreviewMesh* mesh = getPreviewMesh( SMDSAbs_Edge );
4940     SMDS_Mesh*  meshDS = mesh->GetMeshDS();
4941     for ( size_t i = 0; i < edges.size(); ++i )
4942     {
4943       SMESH_NodeXYZ xyz1( edges[i]._node1), xyz2( edges[i]._node2);
4944       SMDS_MeshNode* n1 = meshDS->AddNode( xyz1.X(), xyz1.Y(), xyz1.Z() );
4945       SMDS_MeshNode* n2 = meshDS->AddNode( xyz2.X(), xyz2.Y(), xyz2.Z() );
4946       if ( edges[i]._medium )
4947       {
4948         xyz1.Set( edges[i]._medium );
4949         SMDS_MeshNode* nm = meshDS->AddNode( xyz1.X(), xyz1.Y(), xyz1.Z() );
4950         mesh->GetMeshDS()->AddEdge( n1, n2, nm );
4951       }
4952       else
4953       {
4954         mesh->GetMeshDS()->AddEdge( n1, n2 );
4955       }
4956     }
4957   }
4958   else
4959   {
4960     resultEdges->length( edges.size() );
4961     for ( size_t i = 0; i < edges.size(); ++i )
4962     {
4963       resultEdges[ i ].node1  = edges[i]._node1->GetID();
4964       resultEdges[ i ].node2  = edges[i]._node2->GetID();
4965       resultEdges[ i ].medium = edges[i]._medium ? edges[i]._medium->GetID() : 0;
4966     }
4967   }
4968   SMESH_CATCH( SMESH::throwCorbaException );
4969   return resultEdges._retn();
4970 }
4971
4972 //=======================================================================
4973 //function : FindFreeBorders
4974 //purpose  : Returns all or only closed FreeBorder's.
4975 //=======================================================================
4976
4977 SMESH::ListOfFreeBorders* SMESH_MeshEditor_i::FindFreeBorders(CORBA::Boolean closedOnly)
4978   throw (SALOME::SALOME_Exception)
4979 {
4980   SMESH::ListOfFreeBorders_var resBorders = new SMESH::ListOfFreeBorders;
4981   SMESH_TRY;
4982
4983   SMESH_MeshAlgos::TFreeBorderVec foundFreeBordes;
4984   SMESH_MeshAlgos::FindFreeBorders( *getMeshDS(), foundFreeBordes, closedOnly );
4985
4986   resBorders->length( foundFreeBordes.size() );
4987   for ( size_t i = 0; i < foundFreeBordes.size(); ++i )
4988   {
4989     const SMESH_MeshAlgos::TFreeBorder& bordNodes = foundFreeBordes[i];
4990     SMESH::FreeBorder&                    bordOut = resBorders[i];
4991     bordOut.nodeIDs.length( bordNodes.size() );
4992     for ( size_t iN = 0; iN < bordNodes.size(); ++iN )
4993       bordOut.nodeIDs[ iN ] = bordNodes[ iN ]->GetID();
4994   }
4995
4996   SMESH_CATCH( SMESH::throwCorbaException );
4997
4998   return resBorders._retn();
4999 }
5000
5001 //=======================================================================
5002 //function : FillHole
5003 //purpose  : Fill with 2D elements a hole defined by a FreeBorder.
5004 //=======================================================================
5005
5006 SMESH::SMESH_Group_ptr 
5007 SMESH_MeshEditor_i::FillHole(const SMESH::FreeBorder& theHole,
5008                              const char*              theGroupName)
5009   throw (SALOME::SALOME_Exception)
5010 {
5011   initData();
5012
5013   if ( theHole.nodeIDs.length() < 4 )
5014     THROW_SALOME_CORBA_EXCEPTION("A hole should be bound by at least 3 nodes", SALOME::BAD_PARAM);
5015   if ( theHole.nodeIDs[0] != theHole.nodeIDs[ theHole.nodeIDs.length()-1 ] )
5016     THROW_SALOME_CORBA_EXCEPTION("Not closed hole boundary. "
5017                                  "First and last nodes must be same", SALOME::BAD_PARAM);
5018
5019   SMESH_MeshAlgos::TFreeBorder bordNodes;
5020   bordNodes.resize( theHole.nodeIDs.length() );
5021   for ( size_t iN = 0; iN < theHole.nodeIDs.length(); ++iN )
5022   {
5023     bordNodes[ iN ] = getMeshDS()->FindNode( theHole.nodeIDs[ iN ]);
5024     if ( !bordNodes[ iN ] )
5025       THROW_SALOME_CORBA_EXCEPTION(SMESH_Comment("Node #") << theHole.nodeIDs[ iN ]
5026                                    << " does not exist", SALOME::BAD_PARAM);
5027   }
5028
5029   SMESH_TRY;
5030
5031   // prepare a preview mesh
5032   MeshEditor_I::TPreviewMesh* previewMesh = 0;
5033   SMDS_Mesh* meshDS = getMeshDS();
5034   if ( myIsPreviewMode )
5035   {
5036     // copy faces sharing nodes of theHole
5037     TIDSortedElemSet holeFaces;
5038     previewMesh = getPreviewMesh( SMDSAbs_Face );
5039     for ( size_t i = 0; i < bordNodes.size(); ++i )
5040     {
5041       SMDS_ElemIteratorPtr fIt = bordNodes[i]->GetInverseElementIterator( SMDSAbs_Face );
5042       while ( fIt->more() )
5043       {
5044         const SMDS_MeshElement* face = fIt->next();
5045         if ( holeFaces.insert( face ).second )
5046           previewMesh->Copy( face );
5047       }
5048       bordNodes[i] = previewMesh->GetMeshDS()->FindNode( bordNodes[i]->GetID() );
5049       ASSERT( bordNodes[i] );
5050     }
5051     meshDS = previewMesh->GetMeshDS();
5052   }
5053
5054   // fill the hole
5055   std::vector<const SMDS_MeshElement*> newFaces;
5056   SMESH_MeshAlgos::FillHole( bordNodes, *meshDS, newFaces );
5057
5058   if ( myIsPreviewMode )
5059   {
5060     // show new faces
5061     previewMesh->Clear();
5062     for ( size_t i = 0; i < newFaces.size(); ++i )
5063       previewMesh->Copy( newFaces[i] );
5064   }
5065   else
5066   {
5067     // return new faces via a group
5068     SMESH::SMESH_Group_var group;
5069     if ( theGroupName && theGroupName[0] && !newFaces.empty() )
5070     {
5071       SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
5072       for ( CORBA::ULong i = 0; i < groups->length(); ++i )
5073       {
5074         SMESH::SMESH_GroupBase_var g = groups[ i ];
5075         if ( g->GetType() != SMESH::FACE ) continue;
5076         SMESH::SMESH_Group_var standalone = SMESH::SMESH_Group::_narrow( g );
5077         if ( standalone->_is_nil() ) continue;
5078         CORBA::String_var name = g->GetName();
5079         if ( strcmp( theGroupName, name.in() ) == 0 )
5080         {
5081           group = standalone;
5082           break;
5083         }
5084       }
5085       if ( group->_is_nil() )
5086         group = myMesh_i->CreateGroup( SMESH::FACE, theGroupName );
5087
5088       if ( !group->_is_nil() )
5089       {
5090         SMESH_GroupBase_i * grpI = SMESH::DownCast< SMESH_GroupBase_i* >( group );
5091         SMESHDS_Group*     grpDS = static_cast< SMESHDS_Group* >( grpI->GetGroupDS() );
5092         for ( size_t i = 0; i < newFaces.size(); ++i )
5093           grpDS->Add( newFaces[ i ]);
5094       }
5095     }
5096
5097     // fill LastCreated
5098     getEditor().ClearLastCreated();
5099     SMESH_SequenceOfElemPtr& aSeq =
5100       const_cast<SMESH_SequenceOfElemPtr&>( getEditor().GetLastCreatedElems() );
5101     aSeq.swap( newFaces );
5102
5103     TPythonDump pyDump;
5104     if ( group->_is_nil() ) pyDump << "_group = ";
5105     else                    pyDump << group << " = ";
5106     pyDump << this << ".FillHole( SMESH.FreeBorder(" << theHole.nodeIDs << " ))";
5107
5108     return group._retn();
5109   }
5110
5111   SMESH_CATCH( SMESH::throwCorbaException );
5112
5113   return SMESH::SMESH_Group::_nil();
5114 }
5115
5116 //=======================================================================
5117 //function : convError
5118 //purpose  :
5119 //=======================================================================
5120
5121 #define RETCASE(enm) case ::SMESH_MeshEditor::enm: return SMESH::SMESH_MeshEditor::enm;
5122
5123 static SMESH::SMESH_MeshEditor::Sew_Error convError( const::SMESH_MeshEditor::Sew_Error e )
5124 {
5125   switch ( e ) {
5126     RETCASE( SEW_OK );
5127     RETCASE( SEW_BORDER1_NOT_FOUND );
5128     RETCASE( SEW_BORDER2_NOT_FOUND );
5129     RETCASE( SEW_BOTH_BORDERS_NOT_FOUND );
5130     RETCASE( SEW_BAD_SIDE_NODES );
5131     RETCASE( SEW_VOLUMES_TO_SPLIT );
5132     RETCASE( SEW_DIFF_NB_OF_ELEMENTS );
5133     RETCASE( SEW_TOPO_DIFF_SETS_OF_ELEMENTS );
5134     RETCASE( SEW_BAD_SIDE1_NODES );
5135     RETCASE( SEW_BAD_SIDE2_NODES );
5136     RETCASE( SEW_INTERNAL_ERROR );
5137   }
5138   return SMESH::SMESH_MeshEditor::SEW_OK;
5139 }
5140
5141 //=======================================================================
5142 /*!
5143  * Returns groups of FreeBorder's coincident within the given tolerance.
5144  * If the tolerance <= 0.0 then one tenth of an average size of elements adjacent
5145  * to free borders being compared is used.
5146  */
5147 //=======================================================================
5148
5149 SMESH::CoincidentFreeBorders*
5150 SMESH_MeshEditor_i::FindCoincidentFreeBorders(CORBA::Double tolerance)
5151 {
5152   SMESH::CoincidentFreeBorders_var aCFB = new SMESH::CoincidentFreeBorders;
5153
5154   SMESH_TRY;
5155
5156   SMESH_MeshAlgos::CoincidentFreeBorders cfb;
5157   SMESH_MeshAlgos::FindCoincidentFreeBorders( *getMeshDS(), tolerance, cfb );
5158
5159   // copy free borders
5160   aCFB->borders.length( cfb._borders.size() );
5161   for ( size_t i = 0; i < cfb._borders.size(); ++i )
5162   {
5163     SMESH_MeshAlgos::TFreeBorder& nodes = cfb._borders[i];
5164     SMESH::FreeBorder&             aBRD = aCFB->borders[i];
5165     aBRD.nodeIDs.length( nodes.size() );
5166     for ( size_t iN = 0; iN < nodes.size(); ++iN )
5167       aBRD.nodeIDs[ iN ] = nodes[ iN ]->GetID();
5168   }
5169
5170   // copy coincident parts
5171   aCFB->coincidentGroups.length( cfb._coincidentGroups.size() );
5172   for ( size_t i = 0; i < cfb._coincidentGroups.size(); ++i )
5173   {
5174     SMESH_MeshAlgos::TCoincidentGroup& grp = cfb._coincidentGroups[i];
5175     SMESH::FreeBordersGroup&          aGRP = aCFB->coincidentGroups[i];
5176     aGRP.length( grp.size() );
5177     for ( size_t iP = 0; iP < grp.size(); ++iP )
5178     {
5179       SMESH_MeshAlgos::TFreeBorderPart& part = grp[ iP ];
5180       SMESH::FreeBorderPart&           aPART = aGRP[ iP ];
5181       aPART.border   = part._border;
5182       aPART.node1    = part._node1;
5183       aPART.node2    = part._node2;
5184       aPART.nodeLast = part._nodeLast;
5185     }
5186   }
5187   SMESH_CATCH( SMESH::doNothing );
5188
5189   TPythonDump() << "CoincidentFreeBorders = "
5190                 << this << ".FindCoincidentFreeBorders( " << tolerance << " )";
5191
5192   return aCFB._retn();
5193 }
5194
5195 //=======================================================================
5196 /*!
5197  * Sew FreeBorder's of each group
5198  */
5199 //=======================================================================
5200
5201 CORBA::Short SMESH_MeshEditor_i::
5202 SewCoincidentFreeBorders(const SMESH::CoincidentFreeBorders& freeBorders,
5203                          CORBA::Boolean                      createPolygons,
5204                          CORBA::Boolean                      createPolyhedra)
5205   throw (SALOME::SALOME_Exception)
5206 {
5207   CORBA::Short nbSewed = 0;
5208
5209   SMESH_MeshAlgos::TFreeBorderVec groups;
5210   SMESH_MeshAlgos::TFreeBorder    borderNodes; // triples of nodes for every FreeBorderPart
5211
5212   // check the input and collect nodes
5213   for ( CORBA::ULong i = 0; i < freeBorders.coincidentGroups.length(); ++i )
5214   {
5215     borderNodes.clear();
5216     const SMESH::FreeBordersGroup& aGRP = freeBorders.coincidentGroups[ i ];
5217     for ( CORBA::ULong iP = 0; iP < aGRP.length(); ++iP )
5218     {
5219       const SMESH::FreeBorderPart& aPART = aGRP[ iP ];
5220       if ( aPART.border < 0 || aPART.border >= (int) freeBorders.borders.length() )
5221         THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::border index", SALOME::BAD_PARAM);
5222
5223       const SMESH::FreeBorder& aBRD = freeBorders.borders[ aPART.border ];
5224
5225       if ( aPART.node1 < 0 || aPART.node1 > (int) aBRD.nodeIDs.length() )
5226         THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::node1", SALOME::BAD_PARAM);
5227       if ( aPART.node2 < 0 || aPART.node2 > (int) aBRD.nodeIDs.length() )
5228         THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::node2", SALOME::BAD_PARAM);
5229       if ( aPART.nodeLast < 0 || aPART.nodeLast > (int) aBRD.nodeIDs.length() )
5230         THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::nodeLast", SALOME::BAD_PARAM);
5231
5232       // do not keep these nodes for further sewing as nodes can be removed by the sewing
5233       const SMDS_MeshNode* n1 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.node1    ]);
5234       const SMDS_MeshNode* n2 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.node2    ]);
5235       const SMDS_MeshNode* n3 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.nodeLast ]);
5236       if ( !n1)
5237         THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::node1", SALOME::BAD_PARAM);
5238       if ( !n2 )
5239         THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::node2", SALOME::BAD_PARAM);
5240       if ( !n3 )
5241         THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::nodeLast", SALOME::BAD_PARAM);
5242
5243       borderNodes.push_back( n1 );
5244       borderNodes.push_back( n2 );
5245       borderNodes.push_back( n3 );
5246     }
5247     groups.push_back( borderNodes );
5248   }
5249
5250   // SewFreeBorder() can merge nodes, thus nodes stored in 'groups' can become dead;
5251   // to get nodes that replace other nodes during merge we create 0D elements
5252   // on each node and MergeNodes() will replace underlying nodes of 0D elements by
5253   // new ones.
5254
5255   vector< const SMDS_MeshElement* > tmp0Delems;
5256   for ( size_t i = 0; i < groups.size(); ++i )
5257   {
5258     SMESH_MeshAlgos::TFreeBorder& nodes = groups[i];
5259     for ( size_t iN = 0; iN < nodes.size(); ++iN )
5260     {
5261       SMDS_ElemIteratorPtr it0D = nodes[iN]->GetInverseElementIterator(SMDSAbs_0DElement);
5262       if ( it0D->more() )
5263         tmp0Delems.push_back( it0D->next() );
5264       else
5265         tmp0Delems.push_back( getMeshDS()->Add0DElement( nodes[iN] ));
5266     }
5267   }
5268
5269   // cout << endl << "INIT" << endl;
5270   // for ( size_t i = 0; i < tmp0Delems.size(); ++i )
5271   // {
5272   //   cout << i << " ";
5273   //   if ( i % 3 == 0 ) cout << "^ ";
5274   //   tmp0Delems[i]->GetNode(0)->Print( cout );
5275   // }
5276
5277   SMESH_TRY;
5278
5279   ::SMESH_MeshEditor::Sew_Error res, ok = ::SMESH_MeshEditor::SEW_OK;
5280   int i0D = 0;
5281   for ( size_t i = 0; i < groups.size(); ++i )
5282   {
5283     bool isBordToBord = true;
5284     bool   groupSewed = false;
5285     SMESH_MeshAlgos::TFreeBorder& nodes = groups[i];
5286     for ( size_t iN = 3; iN+2 < nodes.size(); iN += 3 )
5287     {
5288       const SMDS_MeshNode* n0 = tmp0Delems[ i0D + 0 ]->GetNode( 0 );
5289       const SMDS_MeshNode* n1 = tmp0Delems[ i0D + 1 ]->GetNode( 0 );
5290       const SMDS_MeshNode* n2 = tmp0Delems[ i0D + 2 ]->GetNode( 0 );
5291
5292       const SMDS_MeshNode* n3 = tmp0Delems[ i0D + 0 + iN ]->GetNode( 0 );
5293       const SMDS_MeshNode* n4 = tmp0Delems[ i0D + 1 + iN ]->GetNode( 0 );
5294       const SMDS_MeshNode* n5 = tmp0Delems[ i0D + 2 + iN ]->GetNode( 0 );
5295
5296       if ( !n0 || !n1 || !n2 || !n3 || !n4 || !n5 )
5297         continue;
5298
5299       // TIDSortedElemSet emptySet, avoidSet;
5300       // if ( !SMESH_MeshAlgos::FindFaceInSet( n0, n1, emptySet, avoidSet))
5301       // {
5302       //   cout << "WRONG 2nd 1" << endl;
5303       //   n0->Print( cout );
5304       //   n1->Print( cout );
5305       // }
5306       // if ( !SMESH_MeshAlgos::FindFaceInSet( n3, n4, emptySet, avoidSet))
5307       // {
5308       //   cout << "WRONG 2nd 2" << endl;
5309       //   n3->Print( cout );
5310       //   n4->Print( cout );
5311       // }
5312
5313       if ( !isBordToBord )
5314       {
5315         n1 = n2; // at border-to-side sewing only last side node (n1) is needed
5316         n2 = 0;  //  and n2 is not used
5317       }
5318       // 1st border moves to 2nd
5319       res = getEditor().SewFreeBorder( n3, n4, n5 ,// 1st
5320                                        n0 ,n1 ,n2 ,// 2nd
5321                                        /*2ndIsFreeBorder=*/ isBordToBord,
5322                                        createPolygons, createPolyhedra);
5323       groupSewed = ( res == ok );
5324
5325       isBordToBord = false;
5326       // cout << endl << "SEWED GROUP " << i << " PART " << iN / 3 << endl;
5327       // for ( size_t t = 0; t < tmp0Delems.size(); ++t )
5328       // {
5329       //   cout << t << " ";
5330       //   if ( t % 3 == 0 ) cout << "^ ";
5331       //   tmp0Delems[t]->GetNode(0)->Print( cout );
5332       // }
5333     }
5334     i0D += nodes.size();
5335     nbSewed += groupSewed;
5336   }
5337
5338   TPythonDump() << "nbSewed = " << this << ".SewCoincidentFreeBorders( "
5339                 << freeBorders     << ", "
5340                 << createPolygons  << ", "
5341                 << createPolyhedra << " )";
5342
5343   SMESH_CATCH( SMESH::doNothing );
5344
5345   declareMeshModified( /*isReComputeSafe=*/false );
5346
5347   // remove tmp 0D elements
5348   SMESH_TRY;
5349   set< const SMDS_MeshElement* > removed0D;
5350   for ( size_t i = 0; i < tmp0Delems.size(); ++i )
5351   {
5352     if ( removed0D.insert( tmp0Delems[i] ).second )
5353       getMeshDS()->RemoveFreeElement( tmp0Delems[i], /*sm=*/0, /*fromGroups=*/false );
5354   }
5355   SMESH_CATCH( SMESH::throwCorbaException );
5356
5357   return nbSewed;
5358 }
5359
5360 //=======================================================================
5361 //function : SewFreeBorders
5362 //purpose  :
5363 //=======================================================================
5364
5365 SMESH::SMESH_MeshEditor::Sew_Error
5366 SMESH_MeshEditor_i::SewFreeBorders(CORBA::Long FirstNodeID1,
5367                                    CORBA::Long SecondNodeID1,
5368                                    CORBA::Long LastNodeID1,
5369                                    CORBA::Long FirstNodeID2,
5370                                    CORBA::Long SecondNodeID2,
5371                                    CORBA::Long LastNodeID2,
5372                                    CORBA::Boolean CreatePolygons,
5373                                    CORBA::Boolean CreatePolyedrs)
5374   throw (SALOME::SALOME_Exception)
5375 {
5376   SMESH_TRY;
5377   initData();
5378
5379   SMESHDS_Mesh* aMesh = getMeshDS();
5380
5381   const SMDS_MeshNode* aBorderFirstNode  = aMesh->FindNode( FirstNodeID1  );
5382   const SMDS_MeshNode* aBorderSecondNode = aMesh->FindNode( SecondNodeID1 );
5383   const SMDS_MeshNode* aBorderLastNode   = aMesh->FindNode( LastNodeID1   );
5384   const SMDS_MeshNode* aSide2FirstNode   = aMesh->FindNode( FirstNodeID2  );
5385   const SMDS_MeshNode* aSide2SecondNode  = aMesh->FindNode( SecondNodeID2 );
5386   const SMDS_MeshNode* aSide2ThirdNode   = aMesh->FindNode( LastNodeID2   );
5387
5388   if (!aBorderFirstNode ||
5389       !aBorderSecondNode||
5390       !aBorderLastNode)
5391     return SMESH::SMESH_MeshEditor::SEW_BORDER1_NOT_FOUND;
5392   if (!aSide2FirstNode  ||
5393       !aSide2SecondNode ||
5394       !aSide2ThirdNode)
5395     return SMESH::SMESH_MeshEditor::SEW_BORDER2_NOT_FOUND;
5396
5397   TPythonDump() << "error = " << this << ".SewFreeBorders( "
5398                 << FirstNodeID1  << ", "
5399                 << SecondNodeID1 << ", "
5400                 << LastNodeID1   << ", "
5401                 << FirstNodeID2  << ", "
5402                 << SecondNodeID2 << ", "
5403                 << LastNodeID2   << ", "
5404                 << CreatePolygons<< ", "
5405                 << CreatePolyedrs<< " )";
5406
5407   SMESH::SMESH_MeshEditor::Sew_Error error =
5408     convError( getEditor().SewFreeBorder (aBorderFirstNode,
5409                                           aBorderSecondNode,
5410                                           aBorderLastNode,
5411                                           aSide2FirstNode,
5412                                           aSide2SecondNode,
5413                                           aSide2ThirdNode,
5414                                           true,
5415                                           CreatePolygons,
5416                                           CreatePolyedrs) );
5417
5418
5419   declareMeshModified( /*isReComputeSafe=*/false );
5420   return error;
5421
5422   SMESH_CATCH( SMESH::throwCorbaException );
5423   return SMESH::SMESH_MeshEditor::Sew_Error(0);
5424 }
5425
5426
5427 //=======================================================================
5428 //function : SewConformFreeBorders
5429 //purpose  :
5430 //=======================================================================
5431
5432 SMESH::SMESH_MeshEditor::Sew_Error
5433 SMESH_MeshEditor_i::SewConformFreeBorders(CORBA::Long FirstNodeID1,
5434                                           CORBA::Long SecondNodeID1,
5435                                           CORBA::Long LastNodeID1,
5436                                           CORBA::Long FirstNodeID2,
5437                                           CORBA::Long SecondNodeID2)
5438   throw (SALOME::SALOME_Exception)
5439 {
5440   SMESH_TRY;
5441   initData();
5442
5443   SMESHDS_Mesh* aMesh = getMeshDS();
5444
5445   const SMDS_MeshNode* aBorderFirstNode  = aMesh->FindNode( FirstNodeID1  );
5446   const SMDS_MeshNode* aBorderSecondNode = aMesh->FindNode( SecondNodeID1 );
5447   const SMDS_MeshNode* aBorderLastNode   = aMesh->FindNode( LastNodeID1   );
5448   const SMDS_MeshNode* aSide2FirstNode   = aMesh->FindNode( FirstNodeID2  );
5449   const SMDS_MeshNode* aSide2SecondNode  = aMesh->FindNode( SecondNodeID2 );
5450   const SMDS_MeshNode* aSide2ThirdNode   = 0;
5451
5452   if (!aBorderFirstNode ||
5453       !aBorderSecondNode||
5454       !aBorderLastNode )
5455     return SMESH::SMESH_MeshEditor::SEW_BORDER1_NOT_FOUND;
5456   if (!aSide2FirstNode  ||
5457       !aSide2SecondNode)
5458     return SMESH::SMESH_MeshEditor::SEW_BORDER2_NOT_FOUND;
5459
5460   TPythonDump() << "error = " << this << ".SewConformFreeBorders( "
5461                 << FirstNodeID1  << ", "
5462                 << SecondNodeID1 << ", "
5463                 << LastNodeID1   << ", "
5464                 << FirstNodeID2  << ", "
5465                 << SecondNodeID2 << " )";
5466
5467   SMESH::SMESH_MeshEditor::Sew_Error error =
5468     convError( getEditor().SewFreeBorder (aBorderFirstNode,
5469                                           aBorderSecondNode,
5470                                           aBorderLastNode,
5471                                           aSide2FirstNode,
5472                                           aSide2SecondNode,
5473                                           aSide2ThirdNode,
5474                                           true,
5475                                           false, false) );
5476
5477   declareMeshModified( /*isReComputeSafe=*/false );
5478   return error;
5479
5480   SMESH_CATCH( SMESH::throwCorbaException );
5481   return SMESH::SMESH_MeshEditor::Sew_Error(0);
5482 }
5483
5484
5485 //=======================================================================
5486 //function : SewBorderToSide
5487 //purpose  :
5488 //=======================================================================
5489
5490 SMESH::SMESH_MeshEditor::Sew_Error
5491 SMESH_MeshEditor_i::SewBorderToSide(CORBA::Long FirstNodeIDOnFreeBorder,
5492                                     CORBA::Long SecondNodeIDOnFreeBorder,
5493                                     CORBA::Long LastNodeIDOnFreeBorder,
5494                                     CORBA::Long FirstNodeIDOnSide,
5495                                     CORBA::Long LastNodeIDOnSide,
5496                                     CORBA::Boolean CreatePolygons,
5497                                     CORBA::Boolean CreatePolyedrs)
5498   throw (SALOME::SALOME_Exception)
5499 {
5500   SMESH_TRY;
5501   initData();
5502
5503   SMESHDS_Mesh* aMesh = getMeshDS();
5504
5505   const SMDS_MeshNode* aBorderFirstNode  = aMesh->FindNode( FirstNodeIDOnFreeBorder  );
5506   const SMDS_MeshNode* aBorderSecondNode = aMesh->FindNode( SecondNodeIDOnFreeBorder );
5507   const SMDS_MeshNode* aBorderLastNode   = aMesh->FindNode( LastNodeIDOnFreeBorder   );
5508   const SMDS_MeshNode* aSide2FirstNode   = aMesh->FindNode( FirstNodeIDOnSide  );
5509   const SMDS_MeshNode* aSide2SecondNode  = aMesh->FindNode( LastNodeIDOnSide );
5510   const SMDS_MeshNode* aSide2ThirdNode   = 0;
5511
5512   if (!aBorderFirstNode ||
5513       !aBorderSecondNode||
5514       !aBorderLastNode  )
5515     return SMESH::SMESH_MeshEditor::SEW_BORDER1_NOT_FOUND;
5516   if (!aSide2FirstNode  ||
5517       !aSide2SecondNode)
5518     return SMESH::SMESH_MeshEditor::SEW_BAD_SIDE_NODES;
5519
5520   TPythonDump() << "error = " << this << ".SewBorderToSide( "
5521                 << FirstNodeIDOnFreeBorder  << ", "
5522                 << SecondNodeIDOnFreeBorder << ", "
5523                 << LastNodeIDOnFreeBorder   << ", "
5524                 << FirstNodeIDOnSide        << ", "
5525                 << LastNodeIDOnSide         << ", "
5526                 << CreatePolygons           << ", "
5527                 << CreatePolyedrs           << ") ";
5528
5529   SMESH::SMESH_MeshEditor::Sew_Error error =
5530     convError( getEditor().SewFreeBorder (aBorderFirstNode,
5531                                           aBorderSecondNode,
5532                                           aBorderLastNode,
5533                                           aSide2FirstNode,
5534                                           aSide2SecondNode,
5535                                           aSide2ThirdNode,
5536                                           false,
5537                                           CreatePolygons,
5538                                           CreatePolyedrs) );
5539
5540   declareMeshModified( /*isReComputeSafe=*/false );
5541   return error;
5542
5543   SMESH_CATCH( SMESH::throwCorbaException );
5544   return SMESH::SMESH_MeshEditor::Sew_Error(0);
5545 }
5546
5547
5548 //=======================================================================
5549 //function : SewSideElements
5550 //purpose  :
5551 //=======================================================================
5552
5553 SMESH::SMESH_MeshEditor::Sew_Error
5554 SMESH_MeshEditor_i::SewSideElements(const SMESH::long_array& IDsOfSide1Elements,
5555                                     const SMESH::long_array& IDsOfSide2Elements,
5556                                     CORBA::Long NodeID1OfSide1ToMerge,
5557                                     CORBA::Long NodeID1OfSide2ToMerge,
5558                                     CORBA::Long NodeID2OfSide1ToMerge,
5559                                     CORBA::Long NodeID2OfSide2ToMerge)
5560   throw (SALOME::SALOME_Exception)
5561 {
5562   SMESH_TRY;
5563   initData();
5564
5565   SMESHDS_Mesh* aMesh = getMeshDS();
5566
5567   const SMDS_MeshNode* aFirstNode1ToMerge  = aMesh->FindNode( NodeID1OfSide1ToMerge );
5568   const SMDS_MeshNode* aFirstNode2ToMerge  = aMesh->FindNode( NodeID1OfSide2ToMerge );
5569   const SMDS_MeshNode* aSecondNode1ToMerge = aMesh->FindNode( NodeID2OfSide1ToMerge );
5570   const SMDS_MeshNode* aSecondNode2ToMerge = aMesh->FindNode( NodeID2OfSide2ToMerge );
5571
5572   if (!aFirstNode1ToMerge ||
5573       !aFirstNode2ToMerge )
5574     return SMESH::SMESH_MeshEditor::SEW_BAD_SIDE1_NODES;
5575   if (!aSecondNode1ToMerge||
5576       !aSecondNode2ToMerge)
5577     return SMESH::SMESH_MeshEditor::SEW_BAD_SIDE2_NODES;
5578
5579   TIDSortedElemSet aSide1Elems, aSide2Elems;
5580   arrayToSet(IDsOfSide1Elements, aMesh, aSide1Elems);
5581   arrayToSet(IDsOfSide2Elements, aMesh, aSide2Elems);
5582
5583   TPythonDump() << "error = " << this << ".SewSideElements( "
5584                 << IDsOfSide1Elements << ", "
5585                 << IDsOfSide2Elements << ", "
5586                 << NodeID1OfSide1ToMerge << ", "
5587                 << NodeID1OfSide2ToMerge << ", "
5588                 << NodeID2OfSide1ToMerge << ", "
5589                 << NodeID2OfSide2ToMerge << ")";
5590
5591   SMESH::SMESH_MeshEditor::Sew_Error error =
5592     convError( getEditor().SewSideElements (aSide1Elems, aSide2Elems,
5593                                          aFirstNode1ToMerge,
5594                                          aFirstNode2ToMerge,
5595                                          aSecondNode1ToMerge,
5596                                          aSecondNode2ToMerge));
5597
5598   declareMeshModified( /*isReComputeSafe=*/false );
5599   return error;
5600
5601   SMESH_CATCH( SMESH::throwCorbaException );
5602   return SMESH::SMESH_MeshEditor::Sew_Error(0);
5603 }
5604
5605 //================================================================================
5606 /*!
5607  * \brief Set new nodes for given element
5608  * \param ide - element id
5609  * \param newIDs - new node ids
5610  * \retval CORBA::Boolean - true if result is OK
5611  */
5612 //================================================================================
5613
5614 CORBA::Boolean SMESH_MeshEditor_i::ChangeElemNodes(CORBA::Long ide,
5615                                                    const SMESH::long_array& newIDs)
5616   throw (SALOME::SALOME_Exception)
5617 {
5618   SMESH_TRY;
5619   initData();
5620
5621   const SMDS_MeshElement* elem = getMeshDS()->FindElement(ide);
5622   if ( !elem ) return false;
5623
5624   int nbn = newIDs.length();
5625   vector<const SMDS_MeshNode*> aNodes(nbn);
5626   for ( int i = 0; i < nbn; i++ ) {
5627     const SMDS_MeshNode* aNode = getMeshDS()->FindNode( newIDs[ i ]);
5628     if ( !aNode )
5629       return false;
5630     aNodes[ i ] = aNode;
5631   }
5632   TPythonDump() << "isDone = " << this << ".ChangeElemNodes( "
5633                 << ide << ", " << newIDs << " )";
5634
5635   bool res = getMeshDS()->ChangeElementNodes( elem, & aNodes[0], aNodes.size() );
5636
5637   declareMeshModified( /*isReComputeSafe=*/ !res );
5638
5639   return res;
5640
5641   SMESH_CATCH( SMESH::throwCorbaException );
5642   return 0;
5643 }
5644
5645 //=======================================================================
5646 /*!
5647  * \brief Makes a part of the mesh quadratic or bi-quadratic
5648  */
5649 //=======================================================================
5650
5651 void SMESH_MeshEditor_i::convertToQuadratic(CORBA::Boolean            theForce3d,
5652                                             CORBA::Boolean            theToBiQuad,
5653                                             SMESH::SMESH_IDSource_ptr theObject)
5654   throw (SALOME::SALOME_Exception)
5655 {
5656   SMESH_TRY;
5657   initData();
5658
5659   TIDSortedElemSet elems;
5660   bool elemsOK;
5661   if ( !( elemsOK = CORBA::is_nil( theObject )))
5662   {
5663     elemsOK = idSourceToSet( theObject, getMeshDS(), elems,
5664                              SMDSAbs_All, /*emptyIfIsMesh=*/true );
5665   }
5666   if ( elemsOK )
5667   {
5668     if ( !elems.empty() && (*elems.begin())->GetType() == SMDSAbs_Node )
5669       THROW_SALOME_CORBA_EXCEPTION("Group of nodes is not allowed", SALOME::BAD_PARAM);
5670
5671     if ( elems.empty() ) getEditor().ConvertToQuadratic(theForce3d, theToBiQuad);
5672     else                 getEditor().ConvertToQuadratic(theForce3d, elems, theToBiQuad);
5673
5674     declareMeshModified( /*isReComputeSafe=*/false );
5675   }
5676
5677   SMESH_CATCH( SMESH::throwCorbaException );
5678 }
5679
5680 //=======================================================================
5681 //function : ConvertFromQuadratic
5682 //purpose  :
5683 //=======================================================================
5684
5685 CORBA::Boolean SMESH_MeshEditor_i::ConvertFromQuadratic()
5686   throw (SALOME::SALOME_Exception)
5687 {
5688   SMESH_TRY;
5689   initData();
5690
5691   CORBA::Boolean isDone = getEditor().ConvertFromQuadratic();
5692   TPythonDump() << this << ".ConvertFromQuadratic()";
5693   declareMeshModified( /*isReComputeSafe=*/!isDone );
5694   return isDone;
5695
5696   SMESH_CATCH( SMESH::throwCorbaException );
5697   return false;
5698 }
5699
5700 //=======================================================================
5701 //function : ConvertToQuadratic
5702 //purpose  :
5703 //=======================================================================
5704
5705 void SMESH_MeshEditor_i::ConvertToQuadratic(CORBA::Boolean theForce3d)
5706   throw (SALOME::SALOME_Exception)
5707 {
5708   convertToQuadratic( theForce3d, false );
5709   TPythonDump() << this << ".ConvertToQuadratic("<<theForce3d<<")";
5710 }
5711
5712 //================================================================================
5713 /*!
5714  * \brief Makes a part of the mesh quadratic
5715  */
5716 //================================================================================
5717
5718 void SMESH_MeshEditor_i::ConvertToQuadraticObject(CORBA::Boolean            theForce3d,
5719                                                   SMESH::SMESH_IDSource_ptr theObject)
5720   throw (SALOME::SALOME_Exception)
5721 {
5722   convertToQuadratic( theForce3d, false, theObject );
5723   TPythonDump() << this << ".ConvertToQuadraticObject("<<theForce3d<<", "<<theObject<<")";
5724 }
5725
5726 //================================================================================
5727 /*!
5728  * \brief Makes a part of the mesh bi-quadratic
5729  */
5730 //================================================================================
5731
5732 void SMESH_MeshEditor_i::ConvertToBiQuadratic(CORBA::Boolean            theForce3d,
5733                                               SMESH::SMESH_IDSource_ptr theObject)
5734   throw (SALOME::SALOME_Exception)
5735 {
5736   convertToQuadratic( theForce3d, true, theObject );
5737   TPythonDump() << this << ".ConvertToBiQuadratic("<<theForce3d<<", "<<theObject<<")";
5738 }
5739
5740 //================================================================================
5741 /*!
5742  * \brief Makes a part of the mesh linear
5743  */
5744 //================================================================================
5745
5746 void SMESH_MeshEditor_i::ConvertFromQuadraticObject(SMESH::SMESH_IDSource_ptr theObject)
5747   throw (SALOME::SALOME_Exception)
5748 {
5749   SMESH_TRY;
5750   initData();
5751
5752   TPythonDump pyDump;
5753
5754   TIDSortedElemSet elems;
5755   if ( idSourceToSet( theObject, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true ))
5756   {
5757     if ( elems.empty() )
5758     {
5759       ConvertFromQuadratic();
5760     }
5761     else if ( (*elems.begin())->GetType() == SMDSAbs_Node )
5762     {
5763       THROW_SALOME_CORBA_EXCEPTION("Group of nodes is not allowed", SALOME::BAD_PARAM);
5764     }
5765     else
5766     {
5767       getEditor().ConvertFromQuadratic(elems);
5768     }
5769   }
5770   declareMeshModified( /*isReComputeSafe=*/false );
5771
5772   pyDump << this << ".ConvertFromQuadraticObject( "<<theObject<<" )";
5773
5774   SMESH_CATCH( SMESH::throwCorbaException );
5775 }
5776
5777 //=======================================================================
5778 //function : makeMesh
5779 //purpose  : create a named imported mesh
5780 //=======================================================================
5781
5782 SMESH::SMESH_Mesh_ptr SMESH_MeshEditor_i::makeMesh(const char* theMeshName)
5783 {
5784   SMESH_Gen_i*              gen = SMESH_Gen_i::GetSMESHGen();
5785   SMESH::SMESH_Mesh_var    mesh = gen->CreateEmptyMesh();
5786   SALOMEDS::SObject_wrap meshSO = gen->ObjectToSObject( mesh );
5787   gen->SetName( meshSO, theMeshName, "Mesh" );
5788   gen->SetPixMap( meshSO, "ICON_SMESH_TREE_MESH_IMPORTED");
5789
5790   return mesh._retn();
5791 }
5792
5793 //=======================================================================
5794 //function : dumpGroupsList
5795 //purpose  :
5796 //=======================================================================
5797
5798 void SMESH_MeshEditor_i::dumpGroupsList(TPythonDump &               theDumpPython,
5799                                         const SMESH::ListOfGroups * theGroupList)
5800 {
5801   bool isDumpGroupList = ( theGroupList && theGroupList->length() > 0 );
5802   if ( isDumpGroupList )
5803     theDumpPython << theGroupList << " = ";
5804 }
5805
5806 //================================================================================
5807 /*!
5808   \brief Generates the unique group name.
5809   \param thePrefix name prefix
5810   \return unique name
5811 */
5812 //================================================================================
5813
5814 std::string SMESH_MeshEditor_i::GenerateGroupName(const std::string& thePrefix)
5815 {
5816   SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
5817   set<std::string> groupNames;
5818
5819   // Get existing group names
5820   for (int i = 0, nbGroups = groups->length(); i < nbGroups; i++ ) {
5821     SMESH::SMESH_GroupBase_var aGroup = groups[i];
5822     if (CORBA::is_nil(aGroup))
5823       continue;
5824
5825     CORBA::String_var name = aGroup->GetName();
5826     groupNames.insert( name.in() );
5827   }
5828
5829   // Find new name
5830   std::string name = thePrefix;
5831   int index = 0;
5832
5833   while (!groupNames.insert(name).second)
5834     name = SMESH_Comment( thePrefix ) << "_" << index++;
5835
5836   return name;
5837 }
5838
5839 //================================================================================
5840 /*!
5841  * \brief Prepare SMESH_IDSource for work
5842  */
5843 //================================================================================
5844
5845 void SMESH_MeshEditor_i::prepareIdSource(SMESH::SMESH_IDSource_ptr theObject)
5846 {
5847   if ( SMESH::Filter_i* filter = SMESH::DownCast<SMESH::Filter_i*>( theObject ))
5848   {
5849     SMESH::SMESH_Mesh_var mesh = myMesh_i->_this();
5850     filter->SetMesh( mesh );
5851   }
5852 }
5853 //================================================================================
5854 /*!
5855  * \brief Retrieve elements of given type from SMESH_IDSource
5856  */
5857 //================================================================================
5858
5859 bool SMESH_MeshEditor_i::idSourceToSet(SMESH::SMESH_IDSource_ptr  theIDSource,
5860                                        const SMESHDS_Mesh*        theMeshDS,
5861                                        TIDSortedElemSet&          theElemSet,
5862                                        const SMDSAbs_ElementType  theType,
5863                                        const bool                 emptyIfIsMesh,
5864                                        IDSource_Error*            error)
5865
5866 {
5867   if ( error ) *error = IDSource_OK;
5868
5869   if ( CORBA::is_nil( theIDSource ))
5870   {
5871     if ( error ) *error = IDSource_INVALID;
5872     return false;
5873   }
5874   if ( emptyIfIsMesh && SMESH::DownCast<SMESH_Mesh_i*>( theIDSource ))
5875   {
5876     if ( error && theMeshDS->GetMeshInfo().NbElements( theType ) == 0 )
5877       *error = IDSource_EMPTY;
5878     return true;
5879   }
5880   if ( getMeshDS() == theMeshDS ) // check if theIDSource belongs to myMesh
5881   {
5882     SMESH::SMESH_Mesh_var mesh = theIDSource->GetMesh();
5883     SMESH_Mesh_i*       mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
5884     if ( mesh_i && mesh_i != myMesh_i )
5885     {
5886       if ( error )
5887         *error = IDSource_INVALID;
5888       return false;
5889     }
5890   }
5891   prepareIdSource( theIDSource );
5892   SMESH::long_array_var anIDs = theIDSource->GetIDs();
5893   if ( anIDs->length() == 0 )
5894   {
5895     if ( error ) *error = IDSource_EMPTY;
5896     return false;
5897   }
5898   SMESH::array_of_ElementType_var types = theIDSource->GetTypes();
5899   if ( types->length() == 1 && types[0] == SMESH::NODE ) // group of nodes
5900   {
5901     if ( theType == SMDSAbs_All || theType == SMDSAbs_Node )
5902     {
5903       arrayToSet( anIDs, getMeshDS(), theElemSet, SMDSAbs_Node );
5904     }
5905     else
5906     {
5907       if ( error ) *error = IDSource_INVALID;
5908       return false;
5909     }
5910   }
5911   else
5912   {
5913     arrayToSet( anIDs, getMeshDS(), theElemSet, theType);
5914     if ( bool(anIDs->length()) != bool(theElemSet.size()))
5915     {
5916       if ( error ) *error = IDSource_INVALID;
5917       return false;
5918     }
5919   }
5920   return true;
5921 }
5922
5923 //================================================================================
5924 /*!
5925  * \brief Duplicates given elements, i.e. creates new elements based on the
5926  *        same nodes as the given ones.
5927  * \param theElements - container of elements to duplicate.
5928  * \param theGroupName - a name of group to contain the generated elements.
5929  *                    If a group with such a name already exists, the new elements
5930  *                    are added to the existing group, else a new group is created.
5931  *                    If \a theGroupName is empty, new elements are not added 
5932  *                    in any group.
5933  * \return a group where the new elements are added. NULL if theGroupName == "".
5934  * \sa DoubleNode()
5935  */
5936 //================================================================================
5937
5938 SMESH::SMESH_Group_ptr
5939 SMESH_MeshEditor_i::DoubleElements(SMESH::SMESH_IDSource_ptr theElements,
5940                                    const char*               theGroupName)
5941   throw (SALOME::SALOME_Exception)
5942 {
5943   SMESH::SMESH_Group_var newGroup;
5944
5945   SMESH_TRY;
5946   initData();
5947
5948   TPythonDump pyDump;
5949
5950   TIDSortedElemSet elems;
5951   if ( idSourceToSet( theElements, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true))
5952   {
5953     getEditor().DoubleElements( elems );
5954
5955     if ( strlen( theGroupName ) && !getEditor().GetLastCreatedElems().empty() )
5956     {
5957       // group type
5958       SMESH::ElementType type =
5959         SMESH::ElementType( getEditor().GetLastCreatedElems()[0]->GetType() );
5960       // find existing group
5961       SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
5962       for ( size_t i = 0; i < groups->length(); ++i )
5963         if ( groups[i]->GetType() == type )
5964         {
5965           CORBA::String_var name = groups[i]->GetName();
5966           if ( strcmp( name, theGroupName ) == 0 ) {
5967             newGroup = SMESH::SMESH_Group::_narrow( groups[i] );
5968             break;
5969           }
5970         }
5971       // create a new group
5972       if ( newGroup->_is_nil() )
5973         newGroup = myMesh_i->CreateGroup( type, theGroupName );
5974       // fill newGroup
5975       if ( SMESH_Group_i* group_i = SMESH::DownCast< SMESH_Group_i* >( newGroup ))
5976       {
5977         SMESHDS_Group* groupDS = static_cast< SMESHDS_Group* >( group_i->GetGroupDS() );
5978         const SMESH_SequenceOfElemPtr& aSeq = getEditor().GetLastCreatedElems();
5979         for ( size_t i = 0; i < aSeq.size(); i++ )
5980           groupDS->SMDSGroup().Add( aSeq[i] );
5981       }
5982     }
5983   }
5984   // python dump
5985   if ( !newGroup->_is_nil() )
5986     pyDump << newGroup << " = ";
5987   pyDump << this << ".DoubleElements( "
5988          << theElements << ", " << "'" << theGroupName <<"')";
5989
5990   SMESH_CATCH( SMESH::throwCorbaException );
5991
5992   return newGroup._retn();
5993 }
5994
5995 //================================================================================
5996 /*!
5997   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5998   \param theNodes - identifiers of nodes to be doubled
5999   \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
6000          nodes. If list of element identifiers is empty then nodes are doubled but
6001          they not assigned to elements
6002   \return TRUE if operation has been completed successfully, FALSE otherwise
6003   \sa DoubleNode(), DoubleNodeGroup(), DoubleNodeGroups()
6004 */
6005 //================================================================================
6006
6007 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodes( const SMESH::long_array& theNodes,
6008                                                 const SMESH::long_array& theModifiedElems )
6009   throw (SALOME::SALOME_Exception)
6010 {
6011   SMESH_TRY;
6012   initData();
6013
6014   list< int > aListOfNodes;
6015   int i, n;
6016   for ( i = 0, n = theNodes.length(); i < n; i++ )
6017     aListOfNodes.push_back( theNodes[ i ] );
6018
6019   list< int > aListOfElems;
6020   for ( i = 0, n = theModifiedElems.length(); i < n; i++ )
6021     aListOfElems.push_back( theModifiedElems[ i ] );
6022
6023   bool aResult = getEditor().DoubleNodes( aListOfNodes, aListOfElems );
6024
6025   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6026
6027   // Update Python script
6028   TPythonDump() << this << ".DoubleNodes( " << theNodes << ", "<< theModifiedElems << " )";
6029
6030   return aResult;
6031
6032   SMESH_CATCH( SMESH::throwCorbaException );
6033   return 0;
6034 }
6035
6036 //================================================================================
6037 /*!
6038   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6039   This method provided for convenience works as DoubleNodes() described above.
6040   \param theNodeId - identifier of node to be doubled.
6041   \param theModifiedElems - identifiers of elements to be updated.
6042   \return TRUE if operation has been completed successfully, FALSE otherwise
6043   \sa DoubleNodes(), DoubleNodeGroup(), DoubleNodeGroups()
6044 */
6045 //================================================================================
6046
6047 CORBA::Boolean SMESH_MeshEditor_i::DoubleNode( CORBA::Long              theNodeId,
6048                                                const SMESH::long_array& theModifiedElems )
6049   throw (SALOME::SALOME_Exception)
6050 {
6051   SMESH_TRY;
6052   SMESH::long_array_var aNodes = new SMESH::long_array;
6053   aNodes->length( 1 );
6054   aNodes[ 0 ] = theNodeId;
6055
6056   TPythonDump pyDump; // suppress dump by the next line
6057
6058   CORBA::Boolean done = DoubleNodes( aNodes, theModifiedElems );
6059
6060   pyDump << this << ".DoubleNode( " << theNodeId << ", " << theModifiedElems << " )";
6061
6062   return done;
6063
6064   SMESH_CATCH( SMESH::throwCorbaException );
6065   return 0;
6066 }
6067
6068 //================================================================================
6069 /*!
6070   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6071   This method provided for convenience works as DoubleNodes() described above.
6072   \param theNodes - group of nodes to be doubled.
6073   \param theModifiedElems - group of elements to be updated.
6074   \return TRUE if operation has been completed successfully, FALSE otherwise
6075   \sa DoubleNode(), DoubleNodes(), DoubleNodeGroups()
6076 */
6077 //================================================================================
6078
6079 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroup(SMESH::SMESH_GroupBase_ptr theNodes,
6080                                                    SMESH::SMESH_GroupBase_ptr theModifiedElems )
6081   throw (SALOME::SALOME_Exception)
6082 {
6083   SMESH_TRY;
6084   if ( CORBA::is_nil( theNodes ) && theNodes->GetType() != SMESH::NODE )
6085     return false;
6086
6087   SMESH::long_array_var aNodes = theNodes->GetListOfID();
6088   SMESH::long_array_var aModifiedElems;
6089   if ( !CORBA::is_nil( theModifiedElems ) )
6090     aModifiedElems = theModifiedElems->GetListOfID();
6091   else
6092     aModifiedElems = new SMESH::long_array;
6093
6094   TPythonDump pyDump; // suppress dump by the next line
6095
6096   bool done = DoubleNodes( aNodes, aModifiedElems );
6097
6098   pyDump << this << ".DoubleNodeGroup( " << theNodes << ", " << theModifiedElems << " )";
6099
6100   return done;
6101
6102   SMESH_CATCH( SMESH::throwCorbaException );
6103   return 0;
6104 }
6105
6106 //================================================================================
6107 /*!
6108  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
6109  * Works as DoubleNodeGroup(), but returns a new group with newly created nodes.
6110  * \param theNodes - group of nodes to be doubled.
6111  * \param theModifiedElems - group of elements to be updated.
6112  * \return a new group with newly created nodes
6113  * \sa DoubleNodeGroup()
6114  */
6115 //================================================================================
6116
6117 SMESH::SMESH_Group_ptr
6118 SMESH_MeshEditor_i::DoubleNodeGroupNew( SMESH::SMESH_GroupBase_ptr theNodes,
6119                                         SMESH::SMESH_GroupBase_ptr theModifiedElems )
6120   throw (SALOME::SALOME_Exception)
6121 {
6122   SMESH_TRY;
6123   SMESH::SMESH_Group_var aNewGroup;
6124
6125   if ( CORBA::is_nil( theNodes ) && theNodes->GetType() != SMESH::NODE )
6126     return aNewGroup._retn();
6127
6128   // Duplicate nodes
6129   SMESH::long_array_var aNodes = theNodes->GetListOfID();
6130   SMESH::long_array_var aModifiedElems;
6131   if ( !CORBA::is_nil( theModifiedElems ) )
6132     aModifiedElems = theModifiedElems->GetListOfID();
6133   else {
6134     aModifiedElems = new SMESH::long_array;
6135     aModifiedElems->length( 0 );
6136   }
6137
6138   TPythonDump pyDump; // suppress dump by the next line
6139
6140   bool aResult = DoubleNodes( aNodes, aModifiedElems );
6141   if ( aResult )
6142   {
6143     // Create group with newly created nodes
6144     SMESH::long_array_var anIds = GetLastCreatedNodes();
6145     if (anIds->length() > 0) {
6146       std::string anUnindexedName (theNodes->GetName());
6147       std::string aNewName = GenerateGroupName(anUnindexedName + "_double");
6148       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
6149       aNewGroup->Add(anIds);
6150       pyDump << aNewGroup << " = ";
6151     }
6152   }
6153
6154   pyDump << this << ".DoubleNodeGroupNew( " << theNodes << ", "
6155          << theModifiedElems << " )";
6156
6157   return aNewGroup._retn();
6158
6159   SMESH_CATCH( SMESH::throwCorbaException );
6160   return 0;
6161 }
6162
6163 //================================================================================
6164 /*!
6165   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6166   This method provided for convenience works as DoubleNodes() described above.
6167   \param theNodes - list of groups of nodes to be doubled
6168   \param theModifiedElems - list of groups of elements to be updated.
6169   \return TRUE if operation has been completed successfully, FALSE otherwise
6170   \sa DoubleNode(), DoubleNodeGroup(), DoubleNodes()
6171 */
6172 //================================================================================
6173
6174 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroups(const SMESH::ListOfGroups& theNodes,
6175                                                     const SMESH::ListOfGroups& theModifiedElems )
6176   throw (SALOME::SALOME_Exception)
6177 {
6178   SMESH_TRY;
6179   initData();
6180
6181   std::list< int > aNodes;
6182   int i, n, j, m;
6183   for ( i = 0, n = theNodes.length(); i < n; i++ )
6184   {
6185     SMESH::SMESH_GroupBase_var aGrp = theNodes[ i ];
6186     if ( !CORBA::is_nil( aGrp ) && aGrp->GetType() == SMESH::NODE )
6187     {
6188       SMESH::long_array_var aCurr = aGrp->GetListOfID();
6189       for ( j = 0, m = aCurr->length(); j < m; j++ )
6190         aNodes.push_back( aCurr[ j ] );
6191     }
6192   }
6193
6194   std::list< int > anElems;
6195   for ( i = 0, n = theModifiedElems.length(); i < n; i++ )
6196   {
6197     SMESH::SMESH_GroupBase_var aGrp = theModifiedElems[ i ];
6198     if ( !CORBA::is_nil( aGrp ) && aGrp->GetType() != SMESH::NODE )
6199     {
6200       SMESH::long_array_var aCurr = aGrp->GetListOfID();
6201       for ( j = 0, m = aCurr->length(); j < m; j++ )
6202         anElems.push_back( aCurr[ j ] );
6203     }
6204   }
6205
6206   bool aResult = getEditor().DoubleNodes( aNodes, anElems );
6207
6208   declareMeshModified( /*isReComputeSafe=*/false );
6209
6210   TPythonDump() << this << ".DoubleNodeGroups( " << theNodes << ", " << theModifiedElems << " )";
6211
6212   return aResult;
6213
6214   SMESH_CATCH( SMESH::throwCorbaException );
6215   return 0;
6216 }
6217
6218 //================================================================================
6219 /*!
6220  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
6221  * Works as DoubleNodeGroups(), but returns a new group with newly created nodes.
6222  * \param theNodes - group of nodes to be doubled.
6223  * \param theModifiedElems - group of elements to be updated.
6224  * \return a new group with newly created nodes
6225  * \sa DoubleNodeGroups()
6226  */
6227 //================================================================================
6228
6229 SMESH::SMESH_Group_ptr
6230 SMESH_MeshEditor_i::DoubleNodeGroupsNew( const SMESH::ListOfGroups& theNodes,
6231                                          const SMESH::ListOfGroups& theModifiedElems )
6232   throw (SALOME::SALOME_Exception)
6233 {
6234   SMESH::SMESH_Group_var aNewGroup;
6235
6236   TPythonDump pyDump; // suppress dump by the next line
6237
6238   bool aResult = DoubleNodeGroups( theNodes, theModifiedElems );
6239
6240   if ( aResult )
6241   {
6242     // Create group with newly created nodes
6243     SMESH::long_array_var anIds = GetLastCreatedNodes();
6244     if (anIds->length() > 0) {
6245       std::string anUnindexedName (theNodes[0]->GetName());
6246       std::string aNewName = GenerateGroupName(anUnindexedName + "_double");
6247       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
6248       aNewGroup->Add(anIds);
6249       pyDump << aNewGroup << " = ";
6250     }
6251   }
6252
6253   pyDump << this << ".DoubleNodeGroupsNew( " << theNodes << ", "
6254          << theModifiedElems << " )";
6255
6256   return aNewGroup._retn();
6257 }
6258
6259
6260 //================================================================================
6261 /*!
6262   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6263   \param theElems - the list of elements (edges or faces) to be replicated
6264   The nodes for duplication could be found from these elements
6265   \param theNodesNot - list of nodes to NOT replicate
6266   \param theAffectedElems - the list of elements (cells and edges) to which the
6267   replicated nodes should be associated to.
6268   \return TRUE if operation has been completed successfully, FALSE otherwise
6269   \sa DoubleNodeGroup(), DoubleNodeGroups()
6270 */
6271 //================================================================================
6272
6273 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElem( const SMESH::long_array& theElems,
6274                                                    const SMESH::long_array& theNodesNot,
6275                                                    const SMESH::long_array& theAffectedElems )
6276   throw (SALOME::SALOME_Exception)
6277 {
6278   SMESH_TRY;
6279   initData();
6280
6281   SMESHDS_Mesh* aMeshDS = getMeshDS();
6282   TIDSortedElemSet anElems, aNodes, anAffected;
6283   arrayToSet(theElems, aMeshDS, anElems, SMDSAbs_All);
6284   arrayToSet(theNodesNot, aMeshDS, aNodes, SMDSAbs_Node);
6285   arrayToSet(theAffectedElems, aMeshDS, anAffected, SMDSAbs_All);
6286
6287   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
6288
6289   // Update Python script
6290   TPythonDump() << this << ".DoubleNodeElem( " << theElems << ", "
6291                 << theNodesNot << ", " << theAffectedElems << " )";
6292
6293   declareMeshModified( /*isReComputeSafe=*/false );
6294   return aResult;
6295
6296   SMESH_CATCH( SMESH::throwCorbaException );
6297   return 0;
6298 }
6299
6300 //================================================================================
6301 /*!
6302   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6303   \param theElems - the list of elements (edges or faces) to be replicated
6304   The nodes for duplication could be found from these elements
6305   \param theNodesNot - list of nodes to NOT replicate
6306   \param theShape - shape to detect affected elements (element which geometric center
6307   located on or inside shape).
6308   The replicated nodes should be associated to affected elements.
6309   \return TRUE if operation has been completed successfully, FALSE otherwise
6310   \sa DoubleNodeGroupInRegion(), DoubleNodeGroupsInRegion()
6311 */
6312 //================================================================================
6313
6314 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemInRegion ( const SMESH::long_array& theElems,
6315                                                             const SMESH::long_array& theNodesNot,
6316                                                             GEOM::GEOM_Object_ptr    theShape )
6317   throw (SALOME::SALOME_Exception)
6318 {
6319   SMESH_TRY;
6320   initData();
6321
6322
6323   SMESHDS_Mesh* aMeshDS = getMeshDS();
6324   TIDSortedElemSet anElems, aNodes;
6325   arrayToSet(theElems, aMeshDS, anElems, SMDSAbs_All);
6326   arrayToSet(theNodesNot, aMeshDS, aNodes, SMDSAbs_Node);
6327
6328   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
6329   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
6330
6331   // Update Python script
6332   TPythonDump() << "isDone = " << this << ".DoubleNodeElemInRegion( " << theElems << ", "
6333                 << theNodesNot << ", " << theShape << " )";
6334
6335   declareMeshModified( /*isReComputeSafe=*/false );
6336   return aResult;
6337
6338   SMESH_CATCH( SMESH::throwCorbaException );
6339   return 0;
6340 }
6341
6342 //================================================================================
6343 /*!
6344   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6345   \param theElems - group of of elements (edges or faces) to be replicated
6346   \param theNodesNot - group of nodes not to replicated
6347   \param theAffectedElems - group of elements to which the replicated nodes
6348   should be associated to.
6349   \return TRUE if operation has been completed successfully, FALSE otherwise
6350   \sa DoubleNodes(), DoubleNodeGroups()
6351 */
6352 //================================================================================
6353
6354 CORBA::Boolean
6355 SMESH_MeshEditor_i::DoubleNodeElemGroup(SMESH::SMESH_GroupBase_ptr theElems,
6356                                         SMESH::SMESH_GroupBase_ptr theNodesNot,
6357                                         SMESH::SMESH_GroupBase_ptr theAffectedElems)
6358   throw (SALOME::SALOME_Exception)
6359 {
6360   SMESH_TRY;
6361   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
6362     return false;
6363
6364   initData();
6365
6366
6367   SMESHDS_Mesh* aMeshDS = getMeshDS();
6368   TIDSortedElemSet anElems, aNodes, anAffected;
6369   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
6370   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
6371   idSourceToSet( theAffectedElems, aMeshDS, anAffected, SMDSAbs_All );
6372
6373   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
6374
6375   // Update Python script
6376   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroup( " << theElems << ", "
6377                 << theNodesNot << ", " << theAffectedElems << " )";
6378
6379   declareMeshModified( /*isReComputeSafe=*/false );
6380   return aResult;
6381
6382   SMESH_CATCH( SMESH::throwCorbaException );
6383   return 0;
6384 }
6385
6386 //================================================================================
6387 /*!
6388  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6389  * Works as DoubleNodeElemGroup(), but returns a new group with newly created elements.
6390  * \param theElems - group of of elements (edges or faces) to be replicated
6391  * \param theNodesNot - group of nodes not to replicated
6392  * \param theAffectedElems - group of elements to which the replicated nodes
6393  *        should be associated to.
6394  * \return a new group with newly created elements
6395  * \sa DoubleNodeElemGroup()
6396  */
6397 //================================================================================
6398
6399 SMESH::SMESH_Group_ptr
6400 SMESH_MeshEditor_i::DoubleNodeElemGroupNew(SMESH::SMESH_GroupBase_ptr theElems,
6401                                            SMESH::SMESH_GroupBase_ptr theNodesNot,
6402                                            SMESH::SMESH_GroupBase_ptr theAffectedElems)
6403   throw (SALOME::SALOME_Exception)
6404 {
6405   TPythonDump pyDump;
6406   SMESH::ListOfGroups_var twoGroups = DoubleNodeElemGroup2New( theElems,
6407                                                                theNodesNot,
6408                                                                theAffectedElems,
6409                                                                true, false );
6410   SMESH::SMESH_GroupBase_var baseGroup = twoGroups[0].in();
6411   SMESH::SMESH_Group_var     elemGroup = SMESH::SMESH_Group::_narrow( baseGroup );
6412
6413   pyDump << elemGroup << " = " << this << ".DoubleNodeElemGroupNew( "
6414          << theElems         << ", "
6415          << theNodesNot      << ", "
6416          << theAffectedElems << " )";
6417
6418   return elemGroup._retn();
6419 }
6420
6421 //================================================================================
6422 /*!
6423  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6424  * Works as DoubleNodeElemGroup(), but returns a new group with newly created elements.
6425  * \param theElems - group of of elements (edges or faces) to be replicated
6426  * \param theNodesNot - group of nodes not to replicated
6427  * \param theAffectedElems - group of elements to which the replicated nodes
6428  *        should be associated to.
6429  * \return a new group with newly created elements
6430  * \sa DoubleNodeElemGroup()
6431  */
6432 //================================================================================
6433
6434 SMESH::ListOfGroups*
6435 SMESH_MeshEditor_i::DoubleNodeElemGroup2New(SMESH::SMESH_GroupBase_ptr theElems,
6436                                             SMESH::SMESH_GroupBase_ptr theNodesNot,
6437                                             SMESH::SMESH_GroupBase_ptr theAffectedElems,
6438                                             CORBA::Boolean             theElemGroupNeeded,
6439                                             CORBA::Boolean             theNodeGroupNeeded)
6440   throw (SALOME::SALOME_Exception)
6441 {
6442   SMESH_TRY;
6443   SMESH::SMESH_Group_var aNewElemGroup, aNewNodeGroup;
6444   SMESH::ListOfGroups_var aTwoGroups = new SMESH::ListOfGroups();
6445   aTwoGroups->length( 2 );
6446
6447   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
6448     return aTwoGroups._retn();
6449
6450   initData();
6451
6452
6453   SMESHDS_Mesh* aMeshDS = getMeshDS();
6454   TIDSortedElemSet anElems, aNodes, anAffected;
6455   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
6456   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
6457   idSourceToSet( theAffectedElems, aMeshDS, anAffected, SMDSAbs_All );
6458
6459
6460   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
6461
6462   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6463
6464   TPythonDump pyDump;
6465
6466   if ( aResult )
6467   {
6468     // Create group with newly created elements
6469     CORBA::String_var elemGroupName = theElems->GetName();
6470     std::string aNewName = GenerateGroupName( std::string(elemGroupName.in()) + "_double");
6471     if ( !getEditor().GetLastCreatedElems().empty() && theElemGroupNeeded )
6472     {
6473       SMESH::long_array_var anIds = GetLastCreatedElems();
6474       SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true);
6475       aNewElemGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str());
6476       aNewElemGroup->Add(anIds);
6477     }
6478     if ( !getEditor().GetLastCreatedNodes().empty() && theNodeGroupNeeded )
6479     {
6480       SMESH::long_array_var anIds = GetLastCreatedNodes();
6481       aNewNodeGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
6482       aNewNodeGroup->Add(anIds);
6483     }
6484   }
6485
6486   // Update Python script
6487
6488   pyDump << "[ ";
6489   if ( aNewElemGroup->_is_nil() ) pyDump << "nothing, ";
6490   else                            pyDump << aNewElemGroup << ", ";
6491   if ( aNewNodeGroup->_is_nil() ) pyDump << "nothing ] = ";
6492   else                            pyDump << aNewNodeGroup << " ] = ";
6493
6494   pyDump << this << ".DoubleNodeElemGroup2New( " << theElems << ", "
6495          << theNodesNot        << ", "
6496          << theAffectedElems   << ", "
6497          << theElemGroupNeeded << ", "
6498          << theNodeGroupNeeded <<" )";
6499
6500   aTwoGroups[0] = aNewElemGroup._retn();
6501   aTwoGroups[1] = aNewNodeGroup._retn();
6502   return aTwoGroups._retn();
6503
6504   SMESH_CATCH( SMESH::throwCorbaException );
6505   return 0;
6506 }
6507
6508 //================================================================================
6509 /*!
6510   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6511   \param theElems - group of of elements (edges or faces) to be replicated
6512   \param theNodesNot - group of nodes not to replicated
6513   \param theShape - shape to detect affected elements (element which geometric center
6514   located on or inside shape).
6515   The replicated nodes should be associated to affected elements.
6516   \return TRUE if operation has been completed successfully, FALSE otherwise
6517   \sa DoubleNodesInRegion(), DoubleNodeGroupsInRegion()
6518 */
6519 //================================================================================
6520
6521 CORBA::Boolean
6522 SMESH_MeshEditor_i::DoubleNodeElemGroupInRegion(SMESH::SMESH_GroupBase_ptr theElems,
6523                                                 SMESH::SMESH_GroupBase_ptr theNodesNot,
6524                                                 GEOM::GEOM_Object_ptr      theShape )
6525   throw (SALOME::SALOME_Exception)
6526 {
6527   SMESH_TRY;
6528   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
6529     return false;
6530
6531   initData();
6532
6533
6534   SMESHDS_Mesh* aMeshDS = getMeshDS();
6535   TIDSortedElemSet anElems, aNodes, anAffected;
6536   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
6537   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
6538
6539   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
6540   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
6541
6542
6543   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6544
6545   // Update Python script
6546   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroupInRegion( " << theElems << ", "
6547                 << theNodesNot << ", " << theShape << " )";
6548   return aResult;
6549
6550   SMESH_CATCH( SMESH::throwCorbaException );
6551   return 0;
6552 }
6553
6554 //================================================================================
6555 /*!
6556  * \brief Re-load elements from a list of groups into a TIDSortedElemSet
6557  *  \param [in] theGrpList - groups
6558  *  \param [in] theMeshDS -  mesh
6559  *  \param [out] theElemSet - set of elements
6560  *  \param [in] theIsNodeGrp - is \a theGrpList includes goups of nodes
6561  */
6562 //================================================================================
6563
6564 static void listOfGroupToSet(const SMESH::ListOfGroups& theGrpList,
6565                              SMESHDS_Mesh*              theMeshDS,
6566                              TIDSortedElemSet&          theElemSet,
6567                              const bool                 theIsNodeGrp)
6568 {
6569   for ( int i = 0, n = theGrpList.length(); i < n; i++ )
6570   {
6571     SMESH::SMESH_GroupBase_var aGrp = theGrpList[ i ];
6572     if ( !CORBA::is_nil( aGrp ) && (theIsNodeGrp ? aGrp->GetType() == SMESH::NODE
6573                                     : aGrp->GetType() != SMESH::NODE ) )
6574     {
6575       SMESH::long_array_var anIDs = aGrp->GetIDs();
6576       arrayToSet( anIDs, theMeshDS, theElemSet, theIsNodeGrp ? SMDSAbs_Node : SMDSAbs_All );
6577     }
6578   }
6579 }
6580
6581 //================================================================================
6582 /*!
6583   \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
6584   This method provided for convenience works as DoubleNodes() described above.
6585   \param theElems - list of groups of elements (edges or faces) to be replicated
6586   \param theNodesNot - list of groups of nodes not to replicated
6587   \param theAffectedElems - group of elements to which the replicated nodes
6588   should be associated to.
6589   \return TRUE if operation has been completed successfully, FALSE otherwise
6590   \sa DoubleNodeGroup(), DoubleNodes(), DoubleNodeElemGroupsNew()
6591 */
6592 //================================================================================
6593
6594 CORBA::Boolean
6595 SMESH_MeshEditor_i::DoubleNodeElemGroups(const SMESH::ListOfGroups& theElems,
6596                                          const SMESH::ListOfGroups& theNodesNot,
6597                                          const SMESH::ListOfGroups& theAffectedElems)
6598   throw (SALOME::SALOME_Exception)
6599 {
6600   SMESH_TRY;
6601   initData();
6602
6603
6604   SMESHDS_Mesh* aMeshDS = getMeshDS();
6605   TIDSortedElemSet anElems, aNodes, anAffected;
6606   listOfGroupToSet(theElems, aMeshDS, anElems, false );
6607   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
6608   listOfGroupToSet(theAffectedElems, aMeshDS, anAffected, false );
6609
6610   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
6611
6612   // Update Python script
6613   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroups( " << &theElems << ", "
6614                 << &theNodesNot << ", " << &theAffectedElems << " )";
6615
6616   declareMeshModified( /*isReComputeSafe=*/false );
6617   return aResult;
6618
6619   SMESH_CATCH( SMESH::throwCorbaException );
6620   return 0;
6621 }
6622
6623 //================================================================================
6624 /*!
6625  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6626  * Works as DoubleNodeElemGroups(), but returns a new group with newly created elements.
6627   \param theElems - list of groups of elements (edges or faces) to be replicated
6628   \param theNodesNot - list of groups of nodes not to replicated
6629   \param theAffectedElems - group of elements to which the replicated nodes
6630   should be associated to.
6631  * \return a new group with newly created elements
6632  * \sa DoubleNodeElemGroups()
6633  */
6634 //================================================================================
6635
6636 SMESH::SMESH_Group_ptr
6637 SMESH_MeshEditor_i::DoubleNodeElemGroupsNew(const SMESH::ListOfGroups& theElems,
6638                                             const SMESH::ListOfGroups& theNodesNot,
6639                                             const SMESH::ListOfGroups& theAffectedElems)
6640   throw (SALOME::SALOME_Exception)
6641 {
6642   TPythonDump pyDump;
6643   SMESH::ListOfGroups_var twoGroups = DoubleNodeElemGroups2New( theElems,
6644                                                                 theNodesNot,
6645                                                                 theAffectedElems,
6646                                                                 true, false );
6647   SMESH::SMESH_GroupBase_var baseGroup = twoGroups[0].in();
6648   SMESH::SMESH_Group_var     elemGroup = SMESH::SMESH_Group::_narrow( baseGroup );
6649
6650   pyDump << elemGroup << " = " << this << ".DoubleNodeElemGroupsNew( "
6651          << theElems         << ", "
6652          << theNodesNot      << ", "
6653          << theAffectedElems << " )";
6654
6655   return elemGroup._retn();
6656 }
6657
6658 //================================================================================
6659 /*!
6660  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6661  * Works as DoubleNodeElemGroups(), but returns a new group with newly created elements.
6662   \param theElems - list of groups of elements (edges or faces) to be replicated
6663   \param theNodesNot - list of groups of nodes not to replicated
6664   \param theAffectedElems - group of elements to which the replicated nodes
6665   should be associated to.
6666  * \return a new group with newly created elements
6667  * \sa DoubleNodeElemGroups()
6668  */
6669 //================================================================================
6670
6671 SMESH::ListOfGroups*
6672 SMESH_MeshEditor_i::DoubleNodeElemGroups2New(const SMESH::ListOfGroups& theElems,
6673                                              const SMESH::ListOfGroups& theNodesNot,
6674                                              const SMESH::ListOfGroups& theAffectedElems,
6675                                              CORBA::Boolean             theElemGroupNeeded,
6676                                              CORBA::Boolean             theNodeGroupNeeded)
6677   throw (SALOME::SALOME_Exception)
6678 {
6679   SMESH_TRY;
6680   SMESH::SMESH_Group_var aNewElemGroup, aNewNodeGroup;
6681   SMESH::ListOfGroups_var aTwoGroups = new SMESH::ListOfGroups();
6682   aTwoGroups->length( 2 );
6683   
6684   initData();
6685
6686
6687   SMESHDS_Mesh* aMeshDS = getMeshDS();
6688   TIDSortedElemSet anElems, aNodes, anAffected;
6689   listOfGroupToSet(theElems, aMeshDS, anElems, false );
6690   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
6691   listOfGroupToSet(theAffectedElems, aMeshDS, anAffected, false );
6692
6693   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
6694
6695   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6696
6697   TPythonDump pyDump;
6698   if ( aResult )
6699   {
6700     // Create group with newly created elements
6701     CORBA::String_var elemGroupName = theElems[0]->GetName();
6702     std::string aNewName = GenerateGroupName( std::string(elemGroupName.in()) + "_double");
6703     if ( !getEditor().GetLastCreatedElems().empty() && theElemGroupNeeded )
6704     {
6705       SMESH::long_array_var anIds = GetLastCreatedElems();
6706       SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true);
6707       aNewElemGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str());
6708       aNewElemGroup->Add(anIds);
6709     }
6710     if ( !getEditor().GetLastCreatedNodes().empty() && theNodeGroupNeeded )
6711     {
6712       SMESH::long_array_var anIds = GetLastCreatedNodes();
6713       aNewNodeGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
6714       aNewNodeGroup->Add(anIds);
6715     }
6716   }
6717
6718   // Update Python script
6719
6720   pyDump << "[ ";
6721   if ( aNewElemGroup->_is_nil() ) pyDump << "nothing, ";
6722   else                            pyDump << aNewElemGroup << ", ";
6723   if ( aNewNodeGroup->_is_nil() ) pyDump << "nothing ] = ";
6724   else                            pyDump << aNewNodeGroup << " ] = ";
6725
6726   pyDump << this << ".DoubleNodeElemGroups2New( " << &theElems << ", "
6727          << &theNodesNot       << ", "
6728          << &theAffectedElems  << ", "
6729          << theElemGroupNeeded << ", "
6730          << theNodeGroupNeeded << " )";
6731
6732   aTwoGroups[0] = aNewElemGroup._retn();
6733   aTwoGroups[1] = aNewNodeGroup._retn();
6734   return aTwoGroups._retn();
6735
6736   SMESH_CATCH( SMESH::throwCorbaException );
6737   return 0;
6738 }
6739
6740 //================================================================================
6741 /*!
6742   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6743   This method provided for convenience works as DoubleNodes() described above.
6744   \param theElems - list of groups of elements (edges or faces) to be replicated
6745   \param theNodesNot - list of groups of nodes not to replicated
6746   \param theShape - shape to detect affected elements (element which geometric center
6747   located on or inside shape).
6748   The replicated nodes should be associated to affected elements.
6749   \return TRUE if operation has been completed successfully, FALSE otherwise
6750   \sa DoubleNodeGroupInRegion(), DoubleNodesInRegion()
6751 */
6752 //================================================================================
6753
6754 CORBA::Boolean
6755 SMESH_MeshEditor_i::DoubleNodeElemGroupsInRegion(const SMESH::ListOfGroups& theElems,
6756                                                  const SMESH::ListOfGroups& theNodesNot,
6757                                                  GEOM::GEOM_Object_ptr      theShape )
6758   throw (SALOME::SALOME_Exception)
6759 {
6760   SMESH_TRY;
6761   initData();
6762
6763
6764   SMESHDS_Mesh* aMeshDS = getMeshDS();
6765   TIDSortedElemSet anElems, aNodes;
6766   listOfGroupToSet(theElems, aMeshDS, anElems,false );
6767   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
6768
6769   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
6770   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
6771
6772   // Update Python script
6773   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroupsInRegion( " << &theElems << ", "
6774                 << &theNodesNot << ", " << theShape << " )";
6775
6776   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6777   return aResult;
6778
6779   SMESH_CATCH( SMESH::throwCorbaException );
6780   return 0;
6781 }
6782
6783 //================================================================================
6784 /*!
6785   \brief Identify the elements that will be affected by node duplication (actual
6786          duplication is not performed.
6787   This method is the first step of DoubleNodeElemGroupsInRegion.
6788   \param theElems - list of groups of elements (edges or faces) to be replicated
6789   \param theNodesNot - list of groups of nodes not to replicated
6790   \param theShape - shape to detect affected elements (element which geometric center
6791          located on or inside shape).
6792          The replicated nodes should be associated to affected elements.
6793   \return groups of affected elements
6794   \sa DoubleNodeElemGroupsInRegion()
6795 */
6796 //================================================================================
6797 SMESH::ListOfGroups*
6798 SMESH_MeshEditor_i::AffectedElemGroupsInRegion( const SMESH::ListOfGroups& theElems,
6799                                                 const SMESH::ListOfGroups& theNodesNot,
6800                                                 GEOM::GEOM_Object_ptr      theShape )
6801   throw (SALOME::SALOME_Exception)
6802 {
6803   SMESH_TRY;
6804   SMESH::ListOfGroups_var aListOfGroups = new SMESH::ListOfGroups();
6805   SMESH::SMESH_Group_var aNewEdgeGroup   = SMESH::SMESH_Group::_nil();
6806   SMESH::SMESH_Group_var aNewFaceGroup   = SMESH::SMESH_Group::_nil();
6807   SMESH::SMESH_Group_var aNewVolumeGroup = SMESH::SMESH_Group::_nil();
6808
6809   initData();
6810
6811   ::SMESH_MeshEditor aMeshEditor(myMesh);
6812
6813   SMESHDS_Mesh* aMeshDS = getMeshDS();
6814   TIDSortedElemSet anElems, aNodes;
6815   bool isNodeGrp = theElems.length() ? theElems[0]->GetType() == SMESH::NODE : false;
6816   listOfGroupToSet(theElems, aMeshDS, anElems, isNodeGrp);
6817   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true);
6818
6819   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape(theShape);
6820   TIDSortedElemSet anAffected;
6821   bool aResult = aMeshEditor.AffectedElemGroupsInRegion(anElems, aNodes, aShape, anAffected);
6822
6823   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6824
6825   TPythonDump pyDump;
6826   if ( aResult && anAffected.size() > 0 )
6827   {
6828     SMESH::long_array_var volumeIds = new SMESH::long_array;
6829     SMESH::long_array_var   faceIds = new SMESH::long_array;
6830     SMESH::long_array_var   edgeIds = new SMESH::long_array;
6831     volumeIds->length( anAffected.size() );
6832     faceIds  ->length( anAffected.size() );
6833     edgeIds  ->length( anAffected.size() );
6834
6835     int ivol = 0;
6836     int iface = 0;
6837     int iedge = 0;
6838     TIDSortedElemSet::const_iterator eIt = anAffected.begin();
6839     for (; eIt != anAffected.end(); ++eIt)
6840     {
6841       const SMDS_MeshElement* anElem = *eIt;
6842       int elemId = anElem->GetID();
6843       switch ( anElem->GetType() ) {
6844       case SMDSAbs_Volume: volumeIds[ivol++] = elemId; break;
6845       case SMDSAbs_Face:    faceIds[iface++] = elemId; break;
6846       case SMDSAbs_Edge:    edgeIds[iedge++] = elemId; break;
6847       default:;
6848       }
6849     }
6850     volumeIds->length(ivol);
6851     faceIds->length(iface);
6852     edgeIds->length(iedge);
6853
6854     int nbGroups = 0;
6855     if ( ivol > 0 )
6856     {
6857       aNewVolumeGroup = myMesh_i->CreateGroup(SMESH::VOLUME,
6858                                               GenerateGroupName("affectedVolumes").c_str());
6859       aNewVolumeGroup->Add(volumeIds);
6860       aListOfGroups->length( nbGroups+1 );
6861       aListOfGroups[ nbGroups++ ] = aNewVolumeGroup._retn();
6862     }
6863     if ( iface > 0 )
6864     {
6865       aNewFaceGroup = myMesh_i->CreateGroup(SMESH::FACE,
6866                                             GenerateGroupName("affectedFaces").c_str());
6867       aNewFaceGroup->Add(faceIds);
6868       aListOfGroups->length( nbGroups+1 );
6869       aListOfGroups[ nbGroups++ ] = aNewFaceGroup._retn();
6870     }
6871     if ( iedge > 0 )
6872     {
6873       aNewEdgeGroup = myMesh_i->CreateGroup(SMESH::EDGE,
6874                                             GenerateGroupName("affectedEdges").c_str());
6875       aNewEdgeGroup->Add(edgeIds);
6876       aListOfGroups->length( nbGroups+1 );
6877       aListOfGroups[ nbGroups++ ] = aNewEdgeGroup._retn();
6878     }
6879   }
6880
6881   // Update Python script
6882
6883   pyDump << aListOfGroups << " = " << this << ".AffectedElemGroupsInRegion( "
6884          << &theElems << ", " << &theNodesNot << ", " << theShape << " )";
6885
6886   return aListOfGroups._retn();
6887
6888   SMESH_CATCH( SMESH::throwCorbaException );
6889   return 0;
6890 }
6891
6892 //================================================================================
6893 /*!
6894   \brief Generated skin mesh (containing 2D cells) from 3D mesh
6895   The created 2D mesh elements based on nodes of free faces of boundary volumes
6896   \return TRUE if operation has been completed successfully, FALSE otherwise
6897 */
6898 //================================================================================
6899
6900 CORBA::Boolean SMESH_MeshEditor_i::Make2DMeshFrom3D()
6901   throw (SALOME::SALOME_Exception)
6902 {
6903   SMESH_TRY;
6904   initData();
6905
6906   bool aResult = getEditor().Make2DMeshFrom3D();
6907
6908   TPythonDump() << "isDone = " << this << ".Make2DMeshFrom3D()";
6909
6910   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6911   return aResult;
6912
6913   SMESH_CATCH( SMESH::throwCorbaException );
6914   return false;
6915 }
6916
6917 //================================================================================
6918 /*!
6919  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
6920  * The list of groups must contain at least two groups. The groups have to be disjoint:
6921  * no common element into two different groups.
6922  * The nodes of the internal faces at the boundaries of the groups are doubled.
6923  * Optionally, the internal faces are replaced by flat elements.
6924  * Triangles are transformed into prisms, and quadrangles into hexahedrons.
6925  * The flat elements are stored in groups of volumes.
6926  * These groups are named according to the position of the group in the list:
6927  * 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.
6928  * 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.
6929  * All the flat elements are gathered into the group named "joints3D" (or "joints2D" in 2D situation).
6930  * The flat element of the multiple junctions between the simple junction are stored in a group named "jointsMultiples".
6931  * \param theDomains - list of groups of volumes
6932  * \param createJointElems - if TRUE, create the elements
6933  * \param onAllBoundaries - if TRUE, the nodes and elements are also created on
6934  *        the boundary between \a theDomains and the rest mesh
6935  * \return TRUE if operation has been completed successfully, FALSE otherwise
6936  */
6937 //================================================================================
6938
6939 CORBA::Boolean
6940 SMESH_MeshEditor_i::DoubleNodesOnGroupBoundaries( const SMESH::ListOfGroups& theDomains,
6941                                                   CORBA::Boolean             createJointElems,
6942                                                   CORBA::Boolean             onAllBoundaries )
6943   throw (SALOME::SALOME_Exception)
6944 {
6945   bool isOK = false;
6946
6947   SMESH_TRY;
6948   initData();
6949
6950   SMESHDS_Mesh* aMeshDS = getMeshDS();
6951
6952   // MESSAGE("theDomains.length = "<<theDomains.length());
6953   if ( theDomains.length() <= 1 && !onAllBoundaries )
6954     THROW_SALOME_CORBA_EXCEPTION("At least 2 groups are required.", SALOME::BAD_PARAM);
6955
6956   vector<TIDSortedElemSet> domains;
6957   domains.resize( theDomains.length() );
6958
6959   for ( int i = 0, n = theDomains.length(); i < n; i++ )
6960   {
6961     SMESH::SMESH_GroupBase_var aGrp = theDomains[ i ];
6962     if ( !CORBA::is_nil( aGrp ) /*&& ( aGrp->GetType() != SMESH::NODE )*/ )
6963     {
6964 //      if ( aGrp->GetType() != SMESH::VOLUME )
6965 //        THROW_SALOME_CORBA_EXCEPTION("Not a volume group", SALOME::BAD_PARAM);
6966       SMESH::long_array_var anIDs = aGrp->GetIDs();
6967       arrayToSet( anIDs, aMeshDS, domains[ i ], SMDSAbs_All );
6968     }
6969   }
6970
6971   isOK = getEditor().DoubleNodesOnGroupBoundaries( domains, createJointElems, onAllBoundaries );
6972   // TODO publish the groups of flat elements in study
6973
6974   declareMeshModified( /*isReComputeSafe=*/ !isOK );
6975
6976   // Update Python script
6977   TPythonDump() << "isDone = " << this << ".DoubleNodesOnGroupBoundaries( " << &theDomains
6978                 << ", " << createJointElems << ", " << onAllBoundaries << " )";
6979
6980   SMESH_CATCH( SMESH::throwCorbaException );
6981
6982   myMesh_i->CreateGroupServants(); // publish created groups if any
6983
6984   return isOK;
6985 }
6986
6987 //================================================================================
6988 /*!
6989  * \brief Double nodes on some external faces and create flat elements.
6990  * Flat elements are mainly used by some types of mechanic calculations.
6991  *
6992  * Each group of the list must be constituted of faces.
6993  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
6994  * @param theGroupsOfFaces - list of groups of faces
6995  * @return TRUE if operation has been completed successfully, FALSE otherwise
6996  */
6997 //================================================================================
6998
6999 CORBA::Boolean
7000 SMESH_MeshEditor_i::CreateFlatElementsOnFacesGroups( const SMESH::ListOfGroups& theGroupsOfFaces )
7001   throw (SALOME::SALOME_Exception)
7002 {
7003   SMESH_TRY;
7004   initData();
7005
7006   SMESHDS_Mesh* aMeshDS = getMeshDS();
7007
7008   vector<TIDSortedElemSet> faceGroups;
7009   faceGroups.clear();
7010
7011   for ( int i = 0, n = theGroupsOfFaces.length(); i < n; i++ )
7012   {
7013     SMESH::SMESH_GroupBase_var aGrp = theGroupsOfFaces[ i ];
7014     if ( !CORBA::is_nil( aGrp ) && ( aGrp->GetType() != SMESH::NODE ) )
7015     {
7016       TIDSortedElemSet faceGroup;
7017       faceGroup.clear();
7018       faceGroups.push_back(faceGroup);
7019       SMESH::long_array_var anIDs = aGrp->GetIDs();
7020       arrayToSet( anIDs, aMeshDS, faceGroups[ i ], SMDSAbs_All );
7021     }
7022   }
7023
7024   bool aResult = getEditor().CreateFlatElementsOnFacesGroups( faceGroups );
7025   // TODO publish the groups of flat elements in study
7026
7027   declareMeshModified( /*isReComputeSafe=*/ !aResult );
7028
7029   // Update Python script
7030   TPythonDump() << this << ".CreateFlatElementsOnFacesGroups( " << &theGroupsOfFaces << " )";
7031   return aResult;
7032
7033   SMESH_CATCH( SMESH::throwCorbaException );
7034   return false;
7035 }
7036
7037 //================================================================================
7038 /*!
7039  *  \brief Identify all the elements around a geom shape, get the faces delimiting
7040  *         the hole.
7041  *
7042  *  Build groups of volume to remove, groups of faces to replace on the skin of the
7043  *  object, groups of faces to remove inside the object, (idem edges).
7044  *  Build ordered list of nodes at the border of each group of faces to replace
7045  *  (to be used to build a geom subshape).
7046  */
7047 //================================================================================
7048
7049 void SMESH_MeshEditor_i::CreateHoleSkin(CORBA::Double                  radius,
7050                                         GEOM::GEOM_Object_ptr          theShape,
7051                                         const char*                    groupName,
7052                                         const SMESH::double_array&     theNodesCoords,
7053                                         SMESH::array_of_long_array_out GroupsOfNodes)
7054   throw (SALOME::SALOME_Exception)
7055 {
7056   SMESH_TRY;
7057
7058   initData();
7059   std::vector<std::vector<int> > aListOfListOfNodes;
7060   ::SMESH_MeshEditor aMeshEditor( myMesh );
7061
7062   theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
7063   if ( !theNodeSearcher )
7064     theNodeSearcher = SMESH_MeshAlgos::GetNodeSearcher( *getMeshDS() );
7065
7066   vector<double> nodesCoords;
7067   for ( CORBA::ULong i = 0; i < theNodesCoords.length(); i++)
7068   {
7069     nodesCoords.push_back( theNodesCoords[i] );
7070   }
7071
7072   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
7073   aMeshEditor.CreateHoleSkin(radius, aShape, theNodeSearcher, groupName,
7074                              nodesCoords, aListOfListOfNodes);
7075
7076   GroupsOfNodes = new SMESH::array_of_long_array;
7077   GroupsOfNodes->length( aListOfListOfNodes.size() );
7078   std::vector<std::vector<int> >::iterator llIt = aListOfListOfNodes.begin();
7079   for ( CORBA::Long i = 0; llIt != aListOfListOfNodes.end(); llIt++, i++ )
7080   {
7081     vector<int>& aListOfNodes = *llIt;
7082     vector<int>::iterator lIt = aListOfNodes.begin();;
7083     SMESH::long_array& aGroup = (*GroupsOfNodes)[ i ];
7084     aGroup.length( aListOfNodes.size() );
7085     for ( int j = 0; lIt != aListOfNodes.end(); lIt++, j++ )
7086       aGroup[ j ] = (*lIt);
7087   }
7088   TPythonDump() << "lists_nodes = " << this << ".CreateHoleSkin( "
7089                 << radius << ", "
7090                 << theShape
7091                 << ", '" << groupName << "', "
7092                 << theNodesCoords << " )";
7093
7094   SMESH_CATCH( SMESH::throwCorbaException );
7095 }
7096
7097 // issue 20749 ===================================================================
7098 /*!
7099  * \brief Creates missing boundary elements
7100  *  \param elements - elements whose boundary is to be checked
7101  *  \param dimension - defines type of boundary elements to create
7102  *  \param groupName - a name of group to store created boundary elements in,
7103  *                     "" means not to create the group
7104  *  \param meshName - a name of new mesh to store created boundary elements in,
7105  *                     "" means not to create the new mesh
7106  *  \param toCopyElements - if true, the checked elements will be copied into the new mesh
7107  *  \param toCopyExistingBondary - if true, not only new but also pre-existing
7108  *                                boundary elements will be copied into the new mesh
7109  *  \param group - returns the create group, if any
7110  *  \retval SMESH::SMESH_Mesh - the mesh where elements were added to
7111  */
7112 // ================================================================================
7113
7114 SMESH::SMESH_Mesh_ptr
7115 SMESH_MeshEditor_i::MakeBoundaryMesh(SMESH::SMESH_IDSource_ptr idSource,
7116                                      SMESH::Bnd_Dimension      dim,
7117                                      const char*               groupName,
7118                                      const char*               meshName,
7119                                      CORBA::Boolean            toCopyElements,
7120                                      CORBA::Boolean            toCopyExistingBondary,
7121                                      SMESH::SMESH_Group_out    group)
7122   throw (SALOME::SALOME_Exception)
7123 {
7124   SMESH_TRY;
7125   initData();
7126
7127   if ( dim > SMESH::BND_1DFROM2D )
7128     THROW_SALOME_CORBA_EXCEPTION("Invalid boundary dimension", SALOME::BAD_PARAM);
7129
7130   SMESHDS_Mesh* aMeshDS = getMeshDS();
7131
7132   SMESH::SMESH_Mesh_var mesh_var;
7133   SMESH::SMESH_Group_var group_var;
7134
7135   TPythonDump pyDump;
7136
7137   TIDSortedElemSet elements;
7138   SMDSAbs_ElementType elemType = (dim == SMESH::BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
7139   if ( idSourceToSet( idSource, aMeshDS, elements, elemType,/*emptyIfIsMesh=*/true ))
7140   {
7141     // mesh to fill in
7142     mesh_var =
7143       strlen(meshName) ? makeMesh(meshName) : SMESH::SMESH_Mesh::_duplicate(myMesh_i->_this());
7144     SMESH_Mesh_i* mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh_var );
7145     // other mesh
7146     SMESH_Mesh* smesh_mesh = (mesh_i==myMesh_i) ? (SMESH_Mesh*)0 : &mesh_i->GetImpl();
7147
7148     // group of new boundary elements
7149     SMESH_Group* smesh_group = 0;
7150     if ( strlen(groupName) )
7151     {
7152       group_var = mesh_i->CreateGroup( SMESH::ElementType(int(elemType)-1),groupName);
7153       if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( group_var ))
7154         smesh_group = group_i->GetSmeshGroup();
7155     }
7156
7157     // do it
7158     getEditor().MakeBoundaryMesh( elements,
7159                                   ::SMESH_MeshEditor::Bnd_Dimension(dim),
7160                                   smesh_group,
7161                                   smesh_mesh,
7162                                   toCopyElements,
7163                                   toCopyExistingBondary);
7164
7165     if ( smesh_mesh )
7166       smesh_mesh->GetMeshDS()->Modified();
7167   }
7168
7169   const char* dimName[] = { "BND_2DFROM3D", "BND_1DFROM3D", "BND_1DFROM2D" };
7170
7171   // result of MakeBoundaryMesh() is a tuple (mesh, group)
7172   if ( mesh_var->_is_nil() )
7173     pyDump << myMesh_i->_this() << ", ";
7174   else
7175     pyDump << mesh_var << ", ";
7176   if ( group_var->_is_nil() )
7177     pyDump << "_NoneGroup = "; // assignment to None is forbidden
7178   else
7179     pyDump << group_var << " = ";
7180   pyDump << this << ".MakeBoundaryMesh( "
7181          << idSource << ", "
7182          << "SMESH." << dimName[int(dim)] << ", "
7183          << "'" << groupName << "', "
7184          << "'" << meshName<< "', "
7185          << toCopyElements << ", "
7186          << toCopyExistingBondary << ")";
7187
7188   group = group_var._retn();
7189   return mesh_var._retn();
7190
7191   SMESH_CATCH( SMESH::throwCorbaException );
7192   return SMESH::SMESH_Mesh::_nil();
7193 }
7194
7195 //================================================================================
7196 /*!
7197  * \brief Creates missing boundary elements
7198  *  \param dimension - defines type of boundary elements to create
7199  *  \param groupName - a name of group to store all boundary elements in,
7200  *    "" means not to create the group
7201  *  \param meshName - a name of a new mesh, which is a copy of the initial 
7202  *    mesh + created boundary elements; "" means not to create the new mesh
7203  *  \param toCopyAll - if true, the whole initial mesh will be copied into
7204  *    the new mesh else only boundary elements will be copied into the new mesh
7205  *  \param groups - optional groups of elements to make boundary around
7206  *  \param mesh - returns the mesh where elements were added to
7207  *  \param group - returns the created group, if any
7208  *  \retval long - number of added boundary elements
7209  */
7210 //================================================================================
7211
7212 CORBA::Long SMESH_MeshEditor_i::MakeBoundaryElements(SMESH::Bnd_Dimension dim,
7213                                                      const char* groupName,
7214                                                      const char* meshName,
7215                                                      CORBA::Boolean toCopyAll,
7216                                                      const SMESH::ListOfIDSources& groups,
7217                                                      SMESH::SMESH_Mesh_out mesh,
7218                                                      SMESH::SMESH_Group_out group)
7219   throw (SALOME::SALOME_Exception)
7220 {
7221   SMESH_TRY;
7222   initData();
7223
7224   if ( dim > SMESH::BND_1DFROM2D )
7225     THROW_SALOME_CORBA_EXCEPTION("Invalid boundary dimension", SALOME::BAD_PARAM);
7226
7227   // separate groups belonging to this and other mesh
7228   SMESH::ListOfIDSources_var groupsOfThisMesh  = new SMESH::ListOfIDSources;
7229   SMESH::ListOfIDSources_var groupsOfOtherMesh = new SMESH::ListOfIDSources;
7230   groupsOfThisMesh ->length( groups.length() );
7231   groupsOfOtherMesh->length( groups.length() );
7232   int nbGroups = 0, nbGroupsOfOtherMesh = 0;
7233   for ( CORBA::ULong i = 0; i < groups.length(); ++i )
7234   {
7235     SMESH::SMESH_Mesh_var m = groups[i]->GetMesh();
7236     if ( !m->_is_nil() && myMesh_i != SMESH::DownCast<SMESH_Mesh_i*>( m ))
7237       groupsOfOtherMesh[ nbGroupsOfOtherMesh++ ] = groups[i];
7238     else
7239       groupsOfThisMesh[ nbGroups++ ] = groups[i];
7240     if ( SMESH::DownCast<SMESH_Mesh_i*>( groups[i] ))
7241       THROW_SALOME_CORBA_EXCEPTION("expected a group but received a mesh", SALOME::BAD_PARAM);
7242   }
7243   groupsOfThisMesh->length( nbGroups );
7244   groupsOfOtherMesh->length( nbGroupsOfOtherMesh );
7245
7246   int nbAdded = 0;
7247   TPythonDump pyDump;
7248
7249   if ( nbGroupsOfOtherMesh > 0 )
7250   {
7251     // process groups belonging to another mesh
7252     SMESH::SMESH_Mesh_var    otherMesh = groupsOfOtherMesh[0]->GetMesh();
7253     SMESH::SMESH_MeshEditor_var editor = otherMesh->GetMeshEditor();
7254     nbAdded += editor->MakeBoundaryElements( dim, groupName, meshName, toCopyAll,
7255                                              groupsOfOtherMesh, mesh, group );
7256   }
7257
7258   SMESH::SMESH_Mesh_var mesh_var;
7259   SMESH::SMESH_Group_var group_var;
7260
7261   // get mesh to fill
7262   mesh_var = SMESH::SMESH_Mesh::_duplicate( myMesh_i->_this() );
7263   const bool toCopyMesh = ( strlen( meshName ) > 0 );
7264   if ( toCopyMesh )
7265   {
7266     if ( toCopyAll )
7267       mesh_var = SMESH_Gen_i::GetSMESHGen()->CopyMesh(mesh_var,
7268                                                       meshName,
7269                                                       /*toCopyGroups=*/false,
7270                                                       /*toKeepIDs=*/true);
7271     else
7272       mesh_var = makeMesh(meshName);
7273   }
7274   SMESH_Mesh_i* mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh_var );
7275   SMESH_Mesh*  tgtMesh = &mesh_i->GetImpl();
7276
7277   // source mesh
7278   SMESH_Mesh*     srcMesh = ( toCopyMesh && !toCopyAll ) ? myMesh : tgtMesh;
7279   SMESHDS_Mesh* srcMeshDS = srcMesh->GetMeshDS();
7280
7281   // group of boundary elements
7282   SMESH_Group* smesh_group = 0;
7283   SMDSAbs_ElementType elemType = (dim == SMESH::BND_2DFROM3D) ? SMDSAbs_Volume : SMDSAbs_Face;
7284   if ( strlen( groupName ))
7285   {
7286     SMESH::ElementType groupType = SMESH::ElementType( int(elemType)-1 );
7287     group_var = mesh_i->CreateGroup( groupType, groupName );
7288     if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( group_var ))
7289       smesh_group = group_i->GetSmeshGroup();
7290   }
7291
7292   TIDSortedElemSet elements;
7293
7294   if ( groups.length() > 0 )
7295   {
7296     for ( int i = 0; i < nbGroups; ++i )
7297     {
7298       elements.clear();
7299       if ( idSourceToSet( groupsOfThisMesh[i], srcMeshDS, elements, elemType,/*emptyIfIsMesh=*/0 ))
7300       {
7301         SMESH::Bnd_Dimension bdim = 
7302           ( elemType == SMDSAbs_Volume ) ? SMESH::BND_2DFROM3D : SMESH::BND_1DFROM2D;
7303         nbAdded += getEditor().MakeBoundaryMesh( elements,
7304                                                  ::SMESH_MeshEditor::Bnd_Dimension(bdim),
7305                                                  smesh_group,
7306                                                  tgtMesh,
7307                                                  /*toCopyElements=*/false,
7308                                                  /*toCopyExistingBondary=*/srcMesh != tgtMesh,
7309                                                  /*toAddExistingBondary=*/true,
7310                                                  /*aroundElements=*/true);
7311       }
7312     }
7313   }
7314   else
7315   {
7316     nbAdded += getEditor().MakeBoundaryMesh( elements,
7317                                              ::SMESH_MeshEditor::Bnd_Dimension(dim),
7318                                              smesh_group,
7319                                              tgtMesh,
7320                                              /*toCopyElements=*/false,
7321                                              /*toCopyExistingBondary=*/srcMesh != tgtMesh,
7322                                              /*toAddExistingBondary=*/true);
7323   }
7324   tgtMesh->GetMeshDS()->Modified();
7325
7326   const char* dimName[] = { "BND_2DFROM3D", "BND_1DFROM3D", "BND_1DFROM2D" };
7327
7328   // result of MakeBoundaryElements() is a tuple (nb, mesh, group)
7329   pyDump << "nbAdded, ";
7330   if ( mesh_var->_is_nil() )
7331     pyDump << myMesh_i->_this() << ", ";
7332   else
7333     pyDump << mesh_var << ", ";
7334   if ( group_var->_is_nil() )
7335     pyDump << "_NoneGroup = "; // assignment to None is forbidden
7336   else
7337     pyDump << group_var << " = ";
7338   pyDump << this << ".MakeBoundaryElements( "
7339          << "SMESH." << dimName[int(dim)] << ", "
7340          << "'" << groupName << "', "
7341          << "'" << meshName<< "', "
7342          << toCopyAll << ", "
7343          << groups << ")";
7344
7345   mesh  = mesh_var._retn();
7346   group = group_var._retn();
7347   return nbAdded;
7348
7349   SMESH_CATCH( SMESH::throwCorbaException );
7350   return 0;
7351 }
7352
7353 //================================================================================
7354 /*!
7355  * \brief Create a polyline consisting of 1D mesh elements each lying on a 2D element of
7356  *        the initial mesh. Positions of new nodes are found by cutting the mesh by the
7357  *        plane passing through pairs of points specified by each PolySegment structure.
7358  *        If there are several paths connecting a pair of points, the shortest path is
7359  *        selected by the module. Position of the cutting plane is defined by the two
7360  *        points and an optional vector lying on the plane specified by a PolySegment.
7361  *        By default the vector is defined by Mesh module as following. A middle point
7362  *        of the two given points is computed. The middle point is projected to the mesh.
7363  *        The vector goes from the middle point to the projection point. In case of planar
7364  *        mesh, the vector is normal to the mesh.
7365  *  \param [inout] segments - PolySegment's defining positions of cutting planes.
7366  *        Return the used vector and position of the middle point.
7367  *  \param [in] groupName - optional name of a group where created mesh segments will
7368  *        be added.
7369  */
7370 //================================================================================
7371
7372 void SMESH_MeshEditor_i::MakePolyLine(SMESH::ListOfPolySegments& theSegments,
7373                                       const char*                theGroupName)
7374   throw (SALOME::SALOME_Exception)
7375 {
7376   if ( theSegments.length() == 0 )
7377     THROW_SALOME_CORBA_EXCEPTION("No segments given", SALOME::BAD_PARAM );
7378   if ( myMesh->NbFaces() == 0 )
7379     THROW_SALOME_CORBA_EXCEPTION("No faces in the mesh", SALOME::BAD_PARAM );
7380
7381   SMESH_TRY;
7382   initData(/*deleteSearchers=*/false);
7383
7384   SMESHDS_Group* groupDS = 0;
7385   SMESHDS_Mesh*   meshDS = getMeshDS();
7386   if ( myIsPreviewMode ) // copy faces to the tmp mesh
7387   {
7388     TPreviewMesh * tmpMesh = getPreviewMesh( SMDSAbs_Edge );
7389     SMDS_ElemIteratorPtr faceIt = getMeshDS()->elementsIterator( SMDSAbs_Face );
7390     while ( faceIt->more() )
7391       tmpMesh->Copy( faceIt->next() );
7392     meshDS = tmpMesh->GetMeshDS();
7393   }
7394   else if ( theGroupName[0] ) // find/create a group of segments
7395   {
7396     // SMESH_Mesh::GroupIteratorPtr grpIt = myMesh->GetGroups();
7397     // while ( !groupDS && grpIt->more() )
7398     // {
7399     //   SMESH_Group* group = grpIt->next();
7400     //   if ( group->GetGroupDS()->GetType() == SMDSAbs_Edge &&
7401     //        strcmp( group->GetName(), theGroupName ) == 0 )
7402     //   {
7403     //     groupDS = dynamic_cast< SMESHDS_Group* >( group->GetGroupDS() );
7404     //   }
7405     // }
7406     if ( !groupDS )
7407     {
7408       SMESH::SMESH_Group_var groupVar = myMesh_i->CreateGroup( SMESH::EDGE, theGroupName );
7409
7410       if ( SMESH_Group_i* groupImpl = SMESH::DownCast<SMESH_Group_i*>( groupVar ))
7411         groupDS = dynamic_cast< SMESHDS_Group* >( groupImpl->GetGroupDS() );
7412     }
7413   }
7414
7415   // convert input polySegments
7416   SMESH_MeshAlgos::TListOfPolySegments segments( theSegments.length() );
7417   for ( CORBA::ULong i = 0; i < theSegments.length(); ++i )
7418   {
7419     SMESH::PolySegment&            segIn = theSegments[ i ];
7420     SMESH_MeshAlgos::PolySegment& segOut = segments[ i ];
7421     segOut.myNode1[0] = meshDS->FindNode( segIn.node1ID1 );
7422     segOut.myNode2[0] = meshDS->FindNode( segIn.node1ID2 );
7423     segOut.myNode1[1] = meshDS->FindNode( segIn.node2ID1 );
7424     segOut.myNode2[1] = meshDS->FindNode( segIn.node2ID2 );
7425     segOut.myXYZ[0].SetCoord( segIn.xyz1.x,
7426                               segIn.xyz1.y,
7427                               segIn.xyz1.z);
7428     segOut.myXYZ[1].SetCoord( segIn.xyz2.x,
7429                               segIn.xyz2.y,
7430                               segIn.xyz2.z);
7431     segOut.myVector.SetCoord( segIn.vector.PS.x,
7432                               segIn.vector.PS.y,
7433                               segIn.vector.PS.z );
7434   }
7435
7436   // get a static ElementSearcher
7437   SMESH::SMESH_IDSource_var idSource = SMESH::SMESH_IDSource::_narrow( myMesh_i->_this() );
7438   theSearchersDeleter.Set( myMesh, getPartIOR( idSource, SMESH::FACE ));
7439   if ( !theElementSearcher )
7440     theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() );
7441
7442   // compute
7443   std::vector<const SMDS_MeshElement*> newEdges;
7444   std::vector<const SMDS_MeshNode*>    newNodes;
7445   SMESH_MeshAlgos::MakePolyLine( meshDS, segments, newEdges, newNodes,
7446                                  groupDS ? &groupDS->SMDSGroup() : 0,
7447                                  theElementSearcher );
7448
7449   const_cast< SMESH_SequenceOfElemPtr& >( getEditor().GetLastCreatedElems() ).
7450     swap( newEdges );
7451   const_cast< SMESH_SequenceOfElemPtr& >( getEditor().GetLastCreatedNodes() ).
7452     assign( newNodes.begin(), newNodes.end() );
7453
7454   // return vectors
7455   if ( myIsPreviewMode )
7456   {
7457     for ( CORBA::ULong i = 0; i < theSegments.length(); ++i )
7458     {
7459       SMESH::PolySegment&           segOut = theSegments[ i ];
7460       SMESH_MeshAlgos::PolySegment& segIn = segments[ i ];
7461       segOut.vector.PS.x = segIn.myVector.X();
7462       segOut.vector.PS.y = segIn.myVector.Y();
7463       segOut.vector.PS.z = segIn.myVector.Z();
7464     }
7465   }
7466   else
7467   {
7468     TPythonDump() << "_segments = []";
7469     for ( CORBA::ULong i = 0; i < theSegments.length(); ++i )
7470     {
7471       SMESH::PolySegment& segIn = theSegments[ i ];
7472       TPythonDump() << "_segments.append( SMESH.PolySegment( "
7473                     << segIn.node1ID1 << ", "
7474                     << segIn.node1ID2 << ", "
7475                     << segIn.node2ID1 << ", "
7476                     << segIn.node2ID2 << ", "
7477                     << "smeshBuilder.MakeDirStruct( "
7478                     << segIn.vector.PS.x << ", "
7479                     << segIn.vector.PS.y << ", "
7480                     << segIn.vector.PS.z << ")))";
7481     }
7482     TPythonDump() << this << ".MakePolyLine( _segments, '" << theGroupName << "')";
7483   }
7484   meshDS->Modified();
7485   SMESH_CATCH( SMESH::throwCorbaException );
7486   return;
7487 }
7488
7489 //================================================================================
7490 /*!
7491  * \brief Create a slot of given width around given 1D elements lying on a triangle mesh.
7492  *        The slot is constructed by cutting faces by cylindrical surfaces made
7493  *        around each segment. Segments are expected to be created by MakePolyLine().
7494  * \return Edges located at the slot boundary
7495  */
7496 //================================================================================
7497
7498 SMESH::ListOfEdges* SMESH_MeshEditor_i::MakeSlot(SMESH::SMESH_GroupBase_ptr theSegments,
7499                                                  CORBA::Double              theWidth)
7500   throw (SALOME::SALOME_Exception)
7501 {
7502   if ( CORBA::is_nil( theSegments ) ||
7503        theSegments->GetType() != SMESH::EDGE )
7504     THROW_SALOME_CORBA_EXCEPTION("No segments given", SALOME::BAD_PARAM );
7505   if ( myMesh->NbFaces() == 0 )
7506     THROW_SALOME_CORBA_EXCEPTION("No faces in the mesh", SALOME::BAD_PARAM );
7507
7508   SMESH::ListOfEdges_var resultEdges = new SMESH::ListOfEdges;
7509
7510   SMESH_TRY;
7511   initData(/*deleteSearchers=*/false);
7512
7513   SMESHDS_Mesh* meshDS = getMeshDS();
7514
7515   // get standalone face groups to be updated
7516   std::vector< SMDS_MeshGroup* > faceGroups;
7517   const std::set<SMESHDS_GroupBase*>& allGroups = meshDS->GetGroups();
7518   std::set<SMESHDS_GroupBase*>::const_iterator grIt = allGroups.begin();
7519   for ( ; grIt != allGroups.end(); ++grIt )
7520     if ( const SMESHDS_Group* gr = dynamic_cast< const SMESHDS_Group* >( *grIt ))
7521       if ( gr->GetType() == SMDSAbs_Face )
7522         faceGroups.push_back( & const_cast< SMESHDS_Group* >( gr )->SMDSGroup() );
7523
7524   std::vector< SMESH_MeshAlgos::Edge > edges =
7525     SMESH_MeshAlgos::MakeSlot( SMESH_Mesh_i::GetElements( theSegments, SMESH::EDGE ),
7526                                theWidth, meshDS, faceGroups );
7527
7528   resultEdges->length( edges.size() );
7529   for ( size_t i = 0; i < edges.size(); ++i )
7530   {
7531     resultEdges[ i ].node1  = edges[i]._node1->GetID();
7532     resultEdges[ i ].node2  = edges[i]._node2->GetID();
7533     resultEdges[ i ].medium = edges[i]._medium ? edges[i]._medium->GetID() : 0;
7534   }
7535
7536   meshDS->Modified();
7537   SMESH_CATCH( SMESH::throwCorbaException );
7538
7539   TSearchersDeleter::Delete(); // face searcher becomes invalid as some faces were removed
7540
7541   return resultEdges._retn();
7542 }