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