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