Salome HOME
IPAL52868: Confusing error message when computing an imported mesh w/o algo assigned
[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     if ( ! ( nodes[i] = getMeshDS()->FindNode( IDsOfNodes[i] )))
1067       return 0;
1068
1069   const SMDS_MeshElement* elem = getMeshDS()->AddPolygonalFace(nodes);
1070
1071   // Update Python script
1072   TPythonDump() <<"faceID = "<<this<<".AddPolygonalFace( "<<IDsOfNodes<<" )";
1073
1074   declareMeshModified( /*isReComputeSafe=*/false );
1075   return elem ? elem->GetID() : 0;
1076
1077   SMESH_CATCH( SMESH::throwCorbaException );
1078   return 0;
1079 }
1080
1081 //=============================================================================
1082 /*!
1083  *  AddQuadPolygonalFace
1084  */
1085 //=============================================================================
1086
1087 CORBA::Long SMESH_MeshEditor_i::AddQuadPolygonalFace (const SMESH::long_array & IDsOfNodes)
1088   throw (SALOME::SALOME_Exception)
1089 {
1090   SMESH_TRY;
1091   initData();
1092
1093   int NbNodes = IDsOfNodes.length();
1094   std::vector<const SMDS_MeshNode*> nodes (NbNodes);
1095   for (int i = 0; i < NbNodes; i++)
1096     nodes[i] = getMeshDS()->FindNode(IDsOfNodes[i]);
1097
1098   const SMDS_MeshElement* elem = getMeshDS()->AddQuadPolygonalFace(nodes);
1099
1100   // Update Python script
1101   TPythonDump() <<"faceID = "<<this<<".AddPolygonalFace( "<<IDsOfNodes<<" )";
1102
1103   declareMeshModified( /*isReComputeSafe=*/false );
1104   return elem ? elem->GetID() : 0;
1105
1106   SMESH_CATCH( SMESH::throwCorbaException );
1107   return 0;
1108 }
1109
1110 //=============================================================================
1111 /*!
1112  * Create volume, either linear and quadratic (this is determed
1113  *  by number of given nodes)
1114  */
1115 //=============================================================================
1116
1117 CORBA::Long SMESH_MeshEditor_i::AddVolume(const SMESH::long_array & IDsOfNodes)
1118   throw (SALOME::SALOME_Exception)
1119 {
1120   SMESH_TRY;
1121   initData();
1122
1123   int NbNodes = IDsOfNodes.length();
1124   vector< const SMDS_MeshNode*> n(NbNodes);
1125   for(int i=0;i<NbNodes;i++)
1126     n[i]= getMeshDS()->FindNode(IDsOfNodes[i]);
1127
1128   SMDS_MeshElement* elem = 0;
1129   switch(NbNodes)
1130   {
1131   case 4 :elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3]); break;
1132   case 5 :elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4]); break;
1133   case 6 :elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5]); break;
1134   case 8 :elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7]); break;
1135   case 10:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],
1136                                         n[6],n[7],n[8],n[9]);
1137     break;
1138   case 12:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],
1139                                         n[6],n[7],n[8],n[9],n[10],n[11]);
1140     break;
1141   case 13:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],
1142                                         n[7],n[8],n[9],n[10],n[11],n[12]);
1143     break;
1144   case 15:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7],n[8],
1145                                         n[9],n[10],n[11],n[12],n[13],n[14]);
1146     break;
1147   case 20:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7],
1148                                         n[8],n[9],n[10],n[11],n[12],n[13],n[14],
1149                                         n[15],n[16],n[17],n[18],n[19]);
1150     break;
1151   case 27:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7],
1152                                         n[8],n[9],n[10],n[11],n[12],n[13],n[14],
1153                                         n[15],n[16],n[17],n[18],n[19],
1154                                         n[20],n[21],n[22],n[23],n[24],n[25],n[26]);
1155     break;
1156   }
1157
1158   // Update Python script
1159   TPythonDump() << "volID = " << this << ".AddVolume( " << IDsOfNodes << " )";
1160
1161   declareMeshModified( /*isReComputeSafe=*/false );
1162   return elem ? elem->GetID() : 0;
1163
1164   SMESH_CATCH( SMESH::throwCorbaException );
1165   return 0;
1166 }
1167
1168 //=============================================================================
1169 /*!
1170  *  AddPolyhedralVolume
1171  */
1172 //=============================================================================
1173 CORBA::Long SMESH_MeshEditor_i::AddPolyhedralVolume (const SMESH::long_array & IDsOfNodes,
1174                                                      const SMESH::long_array & Quantities)
1175   throw (SALOME::SALOME_Exception)
1176 {
1177   SMESH_TRY;
1178   initData();
1179
1180   int NbNodes = IDsOfNodes.length();
1181   std::vector<const SMDS_MeshNode*> n (NbNodes);
1182   for (int i = 0; i < NbNodes; i++)
1183     {
1184       const SMDS_MeshNode* aNode = getMeshDS()->FindNode(IDsOfNodes[i]);
1185       if (!aNode) return 0;
1186       n[i] = aNode;
1187     }
1188
1189   int NbFaces = Quantities.length();
1190   std::vector<int> q (NbFaces);
1191   for (int j = 0; j < NbFaces; j++)
1192     q[j] = Quantities[j];
1193
1194   const SMDS_MeshElement* elem = getMeshDS()->AddPolyhedralVolume(n, q);
1195
1196   // Update Python script
1197   TPythonDump() << "volID = " << this << ".AddPolyhedralVolume( "
1198                 << IDsOfNodes << ", " << Quantities << " )";
1199
1200   declareMeshModified( /*isReComputeSafe=*/false );
1201   return elem ? elem->GetID() : 0;
1202
1203   SMESH_CATCH( SMESH::throwCorbaException );
1204   return 0;
1205 }
1206
1207 //=============================================================================
1208 /*!
1209  *  AddPolyhedralVolumeByFaces
1210  */
1211 //=============================================================================
1212
1213 CORBA::Long SMESH_MeshEditor_i::AddPolyhedralVolumeByFaces (const SMESH::long_array & IdsOfFaces)
1214   throw (SALOME::SALOME_Exception)
1215 {
1216   SMESH_TRY;
1217   initData();
1218
1219   int NbFaces = IdsOfFaces.length();
1220   std::vector<const SMDS_MeshNode*> poly_nodes;
1221   std::vector<int> quantities (NbFaces);
1222
1223   for (int i = 0; i < NbFaces; i++) {
1224     const SMDS_MeshElement* aFace = getMeshDS()->FindElement(IdsOfFaces[i]);
1225     quantities[i] = aFace->NbNodes();
1226
1227     SMDS_ElemIteratorPtr It = aFace->nodesIterator();
1228     while (It->more()) {
1229       poly_nodes.push_back(static_cast<const SMDS_MeshNode *>(It->next()));
1230     }
1231   }
1232
1233   const SMDS_MeshElement* elem = getMeshDS()->AddPolyhedralVolume(poly_nodes, quantities);
1234
1235   // Update Python script
1236   TPythonDump() << "volID = " << this << ".AddPolyhedralVolumeByFaces( "
1237                 << IdsOfFaces << " )";
1238
1239   declareMeshModified( /*isReComputeSafe=*/false );
1240   return elem ? elem->GetID() : 0;
1241
1242   SMESH_CATCH( SMESH::throwCorbaException );
1243   return 0;
1244 }
1245
1246 //=============================================================================
1247 //
1248 // \brief Create 0D elements on all nodes of the given object except those 
1249 //        nodes on which a 0D element already exists.
1250 //  \param theObject object on whose nodes 0D elements will be created.
1251 //  \param theGroupName optional name of a group to add 0D elements created
1252 //         and/or found on nodes of \a theObject.
1253 //  \return an object (a new group or a temporary SMESH_IDSource) holding
1254 //          ids of new and/or found 0D elements.
1255 //
1256 //=============================================================================
1257
1258 SMESH::SMESH_IDSource_ptr
1259 SMESH_MeshEditor_i::Create0DElementsOnAllNodes(SMESH::SMESH_IDSource_ptr theObject,
1260                                                const char*               theGroupName)
1261   throw (SALOME::SALOME_Exception)
1262 {
1263   SMESH_TRY;
1264   initData();
1265
1266   SMESH::SMESH_IDSource_var result;
1267   TPythonDump pyDump;
1268
1269   TIDSortedElemSet elements, elems0D;
1270   if ( idSourceToSet( theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
1271     getEditor().Create0DElementsOnAllNodes( elements, elems0D );
1272
1273   SMESH::long_array_var newElems = new SMESH::long_array;
1274   newElems->length( elems0D.size() );
1275   TIDSortedElemSet::iterator eIt = elems0D.begin();
1276   for ( size_t i = 0; i < elems0D.size(); ++i, ++eIt )
1277     newElems[ i ] = (*eIt)->GetID();
1278
1279   SMESH::SMESH_GroupBase_var groupToFill;
1280   if ( theGroupName && strlen( theGroupName ))
1281   {
1282     // Get existing group named theGroupName
1283     SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
1284     for (int i = 0, nbGroups = groups->length(); i < nbGroups; i++ ) {
1285       SMESH::SMESH_GroupBase_var group = groups[i];
1286       if ( !group->_is_nil() ) {
1287         CORBA::String_var name = group->GetName();
1288         if ( strcmp( name.in(), theGroupName ) == 0 && group->GetType() == SMESH::ELEM0D ) {
1289           groupToFill = group;
1290           break;
1291         }
1292       }
1293     }
1294     if ( groupToFill->_is_nil() )
1295       groupToFill = myMesh_i->CreateGroup( SMESH::ELEM0D, theGroupName );
1296     else if ( !SMESH::DownCast< SMESH_Group_i* > ( groupToFill ))
1297       groupToFill = myMesh_i->ConvertToStandalone( groupToFill );
1298   }
1299
1300   if ( SMESH_Group_i* group_i = SMESH::DownCast< SMESH_Group_i* > ( groupToFill ))
1301   {
1302     group_i->Add( newElems );
1303     result = SMESH::SMESH_IDSource::_narrow( groupToFill );
1304     pyDump << groupToFill;
1305   }
1306   else
1307   {
1308     result = MakeIDSource( newElems, SMESH::ELEM0D );
1309     pyDump << "elem0DIDs";
1310   }
1311
1312   pyDump << " = " << this << ".Create0DElementsOnAllNodes( "
1313          << theObject << ", '" << theGroupName << "' )";
1314
1315   return result._retn();
1316
1317   SMESH_CATCH( SMESH::throwCorbaException );
1318   return 0;
1319 }
1320
1321 //=============================================================================
1322 /*!
1323  * \brief Bind a node to a vertex
1324  * \param NodeID - node ID
1325  * \param VertexID - vertex ID available through GEOM_Object.GetSubShapeIndices()[0]
1326  * \retval boolean - false if NodeID or VertexID is invalid
1327  */
1328 //=============================================================================
1329
1330 void SMESH_MeshEditor_i::SetNodeOnVertex(CORBA::Long NodeID, CORBA::Long VertexID)
1331   throw (SALOME::SALOME_Exception)
1332 {
1333   SMESH_TRY;
1334
1335   SMESHDS_Mesh * mesh = getMeshDS();
1336   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
1337   if ( !node )
1338     THROW_SALOME_CORBA_EXCEPTION("Invalid NodeID", SALOME::BAD_PARAM);
1339
1340   if ( mesh->MaxShapeIndex() < VertexID )
1341     THROW_SALOME_CORBA_EXCEPTION("Invalid VertexID", SALOME::BAD_PARAM);
1342
1343   TopoDS_Shape shape = mesh->IndexToShape( VertexID );
1344   if ( shape.ShapeType() != TopAbs_VERTEX )
1345     THROW_SALOME_CORBA_EXCEPTION("Invalid VertexID", SALOME::BAD_PARAM);
1346
1347   mesh->SetNodeOnVertex( node, VertexID );
1348
1349   myMesh->SetIsModified( true );
1350
1351   SMESH_CATCH( SMESH::throwCorbaException );
1352 }
1353
1354 //=============================================================================
1355 /*!
1356  * \brief Store node position on an edge
1357  * \param NodeID - node ID
1358  * \param EdgeID - edge ID available through GEOM_Object.GetSubShapeIndices()[0]
1359  * \param paramOnEdge - parameter on edge where the node is located
1360  * \retval boolean - false if any parameter is invalid
1361  */
1362 //=============================================================================
1363
1364 void SMESH_MeshEditor_i::SetNodeOnEdge(CORBA::Long NodeID, CORBA::Long EdgeID,
1365                                        CORBA::Double paramOnEdge)
1366   throw (SALOME::SALOME_Exception)
1367 {
1368   SMESH_TRY;
1369
1370   SMESHDS_Mesh * mesh = getMeshDS();
1371   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
1372   if ( !node )
1373     THROW_SALOME_CORBA_EXCEPTION("Invalid NodeID", SALOME::BAD_PARAM);
1374
1375   if ( mesh->MaxShapeIndex() < EdgeID )
1376     THROW_SALOME_CORBA_EXCEPTION("Invalid EdgeID", SALOME::BAD_PARAM);
1377
1378   TopoDS_Shape shape = mesh->IndexToShape( EdgeID );
1379   if ( shape.ShapeType() != TopAbs_EDGE )
1380     THROW_SALOME_CORBA_EXCEPTION("Invalid EdgeID", SALOME::BAD_PARAM);
1381
1382   Standard_Real f,l;
1383   BRep_Tool::Range( TopoDS::Edge( shape ), f,l);
1384   if ( paramOnEdge < f || paramOnEdge > l )
1385     THROW_SALOME_CORBA_EXCEPTION("Invalid paramOnEdge", SALOME::BAD_PARAM);
1386
1387   mesh->SetNodeOnEdge( node, EdgeID, paramOnEdge );
1388
1389   myMesh->SetIsModified( true );
1390
1391   SMESH_CATCH( SMESH::throwCorbaException );
1392 }
1393
1394 //=============================================================================
1395 /*!
1396  * \brief Store node position on a face
1397  * \param NodeID - node ID
1398  * \param FaceID - face ID available through GEOM_Object.GetSubShapeIndices()[0]
1399  * \param u - U parameter on face where the node is located
1400  * \param v - V parameter on face where the node is located
1401  * \retval boolean - false if any parameter is invalid
1402  */
1403 //=============================================================================
1404
1405 void SMESH_MeshEditor_i::SetNodeOnFace(CORBA::Long NodeID, CORBA::Long FaceID,
1406                                        CORBA::Double u, CORBA::Double v)
1407   throw (SALOME::SALOME_Exception)
1408 {
1409   SMESH_TRY;
1410   SMESHDS_Mesh * mesh = getMeshDS();
1411   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
1412   if ( !node )
1413     THROW_SALOME_CORBA_EXCEPTION("Invalid NodeID", SALOME::BAD_PARAM);
1414
1415   if ( mesh->MaxShapeIndex() < FaceID )
1416     THROW_SALOME_CORBA_EXCEPTION("Invalid FaceID", SALOME::BAD_PARAM);
1417
1418   TopoDS_Shape shape = mesh->IndexToShape( FaceID );
1419   if ( shape.ShapeType() != TopAbs_FACE )
1420     THROW_SALOME_CORBA_EXCEPTION("Invalid FaceID", SALOME::BAD_PARAM);
1421
1422   BRepAdaptor_Surface surf( TopoDS::Face( shape ));
1423   bool isOut = ( u < surf.FirstUParameter() ||
1424                  u > surf.LastUParameter()  ||
1425                  v < surf.FirstVParameter() ||
1426                  v > surf.LastVParameter() );
1427
1428   if ( isOut ) {
1429 #ifdef _DEBUG_
1430     MESSAGE ( "FACE " << FaceID << " (" << u << "," << v << ") out of "
1431               << " u( " <<  surf.FirstUParameter()
1432               << "," <<  surf.LastUParameter()
1433               << ") v( " <<  surf.FirstVParameter()
1434               << "," <<  surf.LastVParameter() << ")" );
1435 #endif
1436     THROW_SALOME_CORBA_EXCEPTION("Invalid UV", SALOME::BAD_PARAM);
1437   }
1438
1439   mesh->SetNodeOnFace( node, FaceID, u, v );
1440   myMesh->SetIsModified( true );
1441
1442   SMESH_CATCH( SMESH::throwCorbaException );
1443 }
1444
1445 //=============================================================================
1446 /*!
1447  * \brief Bind a node to a solid
1448  * \param NodeID - node ID
1449  * \param SolidID - vertex ID available through GEOM_Object.GetSubShapeIndices()[0]
1450  * \retval boolean - false if NodeID or SolidID is invalid
1451  */
1452 //=============================================================================
1453
1454 void SMESH_MeshEditor_i::SetNodeInVolume(CORBA::Long NodeID, CORBA::Long SolidID)
1455   throw (SALOME::SALOME_Exception)
1456 {
1457   SMESH_TRY;
1458   SMESHDS_Mesh * mesh = getMeshDS();
1459   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
1460   if ( !node )
1461     THROW_SALOME_CORBA_EXCEPTION("Invalid NodeID", SALOME::BAD_PARAM);
1462
1463   if ( mesh->MaxShapeIndex() < SolidID )
1464     THROW_SALOME_CORBA_EXCEPTION("Invalid SolidID", SALOME::BAD_PARAM);
1465
1466   TopoDS_Shape shape = mesh->IndexToShape( SolidID );
1467   if ( shape.ShapeType() != TopAbs_SOLID &&
1468        shape.ShapeType() != TopAbs_SHELL)
1469     THROW_SALOME_CORBA_EXCEPTION("Invalid SolidID", SALOME::BAD_PARAM);
1470
1471   mesh->SetNodeInVolume( node, SolidID );
1472
1473   SMESH_CATCH( SMESH::throwCorbaException );
1474 }
1475
1476 //=============================================================================
1477 /*!
1478  * \brief Bind an element to a shape
1479  * \param ElementID - element ID
1480  * \param ShapeID - shape ID available through GEOM_Object.GetSubShapeIndices()[0]
1481  */
1482 //=============================================================================
1483
1484 void SMESH_MeshEditor_i::SetMeshElementOnShape(CORBA::Long ElementID,
1485                                                CORBA::Long ShapeID)
1486   throw (SALOME::SALOME_Exception)
1487 {
1488   SMESH_TRY;
1489   SMESHDS_Mesh * mesh = getMeshDS();
1490   SMDS_MeshElement* elem = const_cast<SMDS_MeshElement*>(mesh->FindElement(ElementID));
1491   if ( !elem )
1492     THROW_SALOME_CORBA_EXCEPTION("Invalid ElementID", SALOME::BAD_PARAM);
1493
1494   if ( mesh->MaxShapeIndex() < ShapeID || ShapeID < 1 )
1495     THROW_SALOME_CORBA_EXCEPTION("Invalid ShapeID", SALOME::BAD_PARAM);
1496
1497   TopoDS_Shape shape = mesh->IndexToShape( ShapeID );
1498   if ( shape.ShapeType() != TopAbs_EDGE &&
1499        shape.ShapeType() != TopAbs_FACE &&
1500        shape.ShapeType() != TopAbs_SOLID &&
1501        shape.ShapeType() != TopAbs_SHELL )
1502     THROW_SALOME_CORBA_EXCEPTION("Invalid shape type", SALOME::BAD_PARAM);
1503
1504   mesh->SetMeshElementOnShape( elem, ShapeID );
1505
1506   myMesh->SetIsModified( true );
1507
1508   SMESH_CATCH( SMESH::throwCorbaException );
1509 }
1510
1511 //=============================================================================
1512 /*!
1513  *
1514  */
1515 //=============================================================================
1516
1517 CORBA::Boolean SMESH_MeshEditor_i::InverseDiag(CORBA::Long NodeID1,
1518                                                CORBA::Long NodeID2)
1519   throw (SALOME::SALOME_Exception)
1520 {
1521   SMESH_TRY;
1522   initData();
1523
1524   const SMDS_MeshNode * n1 = getMeshDS()->FindNode( NodeID1 );
1525   const SMDS_MeshNode * n2 = getMeshDS()->FindNode( NodeID2 );
1526   if ( !n1 || !n2 )
1527     return false;
1528
1529   // Update Python script
1530   TPythonDump() << "isDone = " << this << ".InverseDiag( "
1531                 << NodeID1 << ", " << NodeID2 << " )";
1532
1533   int ret =  getEditor().InverseDiag ( n1, n2 );
1534
1535   declareMeshModified( /*isReComputeSafe=*/false );
1536   return ret;
1537
1538   SMESH_CATCH( SMESH::throwCorbaException );
1539   return 0;
1540 }
1541
1542 //=============================================================================
1543 /*!
1544  *
1545  */
1546 //=============================================================================
1547
1548 CORBA::Boolean SMESH_MeshEditor_i::DeleteDiag(CORBA::Long NodeID1,
1549                                               CORBA::Long NodeID2)
1550   throw (SALOME::SALOME_Exception)
1551 {
1552   SMESH_TRY;
1553   initData();
1554
1555   const SMDS_MeshNode * n1 = getMeshDS()->FindNode( NodeID1 );
1556   const SMDS_MeshNode * n2 = getMeshDS()->FindNode( NodeID2 );
1557   if ( !n1 || !n2 )
1558     return false;
1559
1560   // Update Python script
1561   TPythonDump() << "isDone = " << this << ".DeleteDiag( "
1562                 << NodeID1 << ", " << NodeID2 <<  " )";
1563
1564
1565   bool stat = getEditor().DeleteDiag ( n1, n2 );
1566
1567   declareMeshModified( /*isReComputeSafe=*/!stat );
1568
1569   return stat;
1570
1571   SMESH_CATCH( SMESH::throwCorbaException );
1572   return 0;
1573 }
1574
1575 //=============================================================================
1576 /*!
1577  *
1578  */
1579 //=============================================================================
1580
1581 CORBA::Boolean SMESH_MeshEditor_i::Reorient(const SMESH::long_array & IDsOfElements)
1582   throw (SALOME::SALOME_Exception)
1583 {
1584   SMESH_TRY;
1585   initData();
1586
1587   for (int i = 0; i < IDsOfElements.length(); i++)
1588   {
1589     CORBA::Long index = IDsOfElements[i];
1590     const SMDS_MeshElement * elem = getMeshDS()->FindElement(index);
1591     if ( elem )
1592       getEditor().Reorient( elem );
1593   }
1594   // Update Python script
1595   TPythonDump() << "isDone = " << this << ".Reorient( " << IDsOfElements << " )";
1596
1597   declareMeshModified( /*isReComputeSafe=*/ IDsOfElements.length() == 0 );
1598   return true;
1599
1600   SMESH_CATCH( SMESH::throwCorbaException );
1601   return 0;
1602 }
1603
1604 //=============================================================================
1605 /*!
1606  *
1607  */
1608 //=============================================================================
1609
1610 CORBA::Boolean SMESH_MeshEditor_i::ReorientObject(SMESH::SMESH_IDSource_ptr theObject)
1611   throw (SALOME::SALOME_Exception)
1612 {
1613   SMESH_TRY;
1614   initData();
1615
1616   TPythonDump aTPythonDump; // suppress dump in Reorient()
1617
1618   prepareIdSource( theObject );
1619
1620   SMESH::long_array_var anElementsId = theObject->GetIDs();
1621   CORBA::Boolean isDone = Reorient(anElementsId);
1622
1623   // Update Python script
1624   aTPythonDump << "isDone = " << this << ".ReorientObject( " << theObject << " )";
1625
1626   declareMeshModified( /*isReComputeSafe=*/ anElementsId->length() == 0 );
1627   return isDone;
1628
1629   SMESH_CATCH( SMESH::throwCorbaException );
1630   return 0;
1631 }
1632
1633 //=======================================================================
1634 //function : Reorient2D
1635 //purpose  : Reorient faces contained in \a the2Dgroup.
1636 //           the2Dgroup   - the mesh or its part to reorient
1637 //           theDirection - desired direction of normal of \a theFace
1638 //           theFace      - ID of face whose orientation is checked.
1639 //           It can be < 1 then \a thePoint is used to find a face.
1640 //           thePoint     - is used to find a face if \a theFace < 1.
1641 //           return number of reoriented elements.
1642 //=======================================================================
1643
1644 CORBA::Long SMESH_MeshEditor_i::Reorient2D(SMESH::SMESH_IDSource_ptr the2Dgroup,
1645                                            const SMESH::DirStruct&   theDirection,
1646                                            CORBA::Long               theFace,
1647                                            const SMESH::PointStruct& thePoint)
1648   throw (SALOME::SALOME_Exception)
1649 {
1650   SMESH_TRY;
1651   initData(/*deleteSearchers=*/false);
1652
1653   TIDSortedElemSet elements;
1654   IDSource_Error error;
1655   idSourceToSet( the2Dgroup, getMeshDS(), elements, SMDSAbs_Face, /*emptyIfIsMesh=*/1, &error );
1656   if ( error == IDSource_EMPTY )
1657     return 0;
1658   if ( error == IDSource_INVALID )
1659     THROW_SALOME_CORBA_EXCEPTION("No faces in given group", SALOME::BAD_PARAM);
1660
1661
1662   const SMDS_MeshElement* face = 0;
1663   if ( theFace > 0 )
1664   {
1665     face = getMeshDS()->FindElement( theFace );
1666     if ( !face )
1667       THROW_SALOME_CORBA_EXCEPTION("Inexistent face given", SALOME::BAD_PARAM);
1668     if ( face->GetType() != SMDSAbs_Face )
1669       THROW_SALOME_CORBA_EXCEPTION("Wrong element type", SALOME::BAD_PARAM);
1670   }
1671   else
1672   {
1673     // create theElementSearcher if needed
1674     theSearchersDeleter.Set( myMesh, getPartIOR( the2Dgroup, SMESH::FACE ));
1675     if ( !theElementSearcher )
1676     {
1677       if ( elements.empty() ) // search in the whole mesh
1678       {
1679         if ( myMesh->NbFaces() == 0 )
1680           THROW_SALOME_CORBA_EXCEPTION("No faces in the mesh", SALOME::BAD_PARAM);
1681
1682         theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() );
1683       }
1684       else
1685       {
1686         typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator > TIter;
1687         SMDS_ElemIteratorPtr elemsIt( new TIter( elements.begin(), elements.end() ));
1688
1689         theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), elemsIt);
1690       }
1691     }
1692     // find a face
1693     gp_Pnt p( thePoint.x, thePoint.y, thePoint.z );
1694     face = theElementSearcher->FindClosestTo( p, SMDSAbs_Face );
1695
1696     if ( !face )
1697       THROW_SALOME_CORBA_EXCEPTION("No face found by point", SALOME::INTERNAL_ERROR );
1698     if ( !elements.empty() && !elements.count( face ))
1699       THROW_SALOME_CORBA_EXCEPTION("Found face is not in the group", SALOME::BAD_PARAM );
1700   }
1701
1702   const SMESH::PointStruct * P = &theDirection.PS;
1703   gp_Vec dirVec( P->x, P->y, P->z );
1704   if ( dirVec.Magnitude() < std::numeric_limits< double >::min() )
1705     THROW_SALOME_CORBA_EXCEPTION("Zero size vector", SALOME::BAD_PARAM);
1706
1707   int nbReori = getEditor().Reorient2D( elements, dirVec, face );
1708
1709   if ( nbReori ) {
1710     declareMeshModified( /*isReComputeSafe=*/false );
1711   }
1712   TPythonDump() << this << ".Reorient2D( "
1713                 << the2Dgroup << ", "
1714                 << theDirection << ", "
1715                 << theFace << ", "
1716                 << thePoint << " )";
1717
1718   return nbReori;
1719
1720   SMESH_CATCH( SMESH::throwCorbaException );
1721   return 0;
1722 }
1723
1724 //=======================================================================
1725 //function : Reorient2DBy3D
1726 //purpose  : Reorient faces basing on orientation of adjacent volumes.
1727 //=======================================================================
1728
1729 CORBA::Long SMESH_MeshEditor_i::Reorient2DBy3D(const SMESH::ListOfIDSources& faceGroups,
1730                                                SMESH::SMESH_IDSource_ptr     volumeGroup,
1731                                                CORBA::Boolean                outsideNormal)
1732   throw (SALOME::SALOME_Exception)
1733 {
1734   SMESH_TRY;
1735   initData();
1736
1737   TIDSortedElemSet volumes;
1738   IDSource_Error volsError;
1739   idSourceToSet( volumeGroup, getMeshDS(), volumes, SMDSAbs_Volume, /*emptyIfMesh=*/1, &volsError);
1740
1741   int nbReori = 0;
1742   for ( size_t i = 0; i < faceGroups.length(); ++i )
1743   {
1744     SMESH::SMESH_IDSource_ptr faceGrp = faceGroups[i].in();
1745
1746     TIDSortedElemSet faces;
1747     IDSource_Error error;
1748     idSourceToSet( faceGrp, getMeshDS(), faces, SMDSAbs_Face, /*emptyIfIsMesh=*/1, &error );
1749     if ( error == IDSource_INVALID && faceGroups.length() == 1 )
1750       THROW_SALOME_CORBA_EXCEPTION("No faces in a given object", SALOME::BAD_PARAM);
1751     if ( error == IDSource_OK && volsError != IDSource_OK )
1752       THROW_SALOME_CORBA_EXCEPTION("No volumes in a given object", SALOME::BAD_PARAM);
1753
1754     nbReori += getEditor().Reorient2DBy3D( faces, volumes, outsideNormal );
1755
1756     if ( error != IDSource_EMPTY && faces.empty() ) // all faces in the mesh treated
1757       break;
1758   }
1759
1760   if ( nbReori ) {
1761     declareMeshModified( /*isReComputeSafe=*/false );
1762   }
1763   TPythonDump() << this << ".Reorient2DBy3D( "
1764                 << faceGroups << ", "
1765                 << volumeGroup << ", "
1766                 << outsideNormal << " )";
1767
1768   return nbReori;
1769
1770   SMESH_CATCH( SMESH::throwCorbaException );
1771   return 0;
1772 }
1773
1774 //=============================================================================
1775 /*!
1776  * \brief Fuse neighbour triangles into quadrangles.
1777  */
1778 //=============================================================================
1779
1780 CORBA::Boolean SMESH_MeshEditor_i::TriToQuad (const SMESH::long_array &   IDsOfElements,
1781                                               SMESH::NumericalFunctor_ptr Criterion,
1782                                               CORBA::Double               MaxAngle)
1783   throw (SALOME::SALOME_Exception)
1784 {
1785   SMESH_TRY;
1786   initData();
1787
1788   SMESHDS_Mesh* aMesh = getMeshDS();
1789   TIDSortedElemSet faces,copyFaces;
1790   SMDS_MeshElement::GeomFilter triaFilter(SMDSGeom_TRIANGLE);
1791   arrayToSet(IDsOfElements, aMesh, faces, SMDSAbs_Face, & triaFilter);
1792   TIDSortedElemSet* workElements = & faces;
1793
1794   if ( myIsPreviewMode ) {
1795     SMDSAbs_ElementType select =  SMDSAbs_Face;
1796     getPreviewMesh( SMDSAbs_Face )->Copy( faces, copyFaces, select );
1797     workElements = & copyFaces;
1798   }
1799
1800   SMESH::NumericalFunctor_i* aNumericalFunctor =
1801     dynamic_cast<SMESH::NumericalFunctor_i*>( SMESH_Gen_i::GetServant( Criterion ).in() );
1802   SMESH::Controls::NumericalFunctorPtr aCrit;
1803   if ( !aNumericalFunctor )
1804     aCrit.reset( new SMESH::Controls::MaxElementLength2D() );
1805   else
1806     aCrit = aNumericalFunctor->GetNumericalFunctor();
1807
1808   if ( !myIsPreviewMode ) {
1809     // Update Python script
1810     TPythonDump() << "isDone = " << this << ".TriToQuad( "
1811                   << IDsOfElements << ", " << aNumericalFunctor << ", " << TVar( MaxAngle ) << " )";
1812   }
1813
1814   bool stat = getEditor().TriToQuad( *workElements, aCrit, MaxAngle );
1815
1816   declareMeshModified( /*isReComputeSafe=*/!stat );
1817   return stat;
1818
1819   SMESH_CATCH( SMESH::throwCorbaException );
1820   return 0;
1821 }
1822
1823 //=============================================================================
1824 /*!
1825  * \brief Fuse neighbour triangles into quadrangles.
1826  */
1827 //=============================================================================
1828
1829 CORBA::Boolean SMESH_MeshEditor_i::TriToQuadObject (SMESH::SMESH_IDSource_ptr   theObject,
1830                                                     SMESH::NumericalFunctor_ptr Criterion,
1831                                                     CORBA::Double               MaxAngle)
1832   throw (SALOME::SALOME_Exception)
1833 {
1834   SMESH_TRY;
1835   initData();
1836
1837   TPythonDump aTPythonDump;  // suppress dump in TriToQuad()
1838
1839   prepareIdSource( theObject );
1840   SMESH::long_array_var anElementsId = theObject->GetIDs();
1841   CORBA::Boolean isDone = TriToQuad(anElementsId, Criterion, MaxAngle);
1842
1843   if ( !myIsPreviewMode ) {
1844     SMESH::NumericalFunctor_i* aNumericalFunctor =
1845       SMESH::DownCast<SMESH::NumericalFunctor_i*>( Criterion );
1846
1847     // Update Python script
1848     aTPythonDump << "isDone = " << this << ".TriToQuadObject("
1849                  << theObject << ", " << aNumericalFunctor << ", " << TVar( MaxAngle ) << " )";
1850   }
1851
1852   return isDone;
1853
1854   SMESH_CATCH( SMESH::throwCorbaException );
1855   return 0;
1856 }
1857
1858 //=============================================================================
1859 /*!
1860  * \brief Split quadrangles into triangles.
1861  */
1862 //=============================================================================
1863
1864 CORBA::Boolean SMESH_MeshEditor_i::QuadToTri (const SMESH::long_array &   IDsOfElements,
1865                                               SMESH::NumericalFunctor_ptr Criterion)
1866   throw (SALOME::SALOME_Exception)
1867 {
1868   SMESH_TRY;
1869   initData();
1870
1871   SMESHDS_Mesh* aMesh = getMeshDS();
1872   TIDSortedElemSet faces;
1873   arrayToSet(IDsOfElements, aMesh, faces, SMDSAbs_Face);
1874
1875   SMESH::NumericalFunctor_i* aNumericalFunctor =
1876     dynamic_cast<SMESH::NumericalFunctor_i*>( SMESH_Gen_i::GetServant( Criterion ).in() );
1877   SMESH::Controls::NumericalFunctorPtr aCrit;
1878   if ( !aNumericalFunctor )
1879     aCrit.reset( new SMESH::Controls::AspectRatio() );
1880   else
1881     aCrit = aNumericalFunctor->GetNumericalFunctor();
1882
1883
1884   // Update Python script
1885   TPythonDump() << "isDone = " << this << ".QuadToTri( " << IDsOfElements << ", " << aNumericalFunctor << " )";
1886
1887   CORBA::Boolean stat = getEditor().QuadToTri( faces, aCrit );
1888
1889   declareMeshModified( /*isReComputeSafe=*/false );
1890   return stat;
1891
1892   SMESH_CATCH( SMESH::throwCorbaException );
1893   return 0;
1894 }
1895
1896 //=============================================================================
1897 /*!
1898  * \brief Split quadrangles into triangles.
1899  */
1900 //=============================================================================
1901
1902 CORBA::Boolean SMESH_MeshEditor_i::QuadToTriObject (SMESH::SMESH_IDSource_ptr   theObject,
1903                                                     SMESH::NumericalFunctor_ptr Criterion)
1904   throw (SALOME::SALOME_Exception)
1905 {
1906   SMESH_TRY;
1907   initData();
1908
1909   TPythonDump aTPythonDump;  // suppress dump in QuadToTri()
1910
1911   prepareIdSource( theObject );
1912   SMESH::long_array_var anElementsId = theObject->GetIDs();
1913   CORBA::Boolean isDone = QuadToTri(anElementsId, Criterion);
1914
1915   SMESH::NumericalFunctor_i* aNumericalFunctor =
1916     SMESH::DownCast<SMESH::NumericalFunctor_i*>( Criterion );
1917
1918   // Update Python script
1919   aTPythonDump << "isDone = " << this << ".QuadToTriObject( " << theObject << ", " << aNumericalFunctor << " )";
1920
1921   declareMeshModified( /*isReComputeSafe=*/false );
1922   return isDone;
1923
1924   SMESH_CATCH( SMESH::throwCorbaException );
1925   return 0;
1926 }
1927
1928 //================================================================================
1929 /*!
1930  * \brief Split each of quadrangles into 4 triangles.
1931  *  \param [in] theObject - theQuads Container of quadrangles to split.
1932  */
1933 //================================================================================
1934
1935 void SMESH_MeshEditor_i::QuadTo4Tri (SMESH::SMESH_IDSource_ptr theObject)
1936   throw (SALOME::SALOME_Exception)
1937 {
1938   SMESH_TRY;
1939   initData();
1940
1941   TIDSortedElemSet faces;
1942   if ( !idSourceToSet( theObject, getMeshDS(), faces, SMDSAbs_Face, /*emptyIfIsMesh=*/true ) &&
1943        faces.empty() )
1944     THROW_SALOME_CORBA_EXCEPTION("No faces given", SALOME::BAD_PARAM);
1945
1946   getEditor().QuadTo4Tri( faces );
1947   TPythonDump() << this << ".QuadTo4Tri( " << theObject << " )";
1948
1949   SMESH_CATCH( SMESH::throwCorbaException );
1950 }
1951
1952 //=============================================================================
1953 /*!
1954  * \brief Split quadrangles into triangles.
1955  */
1956 //=============================================================================
1957
1958 CORBA::Boolean SMESH_MeshEditor_i::SplitQuad (const SMESH::long_array & IDsOfElements,
1959                                               CORBA::Boolean            Diag13)
1960   throw (SALOME::SALOME_Exception)
1961 {
1962   SMESH_TRY;
1963   initData();
1964
1965   SMESHDS_Mesh* aMesh = getMeshDS();
1966   TIDSortedElemSet faces;
1967   arrayToSet(IDsOfElements, aMesh, faces, SMDSAbs_Face);
1968
1969   // Update Python script
1970   TPythonDump() << "isDone = " << this << ".SplitQuad( "
1971                 << IDsOfElements << ", " << Diag13 << " )";
1972
1973   CORBA::Boolean stat = getEditor().QuadToTri( faces, Diag13 );
1974
1975   declareMeshModified( /*isReComputeSafe=*/ !stat );
1976   return stat;
1977
1978   SMESH_CATCH( SMESH::throwCorbaException );
1979   return 0;
1980 }
1981
1982 //=============================================================================
1983 /*!
1984  * \brief Split quadrangles into triangles.
1985  */
1986 //=============================================================================
1987
1988 CORBA::Boolean SMESH_MeshEditor_i::SplitQuadObject (SMESH::SMESH_IDSource_ptr theObject,
1989                                                     CORBA::Boolean            Diag13)
1990   throw (SALOME::SALOME_Exception)
1991 {
1992   SMESH_TRY;
1993   initData();
1994
1995   TPythonDump aTPythonDump;  // suppress dump in SplitQuad()
1996
1997   prepareIdSource( theObject );
1998   SMESH::long_array_var anElementsId = theObject->GetIDs();
1999   CORBA::Boolean isDone = SplitQuad(anElementsId, Diag13);
2000
2001   // Update Python script
2002   aTPythonDump << "isDone = " << this << ".SplitQuadObject( "
2003                << theObject << ", " << Diag13 << " )";
2004
2005   declareMeshModified( /*isReComputeSafe=*/!isDone );
2006   return isDone;
2007
2008   SMESH_CATCH( SMESH::throwCorbaException );
2009   return 0;
2010 }
2011
2012
2013 //=============================================================================
2014 /*!
2015  * Find better splitting of the given quadrangle.
2016  *  \param IDOfQuad  ID of the quadrangle to be splitted.
2017  *  \param Criterion A criterion to choose a diagonal for splitting.
2018  *  \return 1 if 1-3 diagonal is better, 2 if 2-4
2019  *          diagonal is better, 0 if error occurs.
2020  */
2021 //=============================================================================
2022
2023 CORBA::Long SMESH_MeshEditor_i::BestSplit (CORBA::Long                 IDOfQuad,
2024                                            SMESH::NumericalFunctor_ptr Criterion)
2025   throw (SALOME::SALOME_Exception)
2026 {
2027   SMESH_TRY;
2028   initData();
2029
2030   const SMDS_MeshElement* quad = getMeshDS()->FindElement(IDOfQuad);
2031   if (quad && quad->GetType() == SMDSAbs_Face && quad->NbNodes() == 4)
2032   {
2033     SMESH::NumericalFunctor_i* aNumericalFunctor =
2034       dynamic_cast<SMESH::NumericalFunctor_i*>(SMESH_Gen_i::GetServant(Criterion).in());
2035     SMESH::Controls::NumericalFunctorPtr aCrit;
2036     if (aNumericalFunctor)
2037       aCrit = aNumericalFunctor->GetNumericalFunctor();
2038     else
2039       aCrit.reset(new SMESH::Controls::AspectRatio());
2040
2041     int id = getEditor().BestSplit(quad, aCrit);
2042     declareMeshModified( /*isReComputeSafe=*/ id < 1 );
2043     return id;
2044   }
2045
2046   SMESH_CATCH( SMESH::throwCorbaException );
2047   return 0;
2048 }
2049
2050 //================================================================================
2051 /*!
2052  * \brief Split volumic elements into tetrahedrons
2053  */
2054 //================================================================================
2055
2056 void SMESH_MeshEditor_i::SplitVolumesIntoTetra (SMESH::SMESH_IDSource_ptr elems,
2057                                                 CORBA::Short              methodFlags)
2058   throw (SALOME::SALOME_Exception)
2059 {
2060   SMESH_TRY;
2061   initData();
2062
2063   ::SMESH_MeshEditor::TFacetOfElem elemSet;
2064   const int noneFacet = -1;
2065   SMDS_ElemIteratorPtr volIt = myMesh_i->GetElements( elems, SMESH::VOLUME );
2066   while( volIt->more() )
2067     elemSet.insert( elemSet.end(), make_pair( volIt->next(), noneFacet ));
2068
2069   getEditor().SplitVolumes( elemSet, int( methodFlags ));
2070   declareMeshModified( /*isReComputeSafe=*/true ); // it does not influence Compute()
2071
2072   TPythonDump() << this << ".SplitVolumesIntoTetra( "
2073                 << elems << ", " << methodFlags << " )";
2074
2075   SMESH_CATCH( SMESH::throwCorbaException );
2076 }
2077
2078 //================================================================================
2079 /*!
2080  * \brief Split hexahedra into triangular prisms
2081  *  \param elems - elements to split
2082  *  \param facetToSplitNormal - normal used to find a facet of hexahedron
2083  *         to split into triangles
2084  *  \param methodFlags - flags passing splitting method:
2085  *         1 - split the hexahedron into 2 prisms
2086  *         2 - split the hexahedron into 4 prisms
2087  */
2088 //================================================================================
2089
2090 void SMESH_MeshEditor_i::SplitHexahedraIntoPrisms( SMESH::SMESH_IDSource_ptr  elems,
2091                                                    const SMESH::PointStruct & startHexPoint,
2092                                                    const SMESH::DirStruct&    facetToSplitNormal,
2093                                                    CORBA::Short               methodFlags,
2094                                                    CORBA::Boolean             allDomains)
2095   throw (SALOME::SALOME_Exception)
2096 {
2097   SMESH_TRY;
2098   initData();
2099   prepareIdSource( elems );
2100
2101   gp_Ax1 facetNorm( gp_Pnt( startHexPoint.x,
2102                             startHexPoint.y,
2103                             startHexPoint.z ),
2104                     gp_Dir( facetToSplitNormal.PS.x,
2105                             facetToSplitNormal.PS.y,
2106                             facetToSplitNormal.PS.z ));
2107   TIDSortedElemSet elemSet;
2108   SMESH::long_array_var anElementsId = elems->GetIDs();
2109   SMDS_MeshElement::GeomFilter filter( SMDSGeom_HEXA );
2110   arrayToSet( anElementsId, getMeshDS(), elemSet, SMDSAbs_Volume, &filter );
2111
2112   ::SMESH_MeshEditor::TFacetOfElem elemFacets;
2113   while ( !elemSet.empty() )
2114   {
2115     getEditor().GetHexaFacetsToSplit( elemSet, facetNorm, elemFacets );
2116     if ( !allDomains )
2117       break;
2118
2119     ::SMESH_MeshEditor::TFacetOfElem::iterator ef = elemFacets.begin();
2120     for ( ; ef != elemFacets.end(); ++ef )
2121       elemSet.erase( ef->first );
2122   }
2123
2124   if ( methodFlags == 2 )
2125     methodFlags = int( ::SMESH_MeshEditor::HEXA_TO_4_PRISMS );
2126   else
2127     methodFlags = int( ::SMESH_MeshEditor::HEXA_TO_2_PRISMS );
2128
2129   getEditor().SplitVolumes( elemFacets, int( methodFlags ));
2130   declareMeshModified( /*isReComputeSafe=*/true ); // it does not influence Compute()
2131
2132   TPythonDump() << this << ".SplitHexahedraIntoPrisms( "
2133                 << elems << ", "
2134                 << startHexPoint << ", "
2135                 << facetToSplitNormal<< ", "
2136                 << methodFlags<< ", "
2137                 << allDomains << " )";
2138
2139   SMESH_CATCH( SMESH::throwCorbaException );
2140 }
2141
2142 //================================================================================
2143 /*!
2144  * \brief Split bi-quadratic elements into linear ones without creation of additional nodes:
2145  *   - bi-quadratic triangle will be split into 3 linear quadrangles;
2146  *   - bi-quadratic quadrangle will be split into 4 linear quadrangles;
2147  *   - tri-quadratic hexahedron will be split into 8 linear hexahedra.
2148  *   Quadratic elements of lower dimension  adjacent to the split bi-quadratic element
2149  *   will be split in order to keep the mesh conformal.
2150  *  \param elems - elements to split
2151  */
2152 //================================================================================
2153
2154 void SMESH_MeshEditor_i::SplitBiQuadraticIntoLinear(const SMESH::ListOfIDSources& theElems)
2155   throw (SALOME::SALOME_Exception)
2156 {
2157   SMESH_TRY;
2158   initData();
2159
2160   TIDSortedElemSet elemSet;
2161   for ( size_t i = 0; i < theElems.length(); ++i )
2162   {
2163     SMESH::SMESH_IDSource_ptr elems = theElems[i].in();
2164     SMESH::SMESH_Mesh_var      mesh = elems->GetMesh();
2165     if ( mesh->GetId() != myMesh_i->GetId() )
2166       THROW_SALOME_CORBA_EXCEPTION("Wrong mesh of IDSource", SALOME::BAD_PARAM);
2167
2168     idSourceToSet( elems, getMeshDS(), elemSet, SMDSAbs_All );
2169   }
2170   getEditor().SplitBiQuadraticIntoLinear( elemSet );
2171
2172   declareMeshModified( /*isReComputeSafe=*/true ); // it does not influence Compute()
2173
2174   TPythonDump() << this << ".SplitBiQuadraticIntoLinear( "
2175                 << theElems << " )";
2176
2177   SMESH_CATCH( SMESH::throwCorbaException );
2178 }
2179
2180 //=======================================================================
2181 //function : Smooth
2182 //purpose  :
2183 //=======================================================================
2184
2185 CORBA::Boolean
2186 SMESH_MeshEditor_i::Smooth(const SMESH::long_array &              IDsOfElements,
2187                            const SMESH::long_array &              IDsOfFixedNodes,
2188                            CORBA::Long                            MaxNbOfIterations,
2189                            CORBA::Double                          MaxAspectRatio,
2190                            SMESH::SMESH_MeshEditor::Smooth_Method Method)
2191   throw (SALOME::SALOME_Exception)
2192 {
2193   return smooth( IDsOfElements, IDsOfFixedNodes, MaxNbOfIterations,
2194                  MaxAspectRatio, Method, false );
2195 }
2196
2197
2198 //=======================================================================
2199 //function : SmoothParametric
2200 //purpose  :
2201 //=======================================================================
2202
2203 CORBA::Boolean
2204 SMESH_MeshEditor_i::SmoothParametric(const SMESH::long_array &              IDsOfElements,
2205                                      const SMESH::long_array &              IDsOfFixedNodes,
2206                                      CORBA::Long                            MaxNbOfIterations,
2207                                      CORBA::Double                          MaxAspectRatio,
2208                                      SMESH::SMESH_MeshEditor::Smooth_Method Method)
2209   throw (SALOME::SALOME_Exception)
2210 {
2211   return smooth( IDsOfElements, IDsOfFixedNodes, MaxNbOfIterations,
2212                  MaxAspectRatio, Method, true );
2213 }
2214
2215
2216 //=======================================================================
2217 //function : SmoothObject
2218 //purpose  :
2219 //=======================================================================
2220
2221 CORBA::Boolean
2222 SMESH_MeshEditor_i::SmoothObject(SMESH::SMESH_IDSource_ptr              theObject,
2223                                  const SMESH::long_array &              IDsOfFixedNodes,
2224                                  CORBA::Long                            MaxNbOfIterations,
2225                                  CORBA::Double                          MaxAspectRatio,
2226                                  SMESH::SMESH_MeshEditor::Smooth_Method Method)
2227   throw (SALOME::SALOME_Exception)
2228 {
2229   return smoothObject (theObject, IDsOfFixedNodes, MaxNbOfIterations,
2230                        MaxAspectRatio, Method, false);
2231 }
2232
2233
2234 //=======================================================================
2235 //function : SmoothParametricObject
2236 //purpose  :
2237 //=======================================================================
2238
2239 CORBA::Boolean
2240 SMESH_MeshEditor_i::SmoothParametricObject(SMESH::SMESH_IDSource_ptr              theObject,
2241                                            const SMESH::long_array &              IDsOfFixedNodes,
2242                                            CORBA::Long                            MaxNbOfIterations,
2243                                            CORBA::Double                          MaxAspectRatio,
2244                                            SMESH::SMESH_MeshEditor::Smooth_Method Method)
2245   throw (SALOME::SALOME_Exception)
2246 {
2247   return smoothObject (theObject, IDsOfFixedNodes, MaxNbOfIterations,
2248                        MaxAspectRatio, Method, true);
2249 }
2250
2251
2252 //=============================================================================
2253 /*!
2254  *
2255  */
2256 //=============================================================================
2257
2258 CORBA::Boolean
2259 SMESH_MeshEditor_i::smooth(const SMESH::long_array &              IDsOfElements,
2260                            const SMESH::long_array &              IDsOfFixedNodes,
2261                            CORBA::Long                            MaxNbOfIterations,
2262                            CORBA::Double                          MaxAspectRatio,
2263                            SMESH::SMESH_MeshEditor::Smooth_Method Method,
2264                            bool                                   IsParametric)
2265   throw (SALOME::SALOME_Exception)
2266 {
2267   SMESH_TRY;
2268   initData();
2269
2270   SMESHDS_Mesh* aMesh = getMeshDS();
2271
2272   TIDSortedElemSet elements;
2273   arrayToSet(IDsOfElements, aMesh, elements, SMDSAbs_Face);
2274
2275   set<const SMDS_MeshNode*> fixedNodes;
2276   for (int i = 0; i < IDsOfFixedNodes.length(); i++) {
2277     CORBA::Long index = IDsOfFixedNodes[i];
2278     const SMDS_MeshNode * node = aMesh->FindNode(index);
2279     if ( node )
2280       fixedNodes.insert( node );
2281   }
2282   ::SMESH_MeshEditor::SmoothMethod method = ::SMESH_MeshEditor::LAPLACIAN;
2283   if ( Method != SMESH::SMESH_MeshEditor::LAPLACIAN_SMOOTH )
2284     method = ::SMESH_MeshEditor::CENTROIDAL;
2285
2286   getEditor().Smooth(elements, fixedNodes, method,
2287                   MaxNbOfIterations, MaxAspectRatio, IsParametric );
2288
2289   declareMeshModified( /*isReComputeSafe=*/true ); // does not prevent re-compute
2290
2291   // Update Python script
2292   TPythonDump() << "isDone = " << this << "."
2293                 << (IsParametric ? "SmoothParametric( " : "Smooth( ")
2294                 << IDsOfElements << ", "     << IDsOfFixedNodes << ", "
2295                 << TVar( MaxNbOfIterations ) << ", " << TVar( MaxAspectRatio ) << ", "
2296                 << "SMESH.SMESH_MeshEditor."
2297                 << ( Method == SMESH::SMESH_MeshEditor::CENTROIDAL_SMOOTH ?
2298                      "CENTROIDAL_SMOOTH )" : "LAPLACIAN_SMOOTH )");
2299
2300   return true;
2301
2302   SMESH_CATCH( SMESH::throwCorbaException );
2303   return 0;
2304 }
2305
2306 //=============================================================================
2307 /*!
2308  *
2309  */
2310 //=============================================================================
2311
2312 CORBA::Boolean
2313 SMESH_MeshEditor_i::smoothObject(SMESH::SMESH_IDSource_ptr              theObject,
2314                                  const SMESH::long_array &              IDsOfFixedNodes,
2315                                  CORBA::Long                            MaxNbOfIterations,
2316                                  CORBA::Double                          MaxAspectRatio,
2317                                  SMESH::SMESH_MeshEditor::Smooth_Method Method,
2318                                  bool                                   IsParametric)
2319   throw (SALOME::SALOME_Exception)
2320 {
2321   SMESH_TRY;
2322   initData();
2323
2324   TPythonDump aTPythonDump;  // suppress dump in smooth()
2325
2326   prepareIdSource( theObject );
2327   SMESH::long_array_var anElementsId = theObject->GetIDs();
2328   CORBA::Boolean isDone = smooth (anElementsId, IDsOfFixedNodes, MaxNbOfIterations,
2329                                   MaxAspectRatio, Method, IsParametric);
2330
2331   // Update Python script
2332   aTPythonDump << "isDone = " << this << "."
2333                << (IsParametric ? "SmoothParametricObject( " : "SmoothObject( ")
2334                << theObject << ", " << IDsOfFixedNodes << ", "
2335                << TVar( MaxNbOfIterations ) << ", " << TVar( MaxAspectRatio ) << ", "
2336                << "SMESH.SMESH_MeshEditor."
2337                << ( Method == SMESH::SMESH_MeshEditor::CENTROIDAL_SMOOTH ?
2338                     "CENTROIDAL_SMOOTH )" : "LAPLACIAN_SMOOTH )");
2339
2340   return isDone;
2341
2342   SMESH_CATCH( SMESH::throwCorbaException );
2343   return 0;
2344 }
2345
2346 //=============================================================================
2347 /*!
2348  *
2349  */
2350 //=============================================================================
2351
2352 void SMESH_MeshEditor_i::RenumberNodes()
2353   throw (SALOME::SALOME_Exception)
2354 {
2355   SMESH_TRY;
2356   // Update Python script
2357   TPythonDump() << this << ".RenumberNodes()";
2358
2359   getMeshDS()->Renumber( true );
2360
2361   SMESH_CATCH( SMESH::throwCorbaException );
2362 }
2363
2364 //=============================================================================
2365 /*!
2366  *
2367  */
2368 //=============================================================================
2369
2370 void SMESH_MeshEditor_i::RenumberElements()
2371   throw (SALOME::SALOME_Exception)
2372 {
2373   SMESH_TRY;
2374   // Update Python script
2375   TPythonDump() << this << ".RenumberElements()";
2376
2377   getMeshDS()->Renumber( false );
2378
2379   SMESH_CATCH( SMESH::throwCorbaException );
2380 }
2381
2382 //=======================================================================
2383 /*!
2384  * \brief Return groups by their IDs
2385  */
2386 //=======================================================================
2387
2388 SMESH::ListOfGroups* SMESH_MeshEditor_i::getGroups(const std::list<int>* groupIDs)
2389   throw (SALOME::SALOME_Exception)
2390 {
2391   SMESH_TRY;
2392   if ( !groupIDs )
2393     return 0;
2394   myMesh_i->CreateGroupServants();
2395   return myMesh_i->GetGroups( *groupIDs );
2396
2397   SMESH_CATCH( SMESH::throwCorbaException );
2398   return 0;
2399 }
2400
2401 //=======================================================================
2402 //function : RotationSweepObjects
2403 //purpose  :
2404 //=======================================================================
2405
2406 SMESH::ListOfGroups*
2407 SMESH_MeshEditor_i::RotationSweepObjects(const SMESH::ListOfIDSources & theNodes,
2408                                          const SMESH::ListOfIDSources & theEdges,
2409                                          const SMESH::ListOfIDSources & theFaces,
2410                                          const SMESH::AxisStruct &      theAxis,
2411                                          CORBA::Double                  theAngleInRadians,
2412                                          CORBA::Long                    theNbOfSteps,
2413                                          CORBA::Double                  theTolerance,
2414                                          const bool                     theMakeGroups)
2415   throw (SALOME::SALOME_Exception)
2416 {
2417   SMESH_TRY;
2418   initData();
2419
2420   TIDSortedElemSet elemsNodes[2];
2421   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
2422     SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
2423     while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
2424   }
2425   for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
2426     idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
2427   for ( int i = 0, nb = theFaces.length(); i < nb; ++i )
2428     idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face );
2429
2430   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2431   bool              makeWalls=true;
2432   if ( myIsPreviewMode )
2433   {
2434     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2435     TPreviewMesh * tmpMesh = getPreviewMesh();
2436     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2437     tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid );
2438     workElements = & copyElements[0];
2439     //makeWalls = false; -- faces are needed for preview
2440   }
2441
2442   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2443
2444   gp_Ax1 Ax1 (gp_Pnt( theAxis.x,  theAxis.y,  theAxis.z ),
2445               gp_Vec( theAxis.vx, theAxis.vy, theAxis.vz ));
2446
2447   ::SMESH_MeshEditor::PGroupIDs groupIds =
2448       getEditor().RotationSweep (workElements, Ax1, theAngleInRadians,
2449                                  theNbOfSteps, theTolerance, theMakeGroups, makeWalls);
2450
2451   SMESH::ListOfGroups * aGroups = theMakeGroups ? getGroups( groupIds.get()) : 0;
2452
2453   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2454
2455   if ( !myIsPreviewMode )
2456   {
2457     dumpGroupsList( aPythonDump, aGroups );
2458     aPythonDump << this<< ".RotationSweepObjects( "
2459                 << theNodes                  << ", "
2460                 << theEdges                  << ", "
2461                 << theFaces                  << ", "
2462                 << theAxis                   << ", "
2463                 << TVar( theAngleInRadians ) << ", "
2464                 << TVar( theNbOfSteps      ) << ", "
2465                 << TVar( theTolerance      ) << ", "
2466                 << theMakeGroups             << " )";
2467   }
2468   else
2469   {
2470     getPreviewMesh()->Remove( SMDSAbs_Volume );
2471   }
2472
2473   return aGroups ? aGroups : new SMESH::ListOfGroups;
2474
2475   SMESH_CATCH( SMESH::throwCorbaException );
2476   return 0;
2477 }
2478
2479 namespace MeshEditor_I
2480 {
2481   /*!
2482    * \brief Structure used to pass extrusion parameters to ::SMESH_MeshEditor
2483    */
2484   struct ExtrusionParams : public ::SMESH_MeshEditor::ExtrusParam
2485   {
2486     bool myIsExtrusionByNormal;
2487
2488     static int makeFlags( CORBA::Boolean MakeGroups,
2489                           CORBA::Boolean ByAverageNormal = false,
2490                           CORBA::Boolean UseInputElemsOnly = false,
2491                           CORBA::Long    Flags = 0,
2492                           CORBA::Boolean MakeBoundary = true )
2493     {
2494       if ( MakeGroups       ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_GROUPS;
2495       if ( ByAverageNormal  ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_BY_AVG_NORMAL;
2496       if ( UseInputElemsOnly) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_USE_INPUT_ELEMS_ONLY;
2497       if ( MakeBoundary     ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_BOUNDARY;
2498       return Flags;
2499     }
2500     // standard params
2501     ExtrusionParams(const SMESH::DirStruct &  theDir,
2502                     CORBA::Long               theNbOfSteps,
2503                     CORBA::Boolean            theMakeGroups):
2504       ::SMESH_MeshEditor::ExtrusParam ( gp_Vec( theDir.PS.x,
2505                                                 theDir.PS.y,
2506                                                 theDir.PS.z ),
2507                                         theNbOfSteps,
2508                                         makeFlags( theMakeGroups )),
2509       myIsExtrusionByNormal( false )
2510     {
2511     }
2512     // advanced params
2513     ExtrusionParams(const SMESH::DirStruct &  theDir,
2514                     CORBA::Long               theNbOfSteps,
2515                     CORBA::Boolean            theMakeGroups,
2516                     CORBA::Long               theExtrFlags,
2517                     CORBA::Double             theSewTolerance):
2518       ::SMESH_MeshEditor::ExtrusParam ( gp_Vec( theDir.PS.x,
2519                                                 theDir.PS.y,
2520                                                 theDir.PS.z ),
2521                                         theNbOfSteps,
2522                                         makeFlags( theMakeGroups, false, false,
2523                                                    theExtrFlags, false ),
2524                                         theSewTolerance ),
2525       myIsExtrusionByNormal( false )
2526     {
2527     }
2528     // params for extrusion by normal
2529     ExtrusionParams(CORBA::Double  theStepSize,
2530                     CORBA::Long    theNbOfSteps,
2531                     CORBA::Short   theDim,
2532                     CORBA::Boolean theByAverageNormal,
2533                     CORBA::Boolean theUseInputElemsOnly,
2534                     CORBA::Boolean theMakeGroups ):
2535       ::SMESH_MeshEditor::ExtrusParam ( theStepSize, 
2536                                         theNbOfSteps,
2537                                         makeFlags( theMakeGroups,
2538                                                    theByAverageNormal, theUseInputElemsOnly ),
2539                                         theDim),
2540       myIsExtrusionByNormal( true )
2541     {
2542     }
2543
2544     void SetNoGroups()
2545     {
2546       Flags() &= ~(::SMESH_MeshEditor::EXTRUSION_FLAG_GROUPS);
2547     }
2548   };
2549 }
2550
2551 //=======================================================================
2552 /*!
2553  * \brief Generate dim+1 elements by extrusion of elements along vector
2554  *  \param [in] edges - edges to extrude: a list including groups, sub-meshes or a mesh
2555  *  \param [in] faces - faces to extrude: a list including groups, sub-meshes or a mesh
2556  *  \param [in] nodes - nodes to extrude: a list including groups, sub-meshes or a mesh
2557  *  \param [in] stepVector - vector giving direction and distance of an extrusion step
2558  *  \param [in] nbOfSteps - number of elements to generate from one element
2559  *  \param [in] toMakeGroups - if true, new elements will be included into new groups
2560  *              corresponding to groups the input elements included in.
2561  *  \return ListOfGroups - new groups craeted if \a toMakeGroups is true
2562  */
2563 //=======================================================================
2564
2565 SMESH::ListOfGroups*
2566 SMESH_MeshEditor_i::ExtrusionSweepObjects(const SMESH::ListOfIDSources & theNodes,
2567                                           const SMESH::ListOfIDSources & theEdges,
2568                                           const SMESH::ListOfIDSources & theFaces,
2569                                           const SMESH::DirStruct &       theStepVector,
2570                                           CORBA::Long                    theNbOfSteps,
2571                                           CORBA::Boolean                 theToMakeGroups)
2572   throw (SALOME::SALOME_Exception)
2573 {
2574   SMESH_TRY;
2575   initData();
2576
2577   ExtrusionParams params( theStepVector, theNbOfSteps, theToMakeGroups );
2578
2579   TIDSortedElemSet elemsNodes[2];
2580   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
2581     SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
2582     while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
2583   }
2584   for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
2585     idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
2586   for ( int i = 0, nb = theFaces.length(); i < nb; ++i )
2587     idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face );
2588
2589   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2590   SMDSAbs_ElementType previewType = SMDSAbs_All; //SMDSAbs_Face;
2591   if ( myIsPreviewMode )
2592   {
2593     // if ( (*elemsNodes.begin())->GetType() == SMDSAbs_Node )
2594     //   previewType = SMDSAbs_Edge;
2595
2596     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2597     TPreviewMesh * tmpMesh = getPreviewMesh( previewType );
2598     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2599     tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid );
2600     workElements = & copyElements[0];
2601
2602     params.SetNoGroups();
2603   }
2604   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2605
2606   ::SMESH_MeshEditor::TTElemOfElemListMap aHistory;
2607   ::SMESH_MeshEditor::PGroupIDs groupIds =
2608       getEditor().ExtrusionSweep( workElements, params, aHistory );
2609
2610   SMESH::ListOfGroups * aGroups = theToMakeGroups ? getGroups( groupIds.get()) : 0;
2611
2612   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2613
2614   if ( !myIsPreviewMode )
2615   {
2616     dumpGroupsList( aPythonDump, aGroups );
2617     aPythonDump << this<< ".ExtrusionSweepObjects( "
2618                 << theNodes             << ", "
2619                 << theEdges             << ", "
2620                 << theFaces             << ", "
2621                 << theStepVector        << ", "
2622                 << TVar( theNbOfSteps ) << ", "
2623                 << theToMakeGroups      << " )";
2624   }
2625   else
2626   {
2627     getPreviewMesh( previewType )->Remove( SMDSAbs_Volume );
2628   }
2629
2630   return aGroups ? aGroups : new SMESH::ListOfGroups;
2631
2632   SMESH_CATCH( SMESH::throwCorbaException );
2633   return 0;
2634 }
2635
2636 //=======================================================================
2637 //function : ExtrusionByNormal
2638 //purpose  :
2639 //=======================================================================
2640
2641 SMESH::ListOfGroups*
2642 SMESH_MeshEditor_i::ExtrusionByNormal(const SMESH::ListOfIDSources& objects,
2643                                       CORBA::Double                 stepSize,
2644                                       CORBA::Long                   nbOfSteps,
2645                                       CORBA::Boolean                byAverageNormal,
2646                                       CORBA::Boolean                useInputElemsOnly,
2647                                       CORBA::Boolean                makeGroups,
2648                                       CORBA::Short                  dim)
2649   throw (SALOME::SALOME_Exception)
2650 {
2651   SMESH_TRY;
2652   initData();
2653
2654   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
2655
2656   ExtrusionParams params( stepSize, nbOfSteps, dim,
2657                           byAverageNormal, useInputElemsOnly, makeGroups );
2658
2659   SMDSAbs_ElementType elemType = ( dim == 1 ? SMDSAbs_Edge : SMDSAbs_Face );
2660   if ( objects.length() > 0 && !SMESH::DownCast<SMESH_Mesh_i*>( objects[0] ))
2661   {
2662     SMESH::array_of_ElementType_var elemTypes = objects[0]->GetTypes();
2663     if (( elemTypes->length() == 1 ) &&
2664         ( elemTypes[0] == SMESH::EDGE || elemTypes[0] == SMESH::FACE ))
2665       elemType = ( SMDSAbs_ElementType ) elemTypes[0];
2666   }
2667
2668   TIDSortedElemSet elemsNodes[2];
2669   for ( int i = 0, nb = objects.length(); i < nb; ++i )
2670     idSourceToSet( objects[i], getMeshDS(), elemsNodes[0], elemType );
2671
2672   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2673   SMDSAbs_ElementType previewType = SMDSAbs_Face;
2674   if ( myIsPreviewMode )
2675   {
2676     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2677     TPreviewMesh * tmpMesh = getPreviewMesh( previewType );
2678     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2679     workElements = & copyElements[0];
2680
2681     params.SetNoGroups();
2682   }
2683
2684   ::SMESH_MeshEditor::TTElemOfElemListMap aHistory;
2685   ::SMESH_MeshEditor::PGroupIDs groupIds =
2686       getEditor().ExtrusionSweep( workElements, params, aHistory );
2687
2688   SMESH::ListOfGroups * aGroups = makeGroups ? getGroups( groupIds.get()) : 0;
2689
2690   if (!myIsPreviewMode) {
2691     dumpGroupsList(aPythonDump, aGroups);
2692     aPythonDump << this << ".ExtrusionByNormal( " << objects
2693                 << ", " << TVar( stepSize )
2694                 << ", " << TVar( nbOfSteps )
2695                 << ", " << byAverageNormal
2696                 << ", " << useInputElemsOnly
2697                 << ", " << makeGroups
2698                 << ", " << dim
2699                 << " )";
2700   }
2701   else
2702   {
2703     getPreviewMesh( previewType )->Remove( SMDSAbs_Volume );
2704   }
2705
2706   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2707
2708   return aGroups ? aGroups : new SMESH::ListOfGroups;
2709
2710   SMESH_CATCH( SMESH::throwCorbaException );
2711   return 0;
2712 }
2713
2714 //=======================================================================
2715 //function : AdvancedExtrusion
2716 //purpose  :
2717 //=======================================================================
2718
2719 SMESH::ListOfGroups*
2720 SMESH_MeshEditor_i::AdvancedExtrusion(const SMESH::long_array & theIDsOfElements,
2721                                       const SMESH::DirStruct &  theStepVector,
2722                                       CORBA::Long               theNbOfSteps,
2723                                       CORBA::Long               theExtrFlags,
2724                                       CORBA::Double             theSewTolerance,
2725                                       CORBA::Boolean            theMakeGroups)
2726   throw (SALOME::SALOME_Exception)
2727 {
2728   SMESH_TRY;
2729   initData();
2730
2731   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2732
2733   ExtrusionParams params( theStepVector, theNbOfSteps, theMakeGroups,
2734                           theExtrFlags, theSewTolerance );
2735
2736   TIDSortedElemSet elemsNodes[2];
2737   arrayToSet( theIDsOfElements, getMeshDS(), elemsNodes[0] );
2738
2739   ::SMESH_MeshEditor::TTElemOfElemListMap aHistory;
2740   ::SMESH_MeshEditor::PGroupIDs groupIds =
2741       getEditor().ExtrusionSweep( elemsNodes, params, aHistory );
2742
2743   SMESH::ListOfGroups * aGroups = theMakeGroups ? getGroups( groupIds.get()) : 0;
2744
2745   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2746
2747   if ( !myIsPreviewMode ) {
2748     dumpGroupsList(aPythonDump, aGroups);
2749     aPythonDump << this << ".AdvancedExtrusion( "
2750                 << theIDsOfElements << ", "
2751                 << theStepVector << ", "
2752                 << theNbOfSteps << ", "
2753                 << theExtrFlags << ", "
2754                 << theSewTolerance << ", "
2755                 << theMakeGroups << " )";
2756   }
2757   else
2758   {
2759     getPreviewMesh()->Remove( SMDSAbs_Volume );
2760   }
2761
2762   return aGroups ? aGroups : new SMESH::ListOfGroups;
2763
2764   SMESH_CATCH( SMESH::throwCorbaException );
2765   return 0;
2766 }
2767
2768 //================================================================================
2769 /*!
2770  * \brief Convert extrusion error to IDL enum
2771  */
2772 //================================================================================
2773
2774 namespace
2775 {
2776 #define RETCASE(enm) case ::SMESH_MeshEditor::enm: return SMESH::SMESH_MeshEditor::enm;
2777
2778   SMESH::SMESH_MeshEditor::Extrusion_Error convExtrError( ::SMESH_MeshEditor::Extrusion_Error e )
2779   {
2780     switch ( e ) {
2781       RETCASE( EXTR_OK );
2782       RETCASE( EXTR_NO_ELEMENTS );
2783       RETCASE( EXTR_PATH_NOT_EDGE );
2784       RETCASE( EXTR_BAD_PATH_SHAPE );
2785       RETCASE( EXTR_BAD_STARTING_NODE );
2786       RETCASE( EXTR_BAD_ANGLES_NUMBER );
2787       RETCASE( EXTR_CANT_GET_TANGENT );
2788     }
2789     return SMESH::SMESH_MeshEditor::EXTR_OK;
2790   }
2791 }
2792
2793 //=======================================================================
2794 //function : extrusionAlongPath
2795 //purpose  :
2796 //=======================================================================
2797 SMESH::ListOfGroups*
2798 SMESH_MeshEditor_i::ExtrusionAlongPathObjects(const SMESH::ListOfIDSources & theNodes,
2799                                               const SMESH::ListOfIDSources & theEdges,
2800                                               const SMESH::ListOfIDSources & theFaces,
2801                                               SMESH::SMESH_IDSource_ptr      thePathMesh,
2802                                               GEOM::GEOM_Object_ptr          thePathShape,
2803                                               CORBA::Long                    theNodeStart,
2804                                               CORBA::Boolean                 theHasAngles,
2805                                               const SMESH::double_array &    theAngles,
2806                                               CORBA::Boolean                 theLinearVariation,
2807                                               CORBA::Boolean                 theHasRefPoint,
2808                                               const SMESH::PointStruct &     theRefPoint,
2809                                               bool                           theMakeGroups,
2810                                               SMESH::SMESH_MeshEditor::Extrusion_Error& theError)
2811   throw (SALOME::SALOME_Exception)
2812 {
2813   SMESH_TRY;
2814   initData();
2815
2816   SMESH::ListOfGroups_var aGroups = new SMESH::ListOfGroups;
2817
2818   theError = SMESH::SMESH_MeshEditor::EXTR_BAD_PATH_SHAPE;
2819   if ( thePathMesh->_is_nil() )
2820     return aGroups._retn();
2821
2822   // get a sub-mesh
2823   SMESH_subMesh* aSubMesh = 0;
2824   SMESH_Mesh_i* aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( thePathMesh );
2825   if ( thePathShape->_is_nil() )
2826   {
2827     // thePathMesh should be either a sub-mesh or a mesh with 1D elements only
2828     if ( SMESH_subMesh_i* sm = SMESH::DownCast<SMESH_subMesh_i*>( thePathMesh ))
2829     {
2830       SMESH::SMESH_Mesh_var mesh = thePathMesh->GetMesh();
2831       aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
2832       if ( !aMeshImp ) return aGroups._retn();
2833       aSubMesh = aMeshImp->GetImpl().GetSubMeshContaining( sm->GetId() );
2834       if ( !aSubMesh ) return aGroups._retn();
2835     }
2836     else if ( !aMeshImp ||
2837               aMeshImp->NbEdges() != aMeshImp->NbElements() )
2838     {
2839       return aGroups._retn();
2840     }
2841   }
2842   else
2843   {
2844     if ( !aMeshImp ) return aGroups._retn();
2845     TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( thePathShape );
2846     aSubMesh = aMeshImp->GetImpl().GetSubMesh( aShape );
2847     if ( !aSubMesh || !aSubMesh->GetSubMeshDS() )
2848       return aGroups._retn();
2849   }
2850
2851   SMDS_MeshNode* nodeStart =
2852     (SMDS_MeshNode*)aMeshImp->GetImpl().GetMeshDS()->FindNode(theNodeStart);
2853   if ( !nodeStart ) {
2854     theError = SMESH::SMESH_MeshEditor::EXTR_BAD_STARTING_NODE;
2855     return aGroups._retn();
2856   }
2857
2858   TIDSortedElemSet elemsNodes[2];
2859   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
2860     SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
2861     while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
2862   }
2863   for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
2864     idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
2865   for ( int i = 0, nb = theFaces.length(); i < nb; ++i )
2866     idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face );
2867
2868   list<double> angles;
2869   for (int i = 0; i < theAngles.length(); i++) {
2870     angles.push_back( theAngles[i] );
2871   }
2872
2873   gp_Pnt refPnt( theRefPoint.x, theRefPoint.y, theRefPoint.z );
2874
2875   int nbOldGroups = myMesh->NbGroup();
2876
2877   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2878   if ( myIsPreviewMode )
2879   {
2880     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2881     TPreviewMesh * tmpMesh = getPreviewMesh();
2882     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2883     tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid );
2884     workElements = & copyElements[0];
2885     theMakeGroups = false;
2886   }
2887
2888   ::SMESH_MeshEditor::Extrusion_Error error;
2889   if ( !aSubMesh )
2890     error = getEditor().ExtrusionAlongTrack( workElements, &(aMeshImp->GetImpl()), nodeStart,
2891                                              theHasAngles, angles, theLinearVariation,
2892                                              theHasRefPoint, refPnt, theMakeGroups );
2893   else
2894     error = getEditor().ExtrusionAlongTrack( workElements, aSubMesh, nodeStart,
2895                                              theHasAngles, angles, theLinearVariation,
2896                                              theHasRefPoint, refPnt, theMakeGroups );
2897
2898   declareMeshModified( /*isReComputeSafe=*/true );
2899   theError = convExtrError( error );
2900
2901   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2902   if ( theMakeGroups ) {
2903     list<int> groupIDs = myMesh->GetGroupIds();
2904     list<int>::iterator newBegin = groupIDs.begin();
2905     std::advance( newBegin, nbOldGroups ); // skip old groups
2906     groupIDs.erase( groupIDs.begin(), newBegin );
2907     aGroups = getGroups( & groupIDs );
2908     if ( ! &aGroups.in() ) aGroups = new SMESH::ListOfGroups;
2909   }
2910
2911   if ( !myIsPreviewMode ) {
2912     aPythonDump << "(" << aGroups << ", error) = "
2913                 << this << ".ExtrusionAlongPathObjects( "
2914                 << theNodes            << ", "
2915                 << theEdges            << ", "
2916                 << theFaces            << ", "
2917                 << thePathMesh         << ", "
2918                 << thePathShape        << ", "
2919                 << theNodeStart        << ", "
2920                 << theHasAngles        << ", "
2921                 << theAngles           << ", "
2922                 << theLinearVariation  << ", "
2923                 << theHasRefPoint      << ", "
2924                 << "SMESH.PointStruct( "
2925                 << ( theHasRefPoint ? theRefPoint.x : 0 ) << ", "
2926                 << ( theHasRefPoint ? theRefPoint.y : 0 ) << ", "
2927                 << ( theHasRefPoint ? theRefPoint.z : 0 ) << " ), "
2928                 << theMakeGroups       << " )";
2929   }
2930   else
2931   {
2932     getPreviewMesh()->Remove( SMDSAbs_Volume );
2933   }
2934
2935   return aGroups._retn();
2936
2937   SMESH_CATCH( SMESH::throwCorbaException );
2938   return 0;
2939 }
2940
2941 //================================================================================
2942 /*!
2943  * \brief Compute rotation angles for ExtrusionAlongPath as linear variation
2944  * of given angles along path steps
2945  * \param PathMesh mesh containing a 1D sub-mesh on the edge, along
2946  *                which proceeds the extrusion
2947  * \param PathShape is shape(edge); as the mesh can be complex, the edge
2948  *                 is used to define the sub-mesh for the path
2949  */
2950 //================================================================================
2951
2952 SMESH::double_array*
2953 SMESH_MeshEditor_i::LinearAnglesVariation(SMESH::SMESH_Mesh_ptr       thePathMesh,
2954                                           GEOM::GEOM_Object_ptr       thePathShape,
2955                                           const SMESH::double_array & theAngles)
2956 {
2957   SMESH::double_array_var aResult = new SMESH::double_array();
2958   int nbAngles = theAngles.length();
2959   if ( nbAngles > 0 && !thePathMesh->_is_nil() && !thePathShape->_is_nil() )
2960   {
2961     SMESH_Mesh_i* aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( thePathMesh );
2962     TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( thePathShape );
2963     SMESH_subMesh* aSubMesh = aMeshImp->GetImpl().GetSubMesh( aShape );
2964     if ( !aSubMesh || !aSubMesh->GetSubMeshDS())
2965       return aResult._retn();
2966     int nbSteps = aSubMesh->GetSubMeshDS()->NbElements();
2967     if ( nbSteps == nbAngles )
2968     {
2969       aResult.inout() = theAngles;
2970     }
2971     else
2972     {
2973       aResult->length( nbSteps );
2974       double rAn2St = double( nbAngles ) / double( nbSteps );
2975       double angPrev = 0, angle;
2976       for ( int iSt = 0; iSt < nbSteps; ++iSt )
2977       {
2978         double angCur = rAn2St * ( iSt+1 );
2979         double angCurFloor  = floor( angCur );
2980         double angPrevFloor = floor( angPrev );
2981         if ( angPrevFloor == angCurFloor )
2982           angle = rAn2St * theAngles[ int( angCurFloor ) ];
2983         else
2984         {
2985           int iP = int( angPrevFloor );
2986           double angPrevCeil = ceil(angPrev);
2987           angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
2988
2989           int iC = int( angCurFloor );
2990           if ( iC < nbAngles )
2991             angle += ( angCur - angCurFloor ) * theAngles[ iC ];
2992
2993           iP = int( angPrevCeil );
2994           while ( iC-- > iP )
2995             angle += theAngles[ iC ];
2996         }
2997         aResult[ iSt ] = angle;
2998         angPrev = angCur;
2999       }
3000     }
3001   }
3002   // Update Python script
3003   TPythonDump() << "rotAngles = " << theAngles;
3004   TPythonDump() << "rotAngles = " << this << ".LinearAnglesVariation( "
3005                 << thePathMesh  << ", "
3006                 << thePathShape << ", "
3007                 << "rotAngles )";
3008
3009   return aResult._retn();
3010 }
3011
3012 //=======================================================================
3013 //function : mirror
3014 //purpose  :
3015 //=======================================================================
3016
3017 SMESH::ListOfGroups*
3018 SMESH_MeshEditor_i::mirror(TIDSortedElemSet &                  theElements,
3019                            const SMESH::AxisStruct &           theAxis,
3020                            SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
3021                            CORBA::Boolean                      theCopy,
3022                            bool                                theMakeGroups,
3023                            ::SMESH_Mesh*                       theTargetMesh)
3024   throw (SALOME::SALOME_Exception)
3025 {
3026   SMESH_TRY;
3027   initData();
3028
3029   gp_Pnt P ( theAxis.x, theAxis.y, theAxis.z );
3030   gp_Vec V ( theAxis.vx, theAxis.vy, theAxis.vz );
3031
3032   if ( theTargetMesh )
3033     theCopy = false;
3034
3035   gp_Trsf aTrsf;
3036   switch ( theMirrorType ) {
3037   case  SMESH::SMESH_MeshEditor::POINT:
3038     aTrsf.SetMirror( P );
3039     break;
3040   case  SMESH::SMESH_MeshEditor::AXIS:
3041     aTrsf.SetMirror( gp_Ax1( P, V ));
3042     break;
3043   default:
3044     aTrsf.SetMirror( gp_Ax2( P, V ));
3045   }
3046
3047   TIDSortedElemSet  copyElements;
3048   TIDSortedElemSet* workElements = & theElements;
3049
3050   if ( myIsPreviewMode )
3051   {
3052     TPreviewMesh * tmpMesh = getPreviewMesh();
3053     tmpMesh->Copy( theElements, copyElements);
3054     if ( !theCopy && !theTargetMesh )
3055     {
3056       TIDSortedElemSet elemsAround, elemsAroundCopy;
3057       getElementsAround( theElements, getMeshDS(), elemsAround );
3058       tmpMesh->Copy( elemsAround, elemsAroundCopy);
3059     }
3060     workElements = & copyElements;
3061     theMakeGroups = false;
3062   }
3063
3064   ::SMESH_MeshEditor::PGroupIDs groupIds =
3065       getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
3066
3067   if ( theCopy && !myIsPreviewMode)
3068   {
3069     if ( theTargetMesh )
3070     {
3071       theTargetMesh->GetMeshDS()->Modified();
3072     }
3073     else
3074     {
3075       declareMeshModified( /*isReComputeSafe=*/false );
3076     }
3077   }
3078   return theMakeGroups ? getGroups(groupIds.get()) : 0;
3079