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