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