Salome HOME
fix creation of biquadratic pentahedron from menu add element
[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 : convError
4598 //purpose  :
4599 //=======================================================================
4600
4601 #define RETCASE(enm) case ::SMESH_MeshEditor::enm: return SMESH::SMESH_MeshEditor::enm;
4602
4603 static SMESH::SMESH_MeshEditor::Sew_Error convError( const::SMESH_MeshEditor::Sew_Error e )
4604 {
4605   switch ( e ) {
4606     RETCASE( SEW_OK );
4607     RETCASE( SEW_BORDER1_NOT_FOUND );
4608     RETCASE( SEW_BORDER2_NOT_FOUND );
4609     RETCASE( SEW_BOTH_BORDERS_NOT_FOUND );
4610     RETCASE( SEW_BAD_SIDE_NODES );
4611     RETCASE( SEW_VOLUMES_TO_SPLIT );
4612     RETCASE( SEW_DIFF_NB_OF_ELEMENTS );
4613     RETCASE( SEW_TOPO_DIFF_SETS_OF_ELEMENTS );
4614     RETCASE( SEW_BAD_SIDE1_NODES );
4615     RETCASE( SEW_BAD_SIDE2_NODES );
4616     RETCASE( SEW_INTERNAL_ERROR );
4617   }
4618   return SMESH::SMESH_MeshEditor::SEW_OK;
4619 }
4620
4621 //=======================================================================
4622 /*!
4623  * Returns groups of FreeBorder's coincident within the given tolerance.
4624  * If the tolerance <= 0.0 then one tenth of an average size of elements adjacent
4625  * to free borders being compared is used.
4626  */
4627 //=======================================================================
4628
4629 SMESH::CoincidentFreeBorders*
4630 SMESH_MeshEditor_i::FindCoincidentFreeBorders(CORBA::Double tolerance)
4631 {
4632   SMESH::CoincidentFreeBorders_var aCFB = new SMESH::CoincidentFreeBorders;
4633
4634   SMESH_TRY;
4635
4636   SMESH_MeshAlgos::CoincidentFreeBorders cfb;
4637   SMESH_MeshAlgos::FindCoincidentFreeBorders( *getMeshDS(), tolerance, cfb );
4638
4639   // copy free borders
4640   aCFB->borders.length( cfb._borders.size() );
4641   for ( size_t i = 0; i < cfb._borders.size(); ++i )
4642   {
4643     SMESH_MeshAlgos::TFreeBorder& nodes = cfb._borders[i];
4644     SMESH::FreeBorder&             aBRD = aCFB->borders[i];
4645     aBRD.nodeIDs.length( nodes.size() );
4646     for ( size_t iN = 0; iN < nodes.size(); ++iN )
4647       aBRD.nodeIDs[ iN ] = nodes[ iN ]->GetID();
4648   }
4649
4650   // copy coincident parts
4651   aCFB->coincidentGroups.length( cfb._coincidentGroups.size() );
4652   for ( size_t i = 0; i < cfb._coincidentGroups.size(); ++i )
4653   {
4654     SMESH_MeshAlgos::TCoincidentGroup& grp = cfb._coincidentGroups[i];
4655     SMESH::FreeBordersGroup&          aGRP = aCFB->coincidentGroups[i];
4656     aGRP.length( grp.size() );
4657     for ( size_t iP = 0; iP < grp.size(); ++iP )
4658     {
4659       SMESH_MeshAlgos::TFreeBorderPart& part = grp[ iP ];
4660       SMESH::FreeBorderPart&           aPART = aGRP[ iP ];
4661       aPART.border   = part._border;
4662       aPART.node1    = part._node1;
4663       aPART.node2    = part._node2;
4664       aPART.nodeLast = part._nodeLast;
4665     }
4666   }
4667   SMESH_CATCH( SMESH::doNothing );
4668
4669   TPythonDump() << "CoincidentFreeBorders = "
4670                 << this << ".FindCoincidentFreeBorders( " << tolerance << " )";
4671
4672   return aCFB._retn();
4673 }
4674
4675 //=======================================================================
4676 /*!
4677  * Sew FreeBorder's of each group
4678  */
4679 //=======================================================================
4680
4681 CORBA::Short SMESH_MeshEditor_i::
4682 SewCoincidentFreeBorders(const SMESH::CoincidentFreeBorders& freeBorders,
4683                          CORBA::Boolean                      createPolygons,
4684                          CORBA::Boolean                      createPolyhedra)
4685   throw (SALOME::SALOME_Exception)
4686 {
4687   CORBA::Short nbSewed = 0;
4688
4689   SMESH_MeshAlgos::TFreeBorderVec groups;
4690   SMESH_MeshAlgos::TFreeBorder    borderNodes; // triples of nodes for every FreeBorderPart
4691
4692   // check the input and collect nodes
4693   for ( CORBA::ULong i = 0; i < freeBorders.coincidentGroups.length(); ++i )
4694   {
4695     borderNodes.clear();
4696     const SMESH::FreeBordersGroup& aGRP = freeBorders.coincidentGroups[ i ];
4697     for ( CORBA::ULong iP = 0; iP < aGRP.length(); ++iP )
4698     {
4699       const SMESH::FreeBorderPart& aPART = aGRP[ iP ];
4700       if ( aPART.border < 0 || aPART.border >= (int) freeBorders.borders.length() )
4701         THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::border index", SALOME::BAD_PARAM);
4702
4703       const SMESH::FreeBorder& aBRD = freeBorders.borders[ aPART.border ];
4704
4705       if ( aPART.node1 < 0 || aPART.node1 > (int) aBRD.nodeIDs.length() )
4706         THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::node1", SALOME::BAD_PARAM);
4707       if ( aPART.node2 < 0 || aPART.node2 > (int) aBRD.nodeIDs.length() )
4708         THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::node2", SALOME::BAD_PARAM);
4709       if ( aPART.nodeLast < 0 || aPART.nodeLast > (int) aBRD.nodeIDs.length() )
4710         THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::nodeLast", SALOME::BAD_PARAM);
4711
4712       // do not keep these nodes for further sewing as nodes can be removed by the sewing
4713       const SMDS_MeshNode* n1 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.node1    ]);
4714       const SMDS_MeshNode* n2 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.node2    ]);
4715       const SMDS_MeshNode* n3 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.nodeLast ]);
4716       if ( !n1)
4717         THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::node1", SALOME::BAD_PARAM);
4718       if ( !n2 )
4719         THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::node2", SALOME::BAD_PARAM);
4720       if ( !n3 )
4721         THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::nodeLast", SALOME::BAD_PARAM);
4722
4723       borderNodes.push_back( n1 );
4724       borderNodes.push_back( n2 );
4725       borderNodes.push_back( n3 );
4726     }
4727     groups.push_back( borderNodes );
4728   }
4729
4730   // SewFreeBorder() can merge nodes, thus nodes stored in 'groups' can become dead;
4731   // to get nodes that replace other nodes during merge we create 0D elements
4732   // on each node and MergeNodes() will replace underlying nodes of 0D elements by
4733   // new ones.
4734
4735   vector< const SMDS_MeshElement* > tmp0Delems;
4736   for ( size_t i = 0; i < groups.size(); ++i )
4737   {
4738     SMESH_MeshAlgos::TFreeBorder& nodes = groups[i];
4739     for ( size_t iN = 0; iN < nodes.size(); ++iN )
4740     {
4741       SMDS_ElemIteratorPtr it0D = nodes[iN]->GetInverseElementIterator(SMDSAbs_0DElement);
4742       if ( it0D->more() )
4743         tmp0Delems.push_back( it0D->next() );
4744       else
4745         tmp0Delems.push_back( getMeshDS()->Add0DElement( nodes[iN] ));
4746     }
4747   }
4748
4749   // cout << endl << "INIT" << endl;
4750   // for ( size_t i = 0; i < tmp0Delems.size(); ++i )
4751   // {
4752   //   cout << i << " ";
4753   //   if ( i % 3 == 0 ) cout << "^ ";
4754   //   tmp0Delems[i]->GetNode(0)->Print( cout );
4755   // }
4756
4757   SMESH_TRY;
4758
4759   ::SMESH_MeshEditor::Sew_Error res, ok = ::SMESH_MeshEditor::SEW_OK;
4760   int i0D = 0;
4761   for ( size_t i = 0; i < groups.size(); ++i )
4762   {
4763     bool isBordToBord = true;
4764     bool   groupSewed = false;
4765     SMESH_MeshAlgos::TFreeBorder& nodes = groups[i];
4766     for ( size_t iN = 3; iN+2 < nodes.size(); iN += 3 )
4767     {
4768       const SMDS_MeshNode* n0 = tmp0Delems[ i0D + 0 ]->GetNode( 0 );
4769       const SMDS_MeshNode* n1 = tmp0Delems[ i0D + 1 ]->GetNode( 0 );
4770       const SMDS_MeshNode* n2 = tmp0Delems[ i0D + 2 ]->GetNode( 0 );
4771
4772       const SMDS_MeshNode* n3 = tmp0Delems[ i0D + 0 + iN ]->GetNode( 0 );
4773       const SMDS_MeshNode* n4 = tmp0Delems[ i0D + 1 + iN ]->GetNode( 0 );
4774       const SMDS_MeshNode* n5 = tmp0Delems[ i0D + 2 + iN ]->GetNode( 0 );
4775
4776       if ( !n0 || !n1 || !n2 || !n3 || !n4 || !n5 )
4777         continue;
4778
4779       // TIDSortedElemSet emptySet, avoidSet;
4780       // if ( !SMESH_MeshAlgos::FindFaceInSet( n0, n1, emptySet, avoidSet))
4781       // {
4782       //   cout << "WRONG 2nd 1" << endl;
4783       //   n0->Print( cout );
4784       //   n1->Print( cout );
4785       // }
4786       // if ( !SMESH_MeshAlgos::FindFaceInSet( n3, n4, emptySet, avoidSet))
4787       // {
4788       //   cout << "WRONG 2nd 2" << endl;
4789       //   n3->Print( cout );
4790       //   n4->Print( cout );
4791       // }
4792
4793       if ( !isBordToBord )
4794       {
4795         n1 = n2; // at border-to-side sewing only last side node (n1) is needed
4796         n2 = 0;  //  and n2 is not used
4797       }
4798       // 1st border moves to 2nd
4799       res = getEditor().SewFreeBorder( n3, n4, n5 ,// 1st
4800                                        n0 ,n1 ,n2 ,// 2nd
4801                                        /*2ndIsFreeBorder=*/ isBordToBord,
4802                                        createPolygons, createPolyhedra);
4803       groupSewed = ( res == ok );
4804
4805       isBordToBord = false;
4806       // cout << endl << "SEWED GROUP " << i << " PART " << iN / 3 << endl;
4807       // for ( size_t t = 0; t < tmp0Delems.size(); ++t )
4808       // {
4809       //   cout << t << " ";
4810       //   if ( t % 3 == 0 ) cout << "^ ";
4811       //   tmp0Delems[t]->GetNode(0)->Print( cout );
4812       // }
4813     }
4814     i0D += nodes.size();
4815     nbSewed += groupSewed;
4816   }
4817
4818   TPythonDump() << "nbSewed = " << this << ".SewCoincidentFreeBorders( "
4819                 << freeBorders     << ", "
4820                 << createPolygons  << ", "
4821                 << createPolyhedra << " )";
4822
4823   SMESH_CATCH( SMESH::doNothing );
4824
4825   declareMeshModified( /*isReComputeSafe=*/false );
4826
4827   // remove tmp 0D elements
4828   SMESH_TRY;
4829   set< const SMDS_MeshElement* > removed0D;
4830   for ( size_t i = 0; i < tmp0Delems.size(); ++i )
4831   {
4832     if ( removed0D.insert( tmp0Delems[i] ).second )
4833       getMeshDS()->RemoveFreeElement( tmp0Delems[i], /*sm=*/0, /*fromGroups=*/false );
4834   }
4835   SMESH_CATCH( SMESH::throwCorbaException );
4836
4837   return nbSewed;
4838 }
4839
4840 //=======================================================================
4841 //function : SewFreeBorders
4842 //purpose  :
4843 //=======================================================================
4844
4845 SMESH::SMESH_MeshEditor::Sew_Error
4846 SMESH_MeshEditor_i::SewFreeBorders(CORBA::Long FirstNodeID1,
4847                                    CORBA::Long SecondNodeID1,
4848                                    CORBA::Long LastNodeID1,
4849                                    CORBA::Long FirstNodeID2,
4850                                    CORBA::Long SecondNodeID2,
4851                                    CORBA::Long LastNodeID2,
4852                                    CORBA::Boolean CreatePolygons,
4853                                    CORBA::Boolean CreatePolyedrs)
4854   throw (SALOME::SALOME_Exception)
4855 {
4856   SMESH_TRY;
4857   initData();
4858
4859   SMESHDS_Mesh* aMesh = getMeshDS();
4860
4861   const SMDS_MeshNode* aBorderFirstNode  = aMesh->FindNode( FirstNodeID1  );
4862   const SMDS_MeshNode* aBorderSecondNode = aMesh->FindNode( SecondNodeID1 );
4863   const SMDS_MeshNode* aBorderLastNode   = aMesh->FindNode( LastNodeID1   );
4864   const SMDS_MeshNode* aSide2FirstNode   = aMesh->FindNode( FirstNodeID2  );
4865   const SMDS_MeshNode* aSide2SecondNode  = aMesh->FindNode( SecondNodeID2 );
4866   const SMDS_MeshNode* aSide2ThirdNode   = aMesh->FindNode( LastNodeID2   );
4867
4868   if (!aBorderFirstNode ||
4869       !aBorderSecondNode||
4870       !aBorderLastNode)
4871     return SMESH::SMESH_MeshEditor::SEW_BORDER1_NOT_FOUND;
4872   if (!aSide2FirstNode  ||
4873       !aSide2SecondNode ||
4874       !aSide2ThirdNode)
4875     return SMESH::SMESH_MeshEditor::SEW_BORDER2_NOT_FOUND;
4876
4877   TPythonDump() << "error = " << this << ".SewFreeBorders( "
4878                 << FirstNodeID1  << ", "
4879                 << SecondNodeID1 << ", "
4880                 << LastNodeID1   << ", "
4881                 << FirstNodeID2  << ", "
4882                 << SecondNodeID2 << ", "
4883                 << LastNodeID2   << ", "
4884                 << CreatePolygons<< ", "
4885                 << CreatePolyedrs<< " )";
4886
4887   SMESH::SMESH_MeshEditor::Sew_Error error =
4888     convError( getEditor().SewFreeBorder (aBorderFirstNode,
4889                                           aBorderSecondNode,
4890                                           aBorderLastNode,
4891                                           aSide2FirstNode,
4892                                           aSide2SecondNode,
4893                                           aSide2ThirdNode,
4894                                           true,
4895                                           CreatePolygons,
4896                                           CreatePolyedrs) );
4897
4898
4899   declareMeshModified( /*isReComputeSafe=*/false );
4900   return error;
4901
4902   SMESH_CATCH( SMESH::throwCorbaException );
4903   return SMESH::SMESH_MeshEditor::Sew_Error(0);
4904 }
4905
4906
4907 //=======================================================================
4908 //function : SewConformFreeBorders
4909 //purpose  :
4910 //=======================================================================
4911
4912 SMESH::SMESH_MeshEditor::Sew_Error
4913 SMESH_MeshEditor_i::SewConformFreeBorders(CORBA::Long FirstNodeID1,
4914                                           CORBA::Long SecondNodeID1,
4915                                           CORBA::Long LastNodeID1,
4916                                           CORBA::Long FirstNodeID2,
4917                                           CORBA::Long SecondNodeID2)
4918   throw (SALOME::SALOME_Exception)
4919 {
4920   SMESH_TRY;
4921   initData();
4922
4923   SMESHDS_Mesh* aMesh = getMeshDS();
4924
4925   const SMDS_MeshNode* aBorderFirstNode  = aMesh->FindNode( FirstNodeID1  );
4926   const SMDS_MeshNode* aBorderSecondNode = aMesh->FindNode( SecondNodeID1 );
4927   const SMDS_MeshNode* aBorderLastNode   = aMesh->FindNode( LastNodeID1   );
4928   const SMDS_MeshNode* aSide2FirstNode   = aMesh->FindNode( FirstNodeID2  );
4929   const SMDS_MeshNode* aSide2SecondNode  = aMesh->FindNode( SecondNodeID2 );
4930   const SMDS_MeshNode* aSide2ThirdNode   = 0;
4931
4932   if (!aBorderFirstNode ||
4933       !aBorderSecondNode||
4934       !aBorderLastNode )
4935     return SMESH::SMESH_MeshEditor::SEW_BORDER1_NOT_FOUND;
4936   if (!aSide2FirstNode  ||
4937       !aSide2SecondNode)
4938     return SMESH::SMESH_MeshEditor::SEW_BORDER2_NOT_FOUND;
4939
4940   TPythonDump() << "error = " << this << ".SewConformFreeBorders( "
4941                 << FirstNodeID1  << ", "
4942                 << SecondNodeID1 << ", "
4943                 << LastNodeID1   << ", "
4944                 << FirstNodeID2  << ", "
4945                 << SecondNodeID2 << " )";
4946
4947   SMESH::SMESH_MeshEditor::Sew_Error error =
4948     convError( getEditor().SewFreeBorder (aBorderFirstNode,
4949                                           aBorderSecondNode,
4950                                           aBorderLastNode,
4951                                           aSide2FirstNode,
4952                                           aSide2SecondNode,
4953                                           aSide2ThirdNode,
4954                                           true,
4955                                           false, false) );
4956
4957   declareMeshModified( /*isReComputeSafe=*/false );
4958   return error;
4959
4960   SMESH_CATCH( SMESH::throwCorbaException );
4961   return SMESH::SMESH_MeshEditor::Sew_Error(0);
4962 }
4963
4964
4965 //=======================================================================
4966 //function : SewBorderToSide
4967 //purpose  :
4968 //=======================================================================
4969
4970 SMESH::SMESH_MeshEditor::Sew_Error
4971 SMESH_MeshEditor_i::SewBorderToSide(CORBA::Long FirstNodeIDOnFreeBorder,
4972                                     CORBA::Long SecondNodeIDOnFreeBorder,
4973                                     CORBA::Long LastNodeIDOnFreeBorder,
4974                                     CORBA::Long FirstNodeIDOnSide,
4975                                     CORBA::Long LastNodeIDOnSide,
4976                                     CORBA::Boolean CreatePolygons,
4977                                     CORBA::Boolean CreatePolyedrs)
4978   throw (SALOME::SALOME_Exception)
4979 {
4980   SMESH_TRY;
4981   initData();
4982
4983   SMESHDS_Mesh* aMesh = getMeshDS();
4984
4985   const SMDS_MeshNode* aBorderFirstNode  = aMesh->FindNode( FirstNodeIDOnFreeBorder  );
4986   const SMDS_MeshNode* aBorderSecondNode = aMesh->FindNode( SecondNodeIDOnFreeBorder );
4987   const SMDS_MeshNode* aBorderLastNode   = aMesh->FindNode( LastNodeIDOnFreeBorder   );
4988   const SMDS_MeshNode* aSide2FirstNode   = aMesh->FindNode( FirstNodeIDOnSide  );
4989   const SMDS_MeshNode* aSide2SecondNode  = aMesh->FindNode( LastNodeIDOnSide );
4990   const SMDS_MeshNode* aSide2ThirdNode   = 0;
4991
4992   if (!aBorderFirstNode ||
4993       !aBorderSecondNode||
4994       !aBorderLastNode  )
4995     return SMESH::SMESH_MeshEditor::SEW_BORDER1_NOT_FOUND;
4996   if (!aSide2FirstNode  ||
4997       !aSide2SecondNode)
4998     return SMESH::SMESH_MeshEditor::SEW_BAD_SIDE_NODES;
4999
5000   TPythonDump() << "error = " << this << ".SewBorderToSide( "
5001                 << FirstNodeIDOnFreeBorder  << ", "
5002                 << SecondNodeIDOnFreeBorder << ", "
5003                 << LastNodeIDOnFreeBorder   << ", "
5004                 << FirstNodeIDOnSide        << ", "
5005                 << LastNodeIDOnSide         << ", "
5006                 << CreatePolygons           << ", "
5007                 << CreatePolyedrs           << ") ";
5008
5009   SMESH::SMESH_MeshEditor::Sew_Error error =
5010     convError( getEditor().SewFreeBorder (aBorderFirstNode,
5011                                           aBorderSecondNode,
5012                                           aBorderLastNode,
5013                                           aSide2FirstNode,
5014                                           aSide2SecondNode,
5015                                           aSide2ThirdNode,
5016                                           false,
5017                                           CreatePolygons,
5018                                           CreatePolyedrs) );
5019
5020   declareMeshModified( /*isReComputeSafe=*/false );
5021   return error;
5022
5023   SMESH_CATCH( SMESH::throwCorbaException );
5024   return SMESH::SMESH_MeshEditor::Sew_Error(0);
5025 }
5026
5027
5028 //=======================================================================
5029 //function : SewSideElements
5030 //purpose  :
5031 //=======================================================================
5032
5033 SMESH::SMESH_MeshEditor::Sew_Error
5034 SMESH_MeshEditor_i::SewSideElements(const SMESH::long_array& IDsOfSide1Elements,
5035                                     const SMESH::long_array& IDsOfSide2Elements,
5036                                     CORBA::Long NodeID1OfSide1ToMerge,
5037                                     CORBA::Long NodeID1OfSide2ToMerge,
5038                                     CORBA::Long NodeID2OfSide1ToMerge,
5039                                     CORBA::Long NodeID2OfSide2ToMerge)
5040   throw (SALOME::SALOME_Exception)
5041 {
5042   SMESH_TRY;
5043   initData();
5044
5045   SMESHDS_Mesh* aMesh = getMeshDS();
5046
5047   const SMDS_MeshNode* aFirstNode1ToMerge  = aMesh->FindNode( NodeID1OfSide1ToMerge );
5048   const SMDS_MeshNode* aFirstNode2ToMerge  = aMesh->FindNode( NodeID1OfSide2ToMerge );
5049   const SMDS_MeshNode* aSecondNode1ToMerge = aMesh->FindNode( NodeID2OfSide1ToMerge );
5050   const SMDS_MeshNode* aSecondNode2ToMerge = aMesh->FindNode( NodeID2OfSide2ToMerge );
5051
5052   if (!aFirstNode1ToMerge ||
5053       !aFirstNode2ToMerge )
5054     return SMESH::SMESH_MeshEditor::SEW_BAD_SIDE1_NODES;
5055   if (!aSecondNode1ToMerge||
5056       !aSecondNode2ToMerge)
5057     return SMESH::SMESH_MeshEditor::SEW_BAD_SIDE2_NODES;
5058
5059   TIDSortedElemSet aSide1Elems, aSide2Elems;
5060   arrayToSet(IDsOfSide1Elements, aMesh, aSide1Elems);
5061   arrayToSet(IDsOfSide2Elements, aMesh, aSide2Elems);
5062
5063   TPythonDump() << "error = " << this << ".SewSideElements( "
5064                 << IDsOfSide1Elements << ", "
5065                 << IDsOfSide2Elements << ", "
5066                 << NodeID1OfSide1ToMerge << ", "
5067                 << NodeID1OfSide2ToMerge << ", "
5068                 << NodeID2OfSide1ToMerge << ", "
5069                 << NodeID2OfSide2ToMerge << ")";
5070
5071   SMESH::SMESH_MeshEditor::Sew_Error error =
5072     convError( getEditor().SewSideElements (aSide1Elems, aSide2Elems,
5073                                          aFirstNode1ToMerge,
5074                                          aFirstNode2ToMerge,
5075                                          aSecondNode1ToMerge,
5076                                          aSecondNode2ToMerge));
5077
5078   declareMeshModified( /*isReComputeSafe=*/false );
5079   return error;
5080
5081   SMESH_CATCH( SMESH::throwCorbaException );
5082   return SMESH::SMESH_MeshEditor::Sew_Error(0);
5083 }
5084
5085 //================================================================================
5086 /*!
5087  * \brief Set new nodes for given element
5088  * \param ide - element id
5089  * \param newIDs - new node ids
5090  * \retval CORBA::Boolean - true if result is OK
5091  */
5092 //================================================================================
5093
5094 CORBA::Boolean SMESH_MeshEditor_i::ChangeElemNodes(CORBA::Long ide,
5095                                                    const SMESH::long_array& newIDs)
5096   throw (SALOME::SALOME_Exception)
5097 {
5098   SMESH_TRY;
5099   initData();
5100
5101   const SMDS_MeshElement* elem = getMeshDS()->FindElement(ide);
5102   if(!elem) return false;
5103
5104   int nbn = newIDs.length();
5105   int i=0;
5106   vector<const SMDS_MeshNode*> aNodes(nbn);
5107   int nbn1=-1;
5108   for(; i<nbn; i++) {
5109     const SMDS_MeshNode* aNode = getMeshDS()->FindNode(newIDs[i]);
5110     if(aNode) {
5111       nbn1++;
5112       aNodes[nbn1] = aNode;
5113     }
5114   }
5115   TPythonDump() << "isDone = " << this << ".ChangeElemNodes( "
5116                 << ide << ", " << newIDs << " )";
5117
5118   bool res = getMeshDS()->ChangeElementNodes( elem, & aNodes[0], nbn1+1 );
5119
5120   declareMeshModified( /*isReComputeSafe=*/ !res );
5121
5122   return res;
5123
5124   SMESH_CATCH( SMESH::throwCorbaException );
5125   return 0;
5126 }
5127
5128 //=======================================================================
5129 /*!
5130  * \brief Makes a part of the mesh quadratic or bi-quadratic
5131  */
5132 //=======================================================================
5133
5134 void SMESH_MeshEditor_i::convertToQuadratic(CORBA::Boolean            theForce3d,
5135                                             CORBA::Boolean            theToBiQuad,
5136                                             SMESH::SMESH_IDSource_ptr theObject)
5137   throw (SALOME::SALOME_Exception)
5138 {
5139   SMESH_TRY;
5140   initData();
5141
5142   TIDSortedElemSet elems;
5143   bool elemsOK;
5144   if ( !( elemsOK = CORBA::is_nil( theObject )))
5145   {
5146     elemsOK =  idSourceToSet( theObject, getMeshDS(), elems,
5147                               SMDSAbs_All, /*emptyIfIsMesh=*/true );
5148   }
5149   if ( elemsOK )
5150   {
5151     if ( !elems.empty() && (*elems.begin())->GetType() == SMDSAbs_Node )
5152       THROW_SALOME_CORBA_EXCEPTION("Group of nodes is not allowed", SALOME::BAD_PARAM);
5153
5154     if ( elems.empty() ) getEditor().ConvertToQuadratic(theForce3d, theToBiQuad);
5155     else                 getEditor().ConvertToQuadratic(theForce3d, elems, theToBiQuad);
5156
5157     declareMeshModified( /*isReComputeSafe=*/false );
5158   }
5159
5160   SMESH_CATCH( SMESH::throwCorbaException );
5161 }
5162
5163 //=======================================================================
5164 //function : ConvertFromQuadratic
5165 //purpose  :
5166 //=======================================================================
5167
5168 CORBA::Boolean SMESH_MeshEditor_i::ConvertFromQuadratic()
5169   throw (SALOME::SALOME_Exception)
5170 {
5171   SMESH_TRY;
5172   initData();
5173
5174   CORBA::Boolean isDone = getEditor().ConvertFromQuadratic();
5175   TPythonDump() << this << ".ConvertFromQuadratic()";
5176   declareMeshModified( /*isReComputeSafe=*/!isDone );
5177   return isDone;
5178
5179   SMESH_CATCH( SMESH::throwCorbaException );
5180   return false;
5181 }
5182
5183 //=======================================================================
5184 //function : ConvertToQuadratic
5185 //purpose  :
5186 //=======================================================================
5187
5188 void SMESH_MeshEditor_i::ConvertToQuadratic(CORBA::Boolean theForce3d)
5189   throw (SALOME::SALOME_Exception)
5190 {
5191   convertToQuadratic( theForce3d, false );
5192   TPythonDump() << this << ".ConvertToQuadratic("<<theForce3d<<")";
5193 }
5194
5195 //================================================================================
5196 /*!
5197  * \brief Makes a part of the mesh quadratic
5198  */
5199 //================================================================================
5200
5201 void SMESH_MeshEditor_i::ConvertToQuadraticObject(CORBA::Boolean            theForce3d,
5202                                                   SMESH::SMESH_IDSource_ptr theObject)
5203   throw (SALOME::SALOME_Exception)
5204 {
5205   convertToQuadratic( theForce3d, false, theObject );
5206   TPythonDump() << this << ".ConvertToQuadraticObject("<<theForce3d<<", "<<theObject<<")";
5207 }
5208
5209 //================================================================================
5210 /*!
5211  * \brief Makes a part of the mesh bi-quadratic
5212  */
5213 //================================================================================
5214
5215 void SMESH_MeshEditor_i::ConvertToBiQuadratic(CORBA::Boolean            theForce3d,
5216                                               SMESH::SMESH_IDSource_ptr theObject)
5217   throw (SALOME::SALOME_Exception)
5218 {
5219   convertToQuadratic( theForce3d, true, theObject );
5220   TPythonDump() << this << ".ConvertToBiQuadratic("<<theForce3d<<", "<<theObject<<")";
5221 }
5222
5223 //================================================================================
5224 /*!
5225  * \brief Makes a part of the mesh linear
5226  */
5227 //================================================================================
5228
5229 void SMESH_MeshEditor_i::ConvertFromQuadraticObject(SMESH::SMESH_IDSource_ptr theObject)
5230   throw (SALOME::SALOME_Exception)
5231 {
5232   SMESH_TRY;
5233   initData();
5234
5235   TPythonDump pyDump;
5236
5237   TIDSortedElemSet elems;
5238   if ( idSourceToSet( theObject, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true ))
5239   {
5240     if ( elems.empty() )
5241     {
5242       ConvertFromQuadratic();
5243     }
5244     else if ( (*elems.begin())->GetType() == SMDSAbs_Node )
5245     {
5246       THROW_SALOME_CORBA_EXCEPTION("Group of nodes is not allowed", SALOME::BAD_PARAM);
5247     }
5248     else
5249     {
5250       getEditor().ConvertFromQuadratic(elems);
5251     }
5252   }
5253   declareMeshModified( /*isReComputeSafe=*/false );
5254
5255   pyDump << this << ".ConvertFromQuadraticObject( "<<theObject<<" )";
5256
5257   SMESH_CATCH( SMESH::throwCorbaException );
5258 }
5259
5260 //=======================================================================
5261 //function : makeMesh
5262 //purpose  : create a named imported mesh
5263 //=======================================================================
5264
5265 SMESH::SMESH_Mesh_ptr SMESH_MeshEditor_i::makeMesh(const char* theMeshName)
5266 {
5267   SMESH_Gen_i*              gen = SMESH_Gen_i::GetSMESHGen();
5268   SMESH::SMESH_Mesh_var    mesh = gen->CreateEmptyMesh();
5269   SALOMEDS::Study_var     study = gen->GetCurrentStudy();
5270   SALOMEDS::SObject_wrap meshSO = gen->ObjectToSObject( study, mesh );
5271   gen->SetName( meshSO, theMeshName, "Mesh" );
5272   gen->SetPixMap( meshSO, "ICON_SMESH_TREE_MESH_IMPORTED");
5273
5274   return mesh._retn();
5275 }
5276
5277 //=======================================================================
5278 //function : dumpGroupsList
5279 //purpose  :
5280 //=======================================================================
5281
5282 void SMESH_MeshEditor_i::dumpGroupsList(TPythonDump &               theDumpPython,
5283                                         const SMESH::ListOfGroups * theGroupList)
5284 {
5285   bool isDumpGroupList = ( theGroupList && theGroupList->length() > 0 );
5286   if ( isDumpGroupList )
5287     theDumpPython << theGroupList << " = ";
5288 }
5289
5290 //================================================================================
5291 /*!
5292   \brief Generates the unique group name.
5293   \param thePrefix name prefix
5294   \return unique name
5295 */
5296 //================================================================================
5297
5298 std::string SMESH_MeshEditor_i::generateGroupName(const std::string& thePrefix)
5299 {
5300   SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
5301   set<std::string> groupNames;
5302
5303   // Get existing group names
5304   for (int i = 0, nbGroups = groups->length(); i < nbGroups; i++ ) {
5305     SMESH::SMESH_GroupBase_var aGroup = groups[i];
5306     if (CORBA::is_nil(aGroup))
5307       continue;
5308
5309     CORBA::String_var name = aGroup->GetName();
5310     groupNames.insert( name.in() );
5311   }
5312
5313   // Find new name
5314   std::string name = thePrefix;
5315   int index = 0;
5316
5317   while (!groupNames.insert(name).second)
5318     name = SMESH_Comment( thePrefix ) << "_" << index++;
5319
5320   return name;
5321 }
5322
5323 //================================================================================
5324 /*!
5325  * \brief Prepare SMESH_IDSource for work
5326  */
5327 //================================================================================
5328
5329 void SMESH_MeshEditor_i::prepareIdSource(SMESH::SMESH_IDSource_ptr theObject)
5330 {
5331   if ( SMESH::Filter_i* filter = SMESH::DownCast<SMESH::Filter_i*>( theObject ))
5332   {
5333     SMESH::SMESH_Mesh_var mesh = myMesh_i->_this();
5334     filter->SetMesh( mesh );
5335   }
5336 }
5337 //================================================================================
5338 /*!
5339  * \brief Retrieve elements of given type from SMESH_IDSource
5340  */
5341 //================================================================================
5342
5343 bool SMESH_MeshEditor_i::idSourceToSet(SMESH::SMESH_IDSource_ptr  theIDSource,
5344                                        const SMESHDS_Mesh*        theMeshDS,
5345                                        TIDSortedElemSet&          theElemSet,
5346                                        const SMDSAbs_ElementType  theType,
5347                                        const bool                 emptyIfIsMesh,
5348                                        IDSource_Error*            error)
5349
5350 {
5351   if ( error ) *error = IDSource_OK;
5352
5353   if ( CORBA::is_nil( theIDSource ))
5354   {
5355     if ( error ) *error = IDSource_INVALID;
5356     return false;
5357   }
5358   if ( emptyIfIsMesh && SMESH::DownCast<SMESH_Mesh_i*>( theIDSource ))
5359   {
5360     if ( error && getMeshDS()->GetMeshInfo().NbElements( theType ) == 0 )
5361       *error = IDSource_EMPTY;
5362     return true;
5363   }
5364   prepareIdSource( theIDSource );
5365   SMESH::long_array_var anIDs = theIDSource->GetIDs();
5366   if ( anIDs->length() == 0 )
5367   {
5368     if ( error ) *error = IDSource_EMPTY;
5369     return false;
5370   }
5371   SMESH::array_of_ElementType_var types = theIDSource->GetTypes();
5372   if ( types->length() == 1 && types[0] == SMESH::NODE ) // group of nodes
5373   {
5374     if ( theType == SMDSAbs_All || theType == SMDSAbs_Node )
5375     {
5376       arrayToSet( anIDs, getMeshDS(), theElemSet, SMDSAbs_Node );
5377     }
5378     else
5379     {
5380       if ( error ) *error = IDSource_INVALID;
5381       return false;
5382     }
5383   }
5384   else
5385   {
5386     arrayToSet( anIDs, getMeshDS(), theElemSet, theType);
5387     if ( bool(anIDs->length()) != bool(theElemSet.size()))
5388     {
5389       if ( error ) *error = IDSource_INVALID;
5390       return false;
5391     }
5392   }
5393   return true;
5394 }
5395
5396 //================================================================================
5397 /*!
5398  * \brief Duplicates given elements, i.e. creates new elements based on the
5399  *        same nodes as the given ones.
5400  * \param theElements - container of elements to duplicate.
5401  * \param theGroupName - a name of group to contain the generated elements.
5402  *                    If a group with such a name already exists, the new elements
5403  *                    are added to the existng group, else a new group is created.
5404  *                    If \a theGroupName is empty, new elements are not added 
5405  *                    in any group.
5406  * \return a group where the new elements are added. NULL if theGroupName == "".
5407  * \sa DoubleNode()
5408  */
5409 //================================================================================
5410
5411 SMESH::SMESH_Group_ptr
5412 SMESH_MeshEditor_i::DoubleElements(SMESH::SMESH_IDSource_ptr theElements,
5413                                    const char*               theGroupName)
5414   throw (SALOME::SALOME_Exception)
5415 {
5416   SMESH::SMESH_Group_var newGroup;
5417
5418   SMESH_TRY;
5419   initData();
5420
5421   TPythonDump pyDump;
5422
5423   TIDSortedElemSet elems;
5424   if ( idSourceToSet( theElements, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true))
5425   {
5426     getEditor().DoubleElements( elems );
5427
5428     if ( strlen( theGroupName ) && !getEditor().GetLastCreatedElems().IsEmpty() )
5429     {
5430       // group type
5431       SMESH::ElementType type =
5432         SMESH::ElementType( getEditor().GetLastCreatedElems().Value(1)->GetType() );
5433       // find existing group
5434       SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
5435       for ( size_t i = 0; i < groups->length(); ++i )
5436         if ( groups[i]->GetType() == type )
5437         {
5438           CORBA::String_var name = groups[i]->GetName();
5439           if ( strcmp( name, theGroupName ) == 0 ) {
5440             newGroup = SMESH::SMESH_Group::_narrow( groups[i] );
5441             break;
5442           }
5443         }
5444       // create a new group
5445       if ( newGroup->_is_nil() )
5446         newGroup = myMesh_i->CreateGroup( type, theGroupName );
5447       // fill newGroup
5448       if ( SMESH_Group_i* group_i = SMESH::DownCast< SMESH_Group_i* >( newGroup ))
5449       {
5450         SMESHDS_Group* groupDS = static_cast< SMESHDS_Group* >( group_i->GetGroupDS() );
5451         const SMESH_SequenceOfElemPtr& aSeq = getEditor().GetLastCreatedElems();
5452         for ( int i = 1; i <= aSeq.Length(); i++ )
5453           groupDS->SMDSGroup().Add( aSeq(i) );
5454       }
5455     }
5456   }
5457   // python dump
5458   if ( !newGroup->_is_nil() )
5459     pyDump << newGroup << " = ";
5460   pyDump << this << ".DoubleElements( "
5461          << theElements << ", " << "'" << theGroupName <<"')";
5462
5463   SMESH_CATCH( SMESH::throwCorbaException );
5464
5465   return newGroup._retn();
5466 }
5467
5468 //================================================================================
5469 /*!
5470   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5471   \param theNodes - identifiers of nodes to be doubled
5472   \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
5473          nodes. If list of element identifiers is empty then nodes are doubled but
5474          they not assigned to elements
5475   \return TRUE if operation has been completed successfully, FALSE otherwise
5476   \sa DoubleNode(), DoubleNodeGroup(), DoubleNodeGroups()
5477 */
5478 //================================================================================
5479
5480 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodes( const SMESH::long_array& theNodes,
5481                                                 const SMESH::long_array& theModifiedElems )
5482   throw (SALOME::SALOME_Exception)
5483 {
5484   SMESH_TRY;
5485   initData();
5486
5487   list< int > aListOfNodes;
5488   int i, n;
5489   for ( i = 0, n = theNodes.length(); i < n; i++ )
5490     aListOfNodes.push_back( theNodes[ i ] );
5491
5492   list< int > aListOfElems;
5493   for ( i = 0, n = theModifiedElems.length(); i < n; i++ )
5494     aListOfElems.push_back( theModifiedElems[ i ] );
5495
5496   bool aResult = getEditor().DoubleNodes( aListOfNodes, aListOfElems );
5497
5498   declareMeshModified( /*isReComputeSafe=*/ !aResult );
5499
5500   // Update Python script
5501   TPythonDump() << this << ".DoubleNodes( " << theNodes << ", "<< theModifiedElems << " )";
5502
5503   return aResult;
5504
5505   SMESH_CATCH( SMESH::throwCorbaException );
5506   return 0;
5507 }
5508
5509 //================================================================================
5510 /*!
5511   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5512   This method provided for convenience works as DoubleNodes() described above.
5513   \param theNodeId - identifier of node to be doubled.
5514   \param theModifiedElems - identifiers of elements to be updated.
5515   \return TRUE if operation has been completed successfully, FALSE otherwise
5516   \sa DoubleNodes(), DoubleNodeGroup(), DoubleNodeGroups()
5517 */
5518 //================================================================================
5519
5520 CORBA::Boolean SMESH_MeshEditor_i::DoubleNode( CORBA::Long              theNodeId,
5521                                                const SMESH::long_array& theModifiedElems )
5522   throw (SALOME::SALOME_Exception)
5523 {
5524   SMESH_TRY;
5525   SMESH::long_array_var aNodes = new SMESH::long_array;
5526   aNodes->length( 1 );
5527   aNodes[ 0 ] = theNodeId;
5528
5529   TPythonDump pyDump; // suppress dump by the next line
5530
5531   CORBA::Boolean done = DoubleNodes( aNodes, theModifiedElems );
5532
5533   pyDump << this << ".DoubleNode( " << theNodeId << ", " << theModifiedElems << " )";
5534
5535   return done;
5536
5537   SMESH_CATCH( SMESH::throwCorbaException );
5538   return 0;
5539 }
5540
5541 //================================================================================
5542 /*!
5543   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5544   This method provided for convenience works as DoubleNodes() described above.
5545   \param theNodes - group of nodes to be doubled.
5546   \param theModifiedElems - group of elements to be updated.
5547   \return TRUE if operation has been completed successfully, FALSE otherwise
5548   \sa DoubleNode(), DoubleNodes(), DoubleNodeGroups()
5549 */
5550 //================================================================================
5551
5552 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroup(SMESH::SMESH_GroupBase_ptr theNodes,
5553                                                    SMESH::SMESH_GroupBase_ptr theModifiedElems )
5554   throw (SALOME::SALOME_Exception)
5555 {
5556   SMESH_TRY;
5557   if ( CORBA::is_nil( theNodes ) && theNodes->GetType() != SMESH::NODE )
5558     return false;
5559
5560   SMESH::long_array_var aNodes = theNodes->GetListOfID();
5561   SMESH::long_array_var aModifiedElems;
5562   if ( !CORBA::is_nil( theModifiedElems ) )
5563     aModifiedElems = theModifiedElems->GetListOfID();
5564   else
5565   {
5566     aModifiedElems = new SMESH::long_array;
5567     aModifiedElems->length( 0 );
5568   }
5569
5570   TPythonDump pyDump; // suppress dump by the next line
5571
5572   bool done = DoubleNodes( aNodes, aModifiedElems );
5573
5574   pyDump << this << ".DoubleNodeGroup( " << theNodes << ", " << theModifiedElems << " )";
5575
5576   return done;
5577
5578   SMESH_CATCH( SMESH::throwCorbaException );
5579   return 0;
5580 }
5581
5582 //================================================================================
5583 /*!
5584  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
5585  * Works as DoubleNodeGroup(), but returns a new group with newly created nodes.
5586  * \param theNodes - group of nodes to be doubled.
5587  * \param theModifiedElems - group of elements to be updated.
5588  * \return a new group with newly created nodes
5589  * \sa DoubleNodeGroup()
5590  */
5591 //================================================================================
5592
5593 SMESH::SMESH_Group_ptr
5594 SMESH_MeshEditor_i::DoubleNodeGroupNew( SMESH::SMESH_GroupBase_ptr theNodes,
5595                                         SMESH::SMESH_GroupBase_ptr theModifiedElems )
5596   throw (SALOME::SALOME_Exception)
5597 {
5598   SMESH_TRY;
5599   SMESH::SMESH_Group_var aNewGroup;
5600
5601   if ( CORBA::is_nil( theNodes ) && theNodes->GetType() != SMESH::NODE )
5602     return aNewGroup._retn();
5603
5604   // Duplicate nodes
5605   SMESH::long_array_var aNodes = theNodes->GetListOfID();
5606   SMESH::long_array_var aModifiedElems;
5607   if ( !CORBA::is_nil( theModifiedElems ) )
5608     aModifiedElems = theModifiedElems->GetListOfID();
5609   else {
5610     aModifiedElems = new SMESH::long_array;
5611     aModifiedElems->length( 0 );
5612   }
5613
5614   TPythonDump pyDump; // suppress dump by the next line
5615
5616   bool aResult = DoubleNodes( aNodes, aModifiedElems );
5617   if ( aResult )
5618   {
5619     // Create group with newly created nodes
5620     SMESH::long_array_var anIds = GetLastCreatedNodes();
5621     if (anIds->length() > 0) {
5622       std::string anUnindexedName (theNodes->GetName());
5623       std::string aNewName = generateGroupName(anUnindexedName + "_double");
5624       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
5625       aNewGroup->Add(anIds);
5626       pyDump << aNewGroup << " = ";
5627     }
5628   }
5629
5630   pyDump << this << ".DoubleNodeGroupNew( " << theNodes << ", "
5631          << theModifiedElems << " )";
5632
5633   return aNewGroup._retn();
5634
5635   SMESH_CATCH( SMESH::throwCorbaException );
5636   return 0;
5637 }
5638
5639 //================================================================================
5640 /*!
5641   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5642   This method provided for convenience works as DoubleNodes() described above.
5643   \param theNodes - list of groups of nodes to be doubled
5644   \param theModifiedElems - list of groups of elements to be updated.
5645   \return TRUE if operation has been completed successfully, FALSE otherwise
5646   \sa DoubleNode(), DoubleNodeGroup(), DoubleNodes()
5647 */
5648 //================================================================================
5649
5650 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroups(const SMESH::ListOfGroups& theNodes,
5651                                                     const SMESH::ListOfGroups& theModifiedElems )
5652   throw (SALOME::SALOME_Exception)
5653 {
5654   SMESH_TRY;
5655   initData();
5656
5657   std::list< int > aNodes;
5658   int i, n, j, m;
5659   for ( i = 0, n = theNodes.length(); i < n; i++ )
5660   {
5661     SMESH::SMESH_GroupBase_var aGrp = theNodes[ i ];
5662     if ( !CORBA::is_nil( aGrp ) && aGrp->GetType() == SMESH::NODE )
5663     {
5664       SMESH::long_array_var aCurr = aGrp->GetListOfID();
5665       for ( j = 0, m = aCurr->length(); j < m; j++ )
5666         aNodes.push_back( aCurr[ j ] );
5667     }
5668   }
5669
5670   std::list< int > anElems;
5671   for ( i = 0, n = theModifiedElems.length(); i < n; i++ )
5672   {
5673     SMESH::SMESH_GroupBase_var aGrp = theModifiedElems[ i ];
5674     if ( !CORBA::is_nil( aGrp ) && aGrp->GetType() != SMESH::NODE )
5675     {
5676       SMESH::long_array_var aCurr = aGrp->GetListOfID();
5677       for ( j = 0, m = aCurr->length(); j < m; j++ )
5678         anElems.push_back( aCurr[ j ] );
5679     }
5680   }
5681
5682   bool aResult = getEditor().DoubleNodes( aNodes, anElems );
5683
5684   declareMeshModified( /*isReComputeSafe=*/false );
5685
5686   TPythonDump() << this << ".DoubleNodeGroups( " << theNodes << ", " << theModifiedElems << " )";
5687
5688   return aResult;
5689
5690   SMESH_CATCH( SMESH::throwCorbaException );
5691   return 0;
5692 }
5693
5694 //================================================================================
5695 /*!
5696  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
5697  * Works as DoubleNodeGroups(), but returns a new group with newly created nodes.
5698  * \param theNodes - group of nodes to be doubled.
5699  * \param theModifiedElems - group of elements to be updated.
5700  * \return a new group with newly created nodes
5701  * \sa DoubleNodeGroups()
5702  */
5703 //================================================================================
5704
5705 SMESH::SMESH_Group_ptr
5706 SMESH_MeshEditor_i::DoubleNodeGroupsNew( const SMESH::ListOfGroups& theNodes,
5707                                          const SMESH::ListOfGroups& theModifiedElems )
5708   throw (SALOME::SALOME_Exception)
5709 {
5710   SMESH::SMESH_Group_var aNewGroup;
5711
5712   TPythonDump pyDump; // suppress dump by the next line
5713
5714   bool aResult = DoubleNodeGroups( theNodes, theModifiedElems );
5715
5716   if ( aResult )
5717   {
5718     // Create group with newly created nodes
5719     SMESH::long_array_var anIds = GetLastCreatedNodes();
5720     if (anIds->length() > 0) {
5721       std::string anUnindexedName (theNodes[0]->GetName());
5722       std::string aNewName = generateGroupName(anUnindexedName + "_double");
5723       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
5724       aNewGroup->Add(anIds);
5725       pyDump << aNewGroup << " = ";
5726     }
5727   }
5728
5729   pyDump << this << ".DoubleNodeGroupsNew( " << theNodes << ", "
5730          << theModifiedElems << " )";
5731
5732   return aNewGroup._retn();
5733 }
5734
5735
5736 //================================================================================
5737 /*!
5738   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5739   \param theElems - the list of elements (edges or faces) to be replicated
5740   The nodes for duplication could be found from these elements
5741   \param theNodesNot - list of nodes to NOT replicate
5742   \param theAffectedElems - the list of elements (cells and edges) to which the
5743   replicated nodes should be associated to.
5744   \return TRUE if operation has been completed successfully, FALSE otherwise
5745   \sa DoubleNodeGroup(), DoubleNodeGroups()
5746 */
5747 //================================================================================
5748
5749 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElem( const SMESH::long_array& theElems,
5750                                                    const SMESH::long_array& theNodesNot,
5751                                                    const SMESH::long_array& theAffectedElems )
5752   throw (SALOME::SALOME_Exception)
5753 {
5754   SMESH_TRY;
5755   initData();
5756
5757   SMESHDS_Mesh* aMeshDS = getMeshDS();
5758   TIDSortedElemSet anElems, aNodes, anAffected;
5759   arrayToSet(theElems, aMeshDS, anElems, SMDSAbs_All);
5760   arrayToSet(theNodesNot, aMeshDS, aNodes, SMDSAbs_Node);
5761   arrayToSet(theAffectedElems, aMeshDS, anAffected, SMDSAbs_All);
5762
5763   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5764
5765   // Update Python script
5766   TPythonDump() << this << ".DoubleNodeElem( " << theElems << ", "
5767                 << theNodesNot << ", " << theAffectedElems << " )";
5768
5769   declareMeshModified( /*isReComputeSafe=*/false );
5770   return aResult;
5771
5772   SMESH_CATCH( SMESH::throwCorbaException );
5773   return 0;
5774 }
5775
5776 //================================================================================
5777 /*!
5778   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5779   \param theElems - the list of elements (edges or faces) to be replicated
5780   The nodes for duplication could be found from these elements
5781   \param theNodesNot - list of nodes to NOT replicate
5782   \param theShape - shape to detect affected elements (element which geometric center
5783   located on or inside shape).
5784   The replicated nodes should be associated to affected elements.
5785   \return TRUE if operation has been completed successfully, FALSE otherwise
5786   \sa DoubleNodeGroupInRegion(), DoubleNodeGroupsInRegion()
5787 */
5788 //================================================================================
5789
5790 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemInRegion ( const SMESH::long_array& theElems,
5791                                                             const SMESH::long_array& theNodesNot,
5792                                                             GEOM::GEOM_Object_ptr    theShape )
5793   throw (SALOME::SALOME_Exception)
5794 {
5795   SMESH_TRY;
5796   initData();
5797
5798
5799   SMESHDS_Mesh* aMeshDS = getMeshDS();
5800   TIDSortedElemSet anElems, aNodes;
5801   arrayToSet(theElems, aMeshDS, anElems, SMDSAbs_All);
5802   arrayToSet(theNodesNot, aMeshDS, aNodes, SMDSAbs_Node);
5803
5804   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
5805   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
5806
5807   // Update Python script
5808   TPythonDump() << "isDone = " << this << ".DoubleNodeElemInRegion( " << theElems << ", "
5809                 << theNodesNot << ", " << theShape << " )";
5810
5811   declareMeshModified( /*isReComputeSafe=*/false );
5812   return aResult;
5813
5814   SMESH_CATCH( SMESH::throwCorbaException );
5815   return 0;
5816 }
5817
5818 //================================================================================
5819 /*!
5820   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5821   \param theElems - group of of elements (edges or faces) to be replicated
5822   \param theNodesNot - group of nodes not to replicated
5823   \param theAffectedElems - group of elements to which the replicated nodes
5824   should be associated to.
5825   \return TRUE if operation has been completed successfully, FALSE otherwise
5826   \sa DoubleNodes(), DoubleNodeGroups()
5827 */
5828 //================================================================================
5829
5830 CORBA::Boolean
5831 SMESH_MeshEditor_i::DoubleNodeElemGroup(SMESH::SMESH_GroupBase_ptr theElems,
5832                                         SMESH::SMESH_GroupBase_ptr theNodesNot,
5833                                         SMESH::SMESH_GroupBase_ptr theAffectedElems)
5834   throw (SALOME::SALOME_Exception)
5835 {
5836   SMESH_TRY;
5837   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
5838     return false;
5839
5840   initData();
5841
5842
5843   SMESHDS_Mesh* aMeshDS = getMeshDS();
5844   TIDSortedElemSet anElems, aNodes, anAffected;
5845   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
5846   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
5847   idSourceToSet( theAffectedElems, aMeshDS, anAffected, SMDSAbs_All );
5848
5849   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5850
5851   // Update Python script
5852   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroup( " << theElems << ", "
5853                 << theNodesNot << ", " << theAffectedElems << " )";
5854
5855   declareMeshModified( /*isReComputeSafe=*/false );
5856   return aResult;
5857
5858   SMESH_CATCH( SMESH::throwCorbaException );
5859   return 0;
5860 }
5861
5862 //================================================================================
5863 /*!
5864  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5865  * Works as DoubleNodeElemGroup(), but returns a new group with newly created elements.
5866  * \param theElems - group of of elements (edges or faces) to be replicated
5867  * \param theNodesNot - group of nodes not to replicated
5868  * \param theAffectedElems - group of elements to which the replicated nodes
5869  *        should be associated to.
5870  * \return a new group with newly created elements
5871  * \sa DoubleNodeElemGroup()
5872  */
5873 //================================================================================
5874
5875 SMESH::SMESH_Group_ptr
5876 SMESH_MeshEditor_i::DoubleNodeElemGroupNew(SMESH::SMESH_GroupBase_ptr theElems,
5877                                            SMESH::SMESH_GroupBase_ptr theNodesNot,
5878                                            SMESH::SMESH_GroupBase_ptr theAffectedElems)
5879   throw (SALOME::SALOME_Exception)
5880 {
5881   TPythonDump pyDump;
5882   SMESH::ListOfGroups_var twoGroups = DoubleNodeElemGroup2New( theElems,
5883                                                                theNodesNot,
5884                                                                theAffectedElems,
5885                                                                true, false );
5886   SMESH::SMESH_GroupBase_var baseGroup = twoGroups[0].in();
5887   SMESH::SMESH_Group_var     elemGroup = SMESH::SMESH_Group::_narrow( baseGroup );
5888
5889   pyDump << elemGroup << " = " << this << ".DoubleNodeElemGroupNew( "
5890          << theElems         << ", "
5891          << theNodesNot      << ", "
5892          << theAffectedElems << " )";
5893
5894   return elemGroup._retn();
5895 }
5896
5897 //================================================================================
5898 /*!
5899  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5900  * Works as DoubleNodeElemGroup(), but returns a new group with newly created elements.
5901  * \param theElems - group of of elements (edges or faces) to be replicated
5902  * \param theNodesNot - group of nodes not to replicated
5903  * \param theAffectedElems - group of elements to which the replicated nodes
5904  *        should be associated to.
5905  * \return a new group with newly created elements
5906  * \sa DoubleNodeElemGroup()
5907  */
5908 //================================================================================
5909
5910 SMESH::ListOfGroups*
5911 SMESH_MeshEditor_i::DoubleNodeElemGroup2New(SMESH::SMESH_GroupBase_ptr theElems,
5912                                             SMESH::SMESH_GroupBase_ptr theNodesNot,
5913                                             SMESH::SMESH_GroupBase_ptr theAffectedElems,
5914                                             CORBA::Boolean             theElemGroupNeeded,
5915                                             CORBA::Boolean             theNodeGroupNeeded)
5916   throw (SALOME::SALOME_Exception)
5917 {
5918   SMESH_TRY;
5919   SMESH::SMESH_Group_var aNewElemGroup, aNewNodeGroup;
5920   SMESH::ListOfGroups_var aTwoGroups = new SMESH::ListOfGroups();
5921   aTwoGroups->length( 2 );
5922
5923   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
5924     return aTwoGroups._retn();
5925
5926   initData();
5927
5928
5929   SMESHDS_Mesh* aMeshDS = getMeshDS();
5930   TIDSortedElemSet anElems, aNodes, anAffected;
5931   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
5932   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
5933   idSourceToSet( theAffectedElems, aMeshDS, anAffected, SMDSAbs_All );
5934
5935
5936   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5937
5938   declareMeshModified( /*isReComputeSafe=*/ !aResult );
5939
5940   TPythonDump pyDump;
5941
5942   if ( aResult )
5943   {
5944     // Create group with newly created elements
5945     CORBA::String_var elemGroupName = theElems->GetName();
5946     std::string aNewName = generateGroupName( std::string(elemGroupName.in()) + "_double");
5947     if ( !getEditor().GetLastCreatedElems().IsEmpty() && theElemGroupNeeded )
5948     {
5949       SMESH::long_array_var anIds = GetLastCreatedElems();
5950       SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true);
5951       aNewElemGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str());
5952       aNewElemGroup->Add(anIds);
5953     }
5954     if ( !getEditor().GetLastCreatedNodes().IsEmpty() && theNodeGroupNeeded )
5955     {
5956       SMESH::long_array_var anIds = GetLastCreatedNodes();
5957       aNewNodeGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
5958       aNewNodeGroup->Add(anIds);
5959     }
5960   }
5961
5962   // Update Python script
5963
5964   pyDump << "[ ";
5965   if ( aNewElemGroup->_is_nil() ) pyDump << "nothing, ";
5966   else                            pyDump << aNewElemGroup << ", ";
5967   if ( aNewNodeGroup->_is_nil() ) pyDump << "nothing ] = ";
5968   else                            pyDump << aNewNodeGroup << " ] = ";
5969
5970   pyDump << this << ".DoubleNodeElemGroup2New( " << theElems << ", "
5971          << theNodesNot        << ", "
5972          << theAffectedElems   << ", "
5973          << theElemGroupNeeded << ", "
5974          << theNodeGroupNeeded <<" )";
5975
5976   aTwoGroups[0] = aNewElemGroup._retn();
5977   aTwoGroups[1] = aNewNodeGroup._retn();
5978   return aTwoGroups._retn();
5979
5980   SMESH_CATCH( SMESH::throwCorbaException );
5981   return 0;
5982 }
5983
5984 //================================================================================
5985 /*!
5986   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5987   \param theElems - group of of elements (edges or faces) to be replicated
5988   \param theNodesNot - group of nodes not to replicated
5989   \param theShape - shape to detect affected elements (element which geometric center
5990   located on or inside shape).
5991   The replicated nodes should be associated to affected elements.
5992   \return TRUE if operation has been completed successfully, FALSE otherwise
5993   \sa DoubleNodesInRegion(), DoubleNodeGroupsInRegion()
5994 */
5995 //================================================================================
5996
5997 CORBA::Boolean
5998 SMESH_MeshEditor_i::DoubleNodeElemGroupInRegion(SMESH::SMESH_GroupBase_ptr theElems,
5999                                                 SMESH::SMESH_GroupBase_ptr theNodesNot,
6000                                                 GEOM::GEOM_Object_ptr      theShape )
6001   throw (SALOME::SALOME_Exception)
6002 {
6003   SMESH_TRY;
6004   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
6005     return false;
6006
6007   initData();
6008
6009
6010   SMESHDS_Mesh* aMeshDS = getMeshDS();
6011   TIDSortedElemSet anElems, aNodes, anAffected;
6012   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
6013   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
6014
6015   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
6016   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
6017
6018
6019   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6020
6021   // Update Python script
6022   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroupInRegion( " << theElems << ", "
6023                 << theNodesNot << ", " << theShape << " )";
6024   return aResult;
6025
6026   SMESH_CATCH( SMESH::throwCorbaException );
6027   return 0;
6028 }
6029
6030 //================================================================================
6031 /*!
6032  * \brief Re-load elements from a list of groups into a TIDSortedElemSet
6033  *  \param [in] theGrpList - groups
6034  *  \param [in] theMeshDS -  mesh
6035  *  \param [out] theElemSet - set of elements
6036  *  \param [in] theIsNodeGrp - is \a theGrpList includes goups of nodes
6037  */
6038 //================================================================================
6039
6040 static void listOfGroupToSet(const SMESH::ListOfGroups& theGrpList,
6041                              SMESHDS_Mesh*              theMeshDS,
6042                              TIDSortedElemSet&          theElemSet,
6043                              const bool                 theIsNodeGrp)
6044 {
6045   for ( int i = 0, n = theGrpList.length(); i < n; i++ )
6046   {
6047     SMESH::SMESH_GroupBase_var aGrp = theGrpList[ i ];
6048     if ( !CORBA::is_nil( aGrp ) && (theIsNodeGrp ? aGrp->GetType() == SMESH::NODE
6049                                     : aGrp->GetType() != SMESH::NODE ) )
6050     {
6051       SMESH::long_array_var anIDs = aGrp->GetIDs();
6052       arrayToSet( anIDs, theMeshDS, theElemSet, theIsNodeGrp ? SMDSAbs_Node : SMDSAbs_All );
6053     }
6054   }
6055 }
6056
6057 //================================================================================
6058 /*!
6059   \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
6060   This method provided for convenience works as DoubleNodes() described above.
6061   \param theElems - list of groups of elements (edges or faces) to be replicated
6062   \param theNodesNot - list of groups of nodes not to replicated
6063   \param theAffectedElems - group of elements to which the replicated nodes
6064   should be associated to.
6065   \return TRUE if operation has been completed successfully, FALSE otherwise
6066   \sa DoubleNodeGroup(), DoubleNodes(), DoubleNodeElemGroupsNew()
6067 */
6068 //================================================================================
6069
6070 CORBA::Boolean
6071 SMESH_MeshEditor_i::DoubleNodeElemGroups(const SMESH::ListOfGroups& theElems,
6072                                          const SMESH::ListOfGroups& theNodesNot,
6073                                          const SMESH::ListOfGroups& theAffectedElems)
6074   throw (SALOME::SALOME_Exception)
6075 {
6076   SMESH_TRY;
6077   initData();
6078
6079
6080   SMESHDS_Mesh* aMeshDS = getMeshDS();
6081   TIDSortedElemSet anElems, aNodes, anAffected;
6082   listOfGroupToSet(theElems, aMeshDS, anElems, false );
6083   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
6084   listOfGroupToSet(theAffectedElems, aMeshDS, anAffected, false );
6085
6086   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
6087
6088   // Update Python script
6089   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroups( " << &theElems << ", "
6090                 << &theNodesNot << ", " << &theAffectedElems << " )";
6091
6092   declareMeshModified( /*isReComputeSafe=*/false );
6093   return aResult;
6094
6095   SMESH_CATCH( SMESH::throwCorbaException );
6096   return 0;
6097 }
6098
6099 //================================================================================
6100 /*!
6101  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6102  * Works as DoubleNodeElemGroups(), but returns a new group with newly created elements.
6103   \param theElems - list of groups of elements (edges or faces) to be replicated
6104   \param theNodesNot - list of groups of nodes not to replicated
6105   \param theAffectedElems - group of elements to which the replicated nodes
6106   should be associated to.
6107  * \return a new group with newly created elements
6108  * \sa DoubleNodeElemGroups()
6109  */
6110 //================================================================================
6111
6112 SMESH::SMESH_Group_ptr
6113 SMESH_MeshEditor_i::DoubleNodeElemGroupsNew(const SMESH::ListOfGroups& theElems,
6114                                             const SMESH::ListOfGroups& theNodesNot,
6115                                             const SMESH::ListOfGroups& theAffectedElems)
6116   throw (SALOME::SALOME_Exception)
6117 {
6118   TPythonDump pyDump;
6119   SMESH::ListOfGroups_var twoGroups = DoubleNodeElemGroups2New( theElems,
6120                                                                 theNodesNot,
6121                                                                 theAffectedElems,
6122                                                                 true, false );
6123   SMESH::SMESH_GroupBase_var baseGroup = twoGroups[0].in();
6124   SMESH::SMESH_Group_var     elemGroup = SMESH::SMESH_Group::_narrow( baseGroup );
6125
6126   pyDump << elemGroup << " = " << this << ".DoubleNodeElemGroupsNew( "
6127          << theElems         << ", "
6128          << theNodesNot      << ", "
6129          << theAffectedElems << " )";
6130
6131   return elemGroup._retn();
6132 }
6133
6134 //================================================================================
6135 /*!
6136  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6137  * Works as DoubleNodeElemGroups(), but returns a new group with newly created elements.
6138   \param theElems - list of groups of elements (edges or faces) to be replicated
6139   \param theNodesNot - list of groups of nodes not to replicated
6140   \param theAffectedElems - group of elements to which the replicated nodes
6141   should be associated to.
6142  * \return a new group with newly created elements
6143  * \sa DoubleNodeElemGroups()
6144  */
6145 //================================================================================
6146
6147 SMESH::ListOfGroups*
6148 SMESH_MeshEditor_i::DoubleNodeElemGroups2New(const SMESH::ListOfGroups& theElems,
6149                                              const SMESH::ListOfGroups& theNodesNot,
6150                                              const SMESH::ListOfGroups& theAffectedElems,
6151                                              CORBA::Boolean             theElemGroupNeeded,
6152                                              CORBA::Boolean             theNodeGroupNeeded)
6153   throw (SALOME::SALOME_Exception)
6154 {
6155   SMESH_TRY;
6156   SMESH::SMESH_Group_var aNewElemGroup, aNewNodeGroup;
6157   SMESH::ListOfGroups_var aTwoGroups = new SMESH::ListOfGroups();
6158   aTwoGroups->length( 2 );
6159   
6160   initData();
6161
6162
6163   SMESHDS_Mesh* aMeshDS = getMeshDS();
6164   TIDSortedElemSet anElems, aNodes, anAffected;
6165   listOfGroupToSet(theElems, aMeshDS, anElems, false );
6166   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
6167   listOfGroupToSet(theAffectedElems, aMeshDS, anAffected, false );
6168
6169   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
6170
6171   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6172
6173   TPythonDump pyDump;
6174   if ( aResult )
6175   {
6176     // Create group with newly created elements
6177     CORBA::String_var elemGroupName = theElems[0]->GetName();
6178     std::string aNewName = generateGroupName( std::string(elemGroupName.in()) + "_double");
6179     if ( !getEditor().GetLastCreatedElems().IsEmpty() && theElemGroupNeeded )
6180     {
6181       SMESH::long_array_var anIds = GetLastCreatedElems();
6182       SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true);
6183       aNewElemGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str());
6184       aNewElemGroup->Add(anIds);
6185     }
6186     if ( !getEditor().GetLastCreatedNodes().IsEmpty() && theNodeGroupNeeded )
6187     {
6188       SMESH::long_array_var anIds = GetLastCreatedNodes();
6189       aNewNodeGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
6190       aNewNodeGroup->Add(anIds);
6191     }
6192   }
6193
6194   // Update Python script
6195
6196   pyDump << "[ ";
6197   if ( aNewElemGroup->_is_nil() ) pyDump << "nothing, ";
6198   else                            pyDump << aNewElemGroup << ", ";
6199   if ( aNewNodeGroup->_is_nil() ) pyDump << "nothing ] = ";
6200   else                            pyDump << aNewNodeGroup << " ] = ";
6201
6202   pyDump << this << ".DoubleNodeElemGroups2New( " << &theElems << ", "
6203          << &theNodesNot       << ", "
6204          << &theAffectedElems  << ", "
6205          << theElemGroupNeeded << ", "
6206          << theNodeGroupNeeded << " )";
6207
6208   aTwoGroups[0] = aNewElemGroup._retn();
6209   aTwoGroups[1] = aNewNodeGroup._retn();
6210   return aTwoGroups._retn();
6211
6212   SMESH_CATCH( SMESH::throwCorbaException );
6213   return 0;
6214 }
6215
6216 //================================================================================
6217 /*!
6218   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6219   This method provided for convenience works as DoubleNodes() described above.
6220   \param theElems - list of groups of elements (edges or faces) to be replicated
6221   \param theNodesNot - list of groups of nodes not to replicated
6222   \param theShape - shape to detect affected elements (element which geometric center
6223   located on or inside shape).
6224   The replicated nodes should be associated to affected elements.
6225   \return TRUE if operation has been completed successfully, FALSE otherwise
6226   \sa DoubleNodeGroupInRegion(), DoubleNodesInRegion()
6227 */
6228 //================================================================================
6229
6230 CORBA::Boolean
6231 SMESH_MeshEditor_i::DoubleNodeElemGroupsInRegion(const SMESH::ListOfGroups& theElems,
6232                                                  const SMESH::ListOfGroups& theNodesNot,
6233                                                  GEOM::GEOM_Object_ptr      theShape )
6234   throw (SALOME::SALOME_Exception)
6235 {
6236   SMESH_TRY;
6237   initData();
6238
6239
6240   SMESHDS_Mesh* aMeshDS = getMeshDS();
6241   TIDSortedElemSet anElems, aNodes;
6242   listOfGroupToSet(theElems, aMeshDS, anElems,false );
6243   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
6244
6245   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
6246   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
6247
6248   // Update Python script
6249   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroupsInRegion( " << &theElems << ", "
6250                 << &theNodesNot << ", " << theShape << " )";
6251
6252   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6253   return aResult;
6254
6255   SMESH_CATCH( SMESH::throwCorbaException );
6256   return 0;
6257 }
6258
6259 //================================================================================
6260 /*!
6261   \brief Identify the elements that will be affected by node duplication (actual
6262          duplication is not performed.
6263   This method is the first step of DoubleNodeElemGroupsInRegion.
6264   \param theElems - list of groups of elements (edges or faces) to be replicated
6265   \param theNodesNot - list of groups of nodes not to replicated
6266   \param theShape - shape to detect affected elements (element which geometric center
6267          located on or inside shape).
6268          The replicated nodes should be associated to affected elements.
6269   \return groups of affected elements
6270   \sa DoubleNodeElemGroupsInRegion()
6271 */
6272 //================================================================================
6273 SMESH::ListOfGroups*
6274 SMESH_MeshEditor_i::AffectedElemGroupsInRegion( const SMESH::ListOfGroups& theElems,
6275                                                 const SMESH::ListOfGroups& theNodesNot,
6276                                                 GEOM::GEOM_Object_ptr      theShape )
6277   throw (SALOME::SALOME_Exception)
6278 {
6279   SMESH_TRY;
6280   SMESH::ListOfGroups_var aListOfGroups = new SMESH::ListOfGroups();
6281   bool isEdgeGroup = false;
6282   bool isFaceGroup = false;
6283   bool isVolumeGroup = false;
6284   SMESH::SMESH_Group_var aNewEdgeGroup = myMesh_i->CreateGroup(SMESH::EDGE, "affectedEdges");
6285   SMESH::SMESH_Group_var aNewFaceGroup = myMesh_i->CreateGroup(SMESH::FACE, "affectedFaces");
6286   SMESH::SMESH_Group_var aNewVolumeGroup = myMesh_i->CreateGroup(SMESH::VOLUME, "affectedVolumes");
6287
6288   initData();
6289
6290   ::SMESH_MeshEditor aMeshEditor(myMesh);
6291
6292   SMESHDS_Mesh* aMeshDS = getMeshDS();
6293   TIDSortedElemSet anElems, aNodes;
6294   listOfGroupToSet(theElems, aMeshDS, anElems, false);
6295   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true);
6296
6297   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape(theShape);
6298   TIDSortedElemSet anAffected;
6299   bool aResult = aMeshEditor.AffectedElemGroupsInRegion(anElems, aNodes, aShape, anAffected);
6300
6301
6302   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6303
6304   TPythonDump pyDump;
6305   if (aResult)
6306   {
6307     int lg = anAffected.size();
6308     SMESH::long_array_var volumeIds = new SMESH::long_array;
6309     volumeIds->length(lg);
6310     SMESH::long_array_var faceIds = new SMESH::long_array;
6311     faceIds->length(lg);
6312     SMESH::long_array_var edgeIds = new SMESH::long_array;
6313     edgeIds->length(lg);
6314     int ivol = 0;
6315     int iface = 0;
6316     int iedge = 0;
6317
6318     TIDSortedElemSet::const_iterator eIt = anAffected.begin();
6319     for (; eIt != anAffected.end(); ++eIt)
6320     {
6321       const SMDS_MeshElement* anElem = *eIt;
6322       if (!anElem)
6323         continue;
6324       int elemId = anElem->GetID();
6325       if (myMesh->GetElementType(elemId, true) == SMDSAbs_Volume)
6326         volumeIds[ivol++] = elemId;
6327       else if (myMesh->GetElementType(elemId, true) == SMDSAbs_Face)
6328         faceIds[iface++] = elemId;
6329       else if (myMesh->GetElementType(elemId, true) == SMDSAbs_Edge)
6330         edgeIds[iedge++] = elemId;
6331     }
6332     volumeIds->length(ivol);
6333     faceIds->length(iface);
6334     edgeIds->length(iedge);
6335
6336     aNewVolumeGroup->Add(volumeIds);
6337     aNewFaceGroup->Add(faceIds);
6338     aNewEdgeGroup->Add(edgeIds);
6339     isVolumeGroup = (aNewVolumeGroup->Size() > 0);
6340     isFaceGroup = (aNewFaceGroup->Size() > 0);
6341     isEdgeGroup = (aNewEdgeGroup->Size() > 0);
6342   }
6343
6344   int nbGroups = 0;
6345   if (isEdgeGroup)   nbGroups++;
6346   if (isFaceGroup)   nbGroups++;
6347   if (isVolumeGroup) nbGroups++;
6348   aListOfGroups->length(nbGroups);
6349
6350   int i = 0;
6351   if (isEdgeGroup)   aListOfGroups[i++] = aNewEdgeGroup._retn();
6352   if (isFaceGroup)   aListOfGroups[i++] = aNewFaceGroup._retn();
6353   if (isVolumeGroup) aListOfGroups[i++] = aNewVolumeGroup._retn();
6354
6355   // Update Python script
6356
6357   pyDump << "[ ";
6358   if (isEdgeGroup)   pyDump << aNewEdgeGroup << ", ";
6359   if (isFaceGroup)   pyDump << aNewFaceGroup << ", ";
6360   if (isVolumeGroup) pyDump << aNewVolumeGroup << ", ";
6361   pyDump << "] = ";
6362   pyDump << this << ".AffectedElemGroupsInRegion( "
6363          << &theElems << ", " << &theNodesNot << ", " << theShape << " )";
6364
6365   return aListOfGroups._retn();
6366
6367   SMESH_CATCH( SMESH::throwCorbaException );
6368   return 0;
6369 }
6370
6371 //================================================================================
6372 /*!
6373   \brief Generated skin mesh (containing 2D cells) from 3D mesh
6374    The created 2D mesh elements based on nodes of free faces of boundary volumes
6375   \return TRUE if operation has been completed successfully, FALSE otherwise
6376 */
6377 //================================================================================
6378
6379 CORBA::Boolean SMESH_MeshEditor_i::Make2DMeshFrom3D()
6380   throw (SALOME::SALOME_Exception)
6381 {
6382   SMESH_TRY;
6383   initData();
6384
6385   bool aResult = getEditor().Make2DMeshFrom3D();
6386
6387   TPythonDump() << "isDone = " << this << ".Make2DMeshFrom3D()";
6388
6389   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6390   return aResult;
6391
6392   SMESH_CATCH( SMESH::throwCorbaException );
6393   return false;
6394 }
6395
6396 //================================================================================
6397 /*!
6398  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
6399  * The list of groups must contain at least two groups. The groups have to be disjoint:
6400  * no common element into two different groups.
6401  * The nodes of the internal faces at the boundaries of the groups are doubled.
6402  * Optionally, the internal faces are replaced by flat elements.
6403  * Triangles are transformed into prisms, and quadrangles into hexahedrons.
6404  * The flat elements are stored in groups of volumes.
6405  * These groups are named according to the position of the group in the list:
6406  * 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.
6407  * 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.
6408  * All the flat elements are gathered into the group named "joints3D" (or "joints2D" in 2D situation).
6409  * The flat element of the multiple junctions between the simple junction are stored in a group named "jointsMultiples".
6410  * \param theDomains - list of groups of volumes
6411  * \param createJointElems - if TRUE, create the elements
6412  * \param onAllBoundaries - if TRUE, the nodes and elements are also created on
6413  *        the boundary between \a theDomains and the rest mesh
6414  * \return TRUE if operation has been completed successfully, FALSE otherwise
6415  */
6416 //================================================================================
6417
6418 CORBA::Boolean
6419 SMESH_MeshEditor_i::DoubleNodesOnGroupBoundaries( const SMESH::ListOfGroups& theDomains,
6420                                                   CORBA::Boolean             createJointElems,
6421                                                   CORBA::Boolean             onAllBoundaries )
6422   throw (SALOME::SALOME_Exception)
6423 {
6424   bool isOK = false;
6425
6426   SMESH_TRY;
6427   initData();
6428
6429   SMESHDS_Mesh* aMeshDS = getMeshDS();
6430
6431   // MESSAGE("theDomains.length = "<<theDomains.length());
6432   if ( theDomains.length() <= 1 && !onAllBoundaries )
6433     THROW_SALOME_CORBA_EXCEPTION("At least 2 groups are required.", SALOME::BAD_PARAM);
6434
6435   vector<TIDSortedElemSet> domains;
6436   domains.resize( theDomains.length() );
6437
6438   for ( int i = 0, n = theDomains.length(); i < n; i++ )
6439   {
6440     SMESH::SMESH_GroupBase_var aGrp = theDomains[ i ];
6441     if ( !CORBA::is_nil( aGrp ) /*&& ( aGrp->GetType() != SMESH::NODE )*/ )
6442     {
6443 //      if ( aGrp->GetType() != SMESH::VOLUME )
6444 //        THROW_SALOME_CORBA_EXCEPTION("Not a volume group", SALOME::BAD_PARAM);
6445       SMESH::long_array_var anIDs = aGrp->GetIDs();
6446       arrayToSet( anIDs, aMeshDS, domains[ i ], SMDSAbs_All );
6447     }
6448   }
6449
6450   isOK = getEditor().DoubleNodesOnGroupBoundaries( domains, createJointElems, onAllBoundaries );
6451   // TODO publish the groups of flat elements in study
6452
6453   declareMeshModified( /*isReComputeSafe=*/ !isOK );
6454
6455   // Update Python script
6456   TPythonDump() << "isDone = " << this << ".DoubleNodesOnGroupBoundaries( " << &theDomains
6457                 << ", " << createJointElems << ", " << onAllBoundaries << " )";
6458
6459   SMESH_CATCH( SMESH::throwCorbaException );
6460
6461   myMesh_i->CreateGroupServants(); // publish created groups if any
6462
6463   return isOK;
6464 }
6465
6466 //================================================================================
6467 /*!
6468  * \brief Double nodes on some external faces and create flat elements.
6469  * Flat elements are mainly used by some types of mechanic calculations.
6470  *
6471  * Each group of the list must be constituted of faces.
6472  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
6473  * @param theGroupsOfFaces - list of groups of faces
6474  * @return TRUE if operation has been completed successfully, FALSE otherwise
6475  */
6476 //================================================================================
6477
6478 CORBA::Boolean
6479 SMESH_MeshEditor_i::CreateFlatElementsOnFacesGroups( const SMESH::ListOfGroups& theGroupsOfFaces )
6480   throw (SALOME::SALOME_Exception)
6481 {
6482   SMESH_TRY;
6483   initData();
6484
6485   SMESHDS_Mesh* aMeshDS = getMeshDS();
6486
6487   vector<TIDSortedElemSet> faceGroups;
6488   faceGroups.clear();
6489
6490   for ( int i = 0, n = theGroupsOfFaces.length(); i < n; i++ )
6491   {
6492     SMESH::SMESH_GroupBase_var aGrp = theGroupsOfFaces[ i ];
6493     if ( !CORBA::is_nil( aGrp ) && ( aGrp->GetType() != SMESH::NODE ) )
6494     {
6495       TIDSortedElemSet faceGroup;
6496       faceGroup.clear();
6497       faceGroups.push_back(faceGroup);
6498       SMESH::long_array_var anIDs = aGrp->GetIDs();
6499       arrayToSet( anIDs, aMeshDS, faceGroups[ i ], SMDSAbs_All );
6500     }
6501   }
6502
6503   bool aResult = getEditor().CreateFlatElementsOnFacesGroups( faceGroups );
6504   // TODO publish the groups of flat elements in study
6505
6506   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6507
6508   // Update Python script
6509   TPythonDump() << this << ".CreateFlatElementsOnFacesGroups( " << &theGroupsOfFaces << " )";
6510   return aResult;
6511
6512   SMESH_CATCH( SMESH::throwCorbaException );
6513   return false;
6514 }
6515
6516 //================================================================================
6517 /*!
6518  *  \brief Identify all the elements around a geom shape, get the faces delimiting
6519  *         the hole.
6520  *
6521  *  Build groups of volume to remove, groups of faces to replace on the skin of the
6522  *  object, groups of faces to remove inside the object, (idem edges).
6523  *  Build ordered list of nodes at the border of each group of faces to replace
6524  *  (to be used to build a geom subshape).
6525  */
6526 //================================================================================
6527
6528 void SMESH_MeshEditor_i::CreateHoleSkin(CORBA::Double                  radius,
6529                                         GEOM::GEOM_Object_ptr          theShape,
6530                                         const char*                    groupName,
6531                                         const SMESH::double_array&     theNodesCoords,
6532                                         SMESH::array_of_long_array_out GroupsOfNodes)
6533   throw (SALOME::SALOME_Exception)
6534 {
6535   SMESH_TRY;
6536
6537   initData();
6538   std::vector<std::vector<int> > aListOfListOfNodes;
6539   ::SMESH_MeshEditor aMeshEditor( myMesh );
6540
6541   theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
6542   if ( !theNodeSearcher )
6543     theNodeSearcher = SMESH_MeshAlgos::GetNodeSearcher( *getMeshDS() );
6544
6545   vector<double> nodesCoords;
6546   for ( CORBA::ULong i = 0; i < theNodesCoords.length(); i++)
6547   {
6548     nodesCoords.push_back( theNodesCoords[i] );
6549   }
6550
6551   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
6552   aMeshEditor.CreateHoleSkin(radius, aShape, theNodeSearcher, groupName,
6553                              nodesCoords, aListOfListOfNodes);
6554
6555   GroupsOfNodes = new SMESH::array_of_long_array;
6556   GroupsOfNodes->length( aListOfListOfNodes.size() );
6557   std::vector<std::vector<int> >::iterator llIt = aListOfListOfNodes.begin();
6558   for ( CORBA::Long i = 0; llIt != aListOfListOfNodes.end(); llIt++, i++ )
6559   {
6560     vector<int>& aListOfNodes = *llIt;
6561     vector<int>::iterator lIt = aListOfNodes.begin();;
6562     SMESH::long_array& aGroup = (*GroupsOfNodes)[ i ];
6563     aGroup.length( aListOfNodes.size() );
6564     for ( int j = 0; lIt != aListOfNodes.end(); lIt++, j++ )
6565       aGroup[ j ] = (*lIt);
6566   }
6567   TPythonDump() << "lists_nodes = " << this << ".CreateHoleSkin( "
6568                 << radius << ", "
6569                 << theShape
6570                 << ", '" << groupName << "', "
6571                 << theNodesCoords << " )";
6572
6573   SMESH_CATCH( SMESH::throwCorbaException );
6574 }
6575
6576 // issue 20749 ===================================================================
6577 /*!
6578  * \brief Creates missing boundary elements
6579  *  \param elements - elements whose boundary is to be checked
6580  *  \param dimension - defines type of boundary elements to create
6581  *  \param groupName - a name of group to store created boundary elements in,
6582  *                     "" means not to create the group
6583  *  \param meshName - a name of new mesh to store created boundary elements in,
6584  *                     "" means not to create the new mesh
6585  *  \param toCopyElements - if true, the checked elements will be copied into the new mesh
6586  *  \param toCopyExistingBondary - if true, not only new but also pre-existing
6587  *                                boundary elements will be copied into the new mesh
6588  *  \param group - returns the create group, if any
6589  *  \retval SMESH::SMESH_Mesh - the mesh where elements were added to
6590  */
6591 // ================================================================================
6592
6593 SMESH::SMESH_Mesh_ptr
6594 SMESH_MeshEditor_i::MakeBoundaryMesh(SMESH::SMESH_IDSource_ptr idSource,
6595                                      SMESH::Bnd_Dimension      dim,
6596                                      const char*               groupName,
6597                                      const char*               meshName,
6598                                      CORBA::Boolean            toCopyElements,
6599                                      CORBA::Boolean            toCopyExistingBondary,
6600                                      SMESH::SMESH_Group_out    group)
6601   throw (SALOME::SALOME_Exception)
6602 {
6603   SMESH_TRY;
6604   initData();
6605
6606   if ( dim > SMESH::BND_1DFROM2D )
6607     THROW_SALOME_CORBA_EXCEPTION("Invalid boundary dimension", SALOME::BAD_PARAM);
6608
6609   SMESHDS_Mesh* aMeshDS = getMeshDS();
6610
6611   SMESH::SMESH_Mesh_var mesh_var;
6612   SMESH::SMESH_Group_var group_var;
6613
6614   TPythonDump pyDump;
6615
6616   TIDSortedElemSet elements;
6617   SMDSAbs_ElementType elemType = (dim == SMESH::BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
6618   if ( idSourceToSet( idSource, aMeshDS, elements, elemType,/*emptyIfIsMesh=*/true ))
6619   {
6620     // mesh to fill in
6621     mesh_var =
6622       strlen(meshName) ? makeMesh(meshName) : SMESH::SMESH_Mesh::_duplicate(myMesh_i->_this());
6623     SMESH_Mesh_i* mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh_var );
6624     // other mesh
6625     SMESH_Mesh* smesh_mesh = (mesh_i==myMesh_i) ? (SMESH_Mesh*)0 : &mesh_i->GetImpl();
6626
6627     // group of new boundary elements
6628     SMESH_Group* smesh_group = 0;
6629     if ( strlen(groupName) )
6630     {
6631       group_var = mesh_i->CreateGroup( SMESH::ElementType(int(elemType)-1),groupName);
6632       if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( group_var ))
6633         smesh_group = group_i->GetSmeshGroup();
6634     }
6635
6636     // do it
6637     getEditor().MakeBoundaryMesh( elements,
6638                                   ::SMESH_MeshEditor::Bnd_Dimension(dim),
6639                                   smesh_group,
6640                                   smesh_mesh,
6641                                   toCopyElements,
6642                                   toCopyExistingBondary);
6643
6644     if ( smesh_mesh )
6645       smesh_mesh->GetMeshDS()->Modified();
6646   }
6647
6648   const char* dimName[] = { "BND_2DFROM3D", "BND_1DFROM3D", "BND_1DFROM2D" };
6649
6650   // result of MakeBoundaryMesh() is a tuple (mesh, group)
6651   if ( mesh_var->_is_nil() )
6652     pyDump << myMesh_i->_this() << ", ";
6653   else
6654     pyDump << mesh_var << ", ";
6655   if ( group_var->_is_nil() )
6656     pyDump << "_NoneGroup = "; // assignment to None is forbidden
6657   else
6658     pyDump << group_var << " = ";
6659   pyDump << this << ".MakeBoundaryMesh( "
6660          << idSource << ", "
6661          << "SMESH." << dimName[int(dim)] << ", "
6662          << "'" << groupName << "', "
6663          << "'" << meshName<< "', "
6664          << toCopyElements << ", "
6665          << toCopyExistingBondary << ")";
6666
6667   group = group_var._retn();
6668   return mesh_var._retn();
6669
6670   SMESH_CATCH( SMESH::throwCorbaException );
6671   return SMESH::SMESH_Mesh::_nil();
6672 }
6673
6674 //================================================================================
6675 /*!
6676  * \brief Creates missing boundary elements
6677  *  \param dimension - defines type of boundary elements to create
6678  *  \param groupName - a name of group to store all boundary elements in,
6679  *    "" means not to create the group
6680  *  \param meshName - a name of a new mesh, which is a copy of the initial 
6681  *    mesh + created boundary elements; "" means not to create the new mesh
6682  *  \param toCopyAll - if true, the whole initial mesh will be copied into
6683  *    the new mesh else only boundary elements will be copied into the new mesh
6684  *  \param groups - optional groups of elements to make boundary around
6685  *  \param mesh - returns the mesh where elements were added to
6686  *  \param group - returns the created group, if any
6687  *  \retval long - number of added boundary elements
6688  */
6689 //================================================================================
6690
6691 CORBA::Long SMESH_MeshEditor_i::MakeBoundaryElements(SMESH::Bnd_Dimension dim,
6692                                                      const char* groupName,
6693                                                      const char* meshName,
6694                                                      CORBA::Boolean toCopyAll,
6695                                                      const SMESH::ListOfIDSources& groups,
6696                                                      SMESH::SMESH_Mesh_out mesh,
6697                                                      SMESH::SMESH_Group_out group)
6698   throw (SALOME::SALOME_Exception)
6699 {
6700   SMESH_TRY;
6701   initData();
6702
6703   if ( dim > SMESH::BND_1DFROM2D )
6704     THROW_SALOME_CORBA_EXCEPTION("Invalid boundary dimension", SALOME::BAD_PARAM);
6705
6706   // separate groups belonging to this and other mesh
6707   SMESH::ListOfIDSources_var groupsOfThisMesh  = new SMESH::ListOfIDSources;
6708   SMESH::ListOfIDSources_var groupsOfOtherMesh = new SMESH::ListOfIDSources;
6709   groupsOfThisMesh ->length( groups.length() );
6710   groupsOfOtherMesh->length( groups.length() );
6711   int nbGroups = 0, nbGroupsOfOtherMesh = 0;
6712   for ( CORBA::ULong i = 0; i < groups.length(); ++i )
6713   {
6714     SMESH::SMESH_Mesh_var m = groups[i]->GetMesh();
6715     if ( myMesh_i != SMESH::DownCast<SMESH_Mesh_i*>( m ))
6716       groupsOfOtherMesh[ nbGroupsOfOtherMesh++ ] = groups[i];
6717     else
6718       groupsOfThisMesh[ nbGroups++ ] = groups[i];
6719     if ( SMESH::DownCast<SMESH_Mesh_i*>( groups[i] ))
6720       THROW_SALOME_CORBA_EXCEPTION("expected a group but received a mesh", SALOME::BAD_PARAM);
6721   }
6722   groupsOfThisMesh->length( nbGroups );
6723   groupsOfOtherMesh->length( nbGroupsOfOtherMesh );
6724
6725   int nbAdded = 0;
6726   TPythonDump pyDump;
6727
6728   if ( nbGroupsOfOtherMesh > 0 )
6729   {
6730     // process groups belonging to another mesh
6731     SMESH::SMESH_Mesh_var    otherMesh = groupsOfOtherMesh[0]->GetMesh();
6732     SMESH::SMESH_MeshEditor_var editor = otherMesh->GetMeshEditor();
6733     nbAdded += editor->MakeBoundaryElements( dim, groupName, meshName, toCopyAll,
6734                                              groupsOfOtherMesh, mesh, group );
6735   }
6736
6737   SMESH::SMESH_Mesh_var mesh_var;
6738   SMESH::SMESH_Group_var group_var;
6739
6740   // get mesh to fill
6741   mesh_var = SMESH::SMESH_Mesh::_duplicate( myMesh_i->_this() );
6742   const bool toCopyMesh = ( strlen( meshName ) > 0 );
6743   if ( toCopyMesh )
6744   {
6745     if ( toCopyAll )
6746       mesh_var = SMESH_Gen_i::GetSMESHGen()->CopyMesh(mesh_var,
6747                                                       meshName,
6748                                                       /*toCopyGroups=*/false,
6749                                                       /*toKeepIDs=*/true);
6750     else
6751       mesh_var = makeMesh(meshName);
6752   }
6753   SMESH_Mesh_i* mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh_var );
6754   SMESH_Mesh*  tgtMesh = &mesh_i->GetImpl();
6755
6756   // source mesh
6757   SMESH_Mesh*     srcMesh = ( toCopyMesh && !toCopyAll ) ? myMesh : tgtMesh;
6758   SMESHDS_Mesh* srcMeshDS = srcMesh->GetMeshDS();
6759
6760   // group of boundary elements
6761   SMESH_Group* smesh_group = 0;
6762   SMDSAbs_ElementType elemType = (dim == SMESH::BND_2DFROM3D) ? SMDSAbs_Volume : SMDSAbs_Face;
6763   if ( strlen(groupName) )
6764   {
6765     SMESH::ElementType groupType = SMESH::ElementType( int(elemType)-1 );
6766     group_var = mesh_i->CreateGroup( groupType, groupName );
6767     if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( group_var ))
6768       smesh_group = group_i->GetSmeshGroup();
6769   }
6770
6771   TIDSortedElemSet elements;
6772
6773   if ( groups.length() > 0 )
6774   {
6775     for ( int i = 0; i < nbGroups; ++i )
6776     {
6777       elements.clear();
6778       if ( idSourceToSet( groupsOfThisMesh[i], srcMeshDS, elements, elemType,/*emptyIfIsMesh=*/0 ))
6779       {
6780         SMESH::Bnd_Dimension bdim = 
6781           ( elemType == SMDSAbs_Volume ) ? SMESH::BND_2DFROM3D : SMESH::BND_1DFROM2D;
6782         nbAdded += getEditor().MakeBoundaryMesh( elements,
6783                                                  ::SMESH_MeshEditor::Bnd_Dimension(bdim),
6784                                                  smesh_group,
6785                                                  tgtMesh,
6786                                                  /*toCopyElements=*/false,
6787                                                  /*toCopyExistingBondary=*/srcMesh != tgtMesh,
6788                                                  /*toAddExistingBondary=*/true,
6789                                                  /*aroundElements=*/true);
6790       }
6791     }
6792   }
6793   else
6794   {
6795     nbAdded += getEditor().MakeBoundaryMesh( elements,
6796                                              ::SMESH_MeshEditor::Bnd_Dimension(dim),
6797                                              smesh_group,
6798                                              tgtMesh,
6799                                              /*toCopyElements=*/false,
6800                                              /*toCopyExistingBondary=*/srcMesh != tgtMesh,
6801                                              /*toAddExistingBondary=*/true);
6802   }
6803   tgtMesh->GetMeshDS()->Modified();
6804
6805   const char* dimName[] = { "BND_2DFROM3D", "BND_1DFROM3D", "BND_1DFROM2D" };
6806
6807   // result of MakeBoundaryElements() is a tuple (nb, mesh, group)
6808   pyDump << "nbAdded, ";
6809   if ( mesh_var->_is_nil() )
6810     pyDump << myMesh_i->_this() << ", ";
6811   else
6812     pyDump << mesh_var << ", ";
6813   if ( group_var->_is_nil() )
6814     pyDump << "_NoneGroup = "; // assignment to None is forbidden
6815   else
6816     pyDump << group_var << " = ";
6817   pyDump << this << ".MakeBoundaryElements( "
6818          << "SMESH." << dimName[int(dim)] << ", "
6819          << "'" << groupName << "', "
6820          << "'" << meshName<< "', "
6821          << toCopyAll << ", "
6822          << groups << ")";
6823
6824   mesh  = mesh_var._retn();
6825   group = group_var._retn();
6826   return nbAdded;
6827
6828   SMESH_CATCH( SMESH::throwCorbaException );
6829   return 0;
6830 }