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