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