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