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