Salome HOME
23072: [CEA 1500] Split biquadratic elements into linear elements
[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 /*!
2143  * \brief Split bi-quadratic elements into linear ones without creation of additional nodes:
2144  *   - bi-quadratic triangle will be split into 3 linear quadrangles;
2145  *   - bi-quadratic quadrangle will be split into 4 linear quadrangles;
2146  *   - tri-quadratic hexahedron will be split into 8 linear hexahedra.
2147  *   Quadratic elements of lower dimension  adjacent to the split bi-quadratic element
2148  *   will be split in order to keep the mesh conformal.
2149  *  \param elems - elements to split
2150  */
2151 //================================================================================
2152
2153 void SMESH_MeshEditor_i::SplitBiQuadraticIntoLinear(const SMESH::ListOfIDSources& theElems)
2154   throw (SALOME::SALOME_Exception)
2155 {
2156   SMESH_TRY;
2157   initData();
2158
2159   TIDSortedElemSet elemSet;
2160   for ( size_t i = 0; i < theElems.length(); ++i )
2161   {
2162     SMESH::SMESH_IDSource_ptr elems = theElems[i].in();
2163     SMESH::SMESH_Mesh_var      mesh = elems->GetMesh();
2164     if ( mesh->GetId() != myMesh_i->GetId() )
2165       THROW_SALOME_CORBA_EXCEPTION("Wrong mesh of IDSource", SALOME::BAD_PARAM);
2166
2167     idSourceToSet( elems, getMeshDS(), elemSet, SMDSAbs_All );
2168   }
2169   getEditor().SplitBiQuadraticIntoLinear( elemSet );
2170
2171   declareMeshModified( /*isReComputeSafe=*/true ); // it does not influence Compute()
2172
2173   TPythonDump() << this << ".SplitBiQuadraticIntoLinear( "
2174                 << theElems << " )";
2175
2176   SMESH_CATCH( SMESH::throwCorbaException );
2177 }
2178
2179 //=======================================================================
2180 //function : Smooth
2181 //purpose  :
2182 //=======================================================================
2183
2184 CORBA::Boolean
2185 SMESH_MeshEditor_i::Smooth(const SMESH::long_array &              IDsOfElements,
2186                            const SMESH::long_array &              IDsOfFixedNodes,
2187                            CORBA::Long                            MaxNbOfIterations,
2188                            CORBA::Double                          MaxAspectRatio,
2189                            SMESH::SMESH_MeshEditor::Smooth_Method Method)
2190   throw (SALOME::SALOME_Exception)
2191 {
2192   return smooth( IDsOfElements, IDsOfFixedNodes, MaxNbOfIterations,
2193                  MaxAspectRatio, Method, false );
2194 }
2195
2196
2197 //=======================================================================
2198 //function : SmoothParametric
2199 //purpose  :
2200 //=======================================================================
2201
2202 CORBA::Boolean
2203 SMESH_MeshEditor_i::SmoothParametric(const SMESH::long_array &              IDsOfElements,
2204                                      const SMESH::long_array &              IDsOfFixedNodes,
2205                                      CORBA::Long                            MaxNbOfIterations,
2206                                      CORBA::Double                          MaxAspectRatio,
2207                                      SMESH::SMESH_MeshEditor::Smooth_Method Method)
2208   throw (SALOME::SALOME_Exception)
2209 {
2210   return smooth( IDsOfElements, IDsOfFixedNodes, MaxNbOfIterations,
2211                  MaxAspectRatio, Method, true );
2212 }
2213
2214
2215 //=======================================================================
2216 //function : SmoothObject
2217 //purpose  :
2218 //=======================================================================
2219
2220 CORBA::Boolean
2221 SMESH_MeshEditor_i::SmoothObject(SMESH::SMESH_IDSource_ptr              theObject,
2222                                  const SMESH::long_array &              IDsOfFixedNodes,
2223                                  CORBA::Long                            MaxNbOfIterations,
2224                                  CORBA::Double                          MaxAspectRatio,
2225                                  SMESH::SMESH_MeshEditor::Smooth_Method Method)
2226   throw (SALOME::SALOME_Exception)
2227 {
2228   return smoothObject (theObject, IDsOfFixedNodes, MaxNbOfIterations,
2229                        MaxAspectRatio, Method, false);
2230 }
2231
2232
2233 //=======================================================================
2234 //function : SmoothParametricObject
2235 //purpose  :
2236 //=======================================================================
2237
2238 CORBA::Boolean
2239 SMESH_MeshEditor_i::SmoothParametricObject(SMESH::SMESH_IDSource_ptr              theObject,
2240                                            const SMESH::long_array &              IDsOfFixedNodes,
2241                                            CORBA::Long                            MaxNbOfIterations,
2242                                            CORBA::Double                          MaxAspectRatio,
2243                                            SMESH::SMESH_MeshEditor::Smooth_Method Method)
2244   throw (SALOME::SALOME_Exception)
2245 {
2246   return smoothObject (theObject, IDsOfFixedNodes, MaxNbOfIterations,
2247                        MaxAspectRatio, Method, true);
2248 }
2249
2250
2251 //=============================================================================
2252 /*!
2253  *
2254  */
2255 //=============================================================================
2256
2257 CORBA::Boolean
2258 SMESH_MeshEditor_i::smooth(const SMESH::long_array &              IDsOfElements,
2259                            const SMESH::long_array &              IDsOfFixedNodes,
2260                            CORBA::Long                            MaxNbOfIterations,
2261                            CORBA::Double                          MaxAspectRatio,
2262                            SMESH::SMESH_MeshEditor::Smooth_Method Method,
2263                            bool                                   IsParametric)
2264   throw (SALOME::SALOME_Exception)
2265 {
2266   SMESH_TRY;
2267   initData();
2268
2269   SMESHDS_Mesh* aMesh = getMeshDS();
2270
2271   TIDSortedElemSet elements;
2272   arrayToSet(IDsOfElements, aMesh, elements, SMDSAbs_Face);
2273
2274   set<const SMDS_MeshNode*> fixedNodes;
2275   for (int i = 0; i < IDsOfFixedNodes.length(); i++) {
2276     CORBA::Long index = IDsOfFixedNodes[i];
2277     const SMDS_MeshNode * node = aMesh->FindNode(index);
2278     if ( node )
2279       fixedNodes.insert( node );
2280   }
2281   ::SMESH_MeshEditor::SmoothMethod method = ::SMESH_MeshEditor::LAPLACIAN;
2282   if ( Method != SMESH::SMESH_MeshEditor::LAPLACIAN_SMOOTH )
2283     method = ::SMESH_MeshEditor::CENTROIDAL;
2284
2285   getEditor().Smooth(elements, fixedNodes, method,
2286                   MaxNbOfIterations, MaxAspectRatio, IsParametric );
2287
2288   declareMeshModified( /*isReComputeSafe=*/true ); // does not prevent re-compute
2289
2290   // Update Python script
2291   TPythonDump() << "isDone = " << this << "."
2292                 << (IsParametric ? "SmoothParametric( " : "Smooth( ")
2293                 << IDsOfElements << ", "     << IDsOfFixedNodes << ", "
2294                 << TVar( MaxNbOfIterations ) << ", " << TVar( MaxAspectRatio ) << ", "
2295                 << "SMESH.SMESH_MeshEditor."
2296                 << ( Method == SMESH::SMESH_MeshEditor::CENTROIDAL_SMOOTH ?
2297                      "CENTROIDAL_SMOOTH )" : "LAPLACIAN_SMOOTH )");
2298
2299   return true;
2300
2301   SMESH_CATCH( SMESH::throwCorbaException );
2302   return 0;
2303 }
2304
2305 //=============================================================================
2306 /*!
2307  *
2308  */
2309 //=============================================================================
2310
2311 CORBA::Boolean
2312 SMESH_MeshEditor_i::smoothObject(SMESH::SMESH_IDSource_ptr              theObject,
2313                                  const SMESH::long_array &              IDsOfFixedNodes,
2314                                  CORBA::Long                            MaxNbOfIterations,
2315                                  CORBA::Double                          MaxAspectRatio,
2316                                  SMESH::SMESH_MeshEditor::Smooth_Method Method,
2317                                  bool                                   IsParametric)
2318   throw (SALOME::SALOME_Exception)
2319 {
2320   SMESH_TRY;
2321   initData();
2322
2323   TPythonDump aTPythonDump;  // suppress dump in smooth()
2324
2325   prepareIdSource( theObject );
2326   SMESH::long_array_var anElementsId = theObject->GetIDs();
2327   CORBA::Boolean isDone = smooth (anElementsId, IDsOfFixedNodes, MaxNbOfIterations,
2328                                   MaxAspectRatio, Method, IsParametric);
2329
2330   // Update Python script
2331   aTPythonDump << "isDone = " << this << "."
2332                << (IsParametric ? "SmoothParametricObject( " : "SmoothObject( ")
2333                << theObject << ", " << IDsOfFixedNodes << ", "
2334                << TVar( MaxNbOfIterations ) << ", " << TVar( MaxAspectRatio ) << ", "
2335                << "SMESH.SMESH_MeshEditor."
2336                << ( Method == SMESH::SMESH_MeshEditor::CENTROIDAL_SMOOTH ?
2337                     "CENTROIDAL_SMOOTH )" : "LAPLACIAN_SMOOTH )");
2338
2339   return isDone;
2340
2341   SMESH_CATCH( SMESH::throwCorbaException );
2342   return 0;
2343 }
2344
2345 //=============================================================================
2346 /*!
2347  *
2348  */
2349 //=============================================================================
2350
2351 void SMESH_MeshEditor_i::RenumberNodes()
2352   throw (SALOME::SALOME_Exception)
2353 {
2354   SMESH_TRY;
2355   // Update Python script
2356   TPythonDump() << this << ".RenumberNodes()";
2357
2358   getMeshDS()->Renumber( true );
2359
2360   SMESH_CATCH( SMESH::throwCorbaException );
2361 }
2362
2363 //=============================================================================
2364 /*!
2365  *
2366  */
2367 //=============================================================================
2368
2369 void SMESH_MeshEditor_i::RenumberElements()
2370   throw (SALOME::SALOME_Exception)
2371 {
2372   SMESH_TRY;
2373   // Update Python script
2374   TPythonDump() << this << ".RenumberElements()";
2375
2376   getMeshDS()->Renumber( false );
2377
2378   SMESH_CATCH( SMESH::throwCorbaException );
2379 }
2380
2381 //=======================================================================
2382 /*!
2383  * \brief Return groups by their IDs
2384  */
2385 //=======================================================================
2386
2387 SMESH::ListOfGroups* SMESH_MeshEditor_i::getGroups(const std::list<int>* groupIDs)
2388   throw (SALOME::SALOME_Exception)
2389 {
2390   SMESH_TRY;
2391   if ( !groupIDs )
2392     return 0;
2393   myMesh_i->CreateGroupServants();
2394   return myMesh_i->GetGroups( *groupIDs );
2395
2396   SMESH_CATCH( SMESH::throwCorbaException );
2397   return 0;
2398 }
2399
2400 //=======================================================================
2401 //function : RotationSweepObjects
2402 //purpose  :
2403 //=======================================================================
2404
2405 SMESH::ListOfGroups*
2406 SMESH_MeshEditor_i::RotationSweepObjects(const SMESH::ListOfIDSources & theNodes,
2407                                          const SMESH::ListOfIDSources & theEdges,
2408                                          const SMESH::ListOfIDSources & theFaces,
2409                                          const SMESH::AxisStruct &      theAxis,
2410                                          CORBA::Double                  theAngleInRadians,
2411                                          CORBA::Long                    theNbOfSteps,
2412                                          CORBA::Double                  theTolerance,
2413                                          const bool                     theMakeGroups)
2414   throw (SALOME::SALOME_Exception)
2415 {
2416   SMESH_TRY;
2417   initData();
2418
2419   TIDSortedElemSet elemsNodes[2];
2420   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
2421     SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
2422     while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
2423   }
2424   for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
2425     idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
2426   for ( int i = 0, nb = theFaces.length(); i < nb; ++i )
2427     idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face );
2428
2429   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2430   bool              makeWalls=true;
2431   if ( myIsPreviewMode )
2432   {
2433     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2434     TPreviewMesh * tmpMesh = getPreviewMesh();
2435     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2436     tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid );
2437     workElements = & copyElements[0];
2438     //makeWalls = false; -- faces are needed for preview
2439   }
2440
2441   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2442
2443   gp_Ax1 Ax1 (gp_Pnt( theAxis.x,  theAxis.y,  theAxis.z ),
2444               gp_Vec( theAxis.vx, theAxis.vy, theAxis.vz ));
2445
2446   ::SMESH_MeshEditor::PGroupIDs groupIds =
2447       getEditor().RotationSweep (workElements, Ax1, theAngleInRadians,
2448                                  theNbOfSteps, theTolerance, theMakeGroups, makeWalls);
2449
2450   SMESH::ListOfGroups * aGroups = theMakeGroups ? getGroups( groupIds.get()) : 0;
2451
2452   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2453
2454   if ( !myIsPreviewMode )
2455   {
2456     dumpGroupsList( aPythonDump, aGroups );
2457     aPythonDump << this<< ".RotationSweepObjects( "
2458                 << theNodes                  << ", "
2459                 << theEdges                  << ", "
2460                 << theFaces                  << ", "
2461                 << theAxis                   << ", "
2462                 << TVar( theAngleInRadians ) << ", "
2463                 << TVar( theNbOfSteps      ) << ", "
2464                 << TVar( theTolerance      ) << ", "
2465                 << theMakeGroups             << " )";
2466   }
2467   else
2468   {
2469     getPreviewMesh()->Remove( SMDSAbs_Volume );
2470   }
2471
2472   return aGroups ? aGroups : new SMESH::ListOfGroups;
2473
2474   SMESH_CATCH( SMESH::throwCorbaException );
2475   return 0;
2476 }
2477
2478 namespace MeshEditor_I
2479 {
2480   /*!
2481    * \brief Structure used to pass extrusion parameters to ::SMESH_MeshEditor
2482    */
2483   struct ExtrusionParams : public ::SMESH_MeshEditor::ExtrusParam
2484   {
2485     bool myIsExtrusionByNormal;
2486
2487     static int makeFlags( CORBA::Boolean MakeGroups,
2488                           CORBA::Boolean ByAverageNormal = false,
2489                           CORBA::Boolean UseInputElemsOnly = false,
2490                           CORBA::Long    Flags = 0,
2491                           CORBA::Boolean MakeBoundary = true )
2492     {
2493       if ( MakeGroups       ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_GROUPS;
2494       if ( ByAverageNormal  ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_BY_AVG_NORMAL;
2495       if ( UseInputElemsOnly) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_USE_INPUT_ELEMS_ONLY;
2496       if ( MakeBoundary     ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_BOUNDARY;
2497       return Flags;
2498     }
2499     // standard params
2500     ExtrusionParams(const SMESH::DirStruct &  theDir,
2501                     CORBA::Long               theNbOfSteps,
2502                     CORBA::Boolean            theMakeGroups):
2503       ::SMESH_MeshEditor::ExtrusParam ( gp_Vec( theDir.PS.x,
2504                                                 theDir.PS.y,
2505                                                 theDir.PS.z ),
2506                                         theNbOfSteps,
2507                                         makeFlags( theMakeGroups )),
2508       myIsExtrusionByNormal( false )
2509     {
2510     }
2511     // advanced params
2512     ExtrusionParams(const SMESH::DirStruct &  theDir,
2513                     CORBA::Long               theNbOfSteps,
2514                     CORBA::Boolean            theMakeGroups,
2515                     CORBA::Long               theExtrFlags,
2516                     CORBA::Double             theSewTolerance):
2517       ::SMESH_MeshEditor::ExtrusParam ( gp_Vec( theDir.PS.x,
2518                                                 theDir.PS.y,
2519                                                 theDir.PS.z ),
2520                                         theNbOfSteps,
2521                                         makeFlags( theMakeGroups, false, false,
2522                                                    theExtrFlags, false ),
2523                                         theSewTolerance ),
2524       myIsExtrusionByNormal( false )
2525     {
2526     }
2527     // params for extrusion by normal
2528     ExtrusionParams(CORBA::Double  theStepSize,
2529                     CORBA::Long    theNbOfSteps,
2530                     CORBA::Short   theDim,
2531                     CORBA::Boolean theByAverageNormal,
2532                     CORBA::Boolean theUseInputElemsOnly,
2533                     CORBA::Boolean theMakeGroups ):
2534       ::SMESH_MeshEditor::ExtrusParam ( theStepSize, 
2535                                         theNbOfSteps,
2536                                         makeFlags( theMakeGroups,
2537                                                    theByAverageNormal, theUseInputElemsOnly ),
2538                                         theDim),
2539       myIsExtrusionByNormal( true )
2540     {
2541     }
2542
2543     void SetNoGroups()
2544     {
2545       Flags() &= ~(::SMESH_MeshEditor::EXTRUSION_FLAG_GROUPS);
2546     }
2547   };
2548 }
2549
2550 //=======================================================================
2551 /*!
2552  * \brief Generate dim+1 elements by extrusion of elements along vector
2553  *  \param [in] edges - edges to extrude: a list including groups, sub-meshes or a mesh
2554  *  \param [in] faces - faces to extrude: a list including groups, sub-meshes or a mesh
2555  *  \param [in] nodes - nodes to extrude: a list including groups, sub-meshes or a mesh
2556  *  \param [in] stepVector - vector giving direction and distance of an extrusion step
2557  *  \param [in] nbOfSteps - number of elements to generate from one element
2558  *  \param [in] toMakeGroups - if true, new elements will be included into new groups
2559  *              corresponding to groups the input elements included in.
2560  *  \return ListOfGroups - new groups craeted if \a toMakeGroups is true
2561  */
2562 //=======================================================================
2563
2564 SMESH::ListOfGroups*
2565 SMESH_MeshEditor_i::ExtrusionSweepObjects(const SMESH::ListOfIDSources & theNodes,
2566                                           const SMESH::ListOfIDSources & theEdges,
2567                                           const SMESH::ListOfIDSources & theFaces,
2568                                           const SMESH::DirStruct &       theStepVector,
2569                                           CORBA::Long                    theNbOfSteps,
2570                                           CORBA::Boolean                 theToMakeGroups)
2571   throw (SALOME::SALOME_Exception)
2572 {
2573   SMESH_TRY;
2574   initData();
2575
2576   ExtrusionParams params( theStepVector, theNbOfSteps, theToMakeGroups );
2577
2578   TIDSortedElemSet elemsNodes[2];
2579   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
2580     SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
2581     while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
2582   }
2583   for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
2584     idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
2585   for ( int i = 0, nb = theFaces.length(); i < nb; ++i )
2586     idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face );
2587
2588   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2589   SMDSAbs_ElementType previewType = SMDSAbs_All; //SMDSAbs_Face;
2590   if ( myIsPreviewMode )
2591   {
2592     // if ( (*elemsNodes.begin())->GetType() == SMDSAbs_Node )
2593     //   previewType = SMDSAbs_Edge;
2594
2595     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2596     TPreviewMesh * tmpMesh = getPreviewMesh( previewType );
2597     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2598     tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid );
2599     workElements = & copyElements[0];
2600
2601     params.SetNoGroups();
2602   }
2603   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2604
2605   ::SMESH_MeshEditor::TTElemOfElemListMap aHistory;
2606   ::SMESH_MeshEditor::PGroupIDs groupIds =
2607       getEditor().ExtrusionSweep( workElements, params, aHistory );
2608
2609   SMESH::ListOfGroups * aGroups = theToMakeGroups ? getGroups( groupIds.get()) : 0;
2610
2611   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2612
2613   if ( !myIsPreviewMode )
2614   {
2615     dumpGroupsList( aPythonDump, aGroups );
2616     aPythonDump << this<< ".ExtrusionSweepObjects( "
2617                 << theNodes             << ", "
2618                 << theEdges             << ", "
2619                 << theFaces             << ", "
2620                 << theStepVector        << ", "
2621                 << TVar( theNbOfSteps ) << ", "
2622                 << theToMakeGroups      << " )";
2623   }
2624   else
2625   {
2626     getPreviewMesh( previewType )->Remove( SMDSAbs_Volume );
2627   }
2628
2629   return aGroups ? aGroups : new SMESH::ListOfGroups;
2630
2631   SMESH_CATCH( SMESH::throwCorbaException );
2632   return 0;
2633 }
2634
2635 //=======================================================================
2636 //function : ExtrusionByNormal
2637 //purpose  :
2638 //=======================================================================
2639
2640 SMESH::ListOfGroups*
2641 SMESH_MeshEditor_i::ExtrusionByNormal(const SMESH::ListOfIDSources& objects,
2642                                       CORBA::Double                 stepSize,
2643                                       CORBA::Long                   nbOfSteps,
2644                                       CORBA::Boolean                byAverageNormal,
2645                                       CORBA::Boolean                useInputElemsOnly,
2646                                       CORBA::Boolean                makeGroups,
2647                                       CORBA::Short                  dim)
2648   throw (SALOME::SALOME_Exception)
2649 {
2650   SMESH_TRY;
2651   initData();
2652
2653   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
2654
2655   ExtrusionParams params( stepSize, nbOfSteps, dim,
2656                           byAverageNormal, useInputElemsOnly, makeGroups );
2657
2658   SMDSAbs_ElementType elemType = ( dim == 1 ? SMDSAbs_Edge : SMDSAbs_Face );
2659   if ( objects.length() > 0 && !SMESH::DownCast<SMESH_Mesh_i*>( objects[0] ))
2660   {
2661     SMESH::array_of_ElementType_var elemTypes = objects[0]->GetTypes();
2662     if (( elemTypes->length() == 1 ) &&
2663         ( elemTypes[0] == SMESH::EDGE || elemTypes[0] == SMESH::FACE ))
2664       elemType = ( SMDSAbs_ElementType ) elemTypes[0];
2665   }
2666
2667   TIDSortedElemSet elemsNodes[2];
2668   for ( int i = 0, nb = objects.length(); i < nb; ++i )
2669     idSourceToSet( objects[i], getMeshDS(), elemsNodes[0], elemType );
2670
2671   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2672   SMDSAbs_ElementType previewType = SMDSAbs_Face;
2673   if ( myIsPreviewMode )
2674   {
2675     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2676     TPreviewMesh * tmpMesh = getPreviewMesh( previewType );
2677     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2678     workElements = & copyElements[0];
2679
2680     params.SetNoGroups();
2681   }
2682
2683   ::SMESH_MeshEditor::TTElemOfElemListMap aHistory;
2684   ::SMESH_MeshEditor::PGroupIDs groupIds =
2685       getEditor().ExtrusionSweep( workElements, params, aHistory );
2686
2687   SMESH::ListOfGroups * aGroups = makeGroups ? getGroups( groupIds.get()) : 0;
2688
2689   if (!myIsPreviewMode) {
2690     dumpGroupsList(aPythonDump, aGroups);
2691     aPythonDump << this << ".ExtrusionByNormal( " << objects
2692                 << ", " << TVar( stepSize )
2693                 << ", " << TVar( nbOfSteps )
2694                 << ", " << byAverageNormal
2695                 << ", " << useInputElemsOnly
2696                 << ", " << makeGroups
2697                 << ", " << dim
2698                 << " )";
2699   }
2700   else
2701   {
2702     getPreviewMesh( previewType )->Remove( SMDSAbs_Volume );
2703   }
2704
2705   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2706
2707   return aGroups ? aGroups : new SMESH::ListOfGroups;
2708
2709   SMESH_CATCH( SMESH::throwCorbaException );
2710   return 0;
2711 }
2712
2713 //=======================================================================
2714 //function : AdvancedExtrusion
2715 //purpose  :
2716 //=======================================================================
2717
2718 SMESH::ListOfGroups*
2719 SMESH_MeshEditor_i::AdvancedExtrusion(const SMESH::long_array & theIDsOfElements,
2720                                       const SMESH::DirStruct &  theStepVector,
2721                                       CORBA::Long               theNbOfSteps,
2722                                       CORBA::Long               theExtrFlags,
2723                                       CORBA::Double             theSewTolerance,
2724                                       CORBA::Boolean            theMakeGroups)
2725   throw (SALOME::SALOME_Exception)
2726 {
2727   SMESH_TRY;
2728   initData();
2729
2730   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2731
2732   ExtrusionParams params( theStepVector, theNbOfSteps, theMakeGroups,
2733                           theExtrFlags, theSewTolerance );
2734
2735   TIDSortedElemSet elemsNodes[2];
2736   arrayToSet( theIDsOfElements, getMeshDS(), elemsNodes[0] );
2737
2738   ::SMESH_MeshEditor::TTElemOfElemListMap aHistory;
2739   ::SMESH_MeshEditor::PGroupIDs groupIds =
2740       getEditor().ExtrusionSweep( elemsNodes, params, aHistory );
2741
2742   SMESH::ListOfGroups * aGroups = theMakeGroups ? getGroups( groupIds.get()) : 0;
2743
2744   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2745
2746   if ( !myIsPreviewMode ) {
2747     dumpGroupsList(aPythonDump, aGroups);
2748     aPythonDump << this << ".AdvancedExtrusion( "
2749                 << theIDsOfElements << ", "
2750                 << theStepVector << ", "
2751                 << theNbOfSteps << ", "
2752                 << theExtrFlags << ", "
2753                 << theSewTolerance << ", "
2754                 << theMakeGroups << " )";
2755   }
2756   else
2757   {
2758     getPreviewMesh()->Remove( SMDSAbs_Volume );
2759   }
2760
2761   return aGroups ? aGroups : new SMESH::ListOfGroups;
2762
2763   SMESH_CATCH( SMESH::throwCorbaException );
2764   return 0;
2765 }
2766
2767 //================================================================================
2768 /*!
2769  * \brief Convert extrusion error to IDL enum
2770  */
2771 //================================================================================
2772
2773 namespace
2774 {
2775 #define RETCASE(enm) case ::SMESH_MeshEditor::enm: return SMESH::SMESH_MeshEditor::enm;
2776
2777   SMESH::SMESH_MeshEditor::Extrusion_Error convExtrError( ::SMESH_MeshEditor::Extrusion_Error e )
2778   {
2779     switch ( e ) {
2780       RETCASE( EXTR_OK );
2781       RETCASE( EXTR_NO_ELEMENTS );
2782       RETCASE( EXTR_PATH_NOT_EDGE );
2783       RETCASE( EXTR_BAD_PATH_SHAPE );
2784       RETCASE( EXTR_BAD_STARTING_NODE );
2785       RETCASE( EXTR_BAD_ANGLES_NUMBER );
2786       RETCASE( EXTR_CANT_GET_TANGENT );
2787     }
2788     return SMESH::SMESH_MeshEditor::EXTR_OK;
2789   }
2790 }
2791
2792 //=======================================================================
2793 //function : extrusionAlongPath
2794 //purpose  :
2795 //=======================================================================
2796 SMESH::ListOfGroups*
2797 SMESH_MeshEditor_i::ExtrusionAlongPathObjects(const SMESH::ListOfIDSources & theNodes,
2798                                               const SMESH::ListOfIDSources & theEdges,
2799                                               const SMESH::ListOfIDSources & theFaces,
2800                                               SMESH::SMESH_IDSource_ptr      thePathMesh,
2801                                               GEOM::GEOM_Object_ptr          thePathShape,
2802                                               CORBA::Long                    theNodeStart,
2803                                               CORBA::Boolean                 theHasAngles,
2804                                               const SMESH::double_array &    theAngles,
2805                                               CORBA::Boolean                 theLinearVariation,
2806                                               CORBA::Boolean                 theHasRefPoint,
2807                                               const SMESH::PointStruct &     theRefPoint,
2808                                               bool                           theMakeGroups,
2809                                               SMESH::SMESH_MeshEditor::Extrusion_Error& theError)
2810   throw (SALOME::SALOME_Exception)
2811 {
2812   SMESH_TRY;
2813   initData();
2814
2815   SMESH::ListOfGroups_var aGroups = new SMESH::ListOfGroups;
2816
2817   theError = SMESH::SMESH_MeshEditor::EXTR_BAD_PATH_SHAPE;
2818   if ( thePathMesh->_is_nil() )
2819     return aGroups._retn();
2820
2821   // get a sub-mesh
2822   SMESH_subMesh* aSubMesh = 0;
2823   SMESH_Mesh_i* aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( thePathMesh );
2824   if ( thePathShape->_is_nil() )
2825   {
2826     // thePathMesh should be either a sub-mesh or a mesh with 1D elements only
2827     if ( SMESH_subMesh_i* sm = SMESH::DownCast<SMESH_subMesh_i*>( thePathMesh ))
2828     {
2829       SMESH::SMESH_Mesh_var mesh = thePathMesh->GetMesh();
2830       aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
2831       if ( !aMeshImp ) return aGroups._retn();
2832       aSubMesh = aMeshImp->GetImpl().GetSubMeshContaining( sm->GetId() );
2833       if ( !aSubMesh ) return aGroups._retn();
2834     }
2835     else if ( !aMeshImp ||
2836               aMeshImp->NbEdges() != aMeshImp->NbElements() )
2837     {
2838       return aGroups._retn();
2839     }
2840   }
2841   else
2842   {
2843     if ( !aMeshImp ) return aGroups._retn();
2844     TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( thePathShape );
2845     aSubMesh = aMeshImp->GetImpl().GetSubMesh( aShape );
2846     if ( !aSubMesh || !aSubMesh->GetSubMeshDS() )
2847       return aGroups._retn();
2848   }
2849
2850   SMDS_MeshNode* nodeStart =
2851     (SMDS_MeshNode*)aMeshImp->GetImpl().GetMeshDS()->FindNode(theNodeStart);
2852   if ( !nodeStart ) {
2853     theError = SMESH::SMESH_MeshEditor::EXTR_BAD_STARTING_NODE;
2854     return aGroups._retn();
2855   }
2856
2857   TIDSortedElemSet elemsNodes[2];
2858   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
2859     SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
2860     while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
2861   }
2862   for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
2863     idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
2864   for ( int i = 0, nb = theFaces.length(); i < nb; ++i )
2865     idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face );
2866
2867   list<double> angles;
2868   for (int i = 0; i < theAngles.length(); i++) {
2869     angles.push_back( theAngles[i] );
2870   }
2871
2872   gp_Pnt refPnt( theRefPoint.x, theRefPoint.y, theRefPoint.z );
2873
2874   int nbOldGroups = myMesh->NbGroup();
2875
2876   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2877   if ( myIsPreviewMode )
2878   {
2879     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2880     TPreviewMesh * tmpMesh = getPreviewMesh();
2881     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2882     tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid );
2883     workElements = & copyElements[0];
2884     theMakeGroups = false;
2885   }
2886
2887   ::SMESH_MeshEditor::Extrusion_Error error;
2888   if ( !aSubMesh )
2889     error = getEditor().ExtrusionAlongTrack( workElements, &(aMeshImp->GetImpl()), nodeStart,
2890                                              theHasAngles, angles, theLinearVariation,
2891                                              theHasRefPoint, refPnt, theMakeGroups );
2892   else
2893     error = getEditor().ExtrusionAlongTrack( workElements, aSubMesh, nodeStart,
2894                                              theHasAngles, angles, theLinearVariation,
2895                                              theHasRefPoint, refPnt, theMakeGroups );
2896
2897   declareMeshModified( /*isReComputeSafe=*/true );
2898   theError = convExtrError( error );
2899
2900   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2901   if ( theMakeGroups ) {
2902     list<int> groupIDs = myMesh->GetGroupIds();
2903     list<int>::iterator newBegin = groupIDs.begin();
2904     std::advance( newBegin, nbOldGroups ); // skip old groups
2905     groupIDs.erase( groupIDs.begin(), newBegin );
2906     aGroups = getGroups( & groupIDs );
2907     if ( ! &aGroups.in() ) aGroups = new SMESH::ListOfGroups;
2908   }
2909
2910   if ( !myIsPreviewMode ) {
2911     aPythonDump << "(" << aGroups << ", error) = "
2912                 << this << ".ExtrusionAlongPathObjects( "
2913                 << theNodes            << ", "
2914                 << theEdges            << ", "
2915                 << theFaces            << ", "
2916                 << thePathMesh         << ", "
2917                 << thePathShape        << ", "
2918                 << theNodeStart        << ", "
2919                 << theHasAngles        << ", "
2920                 << theAngles           << ", "
2921                 << theLinearVariation  << ", "
2922                 << theHasRefPoint      << ", "
2923                 << "SMESH.PointStruct( "
2924                 << ( theHasRefPoint ? theRefPoint.x : 0 ) << ", "
2925                 << ( theHasRefPoint ? theRefPoint.y : 0 ) << ", "
2926                 << ( theHasRefPoint ? theRefPoint.z : 0 ) << " ), "
2927                 << theMakeGroups       << " )";
2928   }
2929   else
2930   {
2931     getPreviewMesh()->Remove( SMDSAbs_Volume );
2932   }
2933
2934   return aGroups._retn();
2935
2936   SMESH_CATCH( SMESH::throwCorbaException );
2937   return 0;
2938 }
2939
2940 //================================================================================
2941 /*!
2942  * \brief Compute rotation angles for ExtrusionAlongPath as linear variation
2943  * of given angles along path steps
2944  * \param PathMesh mesh containing a 1D sub-mesh on the edge, along
2945  *                which proceeds the extrusion
2946  * \param PathShape is shape(edge); as the mesh can be complex, the edge
2947  *                 is used to define the sub-mesh for the path
2948  */
2949 //================================================================================
2950
2951 SMESH::double_array*
2952 SMESH_MeshEditor_i::LinearAnglesVariation(SMESH::SMESH_Mesh_ptr       thePathMesh,
2953                                           GEOM::GEOM_Object_ptr       thePathShape,
2954                                           const SMESH::double_array & theAngles)
2955 {
2956   SMESH::double_array_var aResult = new SMESH::double_array();
2957   int nbAngles = theAngles.length();
2958   if ( nbAngles > 0 && !thePathMesh->_is_nil() && !thePathShape->_is_nil() )
2959   {
2960     SMESH_Mesh_i* aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( thePathMesh );
2961     TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( thePathShape );
2962     SMESH_subMesh* aSubMesh = aMeshImp->GetImpl().GetSubMesh( aShape );
2963     if ( !aSubMesh || !aSubMesh->GetSubMeshDS())
2964       return aResult._retn();
2965     int nbSteps = aSubMesh->GetSubMeshDS()->NbElements();
2966     if ( nbSteps == nbAngles )
2967     {
2968       aResult.inout() = theAngles;
2969     }
2970     else
2971     {
2972       aResult->length( nbSteps );
2973       double rAn2St = double( nbAngles ) / double( nbSteps );
2974       double angPrev = 0, angle;
2975       for ( int iSt = 0; iSt < nbSteps; ++iSt )
2976       {
2977         double angCur = rAn2St * ( iSt+1 );
2978         double angCurFloor  = floor( angCur );
2979         double angPrevFloor = floor( angPrev );
2980         if ( angPrevFloor == angCurFloor )
2981           angle = rAn2St * theAngles[ int( angCurFloor ) ];
2982         else
2983         {
2984           int iP = int( angPrevFloor );
2985           double angPrevCeil = ceil(angPrev);
2986           angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
2987
2988           int iC = int( angCurFloor );
2989           if ( iC < nbAngles )
2990             angle += ( angCur - angCurFloor ) * theAngles[ iC ];
2991
2992           iP = int( angPrevCeil );
2993           while ( iC-- > iP )
2994             angle += theAngles[ iC ];
2995         }
2996         aResult[ iSt ] = angle;
2997         angPrev = angCur;
2998       }
2999     }
3000   }
3001   // Update Python script
3002   TPythonDump() << "rotAngles = " << theAngles;
3003   TPythonDump() << "rotAngles = " << this << ".LinearAnglesVariation( "
3004                 << thePathMesh  << ", "
3005                 << thePathShape << ", "
3006                 << "rotAngles )";
3007
3008   return aResult._retn();
3009 }
3010
3011 //=======================================================================
3012 //function : mirror
3013 //purpose  :
3014 //=======================================================================
3015
3016 SMESH::ListOfGroups*
3017 SMESH_MeshEditor_i::mirror(TIDSortedElemSet &                  theElements,
3018                            const SMESH::AxisStruct &           theAxis,
3019                            SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
3020                            CORBA::Boolean                      theCopy,
3021                            bool                                theMakeGroups,
3022                            ::SMESH_Mesh*                       theTargetMesh)
3023   throw (SALOME::SALOME_Exception)
3024 {
3025   SMESH_TRY;
3026   initData();
3027
3028   gp_Pnt P ( theAxis.x, theAxis.y, theAxis.z );
3029   gp_Vec V ( theAxis.vx, theAxis.vy, theAxis.vz );
3030
3031   if ( theTargetMesh )
3032     theCopy = false;
3033
3034   gp_Trsf aTrsf;
3035   switch ( theMirrorType ) {
3036   case  SMESH::SMESH_MeshEditor::POINT:
3037     aTrsf.SetMirror( P );
3038     break;
3039   case  SMESH::SMESH_MeshEditor::AXIS:
3040     aTrsf.SetMirror( gp_Ax1( P, V ));
3041     break;
3042   default:
3043     aTrsf.SetMirror( gp_Ax2( P, V ));
3044   }
3045
3046   TIDSortedElemSet  copyElements;
3047   TIDSortedElemSet* workElements = & theElements;
3048
3049   if ( myIsPreviewMode )
3050   {
3051     TPreviewMesh * tmpMesh = getPreviewMesh();
3052     tmpMesh->Copy( theElements, copyElements);
3053     if ( !theCopy && !theTargetMesh )
3054     {
3055       TIDSortedElemSet elemsAround, elemsAroundCopy;
3056       getElementsAround( theElements, getMeshDS(), elemsAround );
3057       tmpMesh->Copy( elemsAround, elemsAroundCopy);
3058     }
3059     workElements = & copyElements;
3060     theMakeGroups = false;
3061   }
3062
3063   ::SMESH_MeshEditor::PGroupIDs groupIds =
3064       getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
3065
3066   if ( theCopy && !myIsPreviewMode)
3067   {
3068     if ( theTargetMesh )
3069     {
3070       theTargetMesh->GetMeshDS()->Modified();
3071     }
3072     else
3073     {
3074       declareMeshModified( /*isReComputeSafe=*/false );
3075     }
3076   }
3077   return theMakeGroups ? getGroups(groupIds.get()) : 0;
3078
3079   SMESH_CATCH( SMESH::throwCorbaException );
3080   return 0;
3081 }
3082
3083 //=======================================================================
3084 //function : Mirror
3085 //purpose  :
3086 //=======================================================================
3087
3088 void SMESH_MeshEditor_i::Mirror(const SMESH::long_array &           theIDsOfElements,
3089                                 const SMESH::AxisStruct &           theAxis,
3090                                 SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
3091                                 CORBA::Boolean                      theCopy)
3092   throw (SALOME::SALOME_Exception)
3093 {
3094   if ( !myIsPreviewMode ) {
3095     TPythonDump() << this << ".Mirror( "
3096                   << theIDsOfElements              << ", "
3097                   << theAxis                       << ", "
3098                   << mirrorTypeName(theMirrorType) << ", "
3099                   << theCopy                       << " )";
3100   }
3101   if ( theIDsOfElements.length() > 0 )
3102   {
3103     TIDSortedElemSet elements;
3104     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3105     mirror(elements, theAxis, theMirrorType, theCopy, false);
3106   }
3107 }
3108
3109
3110 //=======================================================================
3111 //function : MirrorObject
3112 //purpose  :
3113 //=======================================================================
3114
3115 void SMESH_MeshEditor_i::MirrorObject(SMESH::SMESH_IDSource_ptr           theObject,
3116                                       const SMESH::AxisStruct &           theAxis,
3117                                       SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
3118                                       CORBA::Boolean                      theCopy)
3119   throw (SALOME::SALOME_Exception)
3120 {
3121   if ( !myIsPreviewMode ) {
3122     TPythonDump() << this << ".MirrorObject( "
3123                   << theObject                     << ", "
3124                   << theAxis                       << ", "
3125                   << mirrorTypeName(theMirrorType) << ", "
3126                   << theCopy                       << " )";
3127   }
3128   TIDSortedElemSet elements;
3129
3130   bool emptyIfIsMesh = myIsPreviewMode ? false : true;
3131
3132   if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
3133     mirror(elements, theAxis, theMirrorType, theCopy, false);
3134 }
3135
3136 //=======================================================================
3137 //function : MirrorMakeGroups
3138 //purpose  :
3139 //=======================================================================
3140
3141 SMESH::ListOfGroups*
3142 SMESH_MeshEditor_i::MirrorMakeGroups(const SMESH::long_array&            theIDsOfElements,
3143                                      const SMESH::AxisStruct&            theMirror,
3144                                      SMESH::SMESH_MeshEditor::MirrorType theMirrorType)
3145   throw (SALOME::SALOME_Exception)
3146 {
3147   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3148
3149   SMESH::ListOfGroups * aGroups = 0;
3150   if ( theIDsOfElements.length() > 0 )
3151   {
3152     TIDSortedElemSet elements;
3153     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3154     aGroups = mirror(elements, theMirror, theMirrorType, true, true);
3155   }
3156   if (!myIsPreviewMode) {
3157     dumpGroupsList(aPythonDump, aGroups);
3158     aPythonDump << this << ".MirrorMakeGroups( "
3159                 << theIDsOfElements              << ", "
3160                 << theMirror                     << ", "
3161                 << mirrorTypeName(theMirrorType) << " )";
3162   }
3163   return aGroups;
3164 }
3165
3166 //=======================================================================
3167 //function : MirrorObjectMakeGroups
3168 //purpose  :
3169 //=======================================================================
3170
3171 SMESH::ListOfGroups*
3172 SMESH_MeshEditor_i::MirrorObjectMakeGroups(SMESH::SMESH_IDSource_ptr           theObject,
3173                                            const SMESH::AxisStruct&            theMirror,
3174                                            SMESH::SMESH_MeshEditor::MirrorType theMirrorType)
3175   throw (SALOME::SALOME_Exception)
3176 {
3177   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3178
3179   SMESH::ListOfGroups * aGroups = 0;
3180   TIDSortedElemSet elements;
3181   if ( idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3182     aGroups = mirror(elements, theMirror, theMirrorType, true, true);
3183
3184   if (!myIsPreviewMode)
3185   {
3186     dumpGroupsList(aPythonDump,aGroups);
3187     aPythonDump << this << ".MirrorObjectMakeGroups( "
3188                 << theObject                     << ", "
3189                 << theMirror                     << ", "
3190                 << mirrorTypeName(theMirrorType) << " )";
3191   }
3192   return aGroups;
3193 }
3194
3195 //=======================================================================
3196 //function : MirrorMakeMesh
3197 //purpose  :
3198 //=======================================================================
3199
3200 SMESH::SMESH_Mesh_ptr
3201 SMESH_MeshEditor_i::MirrorMakeMesh(const SMESH::long_array&            theIDsOfElements,
3202                                    const SMESH::AxisStruct&            theMirror,
3203                                    SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
3204                                    CORBA::Boolean                      theCopyGroups,
3205                                    const char*                         theMeshName)
3206   throw (SALOME::SALOME_Exception)
3207 {
3208   SMESH_Mesh_i* mesh_i;
3209   SMESH::SMESH_Mesh_var mesh;
3210   { // open new scope to dump "MakeMesh" command
3211     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3212
3213     TPythonDump pydump; // to prevent dump at mesh creation
3214
3215     mesh = makeMesh( theMeshName );
3216     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3217     if (mesh_i && theIDsOfElements.length() > 0 )
3218     {
3219       TIDSortedElemSet elements;
3220       arrayToSet(theIDsOfElements, getMeshDS(), elements);
3221       mirror(elements, theMirror, theMirrorType,
3222              false, theCopyGroups, & mesh_i->GetImpl());
3223       mesh_i->CreateGroupServants();
3224     }
3225
3226     if (!myIsPreviewMode) {
3227       pydump << mesh << " = " << this << ".MirrorMakeMesh( "
3228              << theIDsOfElements              << ", "
3229              << theMirror                     << ", "
3230              << mirrorTypeName(theMirrorType) << ", "
3231              << theCopyGroups                 << ", '"
3232              << theMeshName                   << "' )";
3233     }
3234   }
3235
3236   //dump "GetGroups"
3237   if (!myIsPreviewMode && mesh_i)
3238     mesh_i->GetGroups();
3239
3240   return mesh._retn();
3241 }
3242
3243 //=======================================================================
3244 //function : MirrorObjectMakeMesh
3245 //purpose  :
3246 //=======================================================================
3247
3248 SMESH::SMESH_Mesh_ptr
3249 SMESH_MeshEditor_i::MirrorObjectMakeMesh(SMESH::SMESH_IDSource_ptr           theObject,
3250                                          const SMESH::AxisStruct&            theMirror,
3251                                          SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
3252                                          CORBA::Boolean                      theCopyGroups,
3253                                          const char*                         theMeshName)
3254   throw (SALOME::SALOME_Exception)
3255 {
3256   SMESH_Mesh_i* mesh_i;
3257   SMESH::SMESH_Mesh_var mesh;
3258   { // open new scope to dump "MakeMesh" command
3259     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3260
3261     TPythonDump pydump; // to prevent dump at mesh creation
3262
3263     mesh = makeMesh( theMeshName );
3264     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3265     TIDSortedElemSet elements;
3266     if ( mesh_i &&
3267          idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3268     {
3269       mirror(elements, theMirror, theMirrorType,
3270              false, theCopyGroups, & mesh_i->GetImpl());
3271       mesh_i->CreateGroupServants();
3272     }
3273     if (!myIsPreviewMode) {
3274       pydump << mesh << " = " << this << ".MirrorObjectMakeMesh( "
3275              << theObject                     << ", "
3276              << theMirror                     << ", "
3277              << mirrorTypeName(theMirrorType) << ", "
3278              << theCopyGroups                 << ", '"
3279              << theMeshName                   << "' )";
3280     }
3281   }
3282
3283   //dump "GetGroups"
3284   if (!myIsPreviewMode && mesh_i)
3285     mesh_i->GetGroups();
3286
3287   return mesh._retn();
3288 }
3289
3290 //=======================================================================
3291 //function : translate
3292 //purpose  :
3293 //=======================================================================
3294
3295 SMESH::ListOfGroups*
3296 SMESH_MeshEditor_i::translate(TIDSortedElemSet        & theElements,
3297                               const SMESH::DirStruct &  theVector,
3298                               CORBA::Boolean            theCopy,
3299                               bool                      theMakeGroups,
3300                               ::SMESH_Mesh*             theTargetMesh)
3301   throw (SALOME::SALOME_Exception)
3302 {
3303   SMESH_TRY;
3304   initData();
3305
3306   if ( theTargetMesh )
3307     theCopy = false;
3308
3309   gp_Trsf aTrsf;
3310   const SMESH::PointStruct * P = &theVector.PS;
3311   aTrsf.SetTranslation( gp_Vec( P->x, P->y, P->z ));
3312
3313   TIDSortedElemSet  copyElements;
3314   TIDSortedElemSet* workElements = &theElements;
3315
3316   if ( myIsPreviewMode )
3317   {
3318     TPreviewMesh * tmpMesh = getPreviewMesh();
3319     tmpMesh->Copy( theElements, copyElements);
3320     if ( !theCopy && !theTargetMesh )
3321     {
3322       TIDSortedElemSet elemsAround, elemsAroundCopy;
3323       getElementsAround( theElements, getMeshDS(), elemsAround );
3324       tmpMesh->Copy( elemsAround, elemsAroundCopy);
3325     }
3326     workElements = & copyElements;
3327     theMakeGroups = false;
3328   }
3329
3330   ::SMESH_MeshEditor::PGroupIDs groupIds =
3331       getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
3332
3333   if ( theCopy && !myIsPreviewMode )
3334   {
3335     if ( theTargetMesh )
3336     {
3337       theTargetMesh->GetMeshDS()->Modified();
3338     }
3339     else
3340     {
3341       declareMeshModified( /*isReComputeSafe=*/false );
3342     }
3343   }
3344
3345   return theMakeGroups ? getGroups(groupIds.get()) : 0;
3346
3347   SMESH_CATCH( SMESH::throwCorbaException );
3348   return 0;
3349 }
3350
3351 //=======================================================================
3352 //function : Translate
3353 //purpose  :
3354 //=======================================================================
3355
3356 void SMESH_MeshEditor_i::Translate(const SMESH::long_array & theIDsOfElements,
3357                                    const SMESH::DirStruct &  theVector,
3358                                    CORBA::Boolean            theCopy)
3359   throw (SALOME::SALOME_Exception)
3360 {
3361   if (!myIsPreviewMode) {
3362     TPythonDump() << this << ".Translate( "
3363                   << theIDsOfElements << ", "
3364                   << theVector        << ", "
3365                   << theCopy          << " )";
3366   }
3367   if (theIDsOfElements.length()) {
3368     TIDSortedElemSet elements;
3369     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3370     translate(elements, theVector, theCopy, false);
3371   }
3372 }
3373
3374 //=======================================================================
3375 //function : TranslateObject
3376 //purpose  :
3377 //=======================================================================
3378
3379 void SMESH_MeshEditor_i::TranslateObject(SMESH::SMESH_IDSource_ptr theObject,
3380                                          const SMESH::DirStruct &  theVector,
3381                                          CORBA::Boolean            theCopy)
3382   throw (SALOME::SALOME_Exception)
3383 {
3384   if (!myIsPreviewMode) {
3385     TPythonDump() << this << ".TranslateObject( "
3386                   << theObject << ", "
3387                   << theVector << ", "
3388                   << theCopy   << " )";
3389   }
3390   TIDSortedElemSet elements;
3391
3392   bool emptyIfIsMesh = myIsPreviewMode ? false : true;
3393
3394   if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
3395     translate(elements, theVector, theCopy, false);
3396 }
3397
3398 //=======================================================================
3399 //function : TranslateMakeGroups
3400 //purpose  :
3401 //=======================================================================
3402
3403 SMESH::ListOfGroups*
3404 SMESH_MeshEditor_i::TranslateMakeGroups(const SMESH::long_array& theIDsOfElements,
3405                                         const SMESH::DirStruct&  theVector)
3406   throw (SALOME::SALOME_Exception)
3407 {
3408   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3409
3410   SMESH::ListOfGroups * aGroups = 0;
3411   if (theIDsOfElements.length()) {
3412     TIDSortedElemSet elements;
3413     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3414     aGroups = translate(elements,theVector,true,true);
3415   }
3416   if (!myIsPreviewMode) {
3417     dumpGroupsList(aPythonDump, aGroups);
3418     aPythonDump << this << ".TranslateMakeGroups( "
3419                 << theIDsOfElements << ", "
3420                 << theVector        << " )";
3421   }
3422   return aGroups;
3423 }
3424
3425 //=======================================================================
3426 //function : TranslateObjectMakeGroups
3427 //purpose  :
3428 //=======================================================================
3429
3430 SMESH::ListOfGroups*
3431 SMESH_MeshEditor_i::TranslateObjectMakeGroups(SMESH::SMESH_IDSource_ptr theObject,
3432                                               const SMESH::DirStruct&   theVector)
3433   throw (SALOME::SALOME_Exception)
3434 {
3435   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3436
3437   SMESH::ListOfGroups * aGroups = 0;
3438   TIDSortedElemSet elements;
3439   if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3440     aGroups = translate(elements, theVector, true, true);
3441
3442   if (!myIsPreviewMode) {
3443     dumpGroupsList(aPythonDump, aGroups);
3444     aPythonDump << this << ".TranslateObjectMakeGroups( "
3445                 << theObject << ", "
3446                 << theVector << " )";
3447   }
3448   return aGroups;
3449 }
3450
3451 //=======================================================================
3452 //function : TranslateMakeMesh
3453 //purpose  :
3454 //=======================================================================
3455
3456 SMESH::SMESH_Mesh_ptr
3457 SMESH_MeshEditor_i::TranslateMakeMesh(const SMESH::long_array& theIDsOfElements,
3458                                       const SMESH::DirStruct&  theVector,
3459                                       CORBA::Boolean           theCopyGroups,
3460                                       const char*              theMeshName)
3461   throw (SALOME::SALOME_Exception)
3462 {
3463   SMESH_Mesh_i* mesh_i;
3464   SMESH::SMESH_Mesh_var mesh;
3465
3466   { // open new scope to dump "MakeMesh" command
3467     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3468
3469     TPythonDump pydump; // to prevent dump at mesh creation
3470
3471     mesh = makeMesh( theMeshName );
3472     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3473
3474     if ( mesh_i && theIDsOfElements.length() )
3475     {
3476       TIDSortedElemSet elements;
3477       arrayToSet(theIDsOfElements, getMeshDS(), elements);
3478       translate(elements, theVector, false, theCopyGroups, & mesh_i->GetImpl());
3479       mesh_i->CreateGroupServants();
3480     }
3481
3482     if ( !myIsPreviewMode ) {
3483       pydump << mesh << " = " << this << ".TranslateMakeMesh( "
3484              << theIDsOfElements << ", "
3485              << theVector        << ", "
3486              << theCopyGroups    << ", '"
3487              << theMeshName      << "' )";
3488     }
3489   }
3490
3491   //dump "GetGroups"
3492   if (!myIsPreviewMode && mesh_i)
3493     mesh_i->GetGroups();
3494
3495   return mesh._retn();
3496 }
3497
3498 //=======================================================================
3499 //function : TranslateObjectMakeMesh
3500 //purpose  :
3501 //=======================================================================
3502
3503 SMESH::SMESH_Mesh_ptr
3504 SMESH_MeshEditor_i::TranslateObjectMakeMesh(SMESH::SMESH_IDSource_ptr theObject,
3505                                             const SMESH::DirStruct&   theVector,
3506                                             CORBA::Boolean            theCopyGroups,
3507                                             const char*               theMeshName)
3508   throw (SALOME::SALOME_Exception)
3509 {
3510   SMESH_TRY;
3511   SMESH_Mesh_i* mesh_i;
3512   SMESH::SMESH_Mesh_var mesh;
3513   { // open new scope to dump "MakeMesh" command
3514     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3515
3516     TPythonDump pydump; // to prevent dump at mesh creation
3517     mesh = makeMesh( theMeshName );
3518     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3519
3520     TIDSortedElemSet elements;
3521     if ( mesh_i &&
3522          idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3523     {
3524       translate(elements, theVector,false, theCopyGroups, & mesh_i->GetImpl());
3525       mesh_i->CreateGroupServants();
3526     }
3527     if ( !myIsPreviewMode ) {
3528       pydump << mesh << " = " << this << ".TranslateObjectMakeMesh( "
3529              << theObject     << ", "
3530              << theVector     << ", "
3531              << theCopyGroups << ", '"
3532              << theMeshName   << "' )";
3533     }
3534   }
3535
3536   // dump "GetGroups"
3537   if (!myIsPreviewMode && mesh_i)
3538     mesh_i->GetGroups();
3539
3540   return mesh._retn();
3541
3542   SMESH_CATCH( SMESH::throwCorbaException );
3543   return 0;
3544 }
3545
3546 //=======================================================================
3547 //function : rotate
3548 //purpose  :
3549 //=======================================================================
3550
3551 SMESH::ListOfGroups*
3552 SMESH_MeshEditor_i::rotate(TIDSortedElemSet &        theElements,
3553                            const SMESH::AxisStruct & theAxis,
3554                            CORBA::Double             theAngle,
3555                            CORBA::Boolean            theCopy,
3556                            bool                      theMakeGroups,
3557                            ::SMESH_Mesh*             theTargetMesh)
3558   throw (SALOME::SALOME_Exception)
3559 {
3560   SMESH_TRY;
3561   initData();
3562
3563   if ( theTargetMesh )
3564     theCopy = false;
3565
3566   gp_Pnt P ( theAxis.x, theAxis.y, theAxis.z );
3567   gp_Vec V ( theAxis.vx, theAxis.vy, theAxis.vz );
3568
3569   gp_Trsf aTrsf;
3570   aTrsf.SetRotation( gp_Ax1( P, V ), theAngle);
3571
3572   TIDSortedElemSet  copyElements;
3573   TIDSortedElemSet* workElements = &theElements;
3574   if ( myIsPreviewMode ) {
3575     TPreviewMesh * tmpMesh = getPreviewMesh();
3576     tmpMesh->Copy( theElements, copyElements );
3577     if ( !theCopy && !theTargetMesh )
3578     {
3579       TIDSortedElemSet elemsAround, elemsAroundCopy;
3580       getElementsAround( theElements, getMeshDS(), elemsAround );
3581       tmpMesh->Copy( elemsAround, elemsAroundCopy);
3582     }
3583     workElements = &copyElements;
3584     theMakeGroups = false;
3585   }
3586
3587   ::SMESH_MeshEditor::PGroupIDs groupIds =
3588       getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
3589
3590   if ( theCopy && !myIsPreviewMode)
3591   {
3592     if ( theTargetMesh ) theTargetMesh->GetMeshDS()->Modified();
3593     else                 declareMeshModified( /*isReComputeSafe=*/false );
3594   }
3595
3596   return theMakeGroups ? getGroups(groupIds.get()) : 0;
3597
3598   SMESH_CATCH( SMESH::throwCorbaException );
3599   return 0;
3600 }
3601
3602 //=======================================================================
3603 //function : Rotate
3604 //purpose  :
3605 //=======================================================================
3606
3607 void SMESH_MeshEditor_i::Rotate(const SMESH::long_array & theIDsOfElements,
3608                                 const SMESH::AxisStruct & theAxis,
3609                                 CORBA::Double             theAngle,
3610                                 CORBA::Boolean            theCopy)
3611   throw (SALOME::SALOME_Exception)
3612 {
3613   if (!myIsPreviewMode) {
3614     TPythonDump() << this << ".Rotate( "
3615                   << theIDsOfElements << ", "
3616                   << theAxis          << ", "
3617                   << TVar( theAngle ) << ", "
3618                   << theCopy          << " )";
3619   }
3620   if (theIDsOfElements.length() > 0)
3621   {
3622     TIDSortedElemSet elements;
3623     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3624     rotate(elements,theAxis,theAngle,theCopy,false);
3625   }
3626 }
3627
3628 //=======================================================================
3629 //function : RotateObject
3630 //purpose  :
3631 //=======================================================================
3632
3633 void SMESH_MeshEditor_i::RotateObject(SMESH::SMESH_IDSource_ptr theObject,
3634                                       const SMESH::AxisStruct & theAxis,
3635                                       CORBA::Double             theAngle,
3636                                       CORBA::Boolean            theCopy)
3637   throw (SALOME::SALOME_Exception)
3638 {
3639   if ( !myIsPreviewMode ) {
3640     TPythonDump() << this << ".RotateObject( "
3641                   << theObject        << ", "
3642                   << theAxis          << ", "
3643                   << TVar( theAngle ) << ", "
3644                   << theCopy          << " )";
3645   }
3646   TIDSortedElemSet elements;
3647   bool emptyIfIsMesh = myIsPreviewMode ? false : true;
3648   if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
3649     rotate(elements,theAxis,theAngle,theCopy,false);
3650 }
3651
3652 //=======================================================================
3653 //function : RotateMakeGroups
3654 //purpose  :
3655 //=======================================================================
3656
3657 SMESH::ListOfGroups*
3658 SMESH_MeshEditor_i::RotateMakeGroups(const SMESH::long_array& theIDsOfElements,
3659                                      const SMESH::AxisStruct& theAxis,
3660                                      CORBA::Double            theAngle)
3661   throw (SALOME::SALOME_Exception)
3662 {
3663   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3664
3665   SMESH::ListOfGroups * aGroups = 0;
3666   if (theIDsOfElements.length() > 0)
3667   {
3668     TIDSortedElemSet elements;
3669     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3670     aGroups = rotate(elements,theAxis,theAngle,true,true);
3671   }
3672   if (!myIsPreviewMode) {
3673     dumpGroupsList(aPythonDump, aGroups);
3674     aPythonDump << this << ".RotateMakeGroups( "
3675                 << theIDsOfElements << ", "
3676                 << theAxis          << ", "
3677                 << TVar( theAngle ) << " )";
3678   }
3679   return aGroups;
3680 }
3681
3682 //=======================================================================
3683 //function : RotateObjectMakeGroups
3684 //purpose  :
3685 //=======================================================================
3686
3687 SMESH::ListOfGroups*
3688 SMESH_MeshEditor_i::RotateObjectMakeGroups(SMESH::SMESH_IDSource_ptr theObject,
3689                                            const SMESH::AxisStruct&  theAxis,
3690                                            CORBA::Double             theAngle)
3691   throw (SALOME::SALOME_Exception)
3692 {
3693   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3694
3695   SMESH::ListOfGroups * aGroups = 0;
3696   TIDSortedElemSet elements;
3697   if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3698     aGroups = rotate(elements, theAxis, theAngle, true, true);
3699
3700   if (!myIsPreviewMode) {
3701     dumpGroupsList(aPythonDump, aGroups);
3702     aPythonDump << this << ".RotateObjectMakeGroups( "
3703                 << theObject        << ", "
3704                 << theAxis          << ", "
3705                 << TVar( theAngle ) << " )";
3706   }
3707   return aGroups;
3708 }
3709
3710 //=======================================================================
3711 //function : RotateMakeMesh
3712 //purpose  :
3713 //=======================================================================
3714
3715 SMESH::SMESH_Mesh_ptr
3716 SMESH_MeshEditor_i::RotateMakeMesh(const SMESH::long_array& theIDsOfElements,
3717                                    const SMESH::AxisStruct& theAxis,
3718                                    CORBA::Double            theAngleInRadians,
3719                                    CORBA::Boolean           theCopyGroups,
3720                                    const char*              theMeshName)
3721   throw (SALOME::SALOME_Exception)
3722 {
3723   SMESH_TRY;
3724   SMESH::SMESH_Mesh_var mesh;
3725   SMESH_Mesh_i* mesh_i;
3726
3727   { // open new scope to dump "MakeMesh" command
3728     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3729
3730     TPythonDump pydump; // to prevent dump at mesh creation
3731
3732     mesh = makeMesh( theMeshName );
3733     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3734
3735     if ( mesh_i && theIDsOfElements.length() > 0 )
3736     {
3737       TIDSortedElemSet elements;
3738       arrayToSet(theIDsOfElements, getMeshDS(), elements);
3739       rotate(elements, theAxis, theAngleInRadians,
3740              false, theCopyGroups, & mesh_i->GetImpl());
3741       mesh_i->CreateGroupServants();
3742     }
3743     if ( !myIsPreviewMode ) {
3744       pydump << mesh << " = " << this << ".RotateMakeMesh( "
3745              << theIDsOfElements          << ", "
3746              << theAxis                   << ", "
3747              << TVar( theAngleInRadians ) << ", "
3748              << theCopyGroups             << ", '"
3749              << theMeshName               << "' )";
3750     }
3751   }
3752
3753   // dump "GetGroups"
3754   if (!myIsPreviewMode && mesh_i && theIDsOfElements.length() > 0 )
3755     mesh_i->GetGroups();
3756
3757   return mesh._retn();
3758
3759   SMESH_CATCH( SMESH::throwCorbaException );
3760   return 0;
3761 }
3762
3763 //=======================================================================
3764 //function : RotateObjectMakeMesh
3765 //purpose  :
3766 //=======================================================================
3767
3768 SMESH::SMESH_Mesh_ptr
3769 SMESH_MeshEditor_i::RotateObjectMakeMesh(SMESH::SMESH_IDSource_ptr theObject,
3770                                          const SMESH::AxisStruct&  theAxis,
3771                                          CORBA::Double             theAngleInRadians,
3772                                          CORBA::Boolean            theCopyGroups,
3773                                          const char*               theMeshName)
3774   throw (SALOME::SALOME_Exception)
3775 {
3776   SMESH_TRY;
3777   SMESH::SMESH_Mesh_var mesh;
3778   SMESH_Mesh_i* mesh_i;
3779
3780   {// open new scope to dump "MakeMesh" command
3781    // and then "GetGroups" using SMESH_Mesh::GetGroups()
3782
3783     TPythonDump pydump; // to prevent dump at mesh creation
3784     mesh = makeMesh( theMeshName );
3785     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3786
3787     TIDSortedElemSet elements;
3788     if (mesh_i &&
3789         idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3790     {
3791       rotate(elements, theAxis, theAngleInRadians,
3792              false, theCopyGroups, & mesh_i->GetImpl());
3793       mesh_i->CreateGroupServants();
3794     }
3795     if ( !myIsPreviewMode ) {
3796       pydump << mesh << " = " << this << ".RotateObjectMakeMesh( "
3797              << theObject                 << ", "
3798              << theAxis                   << ", "
3799              << TVar( theAngleInRadians ) << ", "
3800              << theCopyGroups             << ", '"
3801              << theMeshName               << "' )";
3802     }
3803   }
3804
3805   // dump "GetGroups"
3806   if (!myIsPreviewMode && mesh_i)
3807     mesh_i->GetGroups();
3808
3809   return mesh._retn();
3810
3811   SMESH_CATCH( SMESH::throwCorbaException );
3812   return 0;
3813 }
3814
3815 //=======================================================================
3816 //function : scale
3817 //purpose  :
3818 //=======================================================================
3819
3820 SMESH::ListOfGroups*
3821 SMESH_MeshEditor_i::scale(SMESH::SMESH_IDSource_ptr  theObject,
3822                           const SMESH::PointStruct&  thePoint,
3823                           const SMESH::double_array& theScaleFact,
3824                           CORBA::Boolean             theCopy,
3825                           bool                       theMakeGroups,
3826                           ::SMESH_Mesh*              theTargetMesh)
3827   throw (SALOME::SALOME_Exception)
3828 {
3829   SMESH_TRY;
3830   initData();
3831   if ( theScaleFact.length() < 1 )
3832     THROW_SALOME_CORBA_EXCEPTION("Scale factor not given", SALOME::BAD_PARAM);
3833   if ( theScaleFact.length() == 2 )
3834     THROW_SALOME_CORBA_EXCEPTION("Invalid nb of scale factors : 2", SALOME::BAD_PARAM);
3835
3836   if ( theTargetMesh )
3837     theCopy = false;
3838
3839   TIDSortedElemSet elements;
3840   bool emptyIfIsMesh = myIsPreviewMode ? false : true;
3841   if ( !idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
3842     return 0;
3843
3844   double S[3] = {
3845     theScaleFact[0],
3846     (theScaleFact.length() == 1) ? theScaleFact[0] : theScaleFact[1],
3847     (theScaleFact.length() == 1) ? theScaleFact[0] : theScaleFact[2],
3848   };
3849   gp_Trsf aTrsf;
3850
3851 #if OCC_VERSION_LARGE > 0x06070100
3852   // fight against orthogonalization
3853   // aTrsf.SetValues( S[0], 0,    0,    thePoint.x * (1-S[0]),
3854   //                  0,    S[1], 0,    thePoint.y * (1-S[1]),
3855   //                  0,    0,    S[2], thePoint.z * (1-S[2]) );
3856   aTrsf.SetScale( gp::Origin(), 1.0 ); // set form which is used to make group names
3857   gp_XYZ & loc = ( gp_XYZ& ) aTrsf.TranslationPart();
3858   gp_Mat & M   = ( gp_Mat& ) aTrsf.HVectorialPart();
3859   loc.SetCoord( thePoint.x * (1-S[0]),
3860                 thePoint.y * (1-S[1]),
3861                 thePoint.z * (1-S[2]));
3862   M.SetDiagonal( S[0], S[1], S[2] );
3863
3864 #else
3865   double tol = std::numeric_limits<double>::max();
3866   aTrsf.SetValues( S[0], 0,    0,    thePoint.x * (1-S[0]),
3867                    0,    S[1], 0,    thePoint.y * (1-S[1]),
3868                    0,    0,    S[2], thePoint.z * (1-S[2]),   tol, tol);
3869 #endif
3870
3871   TIDSortedElemSet  copyElements;
3872   TIDSortedElemSet* workElements = &elements;
3873   if ( myIsPreviewMode )
3874   {
3875     TPreviewMesh * tmpMesh = getPreviewMesh();
3876     tmpMesh->Copy( elements, copyElements);
3877     if ( !theCopy && !theTargetMesh )
3878     {
3879       TIDSortedElemSet elemsAround, elemsAroundCopy;
3880       getElementsAround( elements, getMeshDS(), elemsAround );
3881       tmpMesh->Copy( elemsAround, elemsAroundCopy);
3882     }
3883     workElements = & copyElements;
3884     theMakeGroups = false;
3885   }
3886
3887   ::SMESH_MeshEditor::PGroupIDs groupIds =
3888       getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
3889
3890   if ( theCopy && !myIsPreviewMode )
3891   {
3892     if ( theTargetMesh ) theTargetMesh->GetMeshDS()->Modified();
3893     else                 declareMeshModified( /*isReComputeSafe=*/false );
3894   }
3895   return theMakeGroups ? getGroups(groupIds.get()) : 0;
3896
3897   SMESH_CATCH( SMESH::throwCorbaException );
3898   return 0;
3899 }
3900
3901 //=======================================================================
3902 //function : Scale
3903 //purpose  :
3904 //=======================================================================
3905
3906 void SMESH_MeshEditor_i::Scale(SMESH::SMESH_IDSource_ptr  theObject,
3907                                const SMESH::PointStruct&  thePoint,
3908                                const SMESH::double_array& theScaleFact,
3909                                CORBA::Boolean             theCopy)
3910   throw (SALOME::SALOME_Exception)
3911 {
3912   if ( !myIsPreviewMode ) {
3913     TPythonDump() << this << ".Scale( "
3914                   << theObject            << ", "
3915                   << thePoint             << ", "
3916                   << TVar( theScaleFact ) << ", "
3917                   << theCopy              << " )";
3918   }
3919   scale(theObject, thePoint, theScaleFact, theCopy, false);
3920 }
3921
3922
3923 //=======================================================================
3924 //function : ScaleMakeGroups
3925 //purpose  :
3926 //=======================================================================
3927
3928 SMESH::ListOfGroups*
3929 SMESH_MeshEditor_i::ScaleMakeGroups(SMESH::SMESH_IDSource_ptr  theObject,
3930                                     const SMESH::PointStruct&  thePoint,
3931                                     const SMESH::double_array& theScaleFact)
3932   throw (SALOME::SALOME_Exception)
3933 {
3934   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3935
3936   SMESH::ListOfGroups * aGroups = scale(theObject, thePoint, theScaleFact, true, true);
3937   if (!myIsPreviewMode) {
3938     dumpGroupsList(aPythonDump, aGroups);
3939     aPythonDump << this << ".Scale("
3940                 << theObject            << ","
3941                 << thePoint             << ","
3942                 << TVar( theScaleFact ) << ",True,True)";
3943   }
3944   return aGroups;
3945 }
3946
3947
3948 //=======================================================================
3949 //function : ScaleMakeMesh
3950 //purpose  :
3951 //=======================================================================
3952
3953 SMESH::SMESH_Mesh_ptr
3954 SMESH_MeshEditor_i::ScaleMakeMesh(SMESH::SMESH_IDSource_ptr  theObject,
3955                                   const SMESH::PointStruct&  thePoint,
3956                                   const SMESH::double_array& theScaleFact,
3957                                   CORBA::Boolean             theCopyGroups,
3958                                   const char*                theMeshName)
3959   throw (SALOME::SALOME_Exception)
3960 {
3961   SMESH_Mesh_i* mesh_i;
3962   SMESH::SMESH_Mesh_var mesh;
3963   { // open new scope to dump "MakeMesh" command
3964     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3965
3966     TPythonDump pydump; // to prevent dump at mesh creation
3967     mesh = makeMesh( theMeshName );
3968     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3969
3970     if ( mesh_i )
3971     {
3972       scale(theObject, thePoint, theScaleFact,false, theCopyGroups, & mesh_i->GetImpl());
3973       mesh_i->CreateGroupServants();
3974     }
3975     if ( !myIsPreviewMode )
3976       pydump << mesh << " = " << this << ".ScaleMakeMesh( "
3977              << theObject            << ", "
3978              << thePoint             << ", "
3979              << TVar( theScaleFact ) << ", "
3980              << theCopyGroups        << ", '"
3981              << theMeshName          << "' )";
3982   }
3983
3984   // dump "GetGroups"
3985   if (!myIsPreviewMode && mesh_i)
3986     mesh_i->GetGroups();
3987
3988   return mesh._retn();
3989 }
3990
3991
3992 //=======================================================================
3993 //function : findCoincidentNodes
3994 //purpose  :
3995 //=======================================================================
3996
3997 void SMESH_MeshEditor_i::
3998 findCoincidentNodes (TIDSortedNodeSet &             Nodes,
3999                      CORBA::Double                  Tolerance,
4000                      SMESH::array_of_long_array_out GroupsOfNodes,
4001                      CORBA::Boolean                 SeparateCornersAndMedium)
4002 {
4003   ::SMESH_MeshEditor::TListOfListOfNodes aListOfListOfNodes;
4004   getEditor().FindCoincidentNodes( Nodes, Tolerance, aListOfListOfNodes, SeparateCornersAndMedium );
4005
4006   GroupsOfNodes = new SMESH::array_of_long_array;
4007   GroupsOfNodes->length( aListOfListOfNodes.size() );
4008   ::SMESH_MeshEditor::TListOfListOfNodes::iterator llIt = aListOfListOfNodes.begin();
4009   for ( CORBA::Long i = 0; llIt != aListOfListOfNodes.end(); llIt++, i++ )
4010   {
4011     list< const SMDS_MeshNode* >& aListOfNodes = *llIt;
4012     list< const SMDS_MeshNode* >::iterator lIt = aListOfNodes.begin();;
4013     SMESH::long_array& aGroup = (*GroupsOfNodes)[ i ];
4014     aGroup.length( aListOfNodes.size() );
4015     for ( int j = 0; lIt != aListOfNodes.end(); lIt++, j++ )
4016       aGroup[ j ] = (*lIt)->GetID();
4017   }
4018 }
4019
4020 //=======================================================================
4021 //function : FindCoincidentNodes
4022 //purpose  :
4023 //=======================================================================
4024
4025 void SMESH_MeshEditor_i::
4026 FindCoincidentNodes (CORBA::Double                  Tolerance,
4027                      SMESH::array_of_long_array_out GroupsOfNodes,
4028                      CORBA::Boolean                 SeparateCornersAndMedium)
4029   throw (SALOME::SALOME_Exception)
4030 {
4031   SMESH_TRY;
4032   initData();
4033
4034   TIDSortedNodeSet nodes; // no input nodes
4035   findCoincidentNodes( nodes, Tolerance, GroupsOfNodes, SeparateCornersAndMedium );
4036
4037   TPythonDump() << "coincident_nodes = " << this << ".FindCoincidentNodes( "
4038                 << Tolerance << ", "
4039                 << SeparateCornersAndMedium << " )";
4040
4041   SMESH_CATCH( SMESH::throwCorbaException );
4042 }
4043
4044 //=======================================================================
4045 //function : FindCoincidentNodesOnPart
4046 //purpose  :
4047 //=======================================================================
4048
4049 void SMESH_MeshEditor_i::
4050 FindCoincidentNodesOnPart(SMESH::SMESH_IDSource_ptr      theObject,
4051                           CORBA::Double                  Tolerance,
4052                           SMESH::array_of_long_array_out GroupsOfNodes,
4053                           CORBA::Boolean                 SeparateCornersAndMedium)
4054   throw (SALOME::SALOME_Exception)
4055 {
4056   SMESH_TRY;
4057   initData();
4058
4059   TIDSortedNodeSet nodes;
4060   idSourceToNodeSet( theObject, getMeshDS(), nodes );
4061
4062   findCoincidentNodes( nodes, Tolerance, GroupsOfNodes, SeparateCornersAndMedium );
4063
4064   TPythonDump() << "coincident_nodes_on_part = " << this << ".FindCoincidentNodesOnPart( "
4065                 << theObject <<", "
4066                 << Tolerance << ", "
4067                 << SeparateCornersAndMedium << " )";
4068
4069   SMESH_CATCH( SMESH::throwCorbaException );
4070 }
4071
4072 //================================================================================
4073 /*!
4074  * \brief Finds nodes coinsident with Tolerance within Object excluding nodes within
4075  *        ExceptSubMeshOrGroups
4076  */
4077 //================================================================================
4078
4079 void SMESH_MeshEditor_i::
4080 FindCoincidentNodesOnPartBut(SMESH::SMESH_IDSource_ptr      theObject,
4081                              CORBA::Double                  theTolerance,
4082                              SMESH::array_of_long_array_out theGroupsOfNodes,
4083                              const SMESH::ListOfIDSources&  theExceptSubMeshOrGroups,
4084                              CORBA::Boolean                 theSeparateCornersAndMedium)
4085   throw (SALOME::SALOME_Exception)
4086 {
4087   SMESH_TRY;
4088   initData();
4089
4090   TIDSortedNodeSet nodes;
4091   idSourceToNodeSet( theObject, getMeshDS(), nodes );
4092
4093   for ( int i = 0; i < theExceptSubMeshOrGroups.length(); ++i )
4094   {
4095     SMDS_ElemIteratorPtr nodeIt = myMesh_i->GetElements( theExceptSubMeshOrGroups[i],
4096                                                          SMESH::NODE );
4097     while ( nodeIt->more() )
4098       nodes.erase( cast2Node( nodeIt->next() ));
4099   }
4100   findCoincidentNodes( nodes, theTolerance, theGroupsOfNodes, theSeparateCornersAndMedium );
4101
4102   TPythonDump() << "coincident_nodes_on_part = " << this << ".FindCoincidentNodesOnPartBut( "
4103                 << theObject<<", "
4104                 << theTolerance << ", "
4105                 << theExceptSubMeshOrGroups << ", "
4106                 << theSeparateCornersAndMedium << " )";
4107
4108   SMESH_CATCH( SMESH::throwCorbaException );
4109 }
4110
4111 //=======================================================================
4112 //function : MergeNodes
4113 //purpose  :
4114 //=======================================================================
4115
4116 void SMESH_MeshEditor_i::MergeNodes (const SMESH::array_of_long_array& GroupsOfNodes)
4117   throw (SALOME::SALOME_Exception)
4118 {
4119   SMESH_TRY;
4120   initData();
4121
4122   SMESHDS_Mesh* aMesh = getMeshDS();
4123
4124   TPythonDump aTPythonDump;
4125   aTPythonDump << this << ".MergeNodes([";
4126   ::SMESH_MeshEditor::TListOfListOfNodes aListOfListOfNodes;
4127   for (int i = 0; i < GroupsOfNodes.length(); i++)
4128   {
4129     const SMESH::long_array& aNodeGroup = GroupsOfNodes[ i ];
4130     aListOfListOfNodes.push_back( list< const SMDS_MeshNode* >() );
4131     list< const SMDS_MeshNode* >& aListOfNodes = aListOfListOfNodes.back();
4132     for ( int j = 0; j < aNodeGroup.length(); j++ )
4133     {
4134       CORBA::Long index = aNodeGroup[ j ];
4135       const SMDS_MeshNode * node = aMesh->FindNode(index);
4136       if ( node )
4137         aListOfNodes.push_back( node );
4138     }
4139     if ( aListOfNodes.size() < 2 )
4140       aListOfListOfNodes.pop_back();
4141
4142     if ( i > 0 ) aTPythonDump << ", ";
4143     aTPythonDump << aNodeGroup;
4144   }
4145   getEditor().MergeNodes( aListOfListOfNodes );
4146
4147   aTPythonDump <<  "])";
4148
4149   declareMeshModified( /*isReComputeSafe=*/false );
4150
4151   SMESH_CATCH( SMESH::throwCorbaException );
4152 }
4153
4154 //=======================================================================
4155 //function : FindEqualElements
4156 //purpose  :
4157 //=======================================================================
4158
4159 void SMESH_MeshEditor_i::FindEqualElements(SMESH::SMESH_IDSource_ptr      theObject,
4160                                            SMESH::array_of_long_array_out GroupsOfElementsID)
4161   throw (SALOME::SALOME_Exception)
4162 {
4163   SMESH_TRY;
4164   initData();
4165
4166   SMESH::SMESH_GroupBase_var group = SMESH::SMESH_GroupBase::_narrow(theObject);
4167   if ( !(!group->_is_nil() && group->GetType() == SMESH::NODE) )
4168   {
4169     TIDSortedElemSet elems;
4170     idSourceToSet( theObject, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true);
4171
4172     ::SMESH_MeshEditor::TListOfListOfElementsID aListOfListOfElementsID;
4173     getEditor().FindEqualElements( elems, aListOfListOfElementsID );
4174
4175     GroupsOfElementsID = new SMESH::array_of_long_array;
4176     GroupsOfElementsID->length( aListOfListOfElementsID.size() );
4177
4178     ::SMESH_MeshEditor::TListOfListOfElementsID::iterator arraysIt =
4179         aListOfListOfElementsID.begin();
4180     for (CORBA::Long j = 0; arraysIt != aListOfListOfElementsID.end(); ++arraysIt, ++j)
4181     {
4182       SMESH::long_array& aGroup = (*GroupsOfElementsID)[ j ];
4183       list<int>&      listOfIDs = *arraysIt;
4184       aGroup.length( listOfIDs.size() );
4185       list<int>::iterator idIt = listOfIDs.begin();
4186       for (int k = 0; idIt != listOfIDs.end(); ++idIt, ++k )
4187         aGroup[ k ] = *idIt;
4188     }
4189
4190     TPythonDump() << "equal_elements = " << this << ".FindEqualElements( "
4191                   <<theObject<<" )";
4192   }
4193
4194   SMESH_CATCH( SMESH::throwCorbaException );
4195 }
4196
4197 //=======================================================================
4198 //function : MergeElements
4199 //purpose  :
4200 //=======================================================================
4201
4202 void SMESH_MeshEditor_i::MergeElements(const SMESH::array_of_long_array& GroupsOfElementsID)
4203   throw (SALOME::SALOME_Exception)
4204 {
4205   SMESH_TRY;
4206   initData();
4207
4208   TPythonDump aTPythonDump;
4209   aTPythonDump << this << ".MergeElements( [";
4210
4211   ::SMESH_MeshEditor::TListOfListOfElementsID aListOfListOfElementsID;
4212
4213   for (int i = 0; i < GroupsOfElementsID.length(); i++) {
4214     const SMESH::long_array& anElemsIDGroup = GroupsOfElementsID[ i ];
4215     aListOfListOfElementsID.push_back( list< int >() );
4216     list< int >& aListOfElemsID = aListOfListOfElementsID.back();
4217     for ( int j = 0; j < anElemsIDGroup.length(); j++ ) {
4218       CORBA::Long id = anElemsIDGroup[ j ];
4219       aListOfElemsID.push_back( id );
4220     }
4221     if ( aListOfElemsID.size() < 2 )
4222       aListOfListOfElementsID.pop_back();
4223     if ( i > 0 ) aTPythonDump << ", ";
4224     aTPythonDump << anElemsIDGroup;
4225   }
4226
4227   getEditor().MergeElements(aListOfListOfElementsID);
4228
4229   declareMeshModified( /*isReComputeSafe=*/true );
4230
4231   aTPythonDump << "] )";
4232
4233   SMESH_CATCH( SMESH::throwCorbaException );
4234 }
4235
4236 //=======================================================================
4237 //function : MergeEqualElements
4238 //purpose  :
4239 //=======================================================================
4240
4241 void SMESH_MeshEditor_i::MergeEqualElements()
4242   throw (SALOME::SALOME_Exception)
4243 {
4244   SMESH_TRY;
4245   initData();
4246
4247   getEditor().MergeEqualElements();
4248
4249   declareMeshModified( /*isReComputeSafe=*/true );
4250
4251   TPythonDump() << this << ".MergeEqualElements()";
4252
4253   SMESH_CATCH( SMESH::throwCorbaException );
4254 }
4255
4256 //=============================================================================
4257 /*!
4258  * Move the node to a given point
4259  */
4260 //=============================================================================
4261
4262 CORBA::Boolean SMESH_MeshEditor_i::MoveNode(CORBA::Long   NodeID,
4263                                             CORBA::Double x,
4264                                             CORBA::Double y,
4265                                             CORBA::Double z)
4266   throw (SALOME::SALOME_Exception)
4267 {
4268   SMESH_TRY;
4269   initData(/*deleteSearchers=*/false);
4270
4271   const SMDS_MeshNode * node = getMeshDS()->FindNode( NodeID );
4272   if ( !node )
4273     return false;
4274
4275   if ( theNodeSearcher )
4276     theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
4277
4278   if ( myIsPreviewMode ) // make preview data
4279   {
4280     // in a preview mesh, make edges linked to a node
4281     TPreviewMesh& tmpMesh = *getPreviewMesh();
4282     TIDSortedElemSet linkedNodes;
4283     ::SMESH_MeshEditor::GetLinkedNodes( node, linkedNodes );
4284     TIDSortedElemSet::iterator nIt = linkedNodes.begin();
4285     SMDS_MeshNode *nodeCpy1 = tmpMesh.Copy(node);
4286     for ( ; nIt != linkedNodes.end(); ++nIt )
4287     {
4288       SMDS_MeshNode *nodeCpy2 = tmpMesh.Copy ( cast2Node( *nIt ));
4289       tmpMesh.GetMeshDS()->AddEdge(nodeCpy1, nodeCpy2);
4290     }
4291     // move copied node
4292     if ( nodeCpy1 )
4293       tmpMesh.GetMeshDS()->MoveNode(nodeCpy1, x, y, z);
4294     // fill preview data
4295   }
4296   else if ( theNodeSearcher ) // move node and update theNodeSearcher data accordingly
4297     theNodeSearcher->MoveNode(node, gp_Pnt( x,y,z ));
4298   else
4299     getMeshDS()->MoveNode(node, x, y, z);
4300
4301   if ( !myIsPreviewMode )
4302   {
4303     // Update Python script
4304     TPythonDump() << "isDone = " << this << ".MoveNode( "
4305                   << NodeID << ", " << TVar(x) << ", " << TVar(y) << ", " << TVar(z) << " )";
4306     declareMeshModified( /*isReComputeSafe=*/false );
4307   }
4308
4309   SMESH_CATCH( SMESH::throwCorbaException );
4310
4311   return true;
4312 }
4313
4314 //================================================================================
4315 /*!
4316  * \brief Return ID of node closest to a given point
4317  */
4318 //================================================================================
4319
4320 CORBA::Long SMESH_MeshEditor_i::FindNodeClosestTo(CORBA::Double x,
4321                                                   CORBA::Double y,
4322                                                   CORBA::Double z)
4323   throw (SALOME::SALOME_Exception)
4324 {
4325   SMESH_TRY;
4326   theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
4327
4328   if ( !theNodeSearcher ) {
4329     theNodeSearcher = SMESH_MeshAlgos::GetNodeSearcher( *getMeshDS() );
4330   }
4331   gp_Pnt p( x,y,z );
4332   if ( const SMDS_MeshNode* node = theNodeSearcher->FindClosestTo( p ))
4333     return node->GetID();
4334
4335   SMESH_CATCH( SMESH::throwCorbaException );
4336   return 0;
4337 }
4338
4339 //================================================================================
4340 /*!
4341  * \brief If the given ID is a valid node ID (nodeID > 0), just move this node, else
4342  * move the node closest to the point to point's location and return ID of the node
4343  */
4344 //================================================================================
4345
4346 CORBA::Long SMESH_MeshEditor_i::MoveClosestNodeToPoint(CORBA::Double x,
4347                                                        CORBA::Double y,
4348                                                        CORBA::Double z,
4349                                                        CORBA::Long   theNodeID)
4350   throw (SALOME::SALOME_Exception)
4351 {
4352   SMESH_TRY;
4353   // We keep theNodeSearcher until any mesh modification:
4354   // 1) initData() deletes theNodeSearcher at any edition,
4355   // 2) TSearchersDeleter - at any mesh compute event and mesh change
4356
4357   initData(/*deleteSearchers=*/false);
4358
4359   theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
4360
4361   int nodeID = theNodeID;
4362   const SMDS_MeshNode* node = getMeshDS()->FindNode( nodeID );
4363   if ( !node ) // preview moving node
4364   {
4365     if ( !theNodeSearcher ) {
4366       theNodeSearcher = SMESH_MeshAlgos::GetNodeSearcher( *getMeshDS() );
4367     }
4368     gp_Pnt p( x,y,z );
4369     node = theNodeSearcher->FindClosestTo( p );
4370   }
4371   if ( node ) {
4372     nodeID = node->GetID();
4373     if ( myIsPreviewMode ) // make preview data
4374     {
4375       // in a preview mesh, make edges linked to a node
4376       TPreviewMesh tmpMesh = *getPreviewMesh();
4377       TIDSortedElemSet linkedNodes;
4378       ::SMESH_MeshEditor::GetLinkedNodes( node, linkedNodes );
4379       TIDSortedElemSet::iterator nIt = linkedNodes.begin();
4380       for ( ; nIt != linkedNodes.end(); ++nIt )
4381       {
4382         SMDS_LinearEdge edge( node, cast2Node( *nIt ));
4383         tmpMesh.Copy( &edge );
4384       }
4385       // move copied node
4386       node = tmpMesh.GetMeshDS()->FindNode( nodeID );
4387       if ( node )
4388         tmpMesh.GetMeshDS()->MoveNode(node, x, y, z);
4389       // fill preview data
4390     }
4391     else if ( theNodeSearcher ) // move node and update theNodeSearcher data accordingly
4392     {
4393       theNodeSearcher->MoveNode(node, gp_Pnt( x,y,z ));
4394     }
4395     else
4396     {
4397       getMeshDS()->MoveNode(node, x, y, z);
4398     }
4399   }
4400
4401   if ( !myIsPreviewMode )
4402   {
4403     TPythonDump() << "nodeID = " << this
4404                   << ".MoveClosestNodeToPoint( "<< x << ", " << y << ", " << z
4405                   << ", " << nodeID << " )";
4406
4407     declareMeshModified( /*isReComputeSafe=*/false );
4408   }
4409
4410   return nodeID;
4411
4412   SMESH_CATCH( SMESH::throwCorbaException );
4413   return 0;
4414 }
4415
4416 //=======================================================================
4417 /*!
4418  * Return elements of given type where the given point is IN or ON.
4419  *
4420  * 'ALL' type means elements of any type excluding nodes
4421  */
4422 //=======================================================================
4423
4424 SMESH::long_array* SMESH_MeshEditor_i::FindElementsByPoint(CORBA::Double      x,
4425                                                            CORBA::Double      y,
4426                                                            CORBA::Double      z,
4427                                                            SMESH::ElementType type)
4428   throw (SALOME::SALOME_Exception)
4429 {
4430   SMESH_TRY;
4431   SMESH::long_array_var res = new SMESH::long_array;
4432   vector< const SMDS_MeshElement* > foundElems;
4433
4434   theSearchersDeleter.Set( myMesh );
4435   if ( !theElementSearcher ) {
4436     theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() );
4437   }
4438   theElementSearcher->FindElementsByPoint( gp_Pnt( x,y,z ),
4439                                            SMDSAbs_ElementType( type ),
4440                                            foundElems);
4441   res->length( foundElems.size() );
4442   for ( int i = 0; i < foundElems.size(); ++i )
4443     res[i] = foundElems[i]->GetID();
4444
4445   return res._retn();
4446
4447   SMESH_CATCH( SMESH::throwCorbaException );
4448   return 0;
4449 }
4450
4451 //=======================================================================
4452 //function : FindAmongElementsByPoint
4453 //purpose  : Searching among the given elements, return elements of given type 
4454 //           where the given point is IN or ON.
4455 //           'ALL' type means elements of any type excluding nodes
4456 //=======================================================================
4457
4458 SMESH::long_array*
4459 SMESH_MeshEditor_i::FindAmongElementsByPoint(SMESH::SMESH_IDSource_ptr elementIDs,
4460                                              CORBA::Double             x,
4461                                              CORBA::Double             y,
4462                                              CORBA::Double             z,
4463                                              SMESH::ElementType        type)
4464   throw (SALOME::SALOME_Exception)
4465 {
4466   SMESH_TRY;
4467   SMESH::long_array_var res = new SMESH::long_array;
4468   
4469   SMESH::array_of_ElementType_var types = elementIDs->GetTypes();
4470   if ( types->length() == 1 && // a part contains only nodes or 0D elements
4471        ( types[0] == SMESH::NODE || types[0] == SMESH::ELEM0D || types[0] == SMESH::BALL) &&
4472        type != types[0] ) // but search of elements of dim > 0
4473     return res._retn();
4474
4475   if ( SMESH::DownCast<SMESH_Mesh_i*>( elementIDs )) // elementIDs is the whole mesh 
4476     return FindElementsByPoint( x,y,z, type );
4477
4478   TIDSortedElemSet elements; // elems should live until FindElementsByPoint() finishes
4479
4480   theSearchersDeleter.Set( myMesh, getPartIOR( elementIDs, type ));
4481   if ( !theElementSearcher )
4482   {
4483     // create a searcher from elementIDs
4484     SMESH::SMESH_Mesh_var mesh = elementIDs->GetMesh();
4485     SMESHDS_Mesh* meshDS = SMESH::DownCast<SMESH_Mesh_i*>( mesh )->GetImpl().GetMeshDS();
4486
4487     if ( !idSourceToSet( elementIDs, meshDS, elements,
4488                          SMDSAbs_ElementType(type), /*emptyIfIsMesh=*/true))
4489       return res._retn();
4490
4491     typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator > TIter;
4492     SMDS_ElemIteratorPtr elemsIt( new TIter( elements.begin(), elements.end() ));
4493
4494     theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), elemsIt );
4495   }
4496
4497   vector< const SMDS_MeshElement* > foundElems;
4498
4499   theElementSearcher->FindElementsByPoint( gp_Pnt( x,y,z ),
4500                                            SMDSAbs_ElementType( type ),
4501                                            foundElems);
4502   res->length( foundElems.size() );
4503   for ( int i = 0; i < foundElems.size(); ++i )
4504     res[i] = foundElems[i]->GetID();
4505
4506   return res._retn();
4507
4508   SMESH_CATCH( SMESH::throwCorbaException );
4509   return 0;
4510 }
4511
4512 //=======================================================================
4513 //function : GetPointState
4514 //purpose  : Return point state in a closed 2D mesh in terms of TopAbs_State enumeration.
4515 //           TopAbs_UNKNOWN state means that either mesh is wrong or the analysis fails.
4516 //=======================================================================
4517
4518 CORBA::Short SMESH_MeshEditor_i::GetPointState(CORBA::Double x,
4519                                                CORBA::Double y,
4520                                                CORBA::Double z)
4521   throw (SALOME::SALOME_Exception)
4522 {
4523   SMESH_TRY;
4524   theSearchersDeleter.Set( myMesh );
4525   if ( !theElementSearcher ) {
4526     theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() );
4527   }
4528   return CORBA::Short( theElementSearcher->GetPointState( gp_Pnt( x,y,z )));
4529
4530   SMESH_CATCH( SMESH::throwCorbaException );
4531   return 0;
4532 }
4533
4534 //=======================================================================
4535 //function : convError
4536 //purpose  :
4537 //=======================================================================
4538
4539 #define RETCASE(enm) case ::SMESH_MeshEditor::enm: return SMESH::SMESH_MeshEditor::enm;
4540
4541 static SMESH::SMESH_MeshEditor::Sew_Error convError( const::SMESH_MeshEditor::Sew_Error e )
4542 {
4543   switch ( e ) {
4544     RETCASE( SEW_OK );
4545     RETCASE( SEW_BORDER1_NOT_FOUND );
4546     RETCASE( SEW_BORDER2_NOT_FOUND );
4547     RETCASE( SEW_BOTH_BORDERS_NOT_FOUND );
4548     RETCASE( SEW_BAD_SIDE_NODES );
4549     RETCASE( SEW_VOLUMES_TO_SPLIT );
4550     RETCASE( SEW_DIFF_NB_OF_ELEMENTS );
4551     RETCASE( SEW_TOPO_DIFF_SETS_OF_ELEMENTS );
4552     RETCASE( SEW_BAD_SIDE1_NODES );
4553     RETCASE( SEW_BAD_SIDE2_NODES );
4554   }
4555   return SMESH::SMESH_MeshEditor::SEW_OK;
4556 }
4557
4558 //=======================================================================
4559 //function : SewFreeBorders
4560 //purpose  :
4561 //=======================================================================
4562
4563 SMESH::SMESH_MeshEditor::Sew_Error
4564 SMESH_MeshEditor_i::SewFreeBorders(CORBA::Long FirstNodeID1,
4565                                    CORBA::Long SecondNodeID1,
4566                                    CORBA::Long LastNodeID1,
4567                                    CORBA::Long FirstNodeID2,
4568                                    CORBA::Long SecondNodeID2,
4569                                    CORBA::Long LastNodeID2,
4570                                    CORBA::Boolean CreatePolygons,
4571                                    CORBA::Boolean CreatePolyedrs)
4572   throw (SALOME::SALOME_Exception)
4573 {
4574   SMESH_TRY;
4575   initData();
4576
4577   SMESHDS_Mesh* aMesh = getMeshDS();
4578
4579   const SMDS_MeshNode* aBorderFirstNode  = aMesh->FindNode( FirstNodeID1  );
4580   const SMDS_MeshNode* aBorderSecondNode = aMesh->FindNode( SecondNodeID1 );
4581   const SMDS_MeshNode* aBorderLastNode   = aMesh->FindNode( LastNodeID1   );
4582   const SMDS_MeshNode* aSide2FirstNode   = aMesh->FindNode( FirstNodeID2  );
4583   const SMDS_MeshNode* aSide2SecondNode  = aMesh->FindNode( SecondNodeID2 );
4584   const SMDS_MeshNode* aSide2ThirdNode   = aMesh->FindNode( LastNodeID2   );
4585
4586   if (!aBorderFirstNode ||
4587       !aBorderSecondNode||
4588       !aBorderLastNode)
4589     return SMESH::SMESH_MeshEditor::SEW_BORDER1_NOT_FOUND;
4590   if (!aSide2FirstNode  ||
4591       !aSide2SecondNode ||
4592       !aSide2ThirdNode)
4593     return SMESH::SMESH_MeshEditor::SEW_BORDER2_NOT_FOUND;
4594
4595   TPythonDump() << "error = " << this << ".SewFreeBorders( "
4596                 << FirstNodeID1  << ", "
4597                 << SecondNodeID1 << ", "
4598                 << LastNodeID1   << ", "
4599                 << FirstNodeID2  << ", "
4600                 << SecondNodeID2 << ", "
4601                 << LastNodeID2   << ", "
4602                 << CreatePolygons<< ", "
4603                 << CreatePolyedrs<< " )";
4604
4605   SMESH::SMESH_MeshEditor::Sew_Error error =
4606     convError( getEditor().SewFreeBorder (aBorderFirstNode,
4607                                        aBorderSecondNode,
4608                                        aBorderLastNode,
4609                                        aSide2FirstNode,
4610                                        aSide2SecondNode,
4611                                        aSide2ThirdNode,
4612                                        true,
4613                                        CreatePolygons,
4614                                        CreatePolyedrs) );
4615
4616
4617   declareMeshModified( /*isReComputeSafe=*/false );
4618   return error;
4619
4620   SMESH_CATCH( SMESH::throwCorbaException );
4621   return SMESH::SMESH_MeshEditor::Sew_Error(0);
4622 }
4623
4624
4625 //=======================================================================
4626 //function : SewConformFreeBorders
4627 //purpose  :
4628 //=======================================================================
4629
4630 SMESH::SMESH_MeshEditor::Sew_Error
4631 SMESH_MeshEditor_i::SewConformFreeBorders(CORBA::Long FirstNodeID1,
4632                                           CORBA::Long SecondNodeID1,
4633                                           CORBA::Long LastNodeID1,
4634                                           CORBA::Long FirstNodeID2,
4635                                           CORBA::Long SecondNodeID2)
4636   throw (SALOME::SALOME_Exception)
4637 {
4638   SMESH_TRY;
4639   initData();
4640
4641   SMESHDS_Mesh* aMesh = getMeshDS();
4642
4643   const SMDS_MeshNode* aBorderFirstNode  = aMesh->FindNode( FirstNodeID1  );
4644   const SMDS_MeshNode* aBorderSecondNode = aMesh->FindNode( SecondNodeID1 );
4645   const SMDS_MeshNode* aBorderLastNode   = aMesh->FindNode( LastNodeID1   );
4646   const SMDS_MeshNode* aSide2FirstNode   = aMesh->FindNode( FirstNodeID2  );
4647   const SMDS_MeshNode* aSide2SecondNode  = aMesh->FindNode( SecondNodeID2 );
4648   const SMDS_MeshNode* aSide2ThirdNode   = 0;
4649
4650   if (!aBorderFirstNode ||
4651       !aBorderSecondNode||
4652       !aBorderLastNode )
4653     return SMESH::SMESH_MeshEditor::SEW_BORDER1_NOT_FOUND;
4654   if (!aSide2FirstNode  ||
4655       !aSide2SecondNode)
4656     return SMESH::SMESH_MeshEditor::SEW_BORDER2_NOT_FOUND;
4657
4658   TPythonDump() << "error = " << this << ".SewConformFreeBorders( "
4659                 << FirstNodeID1  << ", "
4660                 << SecondNodeID1 << ", "
4661                 << LastNodeID1   << ", "
4662                 << FirstNodeID2  << ", "
4663                 << SecondNodeID2 << " )";
4664
4665   SMESH::SMESH_MeshEditor::Sew_Error error =
4666     convError( getEditor().SewFreeBorder (aBorderFirstNode,
4667                                        aBorderSecondNode,
4668                                        aBorderLastNode,
4669                                        aSide2FirstNode,
4670                                        aSide2SecondNode,
4671                                        aSide2ThirdNode,
4672                                        true,
4673                                        false, false) );
4674
4675   declareMeshModified( /*isReComputeSafe=*/false );
4676   return error;
4677
4678   SMESH_CATCH( SMESH::throwCorbaException );
4679   return SMESH::SMESH_MeshEditor::Sew_Error(0);
4680 }
4681
4682
4683 //=======================================================================
4684 //function : SewBorderToSide
4685 //purpose  :
4686 //=======================================================================
4687
4688 SMESH::SMESH_MeshEditor::Sew_Error
4689 SMESH_MeshEditor_i::SewBorderToSide(CORBA::Long FirstNodeIDOnFreeBorder,
4690                                     CORBA::Long SecondNodeIDOnFreeBorder,
4691                                     CORBA::Long LastNodeIDOnFreeBorder,
4692                                     CORBA::Long FirstNodeIDOnSide,
4693                                     CORBA::Long LastNodeIDOnSide,
4694                                     CORBA::Boolean CreatePolygons,
4695                                     CORBA::Boolean CreatePolyedrs)
4696   throw (SALOME::SALOME_Exception)
4697 {
4698   SMESH_TRY;
4699   initData();
4700
4701   SMESHDS_Mesh* aMesh = getMeshDS();
4702
4703   const SMDS_MeshNode* aBorderFirstNode  = aMesh->FindNode( FirstNodeIDOnFreeBorder  );
4704   const SMDS_MeshNode* aBorderSecondNode = aMesh->FindNode( SecondNodeIDOnFreeBorder );
4705   const SMDS_MeshNode* aBorderLastNode   = aMesh->FindNode( LastNodeIDOnFreeBorder   );
4706   const SMDS_MeshNode* aSide2FirstNode   = aMesh->FindNode( FirstNodeIDOnSide  );
4707   const SMDS_MeshNode* aSide2SecondNode  = aMesh->FindNode( LastNodeIDOnSide );
4708   const SMDS_MeshNode* aSide2ThirdNode   = 0;
4709
4710   if (!aBorderFirstNode ||
4711       !aBorderSecondNode||
4712       !aBorderLastNode  )
4713     return SMESH::SMESH_MeshEditor::SEW_BORDER1_NOT_FOUND;
4714   if (!aSide2FirstNode  ||
4715       !aSide2SecondNode)
4716     return SMESH::SMESH_MeshEditor::SEW_BAD_SIDE_NODES;
4717
4718   TPythonDump() << "error = " << this << ".SewBorderToSide( "
4719                 << FirstNodeIDOnFreeBorder  << ", "
4720                 << SecondNodeIDOnFreeBorder << ", "
4721                 << LastNodeIDOnFreeBorder   << ", "
4722                 << FirstNodeIDOnSide        << ", "
4723                 << LastNodeIDOnSide         << ", "
4724                 << CreatePolygons           << ", "
4725                 << CreatePolyedrs           << ") ";
4726
4727   SMESH::SMESH_MeshEditor::Sew_Error error =
4728     convError( getEditor().SewFreeBorder (aBorderFirstNode,
4729                                        aBorderSecondNode,
4730                                        aBorderLastNode,
4731                                        aSide2FirstNode,
4732                                        aSide2SecondNode,
4733                                        aSide2ThirdNode,
4734                                        false,
4735                                        CreatePolygons,
4736                                        CreatePolyedrs) );
4737
4738   declareMeshModified( /*isReComputeSafe=*/false );
4739   return error;
4740
4741   SMESH_CATCH( SMESH::throwCorbaException );
4742   return SMESH::SMESH_MeshEditor::Sew_Error(0);
4743 }
4744
4745
4746 //=======================================================================
4747 //function : SewSideElements
4748 //purpose  :
4749 //=======================================================================
4750
4751 SMESH::SMESH_MeshEditor::Sew_Error
4752 SMESH_MeshEditor_i::SewSideElements(const SMESH::long_array& IDsOfSide1Elements,
4753                                     const SMESH::long_array& IDsOfSide2Elements,
4754                                     CORBA::Long NodeID1OfSide1ToMerge,
4755                                     CORBA::Long NodeID1OfSide2ToMerge,
4756                                     CORBA::Long NodeID2OfSide1ToMerge,
4757                                     CORBA::Long NodeID2OfSide2ToMerge)
4758   throw (SALOME::SALOME_Exception)
4759 {
4760   SMESH_TRY;
4761   initData();
4762
4763   SMESHDS_Mesh* aMesh = getMeshDS();
4764
4765   const SMDS_MeshNode* aFirstNode1ToMerge  = aMesh->FindNode( NodeID1OfSide1ToMerge );
4766   const SMDS_MeshNode* aFirstNode2ToMerge  = aMesh->FindNode( NodeID1OfSide2ToMerge );
4767   const SMDS_MeshNode* aSecondNode1ToMerge = aMesh->FindNode( NodeID2OfSide1ToMerge );
4768   const SMDS_MeshNode* aSecondNode2ToMerge = aMesh->FindNode( NodeID2OfSide2ToMerge );
4769
4770   if (!aFirstNode1ToMerge ||
4771       !aFirstNode2ToMerge )
4772     return SMESH::SMESH_MeshEditor::SEW_BAD_SIDE1_NODES;
4773   if (!aSecondNode1ToMerge||
4774       !aSecondNode2ToMerge)
4775     return SMESH::SMESH_MeshEditor::SEW_BAD_SIDE2_NODES;
4776
4777   TIDSortedElemSet aSide1Elems, aSide2Elems;
4778   arrayToSet(IDsOfSide1Elements, aMesh, aSide1Elems);
4779   arrayToSet(IDsOfSide2Elements, aMesh, aSide2Elems);
4780
4781   TPythonDump() << "error = " << this << ".SewSideElements( "
4782                 << IDsOfSide1Elements << ", "
4783                 << IDsOfSide2Elements << ", "
4784                 << NodeID1OfSide1ToMerge << ", "
4785                 << NodeID1OfSide2ToMerge << ", "
4786                 << NodeID2OfSide1ToMerge << ", "
4787                 << NodeID2OfSide2ToMerge << ")";
4788
4789   SMESH::SMESH_MeshEditor::Sew_Error error =
4790     convError( getEditor().SewSideElements (aSide1Elems, aSide2Elems,
4791                                          aFirstNode1ToMerge,
4792                                          aFirstNode2ToMerge,
4793                                          aSecondNode1ToMerge,
4794                                          aSecondNode2ToMerge));
4795
4796   declareMeshModified( /*isReComputeSafe=*/false );
4797   return error;
4798
4799   SMESH_CATCH( SMESH::throwCorbaException );
4800   return SMESH::SMESH_MeshEditor::Sew_Error(0);
4801 }
4802
4803 //================================================================================
4804 /*!
4805  * \brief Set new nodes for given element
4806  * \param ide - element id
4807  * \param newIDs - new node ids
4808  * \retval CORBA::Boolean - true if result is OK
4809  */
4810 //================================================================================
4811
4812 CORBA::Boolean SMESH_MeshEditor_i::ChangeElemNodes(CORBA::Long ide,
4813                                                    const SMESH::long_array& newIDs)
4814   throw (SALOME::SALOME_Exception)
4815 {
4816   SMESH_TRY;
4817   initData();
4818
4819   const SMDS_MeshElement* elem = getMeshDS()->FindElement(ide);
4820   if(!elem) return false;
4821
4822   int nbn = newIDs.length();
4823   int i=0;
4824   vector<const SMDS_MeshNode*> aNodes(nbn);
4825   int nbn1=-1;
4826   for(; i<nbn; i++) {
4827     const SMDS_MeshNode* aNode = getMeshDS()->FindNode(newIDs[i]);
4828     if(aNode) {
4829       nbn1++;
4830       aNodes[nbn1] = aNode;
4831     }
4832   }
4833   TPythonDump() << "isDone = " << this << ".ChangeElemNodes( "
4834                 << ide << ", " << newIDs << " )";
4835
4836   MESSAGE("ChangeElementNodes");
4837   bool res = getMeshDS()->ChangeElementNodes( elem, & aNodes[0], nbn1+1 );
4838
4839   declareMeshModified( /*isReComputeSafe=*/ !res );
4840
4841   return res;
4842
4843   SMESH_CATCH( SMESH::throwCorbaException );
4844   return 0;
4845 }
4846
4847 //=======================================================================
4848 /*!
4849  * \brief Makes a part of the mesh quadratic or bi-quadratic
4850  */
4851 //=======================================================================
4852
4853 void SMESH_MeshEditor_i::convertToQuadratic(CORBA::Boolean            theForce3d,
4854                                             CORBA::Boolean            theToBiQuad,
4855                                             SMESH::SMESH_IDSource_ptr theObject)
4856   throw (SALOME::SALOME_Exception)
4857 {
4858   SMESH_TRY;
4859   initData();
4860
4861   TIDSortedElemSet elems;
4862   bool elemsOK;
4863   if ( !( elemsOK = CORBA::is_nil( theObject )))
4864   {
4865     elemsOK =  idSourceToSet( theObject, getMeshDS(), elems,
4866                               SMDSAbs_All, /*emptyIfIsMesh=*/true );
4867   }
4868   if ( elemsOK )
4869   {
4870     if ( !elems.empty() && (*elems.begin())->GetType() == SMDSAbs_Node )
4871       THROW_SALOME_CORBA_EXCEPTION("Group of nodes is not allowed", SALOME::BAD_PARAM);
4872
4873     if ( elems.empty() ) getEditor().ConvertToQuadratic(theForce3d, theToBiQuad);
4874     else                 getEditor().ConvertToQuadratic(theForce3d, elems, theToBiQuad);
4875
4876     declareMeshModified( /*isReComputeSafe=*/false );
4877   }
4878
4879   SMESH_CATCH( SMESH::throwCorbaException );
4880 }
4881
4882 //=======================================================================
4883 //function : ConvertFromQuadratic
4884 //purpose  :
4885 //=======================================================================
4886
4887 CORBA::Boolean SMESH_MeshEditor_i::ConvertFromQuadratic()
4888   throw (SALOME::SALOME_Exception)
4889 {
4890   SMESH_TRY;
4891   initData();
4892
4893   CORBA::Boolean isDone = getEditor().ConvertFromQuadratic();
4894   TPythonDump() << this << ".ConvertFromQuadratic()";
4895   declareMeshModified( /*isReComputeSafe=*/!isDone );
4896   return isDone;
4897
4898   SMESH_CATCH( SMESH::throwCorbaException );
4899   return false;
4900 }
4901
4902 //=======================================================================
4903 //function : ConvertToQuadratic
4904 //purpose  :
4905 //=======================================================================
4906
4907 void SMESH_MeshEditor_i::ConvertToQuadratic(CORBA::Boolean theForce3d)
4908   throw (SALOME::SALOME_Exception)
4909 {
4910   convertToQuadratic( theForce3d, false );
4911   TPythonDump() << this << ".ConvertToQuadratic("<<theForce3d<<")";
4912 }
4913
4914 //================================================================================
4915 /*!
4916  * \brief Makes a part of the mesh quadratic
4917  */
4918 //================================================================================
4919
4920 void SMESH_MeshEditor_i::ConvertToQuadraticObject(CORBA::Boolean            theForce3d,
4921                                                   SMESH::SMESH_IDSource_ptr theObject)
4922   throw (SALOME::SALOME_Exception)
4923 {
4924   convertToQuadratic( theForce3d, false, theObject );
4925   TPythonDump() << this << ".ConvertToQuadraticObject("<<theForce3d<<", "<<theObject<<")";
4926 }
4927
4928 //================================================================================
4929 /*!
4930  * \brief Makes a part of the mesh bi-quadratic
4931  */
4932 //================================================================================
4933
4934 void SMESH_MeshEditor_i::ConvertToBiQuadratic(CORBA::Boolean            theForce3d,
4935                                               SMESH::SMESH_IDSource_ptr theObject)
4936   throw (SALOME::SALOME_Exception)
4937 {
4938   convertToQuadratic( theForce3d, true, theObject );
4939   TPythonDump() << this << ".ConvertToBiQuadratic("<<theForce3d<<", "<<theObject<<")";
4940 }
4941
4942 //================================================================================
4943 /*!
4944  * \brief Makes a part of the mesh linear
4945  */
4946 //================================================================================
4947
4948 void SMESH_MeshEditor_i::ConvertFromQuadraticObject(SMESH::SMESH_IDSource_ptr theObject)
4949   throw (SALOME::SALOME_Exception)
4950 {
4951   SMESH_TRY;
4952   initData();
4953
4954   TPythonDump pyDump;
4955
4956   TIDSortedElemSet elems;
4957   if ( idSourceToSet( theObject, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true ))
4958   {
4959     if ( elems.empty() )
4960     {
4961       ConvertFromQuadratic();
4962     }
4963     else if ( (*elems.begin())->GetType() == SMDSAbs_Node )
4964     {
4965       THROW_SALOME_CORBA_EXCEPTION("Group of nodes is not allowed", SALOME::BAD_PARAM);
4966     }
4967     else
4968     {
4969       getEditor().ConvertFromQuadratic(elems);
4970     }
4971   }
4972   declareMeshModified( /*isReComputeSafe=*/false );
4973
4974   pyDump << this << ".ConvertFromQuadraticObject( "<<theObject<<" )";
4975
4976   SMESH_CATCH( SMESH::throwCorbaException );
4977 }
4978
4979 //=======================================================================
4980 //function : makeMesh
4981 //purpose  : create a named imported mesh
4982 //=======================================================================
4983
4984 SMESH::SMESH_Mesh_ptr SMESH_MeshEditor_i::makeMesh(const char* theMeshName)
4985 {
4986   SMESH_Gen_i*              gen = SMESH_Gen_i::GetSMESHGen();
4987   SMESH::SMESH_Mesh_var    mesh = gen->CreateEmptyMesh();
4988   SALOMEDS::Study_var     study = gen->GetCurrentStudy();
4989   SALOMEDS::SObject_wrap meshSO = gen->ObjectToSObject( study, mesh );
4990   gen->SetName( meshSO, theMeshName, "Mesh" );
4991   gen->SetPixMap( meshSO, "ICON_SMESH_TREE_MESH_IMPORTED");
4992
4993   return mesh._retn();
4994 }
4995
4996 //=======================================================================
4997 //function : dumpGroupsList
4998 //purpose  :
4999 //=======================================================================
5000
5001 void SMESH_MeshEditor_i::dumpGroupsList(TPythonDump &               theDumpPython,
5002                                         const SMESH::ListOfGroups * theGroupList)
5003 {
5004   bool isDumpGroupList = ( theGroupList && theGroupList->length() > 0 );
5005   if ( isDumpGroupList )
5006     theDumpPython << theGroupList << " = ";
5007 }
5008
5009 //================================================================================
5010 /*!
5011   \brief Generates the unique group name.
5012   \param thePrefix name prefix
5013   \return unique name
5014 */
5015 //================================================================================
5016
5017 string SMESH_MeshEditor_i::generateGroupName(const string& thePrefix)
5018 {
5019   SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
5020   set<string> groupNames;
5021
5022   // Get existing group names
5023   for (int i = 0, nbGroups = groups->length(); i < nbGroups; i++ ) {
5024     SMESH::SMESH_GroupBase_var aGroup = groups[i];
5025     if (CORBA::is_nil(aGroup))
5026       continue;
5027
5028     CORBA::String_var name = aGroup->GetName();
5029     groupNames.insert( name.in() );
5030   }
5031
5032   // Find new name
5033   string name = thePrefix;
5034   int index = 0;
5035
5036   while (!groupNames.insert(name).second)
5037     name = SMESH_Comment( thePrefix ) << "_" << index++;
5038
5039   return name;
5040 }
5041
5042 //================================================================================
5043 /*!
5044  * \brief Prepare SMESH_IDSource for work
5045  */
5046 //================================================================================
5047
5048 void SMESH_MeshEditor_i::prepareIdSource(SMESH::SMESH_IDSource_ptr theObject)
5049 {
5050   if ( SMESH::Filter_i* filter = SMESH::DownCast<SMESH::Filter_i*>( theObject ))
5051   {
5052     SMESH::SMESH_Mesh_var mesh = myMesh_i->_this();
5053     filter->SetMesh( mesh );
5054   }
5055 }
5056 //================================================================================
5057 /*!
5058  * \brief Retrieve elements of given type from SMESH_IDSource
5059  */
5060 //================================================================================
5061
5062 bool SMESH_MeshEditor_i::idSourceToSet(SMESH::SMESH_IDSource_ptr  theIDSource,
5063                                        const SMESHDS_Mesh*        theMeshDS,
5064                                        TIDSortedElemSet&          theElemSet,
5065                                        const SMDSAbs_ElementType  theType,
5066                                        const bool                 emptyIfIsMesh,
5067                                        IDSource_Error*            error)
5068
5069 {
5070   if ( error ) *error = IDSource_OK;
5071
5072   if ( CORBA::is_nil( theIDSource ) )
5073   {
5074     if ( error ) *error = IDSource_INVALID;
5075     return false;
5076   }
5077   if ( emptyIfIsMesh && SMESH::DownCast<SMESH_Mesh_i*>( theIDSource ))
5078   {
5079     if ( error && getMeshDS()->GetMeshInfo().NbElements( theType ) == 0 )
5080       *error = IDSource_EMPTY;
5081     return true;
5082   }
5083   prepareIdSource( theIDSource );
5084   SMESH::long_array_var anIDs = theIDSource->GetIDs();
5085   if ( anIDs->length() == 0 )
5086   {
5087     if ( error ) *error = IDSource_EMPTY;
5088     return false;
5089   }
5090   SMESH::array_of_ElementType_var types = theIDSource->GetTypes();
5091   if ( types->length() == 1 && types[0] == SMESH::NODE ) // group of nodes
5092   {
5093     if ( theType == SMDSAbs_All || theType == SMDSAbs_Node )
5094     {
5095       arrayToSet( anIDs, getMeshDS(), theElemSet, SMDSAbs_Node );
5096     }
5097     else
5098     {
5099       if ( error ) *error = IDSource_INVALID;
5100       return false;
5101     }
5102   }
5103   else
5104   {
5105     arrayToSet( anIDs, getMeshDS(), theElemSet, theType);
5106     if ( bool(anIDs->length()) != bool(theElemSet.size()))
5107     {
5108       if ( error ) *error = IDSource_INVALID;
5109       return false;
5110     }
5111   }
5112   return true;
5113 }
5114
5115 //================================================================================
5116 /*!
5117  * \brief Duplicates given elements, i.e. creates new elements based on the
5118  *        same nodes as the given ones.
5119  * \param theElements - container of elements to duplicate.
5120  * \param theGroupName - a name of group to contain the generated elements.
5121  *                    If a group with such a name already exists, the new elements
5122  *                    are added to the existng group, else a new group is created.
5123  *                    If \a theGroupName is empty, new elements are not added 
5124  *                    in any group.
5125  * \return a group where the new elements are added. NULL if theGroupName == "".
5126  * \sa DoubleNode()
5127  */
5128 //================================================================================
5129
5130 SMESH::SMESH_Group_ptr
5131 SMESH_MeshEditor_i::DoubleElements(SMESH::SMESH_IDSource_ptr theElements,
5132                                    const char*               theGroupName)
5133   throw (SALOME::SALOME_Exception)
5134 {
5135   SMESH::SMESH_Group_var newGroup;
5136
5137   SMESH_TRY;
5138   initData();
5139
5140   TPythonDump pyDump;
5141
5142   TIDSortedElemSet elems;
5143   if ( idSourceToSet( theElements, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true))
5144   {
5145     getEditor().DoubleElements( elems );
5146
5147     if ( strlen( theGroupName ) && !getEditor().GetLastCreatedElems().IsEmpty() )
5148     {
5149       // group type
5150       SMESH::ElementType type =
5151         SMESH::ElementType( getEditor().GetLastCreatedElems().Value(1)->GetType() );
5152       // find existing group
5153       SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
5154       for ( size_t i = 0; i < groups->length(); ++i )
5155         if ( groups[i]->GetType() == type )
5156         {
5157           CORBA::String_var name = groups[i]->GetName();
5158           if ( strcmp( name, theGroupName ) == 0 ) {
5159             newGroup = SMESH::SMESH_Group::_narrow( groups[i] );
5160             break;
5161           }
5162         }
5163       // create a new group
5164       if ( newGroup->_is_nil() )
5165         newGroup = myMesh_i->CreateGroup( type, theGroupName );
5166       // fill newGroup
5167       if ( SMESH_Group_i* group_i = SMESH::DownCast< SMESH_Group_i* >( newGroup ))
5168       {
5169         SMESHDS_Group* groupDS = static_cast< SMESHDS_Group* >( group_i->GetGroupDS() );
5170         const SMESH_SequenceOfElemPtr& aSeq = getEditor().GetLastCreatedElems();
5171         for ( int i = 1; i <= aSeq.Length(); i++ )
5172           groupDS->SMDSGroup().Add( aSeq(i) );
5173       }
5174     }
5175   }
5176   // python dump
5177   if ( !newGroup->_is_nil() )
5178     pyDump << newGroup << " = ";
5179   pyDump << this << ".DoubleElements( "
5180          << theElements << ", " << "'" << theGroupName <<"')";
5181
5182   SMESH_CATCH( SMESH::throwCorbaException );
5183
5184   return newGroup._retn();
5185 }
5186
5187 //================================================================================
5188 /*!
5189   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5190   \param theNodes - identifiers of nodes to be doubled
5191   \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
5192          nodes. If list of element identifiers is empty then nodes are doubled but
5193          they not assigned to elements
5194   \return TRUE if operation has been completed successfully, FALSE otherwise
5195   \sa DoubleNode(), DoubleNodeGroup(), DoubleNodeGroups()
5196 */
5197 //================================================================================
5198
5199 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodes( const SMESH::long_array& theNodes,
5200                                                 const SMESH::long_array& theModifiedElems )
5201   throw (SALOME::SALOME_Exception)
5202 {
5203   SMESH_TRY;
5204   initData();
5205
5206   list< int > aListOfNodes;
5207   int i, n;
5208   for ( i = 0, n = theNodes.length(); i < n; i++ )
5209     aListOfNodes.push_back( theNodes[ i ] );
5210
5211   list< int > aListOfElems;
5212   for ( i = 0, n = theModifiedElems.length(); i < n; i++ )
5213     aListOfElems.push_back( theModifiedElems[ i ] );
5214
5215   bool aResult = getEditor().DoubleNodes( aListOfNodes, aListOfElems );
5216
5217   declareMeshModified( /*isReComputeSafe=*/ !aResult );
5218
5219   // Update Python script
5220   TPythonDump() << this << ".DoubleNodes( " << theNodes << ", "<< theModifiedElems << " )";
5221
5222   return aResult;
5223
5224   SMESH_CATCH( SMESH::throwCorbaException );
5225   return 0;
5226 }
5227
5228 //================================================================================
5229 /*!
5230   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5231   This method provided for convenience works as DoubleNodes() described above.
5232   \param theNodeId - identifier of node to be doubled.
5233   \param theModifiedElems - identifiers of elements to be updated.
5234   \return TRUE if operation has been completed successfully, FALSE otherwise
5235   \sa DoubleNodes(), DoubleNodeGroup(), DoubleNodeGroups()
5236 */
5237 //================================================================================
5238
5239 CORBA::Boolean SMESH_MeshEditor_i::DoubleNode( CORBA::Long              theNodeId,
5240                                                const SMESH::long_array& theModifiedElems )
5241   throw (SALOME::SALOME_Exception)
5242 {
5243   SMESH_TRY;
5244   SMESH::long_array_var aNodes = new SMESH::long_array;
5245   aNodes->length( 1 );
5246   aNodes[ 0 ] = theNodeId;
5247
5248   TPythonDump pyDump; // suppress dump by the next line
5249
5250   CORBA::Boolean done = DoubleNodes( aNodes, theModifiedElems );
5251
5252   pyDump << this << ".DoubleNode( " << theNodeId << ", " << theModifiedElems << " )";
5253
5254   return done;
5255
5256   SMESH_CATCH( SMESH::throwCorbaException );
5257   return 0;
5258 }
5259
5260 //================================================================================
5261 /*!
5262   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5263   This method provided for convenience works as DoubleNodes() described above.
5264   \param theNodes - group of nodes to be doubled.
5265   \param theModifiedElems - group of elements to be updated.
5266   \return TRUE if operation has been completed successfully, FALSE otherwise
5267   \sa DoubleNode(), DoubleNodes(), DoubleNodeGroups()
5268 */
5269 //================================================================================
5270
5271 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroup(SMESH::SMESH_GroupBase_ptr theNodes,
5272                                                    SMESH::SMESH_GroupBase_ptr theModifiedElems )
5273   throw (SALOME::SALOME_Exception)
5274 {
5275   SMESH_TRY;
5276   if ( CORBA::is_nil( theNodes ) && theNodes->GetType() != SMESH::NODE )
5277     return false;
5278
5279   SMESH::long_array_var aNodes = theNodes->GetListOfID();
5280   SMESH::long_array_var aModifiedElems;
5281   if ( !CORBA::is_nil( theModifiedElems ) )
5282     aModifiedElems = theModifiedElems->GetListOfID();
5283   else
5284   {
5285     aModifiedElems = new SMESH::long_array;
5286     aModifiedElems->length( 0 );
5287   }
5288
5289   TPythonDump pyDump; // suppress dump by the next line
5290
5291   bool done = DoubleNodes( aNodes, aModifiedElems );
5292
5293   pyDump << this << ".DoubleNodeGroup( " << theNodes << ", " << theModifiedElems << " )";
5294
5295   return done;
5296
5297   SMESH_CATCH( SMESH::throwCorbaException );
5298   return 0;
5299 }
5300
5301 //================================================================================
5302 /*!
5303  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
5304  * Works as DoubleNodeGroup(), but returns a new group with newly created nodes.
5305  * \param theNodes - group of nodes to be doubled.
5306  * \param theModifiedElems - group of elements to be updated.
5307  * \return a new group with newly created nodes
5308  * \sa DoubleNodeGroup()
5309  */
5310 //================================================================================
5311
5312 SMESH::SMESH_Group_ptr
5313 SMESH_MeshEditor_i::DoubleNodeGroupNew( SMESH::SMESH_GroupBase_ptr theNodes,
5314                                         SMESH::SMESH_GroupBase_ptr theModifiedElems )
5315   throw (SALOME::SALOME_Exception)
5316 {
5317   SMESH_TRY;
5318   SMESH::SMESH_Group_var aNewGroup;
5319
5320   if ( CORBA::is_nil( theNodes ) && theNodes->GetType() != SMESH::NODE )
5321     return aNewGroup._retn();
5322
5323   // Duplicate nodes
5324   SMESH::long_array_var aNodes = theNodes->GetListOfID();
5325   SMESH::long_array_var aModifiedElems;
5326   if ( !CORBA::is_nil( theModifiedElems ) )
5327     aModifiedElems = theModifiedElems->GetListOfID();
5328   else {
5329     aModifiedElems = new SMESH::long_array;
5330     aModifiedElems->length( 0 );
5331   }
5332
5333   TPythonDump pyDump; // suppress dump by the next line
5334
5335   bool aResult = DoubleNodes( aNodes, aModifiedElems );
5336   if ( aResult )
5337   {
5338     // Create group with newly created nodes
5339     SMESH::long_array_var anIds = GetLastCreatedNodes();
5340     if (anIds->length() > 0) {
5341       string anUnindexedName (theNodes->GetName());
5342       string aNewName = generateGroupName(anUnindexedName + "_double");
5343       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
5344       aNewGroup->Add(anIds);
5345       pyDump << aNewGroup << " = ";
5346     }
5347   }
5348
5349   pyDump << this << ".DoubleNodeGroupNew( " << theNodes << ", "
5350          << theModifiedElems << " )";
5351
5352   return aNewGroup._retn();
5353
5354   SMESH_CATCH( SMESH::throwCorbaException );
5355   return 0;
5356 }
5357
5358 //================================================================================
5359 /*!
5360   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5361   This method provided for convenience works as DoubleNodes() described above.
5362   \param theNodes - list of groups of nodes to be doubled
5363   \param theModifiedElems - list of groups of elements to be updated.
5364   \return TRUE if operation has been completed successfully, FALSE otherwise
5365   \sa DoubleNode(), DoubleNodeGroup(), DoubleNodes()
5366 */
5367 //================================================================================
5368
5369 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroups(const SMESH::ListOfGroups& theNodes,
5370                                                     const SMESH::ListOfGroups& theModifiedElems )
5371   throw (SALOME::SALOME_Exception)
5372 {
5373   SMESH_TRY;
5374   initData();
5375
5376   std::list< int > aNodes;
5377   int i, n, j, m;
5378   for ( i = 0, n = theNodes.length(); i < n; i++ )
5379   {
5380     SMESH::SMESH_GroupBase_var aGrp = theNodes[ i ];
5381     if ( !CORBA::is_nil( aGrp ) && aGrp->GetType() == SMESH::NODE )
5382     {
5383       SMESH::long_array_var aCurr = aGrp->GetListOfID();
5384       for ( j = 0, m = aCurr->length(); j < m; j++ )
5385         aNodes.push_back( aCurr[ j ] );
5386     }
5387   }
5388
5389   std::list< int > anElems;
5390   for ( i = 0, n = theModifiedElems.length(); i < n; i++ )
5391   {
5392     SMESH::SMESH_GroupBase_var aGrp = theModifiedElems[ i ];
5393     if ( !CORBA::is_nil( aGrp ) && aGrp->GetType() != SMESH::NODE )
5394     {
5395       SMESH::long_array_var aCurr = aGrp->GetListOfID();
5396       for ( j = 0, m = aCurr->length(); j < m; j++ )
5397         anElems.push_back( aCurr[ j ] );
5398     }
5399   }
5400
5401   bool aResult = getEditor().DoubleNodes( aNodes, anElems );
5402
5403   declareMeshModified( /*isReComputeSafe=*/false );
5404
5405   TPythonDump() << this << ".DoubleNodeGroups( " << theNodes << ", " << theModifiedElems << " )";
5406
5407   return aResult;
5408
5409   SMESH_CATCH( SMESH::throwCorbaException );
5410   return 0;
5411 }
5412
5413 //================================================================================
5414 /*!
5415  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
5416  * Works as DoubleNodeGroups(), but returns a new group with newly created nodes.
5417  * \param theNodes - group of nodes to be doubled.
5418  * \param theModifiedElems - group of elements to be updated.
5419  * \return a new group with newly created nodes
5420  * \sa DoubleNodeGroups()
5421  */
5422 //================================================================================
5423
5424 SMESH::SMESH_Group_ptr
5425 SMESH_MeshEditor_i::DoubleNodeGroupsNew( const SMESH::ListOfGroups& theNodes,
5426                                          const SMESH::ListOfGroups& theModifiedElems )
5427   throw (SALOME::SALOME_Exception)
5428 {
5429   SMESH::SMESH_Group_var aNewGroup;
5430
5431   TPythonDump pyDump; // suppress dump by the next line
5432
5433   bool aResult = DoubleNodeGroups( theNodes, theModifiedElems );
5434
5435   if ( aResult )
5436   {
5437     // Create group with newly created nodes
5438     SMESH::long_array_var anIds = GetLastCreatedNodes();
5439     if (anIds->length() > 0) {
5440       string anUnindexedName (theNodes[0]->GetName());
5441       string aNewName = generateGroupName(anUnindexedName + "_double");
5442       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
5443       aNewGroup->Add(anIds);
5444       pyDump << aNewGroup << " = ";
5445     }
5446   }
5447
5448   pyDump << this << ".DoubleNodeGroupsNew( " << theNodes << ", "
5449          << theModifiedElems << " )";
5450
5451   return aNewGroup._retn();
5452 }
5453
5454
5455 //================================================================================
5456 /*!
5457   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5458   \param theElems - the list of elements (edges or faces) to be replicated
5459   The nodes for duplication could be found from these elements
5460   \param theNodesNot - list of nodes to NOT replicate
5461   \param theAffectedElems - the list of elements (cells and edges) to which the
5462   replicated nodes should be associated to.
5463   \return TRUE if operation has been completed successfully, FALSE otherwise
5464   \sa DoubleNodeGroup(), DoubleNodeGroups()
5465 */
5466 //================================================================================
5467
5468 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElem( const SMESH::long_array& theElems,
5469                                                    const SMESH::long_array& theNodesNot,
5470                                                    const SMESH::long_array& theAffectedElems )
5471   throw (SALOME::SALOME_Exception)
5472 {
5473   SMESH_TRY;
5474   initData();
5475
5476   SMESHDS_Mesh* aMeshDS = getMeshDS();
5477   TIDSortedElemSet anElems, aNodes, anAffected;
5478   arrayToSet(theElems, aMeshDS, anElems, SMDSAbs_All);
5479   arrayToSet(theNodesNot, aMeshDS, aNodes, SMDSAbs_Node);
5480   arrayToSet(theAffectedElems, aMeshDS, anAffected, SMDSAbs_All);
5481
5482   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5483
5484   // Update Python script
5485   TPythonDump() << this << ".DoubleNodeElem( " << theElems << ", "
5486                 << theNodesNot << ", " << theAffectedElems << " )";
5487
5488   declareMeshModified( /*isReComputeSafe=*/false );
5489   return aResult;
5490
5491   SMESH_CATCH( SMESH::throwCorbaException );
5492   return 0;
5493 }
5494
5495 //================================================================================
5496 /*!
5497   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5498   \param theElems - the list of elements (edges or faces) to be replicated
5499   The nodes for duplication could be found from these elements
5500   \param theNodesNot - list of nodes to NOT replicate
5501   \param theShape - shape to detect affected elements (element which geometric center
5502   located on or inside shape).
5503   The replicated nodes should be associated to affected elements.
5504   \return TRUE if operation has been completed successfully, FALSE otherwise
5505   \sa DoubleNodeGroupInRegion(), DoubleNodeGroupsInRegion()
5506 */
5507 //================================================================================
5508
5509 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemInRegion ( const SMESH::long_array& theElems,
5510                                                             const SMESH::long_array& theNodesNot,
5511                                                             GEOM::GEOM_Object_ptr    theShape )
5512   throw (SALOME::SALOME_Exception)
5513 {
5514   SMESH_TRY;
5515   initData();
5516
5517
5518   SMESHDS_Mesh* aMeshDS = getMeshDS();
5519   TIDSortedElemSet anElems, aNodes;
5520   arrayToSet(theElems, aMeshDS, anElems, SMDSAbs_All);
5521   arrayToSet(theNodesNot, aMeshDS, aNodes, SMDSAbs_Node);
5522
5523   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
5524   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
5525
5526   // Update Python script
5527   TPythonDump() << "isDone = " << this << ".DoubleNodeElemInRegion( " << theElems << ", "
5528                 << theNodesNot << ", " << theShape << " )";
5529
5530   declareMeshModified( /*isReComputeSafe=*/false );
5531   return aResult;
5532
5533   SMESH_CATCH( SMESH::throwCorbaException );
5534   return 0;
5535 }
5536
5537 //================================================================================
5538 /*!
5539   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5540   \param theElems - group of of elements (edges or faces) to be replicated
5541   \param theNodesNot - group of nodes not to replicated
5542   \param theAffectedElems - group of elements to which the replicated nodes
5543   should be associated to.
5544   \return TRUE if operation has been completed successfully, FALSE otherwise
5545   \sa DoubleNodes(), DoubleNodeGroups()
5546 */
5547 //================================================================================
5548
5549 CORBA::Boolean
5550 SMESH_MeshEditor_i::DoubleNodeElemGroup(SMESH::SMESH_GroupBase_ptr theElems,
5551                                         SMESH::SMESH_GroupBase_ptr theNodesNot,
5552                                         SMESH::SMESH_GroupBase_ptr theAffectedElems)
5553   throw (SALOME::SALOME_Exception)
5554 {
5555   SMESH_TRY;
5556   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
5557     return false;
5558
5559   initData();
5560
5561
5562   SMESHDS_Mesh* aMeshDS = getMeshDS();
5563   TIDSortedElemSet anElems, aNodes, anAffected;
5564   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
5565   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
5566   idSourceToSet( theAffectedElems, aMeshDS, anAffected, SMDSAbs_All );
5567
5568   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5569
5570   // Update Python script
5571   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroup( " << theElems << ", "
5572                 << theNodesNot << ", " << theAffectedElems << " )";
5573
5574   declareMeshModified( /*isReComputeSafe=*/false );
5575   return aResult;
5576
5577   SMESH_CATCH( SMESH::throwCorbaException );
5578   return 0;
5579 }
5580
5581 //================================================================================
5582 /*!
5583  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5584  * Works as DoubleNodeElemGroup(), but returns a new group with newly created elements.
5585  * \param theElems - group of of elements (edges or faces) to be replicated
5586  * \param theNodesNot - group of nodes not to replicated
5587  * \param theAffectedElems - group of elements to which the replicated nodes
5588  *        should be associated to.
5589  * \return a new group with newly created elements
5590  * \sa DoubleNodeElemGroup()
5591  */
5592 //================================================================================
5593
5594 SMESH::SMESH_Group_ptr
5595 SMESH_MeshEditor_i::DoubleNodeElemGroupNew(SMESH::SMESH_GroupBase_ptr theElems,
5596                                            SMESH::SMESH_GroupBase_ptr theNodesNot,
5597                                            SMESH::SMESH_GroupBase_ptr theAffectedElems)
5598   throw (SALOME::SALOME_Exception)
5599 {
5600   TPythonDump pyDump;
5601   SMESH::ListOfGroups_var twoGroups = DoubleNodeElemGroup2New( theElems,
5602                                                                theNodesNot,
5603                                                                theAffectedElems,
5604                                                                true, false );
5605   SMESH::SMESH_GroupBase_var baseGroup = twoGroups[0].in();
5606   SMESH::SMESH_Group_var     elemGroup = SMESH::SMESH_Group::_narrow( baseGroup );
5607
5608   pyDump << elemGroup << " = " << this << ".DoubleNodeElemGroupNew( "
5609          << theElems         << ", "
5610          << theNodesNot      << ", "
5611          << theAffectedElems << " )";
5612
5613   return elemGroup._retn();
5614 }
5615
5616 //================================================================================
5617 /*!
5618  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5619  * Works as DoubleNodeElemGroup(), but returns a new group with newly created elements.
5620  * \param theElems - group of of elements (edges or faces) to be replicated
5621  * \param theNodesNot - group of nodes not to replicated
5622  * \param theAffectedElems - group of elements to which the replicated nodes
5623  *        should be associated to.
5624  * \return a new group with newly created elements
5625  * \sa DoubleNodeElemGroup()
5626  */
5627 //================================================================================
5628
5629 SMESH::ListOfGroups*
5630 SMESH_MeshEditor_i::DoubleNodeElemGroup2New(SMESH::SMESH_GroupBase_ptr theElems,
5631                                             SMESH::SMESH_GroupBase_ptr theNodesNot,
5632                                             SMESH::SMESH_GroupBase_ptr theAffectedElems,
5633                                             CORBA::Boolean             theElemGroupNeeded,
5634                                             CORBA::Boolean             theNodeGroupNeeded)
5635   throw (SALOME::SALOME_Exception)
5636 {
5637   SMESH_TRY;
5638   SMESH::SMESH_Group_var aNewElemGroup, aNewNodeGroup;
5639   SMESH::ListOfGroups_var aTwoGroups = new SMESH::ListOfGroups();
5640   aTwoGroups->length( 2 );
5641
5642   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
5643     return aTwoGroups._retn();
5644
5645   initData();
5646
5647
5648   SMESHDS_Mesh* aMeshDS = getMeshDS();
5649   TIDSortedElemSet anElems, aNodes, anAffected;
5650   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
5651   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
5652   idSourceToSet( theAffectedElems, aMeshDS, anAffected, SMDSAbs_All );
5653
5654
5655   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5656
5657   declareMeshModified( /*isReComputeSafe=*/ !aResult );
5658
5659   TPythonDump pyDump;
5660
5661   if ( aResult )
5662   {
5663     // Create group with newly created elements
5664     CORBA::String_var elemGroupName = theElems->GetName();
5665     string aNewName = generateGroupName( string(elemGroupName.in()) + "_double");
5666     if ( !getEditor().GetLastCreatedElems().IsEmpty() && theElemGroupNeeded )
5667     {
5668       SMESH::long_array_var anIds = GetLastCreatedElems();
5669       SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true);
5670       aNewElemGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str());
5671       aNewElemGroup->Add(anIds);
5672     }
5673     if ( !getEditor().GetLastCreatedNodes().IsEmpty() && theNodeGroupNeeded )
5674     {
5675       SMESH::long_array_var anIds = GetLastCreatedNodes();
5676       aNewNodeGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
5677       aNewNodeGroup->Add(anIds);
5678     }
5679   }
5680
5681   // Update Python script
5682
5683   pyDump << "[ ";
5684   if ( aNewElemGroup->_is_nil() ) pyDump << "nothing, ";
5685   else                            pyDump << aNewElemGroup << ", ";
5686   if ( aNewNodeGroup->_is_nil() ) pyDump << "nothing ] = ";
5687   else                            pyDump << aNewNodeGroup << " ] = ";
5688
5689   pyDump << this << ".DoubleNodeElemGroup2New( " << theElems << ", "
5690          << theNodesNot        << ", "
5691          << theAffectedElems   << ", "
5692          << theElemGroupNeeded << ", "
5693          << theNodeGroupNeeded <<" )";
5694
5695   aTwoGroups[0] = aNewElemGroup._retn();
5696   aTwoGroups[1] = aNewNodeGroup._retn();
5697   return aTwoGroups._retn();
5698
5699   SMESH_CATCH( SMESH::throwCorbaException );
5700   return 0;
5701 }
5702
5703 //================================================================================
5704 /*!
5705   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5706   \param theElems - group of of elements (edges or faces) to be replicated
5707   \param theNodesNot - group of nodes not to replicated
5708   \param theShape - shape to detect affected elements (element which geometric center
5709   located on or inside shape).
5710   The replicated nodes should be associated to affected elements.
5711   \return TRUE if operation has been completed successfully, FALSE otherwise
5712   \sa DoubleNodesInRegion(), DoubleNodeGroupsInRegion()
5713 */
5714 //================================================================================
5715
5716 CORBA::Boolean
5717 SMESH_MeshEditor_i::DoubleNodeElemGroupInRegion(SMESH::SMESH_GroupBase_ptr theElems,
5718                                                 SMESH::SMESH_GroupBase_ptr theNodesNot,
5719                                                 GEOM::GEOM_Object_ptr      theShape )
5720   throw (SALOME::SALOME_Exception)
5721 {
5722   SMESH_TRY;
5723   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
5724     return false;
5725
5726   initData();
5727
5728
5729   SMESHDS_Mesh* aMeshDS = getMeshDS();
5730   TIDSortedElemSet anElems, aNodes, anAffected;
5731   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
5732   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
5733
5734   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
5735   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
5736
5737
5738   declareMeshModified( /*isReComputeSafe=*/ !aResult );
5739
5740   // Update Python script
5741   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroupInRegion( " << theElems << ", "
5742                 << theNodesNot << ", " << theShape << " )";
5743   return aResult;
5744
5745   SMESH_CATCH( SMESH::throwCorbaException );
5746   return 0;
5747 }
5748
5749 //================================================================================
5750 /*!
5751  * \brief Re-load elements from a list of groups into a TIDSortedElemSet
5752  *  \param [in] theGrpList - groups
5753  *  \param [in] theMeshDS -  mesh
5754  *  \param [out] theElemSet - set of elements
5755  *  \param [in] theIsNodeGrp - is \a theGrpList includes goups of nodes
5756  */
5757 //================================================================================
5758
5759 static void listOfGroupToSet(const SMESH::ListOfGroups& theGrpList,
5760                              SMESHDS_Mesh*              theMeshDS,
5761                              TIDSortedElemSet&          theElemSet,
5762                              const bool                 theIsNodeGrp)
5763 {
5764   for ( int i = 0, n = theGrpList.length(); i < n; i++ )
5765   {
5766     SMESH::SMESH_GroupBase_var aGrp = theGrpList[ i ];
5767     if ( !CORBA::is_nil( aGrp ) && (theIsNodeGrp ? aGrp->GetType() == SMESH::NODE
5768                                     : aGrp->GetType() != SMESH::NODE ) )
5769     {
5770       SMESH::long_array_var anIDs = aGrp->GetIDs();
5771       arrayToSet( anIDs, theMeshDS, theElemSet, theIsNodeGrp ? SMDSAbs_Node : SMDSAbs_All );
5772     }
5773   }
5774 }
5775
5776 //================================================================================
5777 /*!
5778   \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
5779   This method provided for convenience works as DoubleNodes() described above.
5780   \param theElems - list of groups of elements (edges or faces) to be replicated
5781   \param theNodesNot - list of groups of nodes not to replicated
5782   \param theAffectedElems - group of elements to which the replicated nodes
5783   should be associated to.
5784   \return TRUE if operation has been completed successfully, FALSE otherwise
5785   \sa DoubleNodeGroup(), DoubleNodes(), DoubleNodeElemGroupsNew()
5786 */
5787 //================================================================================
5788
5789 CORBA::Boolean
5790 SMESH_MeshEditor_i::DoubleNodeElemGroups(const SMESH::ListOfGroups& theElems,
5791                                          const SMESH::ListOfGroups& theNodesNot,
5792                                          const SMESH::ListOfGroups& theAffectedElems)
5793   throw (SALOME::SALOME_Exception)
5794 {
5795   SMESH_TRY;
5796   initData();
5797
5798
5799   SMESHDS_Mesh* aMeshDS = getMeshDS();
5800   TIDSortedElemSet anElems, aNodes, anAffected;
5801   listOfGroupToSet(theElems, aMeshDS, anElems, false );
5802   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
5803   listOfGroupToSet(theAffectedElems, aMeshDS, anAffected, false );
5804
5805   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5806
5807   // Update Python script
5808   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroups( " << &theElems << ", "
5809                 << &theNodesNot << ", " << &theAffectedElems << " )";
5810
5811   declareMeshModified( /*isReComputeSafe=*/false );
5812   return aResult;
5813
5814   SMESH_CATCH( SMESH::throwCorbaException );
5815   return 0;
5816 }
5817
5818 //================================================================================
5819 /*!
5820  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5821  * Works as DoubleNodeElemGroups(), but returns a new group with newly created elements.
5822   \param theElems - list of groups of elements (edges or faces) to be replicated
5823   \param theNodesNot - list of groups of nodes not to replicated
5824   \param theAffectedElems - group of elements to which the replicated nodes
5825   should be associated to.
5826  * \return a new group with newly created elements
5827  * \sa DoubleNodeElemGroups()
5828  */
5829 //================================================================================
5830
5831 SMESH::SMESH_Group_ptr
5832 SMESH_MeshEditor_i::DoubleNodeElemGroupsNew(const SMESH::ListOfGroups& theElems,
5833                                             const SMESH::ListOfGroups& theNodesNot,
5834                                             const SMESH::ListOfGroups& theAffectedElems)
5835   throw (SALOME::SALOME_Exception)
5836 {
5837   TPythonDump pyDump;
5838   SMESH::ListOfGroups_var twoGroups = DoubleNodeElemGroups2New( theElems,
5839                                                                 theNodesNot,
5840                                                                 theAffectedElems,
5841                                                                 true, false );
5842   SMESH::SMESH_GroupBase_var baseGroup = twoGroups[0].in();
5843   SMESH::SMESH_Group_var     elemGroup = SMESH::SMESH_Group::_narrow( baseGroup );
5844
5845   pyDump << elemGroup << " = " << this << ".DoubleNodeElemGroupsNew( "
5846          << theElems         << ", "
5847          << theNodesNot      << ", "
5848          << theAffectedElems << " )";
5849
5850   return elemGroup._retn();
5851 }
5852
5853 //================================================================================
5854 /*!
5855  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5856  * Works as DoubleNodeElemGroups(), but returns a new group with newly created elements.
5857   \param theElems - list of groups of elements (edges or faces) to be replicated
5858   \param theNodesNot - list of groups of nodes not to replicated
5859   \param theAffectedElems - group of elements to which the replicated nodes
5860   should be associated to.
5861  * \return a new group with newly created elements
5862  * \sa DoubleNodeElemGroups()
5863  */
5864 //================================================================================
5865
5866 SMESH::ListOfGroups*
5867 SMESH_MeshEditor_i::DoubleNodeElemGroups2New(const SMESH::ListOfGroups& theElems,
5868                                              const SMESH::ListOfGroups& theNodesNot,
5869                                              const SMESH::ListOfGroups& theAffectedElems,
5870                                              CORBA::Boolean             theElemGroupNeeded,
5871                                              CORBA::Boolean             theNodeGroupNeeded)
5872   throw (SALOME::SALOME_Exception)
5873 {
5874   SMESH_TRY;
5875   SMESH::SMESH_Group_var aNewElemGroup, aNewNodeGroup;
5876   SMESH::ListOfGroups_var aTwoGroups = new SMESH::ListOfGroups();
5877   aTwoGroups->length( 2 );
5878   
5879   initData();
5880
5881
5882   SMESHDS_Mesh* aMeshDS = getMeshDS();
5883   TIDSortedElemSet anElems, aNodes, anAffected;
5884   listOfGroupToSet(theElems, aMeshDS, anElems, false );
5885   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
5886   listOfGroupToSet(theAffectedElems, aMeshDS, anAffected, false );
5887
5888   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5889
5890   declareMeshModified( /*isReComputeSafe=*/ !aResult );
5891
5892   TPythonDump pyDump;
5893   if ( aResult )
5894   {
5895     // Create group with newly created elements
5896     CORBA::String_var elemGroupName = theElems[0]->GetName();
5897     string aNewName = generateGroupName( string(elemGroupName.in()) + "_double");
5898     if ( !getEditor().GetLastCreatedElems().IsEmpty() && theElemGroupNeeded )
5899     {
5900       SMESH::long_array_var anIds = GetLastCreatedElems();
5901       SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true);
5902       aNewElemGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str());
5903       aNewElemGroup->Add(anIds);
5904     }
5905     if ( !getEditor().GetLastCreatedNodes().IsEmpty() && theNodeGroupNeeded )
5906     {
5907       SMESH::long_array_var anIds = GetLastCreatedNodes();
5908       aNewNodeGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
5909       aNewNodeGroup->Add(anIds);
5910     }
5911   }
5912
5913   // Update Python script
5914
5915   pyDump << "[ ";
5916   if ( aNewElemGroup->_is_nil() ) pyDump << "nothing, ";
5917   else                            pyDump << aNewElemGroup << ", ";
5918   if ( aNewNodeGroup->_is_nil() ) pyDump << "nothing ] = ";
5919   else                            pyDump << aNewNodeGroup << " ] = ";
5920
5921   pyDump << this << ".DoubleNodeElemGroups2New( " << &theElems << ", "
5922          << &theNodesNot       << ", "
5923          << &theAffectedElems  << ", "
5924          << theElemGroupNeeded << ", "
5925          << theNodeGroupNeeded << " )";
5926
5927   aTwoGroups[0] = aNewElemGroup._retn();
5928   aTwoGroups[1] = aNewNodeGroup._retn();
5929   return aTwoGroups._retn();
5930
5931   SMESH_CATCH( SMESH::throwCorbaException );
5932   return 0;
5933 }
5934
5935 //================================================================================
5936 /*!
5937   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5938   This method provided for convenience works as DoubleNodes() described above.
5939   \param theElems - list of groups of elements (edges or faces) to be replicated
5940   \param theNodesNot - list of groups of nodes not to replicated
5941   \param theShape - shape to detect affected elements (element which geometric center
5942   located on or inside shape).
5943   The replicated nodes should be associated to affected elements.
5944   \return TRUE if operation has been completed successfully, FALSE otherwise
5945   \sa DoubleNodeGroupInRegion(), DoubleNodesInRegion()
5946 */
5947 //================================================================================
5948
5949 CORBA::Boolean
5950 SMESH_MeshEditor_i::DoubleNodeElemGroupsInRegion(const SMESH::ListOfGroups& theElems,
5951                                                  const SMESH::ListOfGroups& theNodesNot,
5952                                                  GEOM::GEOM_Object_ptr      theShape )
5953   throw (SALOME::SALOME_Exception)
5954 {
5955   SMESH_TRY;
5956   initData();
5957
5958
5959   SMESHDS_Mesh* aMeshDS = getMeshDS();
5960   TIDSortedElemSet anElems, aNodes;
5961   listOfGroupToSet(theElems, aMeshDS, anElems,false );
5962   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
5963
5964   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
5965   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
5966
5967   // Update Python script
5968   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroupsInRegion( " << &theElems << ", "
5969                 << &theNodesNot << ", " << theShape << " )";
5970
5971   declareMeshModified( /*isReComputeSafe=*/ !aResult );
5972   return aResult;
5973
5974   SMESH_CATCH( SMESH::throwCorbaException );
5975   return 0;
5976 }
5977
5978 //================================================================================
5979 /*!
5980   \brief Identify the elements that will be affected by node duplication (actual
5981          duplication is not performed.
5982   This method is the first step of DoubleNodeElemGroupsInRegion.
5983   \param theElems - list of groups of elements (edges or faces) to be replicated
5984   \param theNodesNot - list of groups of nodes not to replicated
5985   \param theShape - shape to detect affected elements (element which geometric center
5986          located on or inside shape).
5987          The replicated nodes should be associated to affected elements.
5988   \return groups of affected elements
5989   \sa DoubleNodeElemGroupsInRegion()
5990 */
5991 //================================================================================
5992 SMESH::ListOfGroups*
5993 SMESH_MeshEditor_i::AffectedElemGroupsInRegion( const SMESH::ListOfGroups& theElems,
5994                                                 const SMESH::ListOfGroups& theNodesNot,
5995                                                 GEOM::GEOM_Object_ptr      theShape )
5996   throw (SALOME::SALOME_Exception)
5997 {
5998   SMESH_TRY;
5999   MESSAGE("AffectedElemGroupsInRegion");
6000   SMESH::ListOfGroups_var aListOfGroups = new SMESH::ListOfGroups();
6001   bool isEdgeGroup = false;
6002   bool isFaceGroup = false;
6003   bool isVolumeGroup = false;
6004   SMESH::SMESH_Group_var aNewEdgeGroup = myMesh_i->CreateGroup(SMESH::EDGE, "affectedEdges");
6005   SMESH::SMESH_Group_var aNewFaceGroup = myMesh_i->CreateGroup(SMESH::FACE, "affectedFaces");
6006   SMESH::SMESH_Group_var aNewVolumeGroup = myMesh_i->CreateGroup(SMESH::VOLUME, "affectedVolumes");
6007
6008   initData();
6009
6010   ::SMESH_MeshEditor aMeshEditor(myMesh);
6011
6012   SMESHDS_Mesh* aMeshDS = getMeshDS();
6013   TIDSortedElemSet anElems, aNodes;
6014   listOfGroupToSet(theElems, aMeshDS, anElems, false);
6015   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true);
6016
6017   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape(theShape);
6018   TIDSortedElemSet anAffected;
6019   bool aResult = aMeshEditor.AffectedElemGroupsInRegion(anElems, aNodes, aShape, anAffected);
6020
6021
6022   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6023
6024   TPythonDump pyDump;
6025   if (aResult)
6026   {
6027     int lg = anAffected.size();
6028     MESSAGE("lg="<< lg);
6029     SMESH::long_array_var volumeIds = new SMESH::long_array;
6030     volumeIds->length(lg);
6031     SMESH::long_array_var faceIds = new SMESH::long_array;
6032     faceIds->length(lg);
6033     SMESH::long_array_var edgeIds = new SMESH::long_array;
6034     edgeIds->length(lg);
6035     int ivol = 0;
6036     int iface = 0;
6037     int iedge = 0;
6038
6039     TIDSortedElemSet::const_iterator eIt = anAffected.begin();
6040     for (; eIt != anAffected.end(); ++eIt)
6041     {
6042       const SMDS_MeshElement* anElem = *eIt;
6043       if (!anElem)
6044         continue;
6045       int elemId = anElem->GetID();
6046       if (myMesh->GetElementType(elemId, true) == SMDSAbs_Volume)
6047         volumeIds[ivol++] = elemId;
6048       else if (myMesh->GetElementType(elemId, true) == SMDSAbs_Face)
6049         faceIds[iface++] = elemId;
6050       else if (myMesh->GetElementType(elemId, true) == SMDSAbs_Edge)
6051         edgeIds[iedge++] = elemId;
6052     }
6053     volumeIds->length(ivol);
6054     faceIds->length(iface);
6055     edgeIds->length(iedge);
6056
6057     aNewVolumeGroup->Add(volumeIds);
6058     aNewFaceGroup->Add(faceIds);
6059     aNewEdgeGroup->Add(edgeIds);
6060     isVolumeGroup = (aNewVolumeGroup->Size() > 0);
6061     isFaceGroup = (aNewFaceGroup->Size() > 0);
6062     isEdgeGroup = (aNewEdgeGroup->Size() > 0);
6063   }
6064
6065   int nbGroups = 0;
6066   if (isEdgeGroup)   nbGroups++;
6067   if (isFaceGroup)   nbGroups++;
6068   if (isVolumeGroup) nbGroups++;
6069   aListOfGroups->length(nbGroups);
6070
6071   int i = 0;
6072   if (isEdgeGroup)   aListOfGroups[i++] = aNewEdgeGroup._retn();
6073   if (isFaceGroup)   aListOfGroups[i++] = aNewFaceGroup._retn();
6074   if (isVolumeGroup) aListOfGroups[i++] = aNewVolumeGroup._retn();
6075
6076   // Update Python script
6077
6078   pyDump << "[ ";
6079   if (isEdgeGroup)   pyDump << aNewEdgeGroup << ", ";
6080   if (isFaceGroup)   pyDump << aNewFaceGroup << ", ";
6081   if (isVolumeGroup) pyDump << aNewVolumeGroup << ", ";
6082   pyDump << "] = ";
6083   pyDump << this << ".AffectedElemGroupsInRegion( "
6084          << &theElems << ", " << &theNodesNot << ", " << theShape << " )";
6085
6086   return aListOfGroups._retn();
6087
6088   SMESH_CATCH( SMESH::throwCorbaException );
6089   return 0;
6090 }
6091
6092 //================================================================================
6093 /*!
6094   \brief Generated skin mesh (containing 2D cells) from 3D mesh
6095    The created 2D mesh elements based on nodes of free faces of boundary volumes
6096   \return TRUE if operation has been completed successfully, FALSE otherwise
6097 */
6098 //================================================================================
6099
6100 CORBA::Boolean SMESH_MeshEditor_i::Make2DMeshFrom3D()
6101   throw (SALOME::SALOME_Exception)
6102 {
6103   SMESH_TRY;
6104   initData();
6105
6106   bool aResult = getEditor().Make2DMeshFrom3D();
6107
6108   TPythonDump() << "isDone = " << this << ".Make2DMeshFrom3D()";
6109
6110   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6111   return aResult;
6112
6113   SMESH_CATCH( SMESH::throwCorbaException );
6114   return false;
6115 }
6116
6117 //================================================================================
6118 /*!
6119  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
6120  * The list of groups must contain at least two groups. The groups have to be disjoint:
6121  * no common element into two different groups.
6122  * The nodes of the internal faces at the boundaries of the groups are doubled.
6123  * Optionally, the internal faces are replaced by flat elements.
6124  * Triangles are transformed into prisms, and quadrangles into hexahedrons.
6125  * The flat elements are stored in groups of volumes.
6126  * These groups are named according to the position of the group in the list:
6127  * 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.
6128  * 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.
6129  * All the flat elements are gathered into the group named "joints3D" (or "joints2D" in 2D situation).
6130  * The flat element of the multiple junctions between the simple junction are stored in a group named "jointsMultiples".
6131  * \param theDomains - list of groups of volumes
6132  * \param createJointElems - if TRUE, create the elements
6133  * \param onAllBoundaries - if TRUE, the nodes and elements are also created on
6134  *        the boundary between \a theDomains and the rest mesh
6135  * \return TRUE if operation has been completed successfully, FALSE otherwise
6136  */
6137 //================================================================================
6138
6139 CORBA::Boolean
6140 SMESH_MeshEditor_i::DoubleNodesOnGroupBoundaries( const SMESH::ListOfGroups& theDomains,
6141                                                   CORBA::Boolean             createJointElems,
6142                                                   CORBA::Boolean             onAllBoundaries )
6143   throw (SALOME::SALOME_Exception)
6144 {
6145   bool isOK = false;
6146
6147   SMESH_TRY;
6148   initData();
6149
6150   SMESHDS_Mesh* aMeshDS = getMeshDS();
6151
6152   // MESSAGE("theDomains.length = "<<theDomains.length());
6153   if ( theDomains.length() <= 1 && !onAllBoundaries )
6154     THROW_SALOME_CORBA_EXCEPTION("At least 2 groups are required.", SALOME::BAD_PARAM);
6155
6156   vector<TIDSortedElemSet> domains;
6157   domains.resize( theDomains.length() );
6158
6159   for ( int i = 0, n = theDomains.length(); i < n; i++ )
6160   {
6161     SMESH::SMESH_GroupBase_var aGrp = theDomains[ i ];
6162     if ( !CORBA::is_nil( aGrp ) /*&& ( aGrp->GetType() != SMESH::NODE )*/ )
6163     {
6164 //      if ( aGrp->GetType() != SMESH::VOLUME )
6165 //        THROW_SALOME_CORBA_EXCEPTION("Not a volume group", SALOME::BAD_PARAM);
6166       SMESH::long_array_var anIDs = aGrp->GetIDs();
6167       arrayToSet( anIDs, aMeshDS, domains[ i ], SMDSAbs_All );
6168     }
6169   }
6170
6171   isOK = getEditor().DoubleNodesOnGroupBoundaries( domains, createJointElems, onAllBoundaries );
6172   // TODO publish the groups of flat elements in study
6173
6174   declareMeshModified( /*isReComputeSafe=*/ !isOK );
6175
6176   // Update Python script
6177   TPythonDump() << "isDone = " << this << ".DoubleNodesOnGroupBoundaries( " << &theDomains
6178                 << ", " << createJointElems << ", " << onAllBoundaries << " )";
6179
6180   SMESH_CATCH( SMESH::throwCorbaException );
6181
6182   myMesh_i->CreateGroupServants(); // publish created groups if any
6183
6184   return isOK;
6185 }
6186
6187 //================================================================================
6188 /*!
6189  * \brief Double nodes on some external faces and create flat elements.
6190  * Flat elements are mainly used by some types of mechanic calculations.
6191  *
6192  * Each group of the list must be constituted of faces.
6193  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
6194  * @param theGroupsOfFaces - list of groups of faces
6195  * @return TRUE if operation has been completed successfully, FALSE otherwise
6196  */
6197 //================================================================================
6198
6199 CORBA::Boolean
6200 SMESH_MeshEditor_i::CreateFlatElementsOnFacesGroups( const SMESH::ListOfGroups& theGroupsOfFaces )
6201   throw (SALOME::SALOME_Exception)
6202 {
6203   SMESH_TRY;
6204   initData();
6205
6206   SMESHDS_Mesh* aMeshDS = getMeshDS();
6207
6208   vector<TIDSortedElemSet> faceGroups;
6209   faceGroups.clear();
6210
6211   for ( int i = 0, n = theGroupsOfFaces.length(); i < n; i++ )
6212   {
6213     SMESH::SMESH_GroupBase_var aGrp = theGroupsOfFaces[ i ];
6214     if ( !CORBA::is_nil( aGrp ) && ( aGrp->GetType() != SMESH::NODE ) )
6215     {
6216       TIDSortedElemSet faceGroup;
6217       faceGroup.clear();
6218       faceGroups.push_back(faceGroup);
6219       SMESH::long_array_var anIDs = aGrp->GetIDs();
6220       arrayToSet( anIDs, aMeshDS, faceGroups[ i ], SMDSAbs_All );
6221     }
6222   }
6223
6224   bool aResult = getEditor().CreateFlatElementsOnFacesGroups( faceGroups );
6225   // TODO publish the groups of flat elements in study
6226
6227   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6228
6229   // Update Python script
6230   TPythonDump() << this << ".CreateFlatElementsOnFacesGroups( " << &theGroupsOfFaces << " )";
6231   return aResult;
6232
6233   SMESH_CATCH( SMESH::throwCorbaException );
6234   return false;
6235 }
6236
6237 //================================================================================
6238 /*!
6239  *  \brief Identify all the elements around a geom shape, get the faces delimiting
6240  *         the hole.
6241  *
6242  *  Build groups of volume to remove, groups of faces to replace on the skin of the
6243  *  object, groups of faces to remove inside the object, (idem edges).
6244  *  Build ordered list of nodes at the border of each group of faces to replace
6245  *  (to be used to build a geom subshape).
6246  */
6247 //================================================================================
6248
6249 void SMESH_MeshEditor_i::CreateHoleSkin(CORBA::Double                  radius,
6250                                         GEOM::GEOM_Object_ptr          theShape,
6251                                         const char*                    groupName,
6252                                         const SMESH::double_array&     theNodesCoords,
6253                                         SMESH::array_of_long_array_out GroupsOfNodes)
6254   throw (SALOME::SALOME_Exception)
6255 {
6256   SMESH_TRY;
6257
6258   initData();
6259   std::vector<std::vector<int> > aListOfListOfNodes;
6260   ::SMESH_MeshEditor aMeshEditor( myMesh );
6261
6262   theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
6263   if ( !theNodeSearcher )
6264     theNodeSearcher = SMESH_MeshAlgos::GetNodeSearcher( *getMeshDS() );
6265
6266   vector<double> nodesCoords;
6267   for (int i = 0; i < theNodesCoords.length(); i++)
6268   {
6269     nodesCoords.push_back( theNodesCoords[i] );
6270   }
6271
6272   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
6273   aMeshEditor.CreateHoleSkin(radius, aShape, theNodeSearcher, groupName,
6274                              nodesCoords, aListOfListOfNodes);
6275
6276   GroupsOfNodes = new SMESH::array_of_long_array;
6277   GroupsOfNodes->length( aListOfListOfNodes.size() );
6278   std::vector<std::vector<int> >::iterator llIt = aListOfListOfNodes.begin();
6279   for ( CORBA::Long i = 0; llIt != aListOfListOfNodes.end(); llIt++, i++ )
6280   {
6281     vector<int>& aListOfNodes = *llIt;
6282     vector<int>::iterator lIt = aListOfNodes.begin();;
6283     SMESH::long_array& aGroup = (*GroupsOfNodes)[ i ];
6284     aGroup.length( aListOfNodes.size() );
6285     for ( int j = 0; lIt != aListOfNodes.end(); lIt++, j++ )
6286       aGroup[ j ] = (*lIt);
6287   }
6288   TPythonDump() << "lists_nodes = " << this << ".CreateHoleSkin( "
6289                 << radius << ", "
6290                 << theShape
6291                 << ", '" << groupName << "', "
6292                 << theNodesCoords << " )";
6293
6294   SMESH_CATCH( SMESH::throwCorbaException );
6295 }
6296
6297 // issue 20749 ===================================================================
6298 /*!
6299  * \brief Creates missing boundary elements
6300  *  \param elements - elements whose boundary is to be checked
6301  *  \param dimension - defines type of boundary elements to create
6302  *  \param groupName - a name of group to store created boundary elements in,
6303  *                     "" means not to create the group
6304  *  \param meshName - a name of new mesh to store created boundary elements in,
6305  *                     "" means not to create the new mesh
6306  *  \param toCopyElements - if true, the checked elements will be copied into the new mesh
6307  *  \param toCopyExistingBondary - if true, not only new but also pre-existing
6308  *                                boundary elements will be copied into the new mesh
6309  *  \param group - returns the create group, if any
6310  *  \retval SMESH::SMESH_Mesh - the mesh where elements were added to
6311  */
6312 // ================================================================================
6313
6314 SMESH::SMESH_Mesh_ptr
6315 SMESH_MeshEditor_i::MakeBoundaryMesh(SMESH::SMESH_IDSource_ptr idSource,
6316                                      SMESH::Bnd_Dimension      dim,
6317                                      const char*               groupName,
6318                                      const char*               meshName,
6319                                      CORBA::Boolean            toCopyElements,
6320                                      CORBA::Boolean            toCopyExistingBondary,
6321                                      SMESH::SMESH_Group_out    group)
6322   throw (SALOME::SALOME_Exception)
6323 {
6324   SMESH_TRY;
6325   initData();
6326
6327   if ( dim > SMESH::BND_1DFROM2D )
6328     THROW_SALOME_CORBA_EXCEPTION("Invalid boundary dimension", SALOME::BAD_PARAM);
6329
6330   SMESHDS_Mesh* aMeshDS = getMeshDS();
6331
6332   SMESH::SMESH_Mesh_var mesh_var;
6333   SMESH::SMESH_Group_var group_var;
6334
6335   TPythonDump pyDump;
6336
6337   TIDSortedElemSet elements;
6338   SMDSAbs_ElementType elemType = (dim == SMESH::BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
6339   if ( idSourceToSet( idSource, aMeshDS, elements, elemType,/*emptyIfIsMesh=*/true ))
6340   {
6341     // mesh to fill in
6342     mesh_var =
6343       strlen(meshName) ? makeMesh(meshName) : SMESH::SMESH_Mesh::_duplicate(myMesh_i->_this());
6344     SMESH_Mesh_i* mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh_var );
6345     // other mesh
6346     SMESH_Mesh* smesh_mesh = (mesh_i==myMesh_i) ? (SMESH_Mesh*)0 : &mesh_i->GetImpl();
6347
6348     // group of new boundary elements
6349     SMESH_Group* smesh_group = 0;
6350     if ( strlen(groupName) )
6351     {
6352       group_var = mesh_i->CreateGroup( SMESH::ElementType(int(elemType)-1),groupName);
6353       if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( group_var ))
6354         smesh_group = group_i->GetSmeshGroup();
6355     }
6356
6357     // do it
6358     getEditor().MakeBoundaryMesh( elements,
6359                                   ::SMESH_MeshEditor::Bnd_Dimension(dim),
6360                                   smesh_group,
6361                                   smesh_mesh,
6362                                   toCopyElements,
6363                                   toCopyExistingBondary);
6364
6365     if ( smesh_mesh )
6366       smesh_mesh->GetMeshDS()->Modified();
6367   }
6368
6369   const char* dimName[] = { "BND_2DFROM3D", "BND_1DFROM3D", "BND_1DFROM2D" };
6370
6371   // result of MakeBoundaryMesh() is a tuple (mesh, group)
6372   if ( mesh_var->_is_nil() )
6373     pyDump << myMesh_i->_this() << ", ";
6374   else
6375     pyDump << mesh_var << ", ";
6376   if ( group_var->_is_nil() )
6377     pyDump << "_NoneGroup = "; // assignment to None is forbiden
6378   else
6379     pyDump << group_var << " = ";
6380   pyDump << this << ".MakeBoundaryMesh( "
6381          << idSource << ", "
6382          << "SMESH." << dimName[int(dim)] << ", "
6383          << "'" << groupName << "', "
6384          << "'" << meshName<< "', "
6385          << toCopyElements << ", "
6386          << toCopyExistingBondary << ")";
6387
6388   group = group_var._retn();
6389   return mesh_var._retn();
6390
6391   SMESH_CATCH( SMESH::throwCorbaException );
6392   return SMESH::SMESH_Mesh::_nil();
6393 }
6394
6395 //================================================================================
6396 /*!
6397  * \brief Creates missing boundary elements
6398  *  \param dimension - defines type of boundary elements to create
6399  *  \param groupName - a name of group to store all boundary elements in,
6400  *    "" means not to create the group
6401  *  \param meshName - a name of a new mesh, which is a copy of the initial 
6402  *    mesh + created boundary elements; "" means not to create the new mesh
6403  *  \param toCopyAll - if true, the whole initial mesh will be copied into
6404  *    the new mesh else only boundary elements will be copied into the new mesh
6405  *  \param groups - optional groups of elements to make boundary around
6406  *  \param mesh - returns the mesh where elements were added to
6407  *  \param group - returns the created group, if any
6408  *  \retval long - number of added boundary elements
6409  */
6410 //================================================================================
6411
6412 CORBA::Long SMESH_MeshEditor_i::MakeBoundaryElements(SMESH::Bnd_Dimension dim,
6413                                                      const char* groupName,
6414                                                      const char* meshName,
6415                                                      CORBA::Boolean toCopyAll,
6416                                                      const SMESH::ListOfIDSources& groups,
6417                                                      SMESH::SMESH_Mesh_out mesh,
6418                                                      SMESH::SMESH_Group_out group)
6419   throw (SALOME::SALOME_Exception)
6420 {
6421   SMESH_TRY;
6422   initData();
6423
6424   if ( dim > SMESH::BND_1DFROM2D )
6425     THROW_SALOME_CORBA_EXCEPTION("Invalid boundary dimension", SALOME::BAD_PARAM);
6426
6427   // separate groups belonging to this and other mesh
6428   SMESH::ListOfIDSources_var groupsOfThisMesh = new SMESH::ListOfIDSources;
6429   SMESH::ListOfIDSources_var groupsOfOtherMesh = new SMESH::ListOfIDSources;
6430   groupsOfThisMesh->length( groups.length() );
6431   groupsOfOtherMesh->length( groups.length() );
6432   int nbGroups = 0, nbGroupsOfOtherMesh = 0;
6433   for ( int i = 0; i < groups.length(); ++i )
6434   {
6435     SMESH::SMESH_Mesh_var m = groups[i]->GetMesh();
6436     if ( myMesh_i != SMESH::DownCast<SMESH_Mesh_i*>( m ))
6437       groupsOfOtherMesh[ nbGroupsOfOtherMesh++ ] = groups[i];
6438     else
6439       groupsOfThisMesh[ nbGroups++ ] = groups[i];
6440     if ( SMESH::DownCast<SMESH_Mesh_i*>( groups[i] ))
6441       THROW_SALOME_CORBA_EXCEPTION("expect a group but recieve a mesh", SALOME::BAD_PARAM);
6442   }
6443   groupsOfThisMesh->length( nbGroups );
6444   groupsOfOtherMesh->length( nbGroupsOfOtherMesh );
6445
6446   int nbAdded = 0;
6447   TPythonDump pyDump;
6448
6449   if ( nbGroupsOfOtherMesh > 0 )
6450   {
6451     // process groups belonging to another mesh
6452     SMESH::SMESH_Mesh_var    otherMesh = groupsOfOtherMesh[0]->GetMesh();
6453     SMESH::SMESH_MeshEditor_var editor = otherMesh->GetMeshEditor();
6454     nbAdded += editor->MakeBoundaryElements( dim, groupName, meshName, toCopyAll,
6455                                              groupsOfOtherMesh, mesh, group );
6456   }
6457
6458   SMESH::SMESH_Mesh_var mesh_var;
6459   SMESH::SMESH_Group_var group_var;
6460
6461   // get mesh to fill
6462   mesh_var = SMESH::SMESH_Mesh::_duplicate( myMesh_i->_this() );
6463   const bool toCopyMesh = ( strlen( meshName ) > 0 );
6464   if ( toCopyMesh )
6465   {
6466     if ( toCopyAll )
6467       mesh_var = SMESH_Gen_i::GetSMESHGen()->CopyMesh(mesh_var,
6468                                                       meshName,
6469                                                       /*toCopyGroups=*/false,
6470                                                       /*toKeepIDs=*/true);
6471     else
6472       mesh_var = makeMesh(meshName);
6473   }
6474   SMESH_Mesh_i* mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh_var );
6475   SMESH_Mesh*  tgtMesh = &mesh_i->GetImpl();
6476
6477   // source mesh
6478   SMESH_Mesh*     srcMesh = ( toCopyMesh && !toCopyAll ) ? myMesh : tgtMesh;
6479   SMESHDS_Mesh* srcMeshDS = srcMesh->GetMeshDS();
6480
6481   // group of boundary elements
6482   SMESH_Group* smesh_group = 0;
6483   SMDSAbs_ElementType elemType = (dim == SMESH::BND_2DFROM3D) ? SMDSAbs_Volume : SMDSAbs_Face;
6484   if ( strlen(groupName) )
6485   {
6486     SMESH::ElementType groupType = SMESH::ElementType( int(elemType)-1 );
6487     group_var = mesh_i->CreateGroup( groupType, groupName );
6488     if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( group_var ))
6489       smesh_group = group_i->GetSmeshGroup();
6490   }
6491
6492   TIDSortedElemSet elements;
6493
6494   if ( groups.length() > 0 )
6495   {
6496     for ( int i = 0; i < nbGroups; ++i )
6497     {
6498       elements.clear();
6499       if ( idSourceToSet( groupsOfThisMesh[i], srcMeshDS, elements, elemType,/*emptyIfIsMesh=*/0 ))
6500       {
6501         SMESH::Bnd_Dimension bdim = 
6502           ( elemType == SMDSAbs_Volume ) ? SMESH::BND_2DFROM3D : SMESH::BND_1DFROM2D;
6503         nbAdded += getEditor().MakeBoundaryMesh( elements,
6504                                                  ::SMESH_MeshEditor::Bnd_Dimension(bdim),
6505                                                  smesh_group,
6506                                                  tgtMesh,
6507                                                  /*toCopyElements=*/false,
6508                                                  /*toCopyExistingBondary=*/srcMesh != tgtMesh,
6509                                                  /*toAddExistingBondary=*/true,
6510                                                  /*aroundElements=*/true);
6511       }
6512     }
6513   }
6514   else
6515   {
6516     nbAdded += getEditor().MakeBoundaryMesh( elements,
6517                                              ::SMESH_MeshEditor::Bnd_Dimension(dim),
6518                                              smesh_group,
6519                                              tgtMesh,
6520                                              /*toCopyElements=*/false,
6521                                              /*toCopyExistingBondary=*/srcMesh != tgtMesh,
6522                                              /*toAddExistingBondary=*/true);
6523   }
6524   tgtMesh->GetMeshDS()->Modified();
6525
6526   const char* dimName[] = { "BND_2DFROM3D", "BND_1DFROM3D", "BND_1DFROM2D" };
6527
6528   // result of MakeBoundaryElements() is a tuple (nb, mesh, group)
6529   pyDump << "nbAdded, ";
6530   if ( mesh_var->_is_nil() )
6531     pyDump << myMesh_i->_this() << ", ";
6532   else
6533     pyDump << mesh_var << ", ";
6534   if ( group_var->_is_nil() )
6535     pyDump << "_NoneGroup = "; // assignment to None is forbiden
6536   else
6537     pyDump << group_var << " = ";
6538   pyDump << this << ".MakeBoundaryElements( "
6539          << "SMESH." << dimName[int(dim)] << ", "
6540          << "'" << groupName << "', "
6541          << "'" << meshName<< "', "
6542          << toCopyAll << ", "
6543          << groups << ")";
6544
6545   mesh  = mesh_var._retn();
6546   group = group_var._retn();
6547   return nbAdded;
6548
6549   SMESH_CATCH( SMESH::throwCorbaException );
6550   return 0;
6551 }