Salome HOME
23080: [CEA 1497] Do not merge a middle node in quadratic with the extreme nodes...
[modules/smesh.git] / src / SMESH_I / SMESH_MeshEditor_i.cxx
1 // Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //  File   : SMESH_MeshEditor_i.cxx
23 //  Author : Nicolas REJNERI
24 //  Module : SMESH
25
26 #ifdef WIN32
27 #define NOMINMAX
28 #endif
29
30 // A macro used in SMESH_TryCatch.hxx,
31 // it re-raises a CORBA SALOME exception thrown by SMESH_MeshEditor_i and caught by SMESH_CATCH
32 #define SMY_OWN_CATCH \
33   catch ( SALOME::SALOME_Exception & e ) { throw e; }
34
35 #include "SMESH_MeshEditor_i.hxx"
36
37 #include "SMDS_EdgePosition.hxx"
38 #include "SMDS_ElemIterator.hxx"
39 #include "SMDS_FacePosition.hxx"
40 #include "SMDS_IteratorOnIterators.hxx"
41 #include "SMDS_LinearEdge.hxx"
42 #include "SMDS_Mesh0DElement.hxx"
43 #include "SMDS_MeshFace.hxx"
44 #include "SMDS_MeshVolume.hxx"
45 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
46 #include "SMDS_SetIterator.hxx"
47 #include "SMDS_VolumeTool.hxx"
48 #include "SMESHDS_Group.hxx"
49 #include "SMESHDS_GroupOnGeom.hxx"
50 #include "SMESH_ControlsDef.hxx"
51 #include "SMESH_Filter_i.hxx"
52 #include "SMESH_Gen_i.hxx"
53 #include "SMESH_Group.hxx"
54 #include "SMESH_Group_i.hxx"
55 #include "SMESH_MeshAlgos.hxx"
56 #include "SMESH_MeshPartDS.hxx"
57 #include "SMESH_MesherHelper.hxx"
58 #include "SMESH_PythonDump.hxx"
59 #include "SMESH_subMeshEventListener.hxx"
60 #include "SMESH_subMesh_i.hxx"
61
62 #include <utilities.h>
63 #include <Utils_ExceptHandlers.hxx>
64 #include <Utils_CorbaException.hxx>
65 #include <SALOMEDS_wrap.hxx>
66 #include <SALOME_GenericObj_i.hh>
67 #include <Basics_OCCTVersion.hxx>
68
69 #include <BRepAdaptor_Surface.hxx>
70 #include <BRep_Tool.hxx>
71 #include <TopExp_Explorer.hxx>
72 #include <TopoDS.hxx>
73 #include <TopoDS_Edge.hxx>
74 #include <TopoDS_Face.hxx>
75 #include <gp_Ax1.hxx>
76 #include <gp_Ax2.hxx>
77 #include <gp_Vec.hxx>
78
79 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
80 #define NO_CAS_CATCH
81 #endif
82
83 #include <Standard_Failure.hxx>
84
85 #ifdef NO_CAS_CATCH
86 #include <Standard_ErrorHandler.hxx>
87 #endif
88
89 #include <sstream>
90 #include <limits>
91
92 #include "SMESH_TryCatch.hxx" // include after OCCT headers!
93
94 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
95
96 using namespace std;
97 using SMESH::TPythonDump;
98 using SMESH::TVar;
99
100 namespace MeshEditor_I {
101
102   //=============================================================================
103   /*!
104    * \brief Mesh to apply modifications for preview purposes
105    */
106   //=============================================================================
107
108   struct TPreviewMesh: public SMESH_Mesh
109   {
110     SMDSAbs_ElementType myPreviewType; // type to show
111     //!< Constructor
112     TPreviewMesh(SMDSAbs_ElementType previewElements = SMDSAbs_All) {
113       _isShapeToMesh = (_id =_studyId = 0);
114       _myMeshDS  = new SMESHDS_Mesh( _id, true );
115       myPreviewType = previewElements;
116     }
117     //!< Copy a set of elements
118     void Copy(const TIDSortedElemSet & theElements,
119               TIDSortedElemSet&        theCopyElements,
120               SMDSAbs_ElementType      theSelectType = SMDSAbs_All,
121               SMDSAbs_ElementType      theAvoidType = SMDSAbs_All)
122     {
123       // loop on theIDsOfElements
124       TIDSortedElemSet::const_iterator eIt = theElements.begin();
125       for ( ; eIt != theElements.end(); ++eIt )
126       {
127         const SMDS_MeshElement* anElem = *eIt;
128         if ( !anElem ) continue;
129         SMDSAbs_ElementType type = anElem->GetType();
130         if ( type == theAvoidType ||
131              ( theSelectType != SMDSAbs_All && type != theSelectType ))
132           continue;
133         const SMDS_MeshElement* anElemCopy;
134         if ( type == SMDSAbs_Node)
135           anElemCopy = Copy( cast2Node(anElem) );
136         else
137           anElemCopy = Copy( anElem );
138         if ( anElemCopy )
139           theCopyElements.insert( theCopyElements.end(), anElemCopy );
140       }
141     }
142     //!< Copy an element
143     SMDS_MeshElement* Copy( const SMDS_MeshElement* anElem )
144     {
145       // copy element nodes
146       int anElemNbNodes = anElem->NbNodes();
147       vector< int > anElemNodesID( anElemNbNodes ) ;
148       SMDS_ElemIteratorPtr itElemNodes = anElem->nodesIterator();
149       for ( int i = 0; itElemNodes->more(); i++)
150       {
151         const SMDS_MeshNode* anElemNode = cast2Node( itElemNodes->next() );
152         Copy( anElemNode );
153         anElemNodesID[i] = anElemNode->GetID();
154       }
155
156       // creates a corresponding element on copied nodes
157       ::SMESH_MeshEditor::ElemFeatures elemType;
158       elemType.Init( anElem, /*basicOnly=*/false );
159       elemType.SetID( anElem->GetID() );
160       SMDS_MeshElement* anElemCopy =
161         ::SMESH_MeshEditor(this).AddElement( anElemNodesID, elemType );
162       return anElemCopy;
163     }
164     //!< Copy a node
165     SMDS_MeshNode* Copy( const SMDS_MeshNode* anElemNode )
166     {
167       return _myMeshDS->AddNodeWithID(anElemNode->X(), anElemNode->Y(), anElemNode->Z(),
168                                       anElemNode->GetID());
169     }
170     void RemoveAll()
171     {
172       GetMeshDS()->ClearMesh();
173     }
174     void Remove( SMDSAbs_ElementType type )
175     {
176       SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator( type );
177       while ( eIt->more() )
178         GetMeshDS()->RemoveFreeElement( eIt->next(), /*sm=*/0, /*fromGroups=*/false );
179     }
180   };// struct TPreviewMesh
181
182   static SMESH_NodeSearcher *    theNodeSearcher    = 0;
183   static SMESH_ElementSearcher * theElementSearcher = 0;
184
185   //=============================================================================
186   /*!
187    * \brief Deleter of theNodeSearcher at any compute event occured
188    */
189   //=============================================================================
190
191   struct TSearchersDeleter : public SMESH_subMeshEventListener
192   {
193     SMESH_Mesh* myMesh;
194     string      myMeshPartIOR;
195     //!< Constructor
196     TSearchersDeleter(): SMESH_subMeshEventListener( false, // won't be deleted by submesh
197                                                      "SMESH_MeshEditor_i::TSearchersDeleter"),
198                          myMesh(0) {}
199     //!< Delete theNodeSearcher
200     static void Delete()
201     {
202       if ( theNodeSearcher )    delete theNodeSearcher;    theNodeSearcher    = 0;
203       if ( theElementSearcher ) delete theElementSearcher; theElementSearcher = 0;
204     }
205     typedef map < int, SMESH_subMesh * > TDependsOnMap;
206     //!< The meshod called by submesh: do my main job
207     void ProcessEvent(const int, const int eventType, SMESH_subMesh* sm,
208                       SMESH_subMeshEventListenerData*,const SMESH_Hypothesis*)
209     {
210       if ( eventType == SMESH_subMesh::COMPUTE_EVENT ) {
211         Delete();
212         Unset( sm->GetFather() );
213       }
214     }
215     //!< set self on all submeshes and delete theNodeSearcher if other mesh is set
216     void Set(SMESH_Mesh* mesh, const string& meshPartIOR = string())
217     {
218       if ( myMesh != mesh || myMeshPartIOR != meshPartIOR)
219       {
220         if ( myMesh ) {
221           Delete();
222           Unset( myMesh );
223         }
224         myMesh = mesh;
225         myMeshPartIOR = meshPartIOR;
226         SMESH_subMesh* sm = mesh->GetSubMesh( mesh->GetShapeToMesh() );
227         SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator( /*includeSelf=*/true );
228         while ( smIt->more() )
229         {
230           sm = smIt->next();
231           sm->SetEventListener( this, 0, sm );
232         }
233       }
234     }
235     //!<  delete self from all submeshes
236     void Unset(SMESH_Mesh* mesh)
237     {
238       if ( SMESH_subMesh* sm = mesh->GetSubMeshContaining(1) ) {
239         SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator( /*includeSelf=*/true );
240         while ( smIt->more() )
241           smIt->next()->DeleteEventListener( this );
242       }
243       myMesh = 0;
244     }
245
246   } theSearchersDeleter;
247
248   TCollection_AsciiString mirrorTypeName( SMESH::SMESH_MeshEditor::MirrorType theMirrorType )
249   {
250     TCollection_AsciiString typeStr;
251     switch ( theMirrorType ) {
252     case  SMESH::SMESH_MeshEditor::POINT:
253       typeStr = "SMESH.SMESH_MeshEditor.POINT";
254       break;
255     case  SMESH::SMESH_MeshEditor::AXIS:
256       typeStr = "SMESH.SMESH_MeshEditor.AXIS";
257       break;
258     default:
259       typeStr = "SMESH.SMESH_MeshEditor.PLANE";
260     }
261     return typeStr;
262   }
263   //================================================================================
264   /*!
265    * \brief function for conversion of long_array to TIDSortedElemSet
266    * \param IDs - array of IDs
267    * \param aMesh - mesh
268    * \param aMap - collection to fill
269    * \param aType - element type
270    */
271   //================================================================================
272
273   void arrayToSet(const SMESH::long_array & IDs,
274                   const SMESHDS_Mesh*       aMesh,
275                   TIDSortedElemSet&         aMap,
276                   const SMDSAbs_ElementType aType = SMDSAbs_All,
277                   SMDS_MeshElement::Filter* aFilter = NULL)
278   {
279     SMDS_MeshElement::NonNullFilter filter1;
280     SMDS_MeshElement::TypeFilter    filter2( aType );
281
282     if ( aFilter == NULL )
283       aFilter = ( aType == SMDSAbs_All ) ? (SMDS_MeshElement::Filter*) &filter1 : (SMDS_MeshElement::Filter*) &filter2;
284     
285     SMDS_MeshElement::Filter & filter = *aFilter;
286
287     if ( aType == SMDSAbs_Node )
288       for (int i=0; i<IDs.length(); i++) {
289         const SMDS_MeshElement * elem = aMesh->FindNode( IDs[i] );
290         if ( filter( elem ))
291           aMap.insert( aMap.end(), elem );
292       }
293     else
294       for (int i=0; i<IDs.length(); i++) {
295         const SMDS_MeshElement * elem = aMesh->FindElement( IDs[i] );
296         if ( filter( elem ))
297           aMap.insert( aMap.end(), elem );
298       }
299   }
300
301   //================================================================================
302   /*!
303    * \brief Retrieve nodes from SMESH_IDSource
304    */
305   //================================================================================
306
307   void idSourceToNodeSet(SMESH::SMESH_IDSource_ptr  theObject,
308                          const SMESHDS_Mesh*        theMeshDS,
309                          TIDSortedNodeSet&          theNodeSet)
310
311   {
312     if ( CORBA::is_nil( theObject ) )
313       return;
314     SMESH::array_of_ElementType_var types = theObject->GetTypes();
315     SMESH::long_array_var     aElementsId = theObject->GetIDs();
316     if ( types->length() == 1 && types[0] == SMESH::NODE)
317     {
318       for(int i = 0; i < aElementsId->length(); i++)
319         if ( const SMDS_MeshNode * n = theMeshDS->FindNode( aElementsId[i] ))
320           theNodeSet.insert( theNodeSet.end(), n);
321     }
322     else if ( SMESH::DownCast<SMESH_Mesh_i*>( theObject ))
323     {
324       SMDS_NodeIteratorPtr nIt = theMeshDS->nodesIterator();
325       while ( nIt->more( ))
326         if( const SMDS_MeshElement * elem = nIt->next() )
327           theNodeSet.insert( elem->begin_nodes(), elem->end_nodes());
328     }
329     else
330     {
331       for(int i = 0; i < aElementsId->length(); i++)
332         if( const SMDS_MeshElement * elem = theMeshDS->FindElement( aElementsId[i] ))
333           theNodeSet.insert( elem->begin_nodes(), elem->end_nodes());
334     }
335   }
336
337   //================================================================================
338   /*!
339    * \brief Returns elements connected to the given elements
340    */
341   //================================================================================
342
343   void getElementsAround(const TIDSortedElemSet& theElements,
344                          const SMESHDS_Mesh*     theMeshDS,
345                          TIDSortedElemSet&       theElementsAround)
346   {
347     if ( theElements.empty() ) return;
348
349     SMDSAbs_ElementType elemType    = (*theElements.begin())->GetType();
350     bool sameElemType = ( elemType == (*theElements.rbegin())->GetType() );
351     if ( sameElemType &&
352          theMeshDS->GetMeshInfo().NbElements( elemType ) == theElements.size() )
353       return; // all the elements are in theElements
354
355     if ( !sameElemType )
356       elemType = SMDSAbs_All;
357
358     vector<bool> isNodeChecked( theMeshDS->NbNodes(), false );
359
360     TIDSortedElemSet::const_iterator elemIt = theElements.begin();
361     for ( ; elemIt != theElements.end(); ++elemIt )
362     {
363       const SMDS_MeshElement* e = *elemIt;
364       int i = e->NbCornerNodes();
365       while ( --i != -1 )
366       {
367         const SMDS_MeshNode* n = e->GetNode( i );
368         if ( !isNodeChecked[ n->GetID() ])
369         {
370           isNodeChecked[ n->GetID() ] = true;
371           SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator(elemType);
372           while ( invIt->more() )
373           {
374             const SMDS_MeshElement* elemAround = invIt->next();
375             if ( !theElements.count( elemAround ))
376               theElementsAround.insert( elemAround );
377           }
378         }
379       }
380     }
381   }
382
383   //================================================================================
384   /*!
385    * \brief Return a string used to detect change of mesh part on which theElementSearcher
386    * is going to be used
387    */
388   //================================================================================
389
390   string getPartIOR( SMESH::SMESH_IDSource_ptr theMeshPart, SMESH::ElementType type)
391   {
392     string partIOR = SMESH_Gen_i::GetORB()->object_to_string( theMeshPart );
393     if ( SMESH_Group_i* group_i = SMESH::DownCast<SMESH_Group_i*>( theMeshPart ))
394       // take into account passible group modification
395       partIOR += SMESH_Comment( ((SMESHDS_Group*)group_i->GetGroupDS())->SMDSGroup().Tic() );
396     partIOR += SMESH_Comment( type );
397     return partIOR;
398   }
399
400 } // namespace MeshEditor_I
401
402 using namespace MeshEditor_I;
403
404 //=============================================================================
405 /*!
406  *
407  */
408 //=============================================================================
409
410 SMESH_MeshEditor_i::SMESH_MeshEditor_i(SMESH_Mesh_i* theMesh, bool isPreview):
411   myMesh_i( theMesh ),
412   myMesh( &theMesh->GetImpl() ),
413   myEditor( myMesh ),
414   myIsPreviewMode ( isPreview ),
415   myPreviewMesh( 0 ),
416   myPreviewEditor( 0 )
417 {
418 }
419
420 //================================================================================
421 /*!
422  * \brief Destructor
423  */
424 //================================================================================
425
426 SMESH_MeshEditor_i::~SMESH_MeshEditor_i()
427 {
428   PortableServer::POA_var poa = SMESH_Gen_i::GetPOA();
429   PortableServer::ObjectId_var anObjectId = poa->servant_to_id(this);
430   poa->deactivate_object(anObjectId.in());
431
432   //deleteAuxIDSources();
433   delete myPreviewMesh;   myPreviewMesh = 0;
434   delete myPreviewEditor; myPreviewEditor = 0;
435 }
436
437 //================================================================================
438 /*!
439  * \brief Returns the mesh
440  */
441 //================================================================================
442
443 SMESH::SMESH_Mesh_ptr SMESH_MeshEditor_i::GetMesh()
444 {
445   return myMesh_i->_this();
446 }
447
448 //================================================================================
449 /*!
450  * \brief Clear members
451  */
452 //================================================================================
453
454 void SMESH_MeshEditor_i::initData(bool deleteSearchers)
455 {
456   if ( myIsPreviewMode ) {
457     if ( myPreviewMesh ) myPreviewMesh->RemoveAll();
458   }
459   else {
460     if ( deleteSearchers )
461       TSearchersDeleter::Delete();
462   }
463   getEditor().GetError().reset();
464   getEditor().ClearLastCreated();
465 }
466
467 //================================================================================
468 /*!
469  * \brief Increment mesh modif time and optionally record that the performed
470  *        modification may influence futher mesh re-compute.
471  *  \param [in] isReComputeSafe - true if the modification does not influence
472  *              futher mesh re-compute
473  */
474 //================================================================================
475
476 void SMESH_MeshEditor_i::declareMeshModified( bool isReComputeSafe )
477 {
478   myMesh->GetMeshDS()->Modified();
479   if ( !isReComputeSafe )
480     myMesh->SetIsModified( true );
481 }
482
483 //================================================================================
484 /*!
485  * \brief Return either myEditor or myPreviewEditor depending on myIsPreviewMode.
486  *        WARNING: in preview mode call getPreviewMesh() before getEditor()!
487  */
488 //================================================================================
489
490 ::SMESH_MeshEditor& SMESH_MeshEditor_i::getEditor()
491 {
492   if ( myIsPreviewMode && !myPreviewEditor ) {
493     if ( !myPreviewMesh ) getPreviewMesh();
494     myPreviewEditor = new ::SMESH_MeshEditor( myPreviewMesh );
495   }
496   return myIsPreviewMode ? *myPreviewEditor : myEditor;
497 }
498
499 //================================================================================
500 /*!
501  * \brief Initialize and return myPreviewMesh
502  *  \param previewElements - type of elements to show in preview
503  *
504  *  WARNING: call it once par a method!
505  */
506 //================================================================================
507
508 TPreviewMesh * SMESH_MeshEditor_i::getPreviewMesh(SMDSAbs_ElementType previewElements)
509 {
510   if ( !myPreviewMesh || myPreviewMesh->myPreviewType != previewElements )
511   {
512     delete myPreviewEditor;
513     myPreviewEditor = 0;
514     delete myPreviewMesh;
515     myPreviewMesh = new TPreviewMesh( previewElements );
516   }
517   myPreviewMesh->Clear();
518   return myPreviewMesh;
519 }
520
521 //================================================================================
522 /*!
523  * Return data of mesh edition preview
524  */
525 //================================================================================
526
527 SMESH::MeshPreviewStruct* SMESH_MeshEditor_i::GetPreviewData()
528   throw (SALOME::SALOME_Exception)
529 {
530   SMESH_TRY;
531   const bool hasBadElems = ( getEditor().GetError() && getEditor().GetError()->HasBadElems() );
532
533   if ( myIsPreviewMode || hasBadElems ) { // --- MeshPreviewStruct filling ---
534
535     list<int> aNodesConnectivity;
536     typedef map<int, int> TNodesMap;
537     TNodesMap nodesMap;
538
539     SMESHDS_Mesh* aMeshDS;
540     std::auto_ptr< SMESH_MeshPartDS > aMeshPartDS;
541     if ( hasBadElems ) {
542       aMeshPartDS.reset( new SMESH_MeshPartDS( getEditor().GetError()->myBadElements ));
543       aMeshDS = aMeshPartDS.get();
544     }
545     else {
546       aMeshDS = getEditor().GetMeshDS();
547     }
548     myPreviewData = new SMESH::MeshPreviewStruct();
549     myPreviewData->nodesXYZ.length(aMeshDS->NbNodes());
550
551
552     SMDSAbs_ElementType previewType = SMDSAbs_All;
553     if ( !hasBadElems )
554       if (TPreviewMesh * aPreviewMesh = dynamic_cast< TPreviewMesh* >( getEditor().GetMesh() )) {
555         previewType = aPreviewMesh->myPreviewType;
556         switch ( previewType ) {
557         case SMDSAbs_Edge  : break;
558         case SMDSAbs_Face  : break;
559         case SMDSAbs_Volume: break;
560         default:;
561           if ( aMeshDS->GetMeshInfo().NbElements() == 0 ) previewType = SMDSAbs_Node;
562         }
563       }
564
565     myPreviewData->elementTypes.length( aMeshDS->GetMeshInfo().NbElements( previewType ));
566     int i = 0, j = 0;
567     SMDS_ElemIteratorPtr itMeshElems = aMeshDS->elementsIterator(previewType);
568
569     while ( itMeshElems->more() ) {
570       const SMDS_MeshElement* aMeshElem = itMeshElems->next();
571       SMDS_NodeIteratorPtr itElemNodes = 
572         (( aMeshElem->GetEntityType() == SMDSEntity_Quad_Polygon ) ?
573          aMeshElem->interlacedNodesIterator() :
574          aMeshElem->nodeIterator() );
575       while ( itElemNodes->more() ) {
576         const SMDS_MeshNode* aMeshNode = itElemNodes->next();
577         int aNodeID = aMeshNode->GetID();
578         TNodesMap::iterator anIter = nodesMap.find(aNodeID);
579         if ( anIter == nodesMap.end() ) {
580           // filling the nodes coordinates
581           myPreviewData->nodesXYZ[j].x = aMeshNode->X();
582           myPreviewData->nodesXYZ[j].y = aMeshNode->Y();
583           myPreviewData->nodesXYZ[j].z = aMeshNode->Z();
584           anIter = nodesMap.insert( make_pair(aNodeID, j) ).first;
585           j++;
586         }
587         aNodesConnectivity.push_back(anIter->second);
588       }
589
590       // filling the elements types
591       SMDSAbs_ElementType aType = aMeshElem->GetType();
592       bool               isPoly = aMeshElem->IsPoly();
593       myPreviewData->elementTypes[i].SMDS_ElementType = (SMESH::ElementType) aType;
594       myPreviewData->elementTypes[i].isPoly           = isPoly;
595       myPreviewData->elementTypes[i].nbNodesInElement = aMeshElem->NbNodes();
596       i++;
597     }
598     myPreviewData->nodesXYZ.length( j );
599
600     // filling the elements connectivities
601     list<int>::iterator aConnIter = aNodesConnectivity.begin();
602     myPreviewData->elementConnectivities.length(aNodesConnectivity.size());
603     for( int i = 0; aConnIter != aNodesConnectivity.end(); aConnIter++, i++ )
604       myPreviewData->elementConnectivities[i] = *aConnIter;
605   }
606   return myPreviewData._retn();
607
608   SMESH_CATCH( SMESH::throwCorbaException );
609   return 0;
610 }
611
612 //================================================================================
613 /*!
614  * \brief Returns list of it's IDs of created nodes
615  * \retval SMESH::long_array* - list of node ID
616  */
617 //================================================================================
618
619 SMESH::long_array* SMESH_MeshEditor_i::GetLastCreatedNodes()
620   throw (SALOME::SALOME_Exception)
621 {
622   SMESH_TRY;
623   SMESH::long_array_var myLastCreatedNodes = new SMESH::long_array();
624
625   const SMESH_SequenceOfElemPtr& aSeq = getEditor().GetLastCreatedNodes();
626   myLastCreatedNodes->length( aSeq.Length() );
627   for (int i = 1; i <= aSeq.Length(); i++)
628     myLastCreatedNodes[i-1] = aSeq.Value(i)->GetID();
629
630   return myLastCreatedNodes._retn();
631   SMESH_CATCH( SMESH::throwCorbaException );
632   return 0;
633 }
634
635 //================================================================================
636 /*!
637  * \brief Returns list of it's IDs of created elements
638  * \retval SMESH::long_array* - list of elements' ID
639  */
640 //================================================================================
641
642 SMESH::long_array* SMESH_MeshEditor_i::GetLastCreatedElems()
643   throw (SALOME::SALOME_Exception)
644 {
645   SMESH_TRY;
646   SMESH::long_array_var myLastCreatedElems = new SMESH::long_array();
647
648   const SMESH_SequenceOfElemPtr& aSeq = getEditor().GetLastCreatedElems();
649   myLastCreatedElems->length( aSeq.Length() );
650   for ( int i = 1; i <= aSeq.Length(); i++ )
651     myLastCreatedElems[i-1] = aSeq.Value(i)->GetID();
652
653   return myLastCreatedElems._retn();
654   SMESH_CATCH( SMESH::throwCorbaException );
655   return 0;
656 }
657
658 //=======================================================================
659 //function : ClearLastCreated
660 //purpose  : Clears sequences of last created elements and nodes 
661 //=======================================================================
662
663 void SMESH_MeshEditor_i::ClearLastCreated() throw (SALOME::SALOME_Exception)
664 {
665   SMESH_TRY;
666   getEditor().ClearLastCreated();
667   SMESH_CATCH( SMESH::throwCorbaException );
668 }
669
670 //=======================================================================
671 /*
672  * Returns description of an error/warning occured during the last operation
673  * WARNING: ComputeError.code >= 100 and no corresponding enum in IDL API
674  */
675 //=======================================================================
676
677 SMESH::ComputeError* SMESH_MeshEditor_i::GetLastError()
678   throw (SALOME::SALOME_Exception)
679 {
680   SMESH_TRY;
681   SMESH::ComputeError_var errOut = new SMESH::ComputeError;
682   SMESH_ComputeErrorPtr&  errIn  = getEditor().GetError();
683   if ( errIn && !errIn->IsOK() )
684   {
685     errOut->code       = -( errIn->myName < 0 ? errIn->myName + 1: errIn->myName ); // -1 -> 0
686     errOut->comment    = errIn->myComment.c_str();
687     errOut->subShapeID = -1;
688     errOut->hasBadMesh = !errIn->myBadElements.empty();
689   }
690   else
691   {
692     errOut->code       = 0;
693     errOut->subShapeID = -1;
694     errOut->hasBadMesh = false;
695   }
696
697   return errOut._retn();
698   SMESH_CATCH( SMESH::throwCorbaException );
699   return 0;
700 }
701
702 //=======================================================================
703 //function : MakeIDSource
704 //purpose  : Wrap a sequence of ids in a SMESH_IDSource.
705 //           Call UnRegister() as you fininsh using it!!
706 //=======================================================================
707
708 struct SMESH_MeshEditor_i::_IDSource : public virtual POA_SMESH::SMESH_IDSource,
709                                        public virtual SALOME::GenericObj_i
710 {
711   SMESH::long_array     _ids;
712   SMESH::ElementType    _type;
713   SMESH::SMESH_Mesh_ptr _mesh;
714   SMESH::long_array* GetIDs()      { return new SMESH::long_array( _ids ); }
715   SMESH::long_array* GetMeshInfo() { return 0; }
716   SMESH::long_array* GetNbElementsByType()
717   {
718     SMESH::long_array_var aRes = new SMESH::long_array();
719     aRes->length(SMESH::NB_ELEMENT_TYPES);
720     for (int i = 0; i < SMESH::NB_ELEMENT_TYPES; i++)
721       aRes[ i ] = ( i == _type ) ? _ids.length() : 0;
722     return aRes._retn();  
723   }
724   SMESH::SMESH_Mesh_ptr GetMesh()  { return SMESH::SMESH_Mesh::_duplicate( _mesh ); }
725   bool IsMeshInfoCorrect()         { return true; }
726   SMESH::array_of_ElementType* GetTypes()
727   {
728     SMESH::array_of_ElementType_var types = new SMESH::array_of_ElementType;
729     if ( _ids.length() > 0 ) {
730       types->length( 1 );
731       types[0] = _type;
732     }
733     return types._retn();
734   }
735   SALOMEDS::TMPFile* GetVtkUgStream()
736   {
737     SALOMEDS::TMPFile_var SeqFile;
738     return SeqFile._retn();
739   }
740 };
741
742 SMESH::SMESH_IDSource_ptr SMESH_MeshEditor_i::MakeIDSource(const SMESH::long_array& ids,
743                                                            SMESH::ElementType       type)
744 {
745   _IDSource* idSrc = new _IDSource;
746   idSrc->_mesh = myMesh_i->_this();
747   idSrc->_ids  = ids;
748   idSrc->_type = type;
749   if ( type == SMESH::ALL && ids.length() > 0 )
750     idSrc->_type = myMesh_i->GetElementType( ids[0], true );
751
752   SMESH::SMESH_IDSource_var anIDSourceVar = idSrc->_this();
753
754   return anIDSourceVar._retn();
755 }
756
757 bool SMESH_MeshEditor_i::IsTemporaryIDSource( SMESH::SMESH_IDSource_ptr& idSource )
758 {
759   return SMESH::DownCast<SMESH_MeshEditor_i::_IDSource*>( idSource );
760 }
761
762 CORBA::Long* SMESH_MeshEditor_i::GetTemporaryIDs( SMESH::SMESH_IDSource_ptr& idSource,
763                                                   int&                       nbIds)
764 {
765   if ( _IDSource* tmpIdSource = SMESH::DownCast<SMESH_MeshEditor_i::_IDSource*>( idSource ))
766   {
767     nbIds = (int) tmpIdSource->_ids.length();
768     return & tmpIdSource->_ids[0];
769   }
770   nbIds = 0;
771   return 0;
772 }
773
774 // void SMESH_MeshEditor_i::deleteAuxIDSources()
775 // {
776 //   std::list< _IDSource* >::iterator idSrcIt = myAuxIDSources.begin();
777 //   for ( ; idSrcIt != myAuxIDSources.end(); ++idSrcIt )
778 //     delete *idSrcIt;
779 //   myAuxIDSources.clear();
780 // }
781
782 //=============================================================================
783 /*!
784  *
785  */
786 //=============================================================================
787
788 CORBA::Boolean
789 SMESH_MeshEditor_i::RemoveElements(const SMESH::long_array & IDsOfElements)
790   throw (SALOME::SALOME_Exception)
791 {
792   SMESH_TRY;
793   initData();
794
795   list< int > IdList;
796
797   for (int i = 0; i < IDsOfElements.length(); i++)
798     IdList.push_back( IDsOfElements[i] );
799
800   // Update Python script
801   TPythonDump() << "isDone = " << this << ".RemoveElements( " << IDsOfElements << " )";
802
803   // Remove Elements
804   bool ret = getEditor().Remove( IdList, false );
805
806   declareMeshModified( /*isReComputeSafe=*/ IDsOfElements.length() == 0 ); // issue 0020693
807   return ret;
808
809   SMESH_CATCH( SMESH::throwCorbaException );
810   return 0;
811 }
812
813 //=============================================================================
814 /*!
815  *
816  */
817 //=============================================================================
818
819 CORBA::Boolean SMESH_MeshEditor_i::RemoveNodes(const SMESH::long_array & IDsOfNodes)
820   throw (SALOME::SALOME_Exception)
821 {
822   SMESH_TRY;
823   initData();
824
825   list< int > IdList;
826   for (int i = 0; i < IDsOfNodes.length(); i++)
827     IdList.push_back( IDsOfNodes[i] );
828
829   // Update Python script
830   TPythonDump() << "isDone = " << this << ".RemoveNodes( " << IDsOfNodes << " )";
831
832   bool ret = getEditor().Remove( IdList, true );
833
834   declareMeshModified( /*isReComputeSafe=*/ !ret ); // issue 0020693
835   return ret;
836
837   SMESH_CATCH( SMESH::throwCorbaException );
838   return 0;
839 }
840
841 //=============================================================================
842 /*!
843  *
844  */
845 //=============================================================================
846
847 CORBA::Long SMESH_MeshEditor_i::RemoveOrphanNodes()
848   throw (SALOME::SALOME_Exception)
849 {
850   SMESH_TRY;
851   initData();
852
853   // Update Python script
854   TPythonDump() << "nbRemoved = " << this << ".RemoveOrphanNodes()";
855
856   // Create filter to find all orphan nodes
857   SMESH::Controls::Filter::TIdSequence seq;
858   SMESH::Controls::PredicatePtr predicate( new SMESH::Controls::FreeNodes() );
859   SMESH::Controls::Filter::GetElementsId( getMeshDS(), predicate, seq );
860
861   // remove orphan nodes (if there are any)
862   list< int > IdList;
863   for ( int i = 0; i < seq.size(); i++ )
864     IdList.push_back( seq[i] );
865
866   int nbNodesBefore = myMesh->NbNodes();
867   getEditor().Remove( IdList, true );
868   int nbNodesAfter = myMesh->NbNodes();
869
870   declareMeshModified( /*isReComputeSafe=*/ IdList.size() == 0 ); // issue 0020693
871   return nbNodesBefore - nbNodesAfter;
872
873   SMESH_CATCH( SMESH::throwCorbaException );
874   return 0;
875 }
876
877 //=============================================================================
878 /*!
879  * Add a new node.
880  */
881 //=============================================================================
882
883 CORBA::Long SMESH_MeshEditor_i::AddNode(CORBA::Double x,CORBA::Double y, CORBA::Double z)
884   throw (SALOME::SALOME_Exception)
885 {
886   SMESH_TRY;
887   initData();
888
889   const SMDS_MeshNode* N = getMeshDS()->AddNode(x, y, z);
890
891   // Update Python script
892   TPythonDump() << "nodeID = " << this << ".AddNode( "
893                 << TVar( x ) << ", " << TVar( y ) << ", " << TVar( z )<< " )";
894
895   declareMeshModified( /*isReComputeSafe=*/false );
896   return N->GetID();
897
898   SMESH_CATCH( SMESH::throwCorbaException );
899   return 0;
900 }
901
902 //=============================================================================
903 /*!
904  * Create 0D element on the given node.
905  */
906 //=============================================================================
907
908 CORBA::Long SMESH_MeshEditor_i::Add0DElement(CORBA::Long IDOfNode)
909   throw (SALOME::SALOME_Exception)
910 {
911   SMESH_TRY;
912   initData();
913
914   const SMDS_MeshNode* aNode = getMeshDS()->FindNode(IDOfNode);
915   SMDS_MeshElement* elem = getMeshDS()->Add0DElement(aNode);
916
917   // Update Python script
918   TPythonDump() << "elem0d = " << this << ".Add0DElement( " << IDOfNode <<" )";
919
920   declareMeshModified( /*isReComputeSafe=*/false );
921
922   return elem ? elem->GetID() : 0;
923
924   SMESH_CATCH( SMESH::throwCorbaException );
925   return 0;
926 }
927
928 //=============================================================================
929 /*!
930  * Create a ball element on the given node.
931  */
932 //=============================================================================
933
934 CORBA::Long SMESH_MeshEditor_i::AddBall(CORBA::Long IDOfNode, CORBA::Double diameter)
935   throw (SALOME::SALOME_Exception)
936 {
937   SMESH_TRY;
938   initData();
939
940   if ( diameter < std::numeric_limits<double>::min() )
941     THROW_SALOME_CORBA_EXCEPTION("Invalid diameter", SALOME::BAD_PARAM);
942
943   const SMDS_MeshNode* aNode = getMeshDS()->FindNode(IDOfNode);
944   SMDS_MeshElement* elem = getMeshDS()->AddBall(aNode, diameter);
945
946   // Update Python script
947   TPythonDump() << "ballElem = "
948                 << this << ".AddBall( " << IDOfNode << ", " << diameter <<" )";
949
950   declareMeshModified( /*isReComputeSafe=*/false );
951   return elem ? elem->GetID() : 0;
952
953   SMESH_CATCH( SMESH::throwCorbaException );
954   return 0;
955 }
956
957 //=============================================================================
958 /*!
959  * Create an edge, either linear and quadratic (this is determed
960  *  by number of given nodes, two or three)
961  */
962 //=============================================================================
963
964 CORBA::Long SMESH_MeshEditor_i::AddEdge(const SMESH::long_array & IDsOfNodes)
965   throw (SALOME::SALOME_Exception)
966 {
967   SMESH_TRY;
968   initData();
969
970   int NbNodes = IDsOfNodes.length();
971   SMDS_MeshElement* elem = 0;
972   if (NbNodes == 2)
973   {
974     CORBA::Long index1 = IDsOfNodes[0];
975     CORBA::Long index2 = IDsOfNodes[1];
976     elem = getMeshDS()->AddEdge( getMeshDS()->FindNode(index1),
977                                  getMeshDS()->FindNode(index2));
978
979     // Update Python script
980     TPythonDump() << "edge = " << this << ".AddEdge([ "
981                   << index1 << ", " << index2 <<" ])";
982   }
983   if (NbNodes == 3) {
984     CORBA::Long n1 = IDsOfNodes[0];
985     CORBA::Long n2 = IDsOfNodes[1];
986     CORBA::Long n12 = IDsOfNodes[2];
987     elem = getMeshDS()->AddEdge( getMeshDS()->FindNode(n1),
988                                  getMeshDS()->FindNode(n2),
989                                  getMeshDS()->FindNode(n12));
990     // Update Python script
991     TPythonDump() << "edgeID = " << this << ".AddEdge([ "
992                   <<n1<<", "<<n2<<", "<<n12<<" ])";
993   }
994
995   declareMeshModified( /*isReComputeSafe=*/false );
996   return elem ? elem->GetID() : 0;
997
998   SMESH_CATCH( SMESH::throwCorbaException );
999   return 0;
1000 }
1001
1002 //=============================================================================
1003 /*!
1004  *  AddFace
1005  */
1006 //=============================================================================
1007
1008 CORBA::Long SMESH_MeshEditor_i::AddFace(const SMESH::long_array & IDsOfNodes)
1009   throw (SALOME::SALOME_Exception)
1010 {
1011   SMESH_TRY;
1012   initData();
1013
1014   int NbNodes = IDsOfNodes.length();
1015   if (NbNodes < 3)
1016   {
1017     return 0;
1018   }
1019
1020   std::vector<const SMDS_MeshNode*> nodes (NbNodes);
1021   for (int i = 0; i < NbNodes; i++)
1022     nodes[i] = getMeshDS()->FindNode(IDsOfNodes[i]);
1023
1024   SMDS_MeshElement* elem = 0;
1025   switch (NbNodes) {
1026   case 3: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2]); break;
1027   case 4: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3]); break;
1028   case 6: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
1029                                       nodes[4], nodes[5]); break;
1030   case 7: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
1031                                       nodes[4], nodes[5], nodes[6]); break;
1032   case 8: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
1033                                       nodes[4], nodes[5], nodes[6], nodes[7]); break;
1034   case 9: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
1035                                       nodes[4], nodes[5], nodes[6], nodes[7],
1036                                       nodes[8] ); break;
1037   default: elem = getMeshDS()->AddPolygonalFace(nodes);
1038   }
1039
1040   // Update Python script
1041   TPythonDump() << "faceID = " << this << ".AddFace( " << IDsOfNodes << " )";
1042
1043   declareMeshModified( /*isReComputeSafe=*/false );
1044
1045   return elem ? elem->GetID() : 0;
1046
1047   SMESH_CATCH( SMESH::throwCorbaException );
1048   return 0;
1049 }
1050
1051 //=============================================================================
1052 /*!
1053  *  AddPolygonalFace
1054  */
1055 //=============================================================================
1056
1057 CORBA::Long SMESH_MeshEditor_i::AddPolygonalFace (const SMESH::long_array & IDsOfNodes)
1058   throw (SALOME::SALOME_Exception)
1059 {
1060   SMESH_TRY;
1061   initData();
1062
1063   int NbNodes = IDsOfNodes.length();
1064   std::vector<const SMDS_MeshNode*> nodes (NbNodes);
1065   for (int i = 0; i < NbNodes; i++)
1066     nodes[i] = getMeshDS()->FindNode(IDsOfNodes[i]);
1067
1068   const SMDS_MeshElement* elem = getMeshDS()->AddPolygonalFace(nodes);
1069
1070   // Update Python script
1071   TPythonDump() <<"faceID = "<<this<<".AddPolygonalFace( "<<IDsOfNodes<<" )";
1072
1073   declareMeshModified( /*isReComputeSafe=*/false );
1074   return elem ? elem->GetID() : 0;
1075
1076   SMESH_CATCH( SMESH::throwCorbaException );
1077   return 0;
1078 }
1079
1080 //=============================================================================
1081 /*!
1082  *  AddQuadPolygonalFace
1083  */
1084 //=============================================================================
1085
1086 CORBA::Long SMESH_MeshEditor_i::AddQuadPolygonalFace (const SMESH::long_array & IDsOfNodes)
1087   throw (SALOME::SALOME_Exception)
1088 {
1089   SMESH_TRY;
1090   initData();
1091
1092   int NbNodes = IDsOfNodes.length();
1093   std::vector<const SMDS_MeshNode*> nodes (NbNodes);
1094   for (int i = 0; i < NbNodes; i++)
1095     nodes[i] = getMeshDS()->FindNode(IDsOfNodes[i]);
1096
1097   const SMDS_MeshElement* elem = getMeshDS()->AddQuadPolygonalFace(nodes);
1098
1099   // Update Python script
1100   TPythonDump() <<"faceID = "<<this<<".AddPolygonalFace( "<<IDsOfNodes<<" )";
1101
1102   declareMeshModified( /*isReComputeSafe=*/false );
1103   return elem ? elem->GetID() : 0;
1104
1105   SMESH_CATCH( SMESH::throwCorbaException );
1106   return 0;
1107 }
1108
1109 //=============================================================================
1110 /*!
1111  * Create volume, either linear and quadratic (this is determed
1112  *  by number of given nodes)
1113  */
1114 //=============================================================================
1115
1116 CORBA::Long SMESH_MeshEditor_i::AddVolume(const SMESH::long_array & IDsOfNodes)
1117   throw (SALOME::SALOME_Exception)
1118 {
1119   SMESH_TRY;
1120   initData();
1121
1122   int NbNodes = IDsOfNodes.length();
1123   vector< const SMDS_MeshNode*> n(NbNodes);
1124   for(int i=0;i<NbNodes;i++)
1125     n[i]= getMeshDS()->FindNode(IDsOfNodes[i]);
1126
1127   SMDS_MeshElement* elem = 0;
1128   switch(NbNodes)
1129   {
1130   case 4 :elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3]); break;
1131   case 5 :elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4]); break;
1132   case 6 :elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5]); break;
1133   case 8 :elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7]); break;
1134   case 10:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],
1135                                         n[6],n[7],n[8],n[9]);
1136     break;
1137   case 12:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],
1138                                         n[6],n[7],n[8],n[9],n[10],n[11]);
1139     break;
1140   case 13:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],
1141                                         n[7],n[8],n[9],n[10],n[11],n[12]);
1142     break;
1143   case 15:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7],n[8],
1144                                         n[9],n[10],n[11],n[12],n[13],n[14]);
1145     break;
1146   case 20:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7],
1147                                         n[8],n[9],n[10],n[11],n[12],n[13],n[14],
1148                                         n[15],n[16],n[17],n[18],n[19]);
1149     break;
1150   case 27:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7],
1151                                         n[8],n[9],n[10],n[11],n[12],n[13],n[14],
1152                                         n[15],n[16],n[17],n[18],n[19],
1153                                         n[20],n[21],n[22],n[23],n[24],n[25],n[26]);
1154     break;
1155   }
1156
1157   // Update Python script
1158   TPythonDump() << "volID = " << this << ".AddVolume( " << IDsOfNodes << " )";
1159
1160   declareMeshModified( /*isReComputeSafe=*/false );
1161   return elem ? elem->GetID() : 0;
1162
1163   SMESH_CATCH( SMESH::throwCorbaException );
1164   return 0;
1165 }
1166
1167 //=============================================================================
1168 /*!
1169  *  AddPolyhedralVolume
1170  */
1171 //=============================================================================
1172 CORBA::Long SMESH_MeshEditor_i::AddPolyhedralVolume (const SMESH::long_array & IDsOfNodes,
1173                                                      const SMESH::long_array & Quantities)
1174   throw (SALOME::SALOME_Exception)
1175 {
1176   SMESH_TRY;
1177   initData();
1178
1179   int NbNodes = IDsOfNodes.length();
1180   std::vector<const SMDS_MeshNode*> n (NbNodes);
1181   for (int i = 0; i < NbNodes; i++)
1182     {
1183       const SMDS_MeshNode* aNode = getMeshDS()->FindNode(IDsOfNodes[i]);
1184       if (!aNode) return 0;
1185       n[i] = aNode;
1186     }
1187
1188   int NbFaces = Quantities.length();
1189   std::vector<int> q (NbFaces);
1190   for (int j = 0; j < NbFaces; j++)
1191     q[j] = Quantities[j];
1192
1193   const SMDS_MeshElement* elem = getMeshDS()->AddPolyhedralVolume(n, q);
1194
1195   // Update Python script
1196   TPythonDump() << "volID = " << this << ".AddPolyhedralVolume( "
1197                 << IDsOfNodes << ", " << Quantities << " )";
1198
1199   declareMeshModified( /*isReComputeSafe=*/false );
1200   return elem ? elem->GetID() : 0;
1201
1202   SMESH_CATCH( SMESH::throwCorbaException );
1203   return 0;
1204 }
1205
1206 //=============================================================================
1207 /*!
1208  *  AddPolyhedralVolumeByFaces
1209  */
1210 //=============================================================================
1211
1212 CORBA::Long SMESH_MeshEditor_i::AddPolyhedralVolumeByFaces (const SMESH::long_array & IdsOfFaces)
1213   throw (SALOME::SALOME_Exception)
1214 {
1215   SMESH_TRY;
1216   initData();
1217
1218   int NbFaces = IdsOfFaces.length();
1219   std::vector<const SMDS_MeshNode*> poly_nodes;
1220   std::vector<int> quantities (NbFaces);
1221
1222   for (int i = 0; i < NbFaces; i++) {
1223     const SMDS_MeshElement* aFace = getMeshDS()->FindElement(IdsOfFaces[i]);
1224     quantities[i] = aFace->NbNodes();
1225
1226     SMDS_ElemIteratorPtr It = aFace->nodesIterator();
1227     while (It->more()) {
1228       poly_nodes.push_back(static_cast<const SMDS_MeshNode *>(It->next()));
1229     }
1230   }
1231
1232   const SMDS_MeshElement* elem = getMeshDS()->AddPolyhedralVolume(poly_nodes, quantities);
1233
1234   // Update Python script
1235   TPythonDump() << "volID = " << this << ".AddPolyhedralVolumeByFaces( "
1236                 << IdsOfFaces << " )";
1237
1238   declareMeshModified( /*isReComputeSafe=*/false );
1239   return elem ? elem->GetID() : 0;
1240
1241   SMESH_CATCH( SMESH::throwCorbaException );
1242   return 0;
1243 }
1244
1245 //=============================================================================
1246 //
1247 // \brief Create 0D elements on all nodes of the given object except those 
1248 //        nodes on which a 0D element already exists.
1249 //  \param theObject object on whose nodes 0D elements will be created.
1250 //  \param theGroupName optional name of a group to add 0D elements created
1251 //         and/or found on nodes of \a theObject.
1252 //  \return an object (a new group or a temporary SMESH_IDSource) holding
1253 //          ids of new and/or found 0D elements.
1254 //
1255 //=============================================================================
1256
1257 SMESH::SMESH_IDSource_ptr
1258 SMESH_MeshEditor_i::Create0DElementsOnAllNodes(SMESH::SMESH_IDSource_ptr theObject,
1259                                                const char*               theGroupName)
1260   throw (SALOME::SALOME_Exception)
1261 {
1262   SMESH_TRY;
1263   initData();
1264
1265   SMESH::SMESH_IDSource_var result;
1266   TPythonDump pyDump;
1267
1268   TIDSortedElemSet elements, elems0D;
1269   if ( idSourceToSet( theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
1270     getEditor().Create0DElementsOnAllNodes( elements, elems0D );
1271
1272   SMESH::long_array_var newElems = new SMESH::long_array;
1273   newElems->length( elems0D.size() );
1274   TIDSortedElemSet::iterator eIt = elems0D.begin();
1275   for ( size_t i = 0; i < elems0D.size(); ++i, ++eIt )
1276     newElems[ i ] = (*eIt)->GetID();
1277
1278   SMESH::SMESH_GroupBase_var groupToFill;
1279   if ( theGroupName && strlen( theGroupName ))
1280   {
1281     // Get existing group named theGroupName
1282     SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
1283     for (int i = 0, nbGroups = groups->length(); i < nbGroups; i++ ) {
1284       SMESH::SMESH_GroupBase_var group = groups[i];
1285       if ( !group->_is_nil() ) {
1286         CORBA::String_var name = group->GetName();
1287         if ( strcmp( name.in(), theGroupName ) == 0 && group->GetType() == SMESH::ELEM0D ) {
1288           groupToFill = group;
1289           break;
1290         }
1291       }
1292     }
1293     if ( groupToFill->_is_nil() )
1294       groupToFill = myMesh_i->CreateGroup( SMESH::ELEM0D, theGroupName );
1295     else if ( !SMESH::DownCast< SMESH_Group_i* > ( groupToFill ))
1296       groupToFill = myMesh_i->ConvertToStandalone( groupToFill );
1297   }
1298
1299   if ( SMESH_Group_i* group_i = SMESH::DownCast< SMESH_Group_i* > ( groupToFill ))
1300   {
1301     group_i->Add( newElems );
1302     result = SMESH::SMESH_IDSource::_narrow( groupToFill );
1303     pyDump << groupToFill;
1304   }
1305   else
1306   {
1307     result = MakeIDSource( newElems, SMESH::ELEM0D );
1308     pyDump << "elem0DIDs";
1309   }
1310
1311   pyDump << " = " << this << ".Create0DElementsOnAllNodes( "
1312          << theObject << ", '" << theGroupName << "' )";
1313
1314   return result._retn();
1315
1316   SMESH_CATCH( SMESH::throwCorbaException );
1317   return 0;
1318 }
1319
1320 //=============================================================================
1321 /*!
1322  * \brief Bind a node to a vertex
1323  * \param NodeID - node ID
1324  * \param VertexID - vertex ID available through GEOM_Object.GetSubShapeIndices()[0]
1325  * \retval boolean - false if NodeID or VertexID is invalid
1326  */
1327 //=============================================================================
1328
1329 void SMESH_MeshEditor_i::SetNodeOnVertex(CORBA::Long NodeID, CORBA::Long VertexID)
1330   throw (SALOME::SALOME_Exception)
1331 {
1332   SMESH_TRY;
1333
1334   SMESHDS_Mesh * mesh = getMeshDS();
1335   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
1336   if ( !node )
1337     THROW_SALOME_CORBA_EXCEPTION("Invalid NodeID", SALOME::BAD_PARAM);
1338
1339   if ( mesh->MaxShapeIndex() < VertexID )
1340     THROW_SALOME_CORBA_EXCEPTION("Invalid VertexID", SALOME::BAD_PARAM);
1341
1342   TopoDS_Shape shape = mesh->IndexToShape( VertexID );
1343   if ( shape.ShapeType() != TopAbs_VERTEX )
1344     THROW_SALOME_CORBA_EXCEPTION("Invalid VertexID", SALOME::BAD_PARAM);
1345
1346   mesh->SetNodeOnVertex( node, VertexID );
1347
1348   myMesh->SetIsModified( true );
1349
1350   SMESH_CATCH( SMESH::throwCorbaException );
1351 }
1352
1353 //=============================================================================
1354 /*!
1355  * \brief Store node position on an edge
1356  * \param NodeID - node ID
1357  * \param EdgeID - edge ID available through GEOM_Object.GetSubShapeIndices()[0]
1358  * \param paramOnEdge - parameter on edge where the node is located
1359  * \retval boolean - false if any parameter is invalid
1360  */
1361 //=============================================================================
1362
1363 void SMESH_MeshEditor_i::SetNodeOnEdge(CORBA::Long NodeID, CORBA::Long EdgeID,
1364                                        CORBA::Double paramOnEdge)
1365   throw (SALOME::SALOME_Exception)
1366 {
1367   SMESH_TRY;
1368
1369   SMESHDS_Mesh * mesh = getMeshDS();
1370   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
1371   if ( !node )
1372     THROW_SALOME_CORBA_EXCEPTION("Invalid NodeID", SALOME::BAD_PARAM);
1373
1374   if ( mesh->MaxShapeIndex() < EdgeID )
1375     THROW_SALOME_CORBA_EXCEPTION("Invalid EdgeID", SALOME::BAD_PARAM);
1376
1377   TopoDS_Shape shape = mesh->IndexToShape( EdgeID );
1378   if ( shape.ShapeType() != TopAbs_EDGE )
1379     THROW_SALOME_CORBA_EXCEPTION("Invalid EdgeID", SALOME::BAD_PARAM);
1380
1381   Standard_Real f,l;
1382   BRep_Tool::Range( TopoDS::Edge( shape ), f,l);
1383   if ( paramOnEdge < f || paramOnEdge > l )
1384     THROW_SALOME_CORBA_EXCEPTION("Invalid paramOnEdge", SALOME::BAD_PARAM);
1385
1386   mesh->SetNodeOnEdge( node, EdgeID, paramOnEdge );
1387
1388   myMesh->SetIsModified( true );
1389
1390   SMESH_CATCH( SMESH::throwCorbaException );
1391 }
1392
1393 //=============================================================================
1394 /*!
1395  * \brief Store node position on a face
1396  * \param NodeID - node ID
1397  * \param FaceID - face ID available through GEOM_Object.GetSubShapeIndices()[0]
1398  * \param u - U parameter on face where the node is located
1399  * \param v - V parameter on face where the node is located
1400  * \retval boolean - false if any parameter is invalid
1401  */
1402 //=============================================================================
1403
1404 void SMESH_MeshEditor_i::SetNodeOnFace(CORBA::Long NodeID, CORBA::Long FaceID,
1405                                        CORBA::Double u, CORBA::Double v)
1406   throw (SALOME::SALOME_Exception)
1407 {
1408   SMESH_TRY;
1409   SMESHDS_Mesh * mesh = getMeshDS();
1410   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
1411   if ( !node )
1412     THROW_SALOME_CORBA_EXCEPTION("Invalid NodeID", SALOME::BAD_PARAM);
1413
1414   if ( mesh->MaxShapeIndex() < FaceID )
1415     THROW_SALOME_CORBA_EXCEPTION("Invalid FaceID", SALOME::BAD_PARAM);
1416
1417   TopoDS_Shape shape = mesh->IndexToShape( FaceID );
1418   if ( shape.ShapeType() != TopAbs_FACE )
1419     THROW_SALOME_CORBA_EXCEPTION("Invalid FaceID", SALOME::BAD_PARAM);
1420
1421   BRepAdaptor_Surface surf( TopoDS::Face( shape ));
1422   bool isOut = ( u < surf.FirstUParameter() ||
1423                  u > surf.LastUParameter()  ||
1424                  v < surf.FirstVParameter() ||
1425                  v > surf.LastVParameter() );
1426
1427   if ( isOut ) {
1428 #ifdef _DEBUG_
1429     MESSAGE ( "FACE " << FaceID << " (" << u << "," << v << ") out of "
1430               << " u( " <<  surf.FirstUParameter()
1431               << "," <<  surf.LastUParameter()
1432               << ") v( " <<  surf.FirstVParameter()
1433               << "," <<  surf.LastVParameter() << ")" );
1434 #endif
1435     THROW_SALOME_CORBA_EXCEPTION("Invalid UV", SALOME::BAD_PARAM);
1436   }
1437
1438   mesh->SetNodeOnFace( node, FaceID, u, v );
1439   myMesh->SetIsModified( true );
1440
1441   SMESH_CATCH( SMESH::throwCorbaException );
1442 }
1443
1444 //=============================================================================
1445 /*!
1446  * \brief Bind a node to a solid
1447  * \param NodeID - node ID
1448  * \param SolidID - vertex ID available through GEOM_Object.GetSubShapeIndices()[0]
1449  * \retval boolean - false if NodeID or SolidID is invalid
1450  */
1451 //=============================================================================
1452
1453 void SMESH_MeshEditor_i::SetNodeInVolume(CORBA::Long NodeID, CORBA::Long SolidID)
1454   throw (SALOME::SALOME_Exception)
1455 {
1456   SMESH_TRY;
1457   SMESHDS_Mesh * mesh = getMeshDS();
1458   SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>( mesh->FindNode(NodeID) );
1459   if ( !node )
1460     THROW_SALOME_CORBA_EXCEPTION("Invalid NodeID", SALOME::BAD_PARAM);
1461
1462   if ( mesh->MaxShapeIndex() < SolidID )
1463     THROW_SALOME_CORBA_EXCEPTION("Invalid SolidID", SALOME::BAD_PARAM);
1464
1465   TopoDS_Shape shape = mesh->IndexToShape( SolidID );
1466   if ( shape.ShapeType() != TopAbs_SOLID &&
1467        shape.ShapeType() != TopAbs_SHELL)
1468     THROW_SALOME_CORBA_EXCEPTION("Invalid SolidID", SALOME::BAD_PARAM);
1469
1470   mesh->SetNodeInVolume( node, SolidID );
1471
1472   SMESH_CATCH( SMESH::throwCorbaException );
1473 }
1474
1475 //=============================================================================
1476 /*!
1477  * \brief Bind an element to a shape
1478  * \param ElementID - element ID
1479  * \param ShapeID - shape ID available through GEOM_Object.GetSubShapeIndices()[0]
1480  */
1481 //=============================================================================
1482
1483 void SMESH_MeshEditor_i::SetMeshElementOnShape(CORBA::Long ElementID,
1484                                                CORBA::Long ShapeID)
1485   throw (SALOME::SALOME_Exception)
1486 {
1487   SMESH_TRY;
1488   SMESHDS_Mesh * mesh = getMeshDS();
1489   SMDS_MeshElement* elem = const_cast<SMDS_MeshElement*>(mesh->FindElement(ElementID));
1490   if ( !elem )
1491     THROW_SALOME_CORBA_EXCEPTION("Invalid ElementID", SALOME::BAD_PARAM);
1492
1493   if ( mesh->MaxShapeIndex() < ShapeID || ShapeID < 1 )
1494     THROW_SALOME_CORBA_EXCEPTION("Invalid ShapeID", SALOME::BAD_PARAM);
1495
1496   TopoDS_Shape shape = mesh->IndexToShape( ShapeID );
1497   if ( shape.ShapeType() != TopAbs_EDGE &&
1498        shape.ShapeType() != TopAbs_FACE &&
1499        shape.ShapeType() != TopAbs_SOLID &&
1500        shape.ShapeType() != TopAbs_SHELL )
1501     THROW_SALOME_CORBA_EXCEPTION("Invalid shape type", SALOME::BAD_PARAM);
1502
1503   mesh->SetMeshElementOnShape( elem, ShapeID );
1504
1505   myMesh->SetIsModified( true );
1506
1507   SMESH_CATCH( SMESH::throwCorbaException );
1508 }
1509
1510 //=============================================================================
1511 /*!
1512  *
1513  */
1514 //=============================================================================
1515
1516 CORBA::Boolean SMESH_MeshEditor_i::InverseDiag(CORBA::Long NodeID1,
1517                                                CORBA::Long NodeID2)
1518   throw (SALOME::SALOME_Exception)
1519 {
1520   SMESH_TRY;
1521   initData();
1522
1523   const SMDS_MeshNode * n1 = getMeshDS()->FindNode( NodeID1 );
1524   const SMDS_MeshNode * n2 = getMeshDS()->FindNode( NodeID2 );
1525   if ( !n1 || !n2 )
1526     return false;
1527
1528   // Update Python script
1529   TPythonDump() << "isDone = " << this << ".InverseDiag( "
1530                 << NodeID1 << ", " << NodeID2 << " )";
1531
1532   int ret =  getEditor().InverseDiag ( n1, n2 );
1533
1534   declareMeshModified( /*isReComputeSafe=*/false );
1535   return ret;
1536
1537   SMESH_CATCH( SMESH::throwCorbaException );
1538   return 0;
1539 }
1540
1541 //=============================================================================
1542 /*!
1543  *
1544  */
1545 //=============================================================================
1546
1547 CORBA::Boolean SMESH_MeshEditor_i::DeleteDiag(CORBA::Long NodeID1,
1548                                               CORBA::Long NodeID2)
1549   throw (SALOME::SALOME_Exception)
1550 {
1551   SMESH_TRY;
1552   initData();
1553
1554   const SMDS_MeshNode * n1 = getMeshDS()->FindNode( NodeID1 );
1555   const SMDS_MeshNode * n2 = getMeshDS()->FindNode( NodeID2 );
1556   if ( !n1 || !n2 )
1557     return false;
1558
1559   // Update Python script
1560   TPythonDump() << "isDone = " << this << ".DeleteDiag( "
1561                 << NodeID1 << ", " << NodeID2 <<  " )";
1562
1563
1564   bool stat = getEditor().DeleteDiag ( n1, n2 );
1565
1566   declareMeshModified( /*isReComputeSafe=*/!stat );
1567
1568   return stat;
1569
1570   SMESH_CATCH( SMESH::throwCorbaException );
1571   return 0;
1572 }
1573
1574 //=============================================================================
1575 /*!
1576  *
1577  */
1578 //=============================================================================
1579
1580 CORBA::Boolean SMESH_MeshEditor_i::Reorient(const SMESH::long_array & IDsOfElements)
1581   throw (SALOME::SALOME_Exception)
1582 {
1583   SMESH_TRY;
1584   initData();
1585
1586   for (int i = 0; i < IDsOfElements.length(); i++)
1587   {
1588     CORBA::Long index = IDsOfElements[i];
1589     const SMDS_MeshElement * elem = getMeshDS()->FindElement(index);
1590     if ( elem )
1591       getEditor().Reorient( elem );
1592   }
1593   // Update Python script
1594   TPythonDump() << "isDone = " << this << ".Reorient( " << IDsOfElements << " )";
1595
1596   declareMeshModified( /*isReComputeSafe=*/ IDsOfElements.length() == 0 );
1597   return true;
1598
1599   SMESH_CATCH( SMESH::throwCorbaException );
1600   return 0;
1601 }
1602
1603 //=============================================================================
1604 /*!
1605  *
1606  */
1607 //=============================================================================
1608
1609 CORBA::Boolean SMESH_MeshEditor_i::ReorientObject(SMESH::SMESH_IDSource_ptr theObject)
1610   throw (SALOME::SALOME_Exception)
1611 {
1612   SMESH_TRY;
1613   initData();
1614
1615   TPythonDump aTPythonDump; // suppress dump in Reorient()
1616
1617   prepareIdSource( theObject );
1618
1619   SMESH::long_array_var anElementsId = theObject->GetIDs();
1620   CORBA::Boolean isDone = Reorient(anElementsId);
1621
1622   // Update Python script
1623   aTPythonDump << "isDone = " << this << ".ReorientObject( " << theObject << " )";
1624
1625   declareMeshModified( /*isReComputeSafe=*/ anElementsId->length() == 0 );
1626   return isDone;
1627
1628   SMESH_CATCH( SMESH::throwCorbaException );
1629   return 0;
1630 }
1631
1632 //=======================================================================
1633 //function : Reorient2D
1634 //purpose  : Reorient faces contained in \a the2Dgroup.
1635 //           the2Dgroup   - the mesh or its part to reorient
1636 //           theDirection - desired direction of normal of \a theFace
1637 //           theFace      - ID of face whose orientation is checked.
1638 //           It can be < 1 then \a thePoint is used to find a face.
1639 //           thePoint     - is used to find a face if \a theFace < 1.
1640 //           return number of reoriented elements.
1641 //=======================================================================
1642
1643 CORBA::Long SMESH_MeshEditor_i::Reorient2D(SMESH::SMESH_IDSource_ptr the2Dgroup,
1644                                            const SMESH::DirStruct&   theDirection,
1645                                            CORBA::Long               theFace,
1646                                            const SMESH::PointStruct& thePoint)
1647   throw (SALOME::SALOME_Exception)
1648 {
1649   SMESH_TRY;
1650   initData(/*deleteSearchers=*/false);
1651
1652   TIDSortedElemSet elements;
1653   IDSource_Error error;
1654   idSourceToSet( the2Dgroup, getMeshDS(), elements, SMDSAbs_Face, /*emptyIfIsMesh=*/1, &error );
1655   if ( error == IDSource_EMPTY )
1656     return 0;
1657   if ( error == IDSource_INVALID )
1658     THROW_SALOME_CORBA_EXCEPTION("No faces in given group", SALOME::BAD_PARAM);
1659
1660
1661   const SMDS_MeshElement* face = 0;
1662   if ( theFace > 0 )
1663   {
1664     face = getMeshDS()->FindElement( theFace );
1665     if ( !face )
1666       THROW_SALOME_CORBA_EXCEPTION("Inexistent face given", SALOME::BAD_PARAM);
1667     if ( face->GetType() != SMDSAbs_Face )
1668       THROW_SALOME_CORBA_EXCEPTION("Wrong element type", SALOME::BAD_PARAM);
1669   }
1670   else
1671   {
1672     // create theElementSearcher if needed
1673     theSearchersDeleter.Set( myMesh, getPartIOR( the2Dgroup, SMESH::FACE ));
1674     if ( !theElementSearcher )
1675     {
1676       if ( elements.empty() ) // search in the whole mesh
1677       {
1678         if ( myMesh->NbFaces() == 0 )
1679           THROW_SALOME_CORBA_EXCEPTION("No faces in the mesh", SALOME::BAD_PARAM);
1680
1681         theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() );
1682       }
1683       else
1684       {
1685         typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator > TIter;
1686         SMDS_ElemIteratorPtr elemsIt( new TIter( elements.begin(), elements.end() ));
1687
1688         theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), elemsIt);
1689       }
1690     }
1691     // find a face
1692     gp_Pnt p( thePoint.x, thePoint.y, thePoint.z );
1693     face = theElementSearcher->FindClosestTo( p, SMDSAbs_Face );
1694
1695     if ( !face )
1696       THROW_SALOME_CORBA_EXCEPTION("No face found by point", SALOME::INTERNAL_ERROR );
1697     if ( !elements.empty() && !elements.count( face ))
1698       THROW_SALOME_CORBA_EXCEPTION("Found face is not in the group", SALOME::BAD_PARAM );
1699   }
1700
1701   const SMESH::PointStruct * P = &theDirection.PS;
1702   gp_Vec dirVec( P->x, P->y, P->z );
1703   if ( dirVec.Magnitude() < std::numeric_limits< double >::min() )
1704     THROW_SALOME_CORBA_EXCEPTION("Zero size vector", SALOME::BAD_PARAM);
1705
1706   int nbReori = getEditor().Reorient2D( elements, dirVec, face );
1707
1708   if ( nbReori ) {
1709     declareMeshModified( /*isReComputeSafe=*/false );
1710   }
1711   TPythonDump() << this << ".Reorient2D( "
1712                 << the2Dgroup << ", "
1713                 << theDirection << ", "
1714                 << theFace << ", "
1715                 << thePoint << " )";
1716
1717   return nbReori;
1718
1719   SMESH_CATCH( SMESH::throwCorbaException );
1720   return 0;
1721 }
1722
1723 //=======================================================================
1724 //function : Reorient2DBy3D
1725 //purpose  : Reorient faces basing on orientation of adjacent volumes.
1726 //=======================================================================
1727
1728 CORBA::Long SMESH_MeshEditor_i::Reorient2DBy3D(const SMESH::ListOfIDSources& faceGroups,
1729                                                SMESH::SMESH_IDSource_ptr     volumeGroup,
1730                                                CORBA::Boolean                outsideNormal)
1731   throw (SALOME::SALOME_Exception)
1732 {
1733   SMESH_TRY;
1734   initData();
1735
1736   TIDSortedElemSet volumes;
1737   IDSource_Error volsError;
1738   idSourceToSet( volumeGroup, getMeshDS(), volumes, SMDSAbs_Volume, /*emptyIfMesh=*/1, &volsError);
1739
1740   int nbReori = 0;
1741   for ( size_t i = 0; i < faceGroups.length(); ++i )
1742   {
1743     SMESH::SMESH_IDSource_ptr faceGrp = faceGroups[i].in();
1744
1745     TIDSortedElemSet faces;
1746     IDSource_Error error;
1747     idSourceToSet( faceGrp, getMeshDS(), faces, SMDSAbs_Face, /*emptyIfIsMesh=*/1, &error );
1748     if ( error == IDSource_INVALID && faceGroups.length() == 1 )
1749       THROW_SALOME_CORBA_EXCEPTION("No faces in a given object", SALOME::BAD_PARAM);
1750     if ( error == IDSource_OK && volsError != IDSource_OK )
1751       THROW_SALOME_CORBA_EXCEPTION("No volumes in a given object", SALOME::BAD_PARAM);
1752
1753     nbReori += getEditor().Reorient2DBy3D( faces, volumes, outsideNormal );
1754
1755     if ( error != IDSource_EMPTY && faces.empty() ) // all faces in the mesh treated
1756       break;
1757   }
1758
1759   if ( nbReori ) {
1760     declareMeshModified( /*isReComputeSafe=*/false );
1761   }
1762   TPythonDump() << this << ".Reorient2DBy3D( "
1763                 << faceGroups << ", "
1764                 << volumeGroup << ", "
1765                 << outsideNormal << " )";
1766
1767   return nbReori;
1768
1769   SMESH_CATCH( SMESH::throwCorbaException );
1770   return 0;
1771 }
1772
1773 //=============================================================================
1774 /*!
1775  * \brief Fuse neighbour triangles into quadrangles.
1776  */
1777 //=============================================================================
1778
1779 CORBA::Boolean SMESH_MeshEditor_i::TriToQuad (const SMESH::long_array &   IDsOfElements,
1780                                               SMESH::NumericalFunctor_ptr Criterion,
1781                                               CORBA::Double               MaxAngle)
1782   throw (SALOME::SALOME_Exception)
1783 {
1784   SMESH_TRY;
1785   initData();
1786
1787   SMESHDS_Mesh* aMesh = getMeshDS();
1788   TIDSortedElemSet faces,copyFaces;
1789   SMDS_MeshElement::GeomFilter triaFilter(SMDSGeom_TRIANGLE);
1790   arrayToSet(IDsOfElements, aMesh, faces, SMDSAbs_Face, & triaFilter);
1791   TIDSortedElemSet* workElements = & faces;
1792
1793   if ( myIsPreviewMode ) {
1794     SMDSAbs_ElementType select =  SMDSAbs_Face;
1795     getPreviewMesh( SMDSAbs_Face )->Copy( faces, copyFaces, select );
1796     workElements = & copyFaces;
1797   }
1798
1799   SMESH::NumericalFunctor_i* aNumericalFunctor =
1800     dynamic_cast<SMESH::NumericalFunctor_i*>( SMESH_Gen_i::GetServant( Criterion ).in() );
1801   SMESH::Controls::NumericalFunctorPtr aCrit;
1802   if ( !aNumericalFunctor )
1803     aCrit.reset( new SMESH::Controls::MaxElementLength2D() );
1804   else
1805     aCrit = aNumericalFunctor->GetNumericalFunctor();
1806
1807   if ( !myIsPreviewMode ) {
1808     // Update Python script
1809     TPythonDump() << "isDone = " << this << ".TriToQuad( "
1810                   << IDsOfElements << ", " << aNumericalFunctor << ", " << TVar( MaxAngle ) << " )";
1811   }
1812
1813   bool stat = getEditor().TriToQuad( *workElements, aCrit, MaxAngle );
1814
1815   declareMeshModified( /*isReComputeSafe=*/!stat );
1816   return stat;
1817
1818   SMESH_CATCH( SMESH::throwCorbaException );
1819   return 0;
1820 }
1821
1822 //=============================================================================
1823 /*!
1824  * \brief Fuse neighbour triangles into quadrangles.
1825  */
1826 //=============================================================================
1827
1828 CORBA::Boolean SMESH_MeshEditor_i::TriToQuadObject (SMESH::SMESH_IDSource_ptr   theObject,
1829                                                     SMESH::NumericalFunctor_ptr Criterion,
1830                                                     CORBA::Double               MaxAngle)
1831   throw (SALOME::SALOME_Exception)
1832 {
1833   SMESH_TRY;
1834   initData();
1835
1836   TPythonDump aTPythonDump;  // suppress dump in TriToQuad()
1837
1838   prepareIdSource( theObject );
1839   SMESH::long_array_var anElementsId = theObject->GetIDs();
1840   CORBA::Boolean isDone = TriToQuad(anElementsId, Criterion, MaxAngle);
1841
1842   if ( !myIsPreviewMode ) {
1843     SMESH::NumericalFunctor_i* aNumericalFunctor =
1844       SMESH::DownCast<SMESH::NumericalFunctor_i*>( Criterion );
1845
1846     // Update Python script
1847     aTPythonDump << "isDone = " << this << ".TriToQuadObject("
1848                  << theObject << ", " << aNumericalFunctor << ", " << TVar( MaxAngle ) << " )";
1849   }
1850
1851   return isDone;
1852
1853   SMESH_CATCH( SMESH::throwCorbaException );
1854   return 0;
1855 }
1856
1857 //=============================================================================
1858 /*!
1859  * \brief Split quadrangles into triangles.
1860  */
1861 //=============================================================================
1862
1863 CORBA::Boolean SMESH_MeshEditor_i::QuadToTri (const SMESH::long_array &   IDsOfElements,
1864                                               SMESH::NumericalFunctor_ptr Criterion)
1865   throw (SALOME::SALOME_Exception)
1866 {
1867   SMESH_TRY;
1868   initData();
1869
1870   SMESHDS_Mesh* aMesh = getMeshDS();
1871   TIDSortedElemSet faces;
1872   arrayToSet(IDsOfElements, aMesh, faces, SMDSAbs_Face);
1873
1874   SMESH::NumericalFunctor_i* aNumericalFunctor =
1875     dynamic_cast<SMESH::NumericalFunctor_i*>( SMESH_Gen_i::GetServant( Criterion ).in() );
1876   SMESH::Controls::NumericalFunctorPtr aCrit;
1877   if ( !aNumericalFunctor )
1878     aCrit.reset( new SMESH::Controls::AspectRatio() );
1879   else
1880     aCrit = aNumericalFunctor->GetNumericalFunctor();
1881
1882
1883   // Update Python script
1884   TPythonDump() << "isDone = " << this << ".QuadToTri( " << IDsOfElements << ", " << aNumericalFunctor << " )";
1885
1886   CORBA::Boolean stat = getEditor().QuadToTri( faces, aCrit );
1887
1888   declareMeshModified( /*isReComputeSafe=*/false );
1889   return stat;
1890
1891   SMESH_CATCH( SMESH::throwCorbaException );
1892   return 0;
1893 }
1894
1895 //=============================================================================
1896 /*!
1897  * \brief Split quadrangles into triangles.
1898  */
1899 //=============================================================================
1900
1901 CORBA::Boolean SMESH_MeshEditor_i::QuadToTriObject (SMESH::SMESH_IDSource_ptr   theObject,
1902                                                     SMESH::NumericalFunctor_ptr Criterion)
1903   throw (SALOME::SALOME_Exception)
1904 {
1905   SMESH_TRY;
1906   initData();
1907
1908   TPythonDump aTPythonDump;  // suppress dump in QuadToTri()
1909
1910   prepareIdSource( theObject );
1911   SMESH::long_array_var anElementsId = theObject->GetIDs();
1912   CORBA::Boolean isDone = QuadToTri(anElementsId, Criterion);
1913
1914   SMESH::NumericalFunctor_i* aNumericalFunctor =
1915     SMESH::DownCast<SMESH::NumericalFunctor_i*>( Criterion );
1916
1917   // Update Python script
1918   aTPythonDump << "isDone = " << this << ".QuadToTriObject( " << theObject << ", " << aNumericalFunctor << " )";
1919
1920   declareMeshModified( /*isReComputeSafe=*/false );
1921   return isDone;
1922
1923   SMESH_CATCH( SMESH::throwCorbaException );
1924   return 0;
1925 }
1926
1927 //================================================================================
1928 /*!
1929  * \brief Split each of quadrangles into 4 triangles.
1930  *  \param [in] theObject - theQuads Container of quadrangles to split.
1931  */
1932 //================================================================================
1933
1934 void SMESH_MeshEditor_i::QuadTo4Tri (SMESH::SMESH_IDSource_ptr theObject)
1935   throw (SALOME::SALOME_Exception)
1936 {
1937   SMESH_TRY;
1938   initData();
1939
1940   TIDSortedElemSet faces;
1941   if ( !idSourceToSet( theObject, getMeshDS(), faces, SMDSAbs_Face, /*emptyIfIsMesh=*/true ) &&
1942        faces.empty() )
1943     THROW_SALOME_CORBA_EXCEPTION("No faces given", SALOME::BAD_PARAM);
1944
1945   getEditor().QuadTo4Tri( faces );
1946   TPythonDump() << this << ".QuadTo4Tri( " << theObject << " )";
1947
1948   SMESH_CATCH( SMESH::throwCorbaException );
1949 }
1950
1951 //=============================================================================
1952 /*!
1953  * \brief Split quadrangles into triangles.
1954  */
1955 //=============================================================================
1956
1957 CORBA::Boolean SMESH_MeshEditor_i::SplitQuad (const SMESH::long_array & IDsOfElements,
1958                                               CORBA::Boolean            Diag13)
1959   throw (SALOME::SALOME_Exception)
1960 {
1961   SMESH_TRY;
1962   initData();
1963
1964   SMESHDS_Mesh* aMesh = getMeshDS();
1965   TIDSortedElemSet faces;
1966   arrayToSet(IDsOfElements, aMesh, faces, SMDSAbs_Face);
1967
1968   // Update Python script
1969   TPythonDump() << "isDone = " << this << ".SplitQuad( "
1970                 << IDsOfElements << ", " << Diag13 << " )";
1971
1972   CORBA::Boolean stat = getEditor().QuadToTri( faces, Diag13 );
1973
1974   declareMeshModified( /*isReComputeSafe=*/ !stat );
1975   return stat;
1976
1977   SMESH_CATCH( SMESH::throwCorbaException );
1978   return 0;
1979 }
1980
1981 //=============================================================================
1982 /*!
1983  * \brief Split quadrangles into triangles.
1984  */
1985 //=============================================================================
1986
1987 CORBA::Boolean SMESH_MeshEditor_i::SplitQuadObject (SMESH::SMESH_IDSource_ptr theObject,
1988                                                     CORBA::Boolean            Diag13)
1989   throw (SALOME::SALOME_Exception)
1990 {
1991   SMESH_TRY;
1992   initData();
1993
1994   TPythonDump aTPythonDump;  // suppress dump in SplitQuad()
1995
1996   prepareIdSource( theObject );
1997   SMESH::long_array_var anElementsId = theObject->GetIDs();
1998   CORBA::Boolean isDone = SplitQuad(anElementsId, Diag13);
1999
2000   // Update Python script
2001   aTPythonDump << "isDone = " << this << ".SplitQuadObject( "
2002                << theObject << ", " << Diag13 << " )";
2003
2004   declareMeshModified( /*isReComputeSafe=*/!isDone );
2005   return isDone;
2006
2007   SMESH_CATCH( SMESH::throwCorbaException );
2008   return 0;
2009 }
2010
2011
2012 //=============================================================================
2013 /*!
2014  * Find better splitting of the given quadrangle.
2015  *  \param IDOfQuad  ID of the quadrangle to be splitted.
2016  *  \param Criterion A criterion to choose a diagonal for splitting.
2017  *  \return 1 if 1-3 diagonal is better, 2 if 2-4
2018  *          diagonal is better, 0 if error occurs.
2019  */
2020 //=============================================================================
2021
2022 CORBA::Long SMESH_MeshEditor_i::BestSplit (CORBA::Long                 IDOfQuad,
2023                                            SMESH::NumericalFunctor_ptr Criterion)
2024   throw (SALOME::SALOME_Exception)
2025 {
2026   SMESH_TRY;
2027   initData();
2028
2029   const SMDS_MeshElement* quad = getMeshDS()->FindElement(IDOfQuad);
2030   if (quad && quad->GetType() == SMDSAbs_Face && quad->NbNodes() == 4)
2031   {
2032     SMESH::NumericalFunctor_i* aNumericalFunctor =
2033       dynamic_cast<SMESH::NumericalFunctor_i*>(SMESH_Gen_i::GetServant(Criterion).in());
2034     SMESH::Controls::NumericalFunctorPtr aCrit;
2035     if (aNumericalFunctor)
2036       aCrit = aNumericalFunctor->GetNumericalFunctor();
2037     else
2038       aCrit.reset(new SMESH::Controls::AspectRatio());
2039
2040     int id = getEditor().BestSplit(quad, aCrit);
2041     declareMeshModified( /*isReComputeSafe=*/ id < 1 );
2042     return id;
2043   }
2044
2045   SMESH_CATCH( SMESH::throwCorbaException );
2046   return 0;
2047 }
2048
2049 //================================================================================
2050 /*!
2051  * \brief Split volumic elements into tetrahedrons
2052  */
2053 //================================================================================
2054
2055 void SMESH_MeshEditor_i::SplitVolumesIntoTetra (SMESH::SMESH_IDSource_ptr elems,
2056                                                 CORBA::Short              methodFlags)
2057   throw (SALOME::SALOME_Exception)
2058 {
2059   SMESH_TRY;
2060   initData();
2061
2062   ::SMESH_MeshEditor::TFacetOfElem elemSet;
2063   const int noneFacet = -1;
2064   SMDS_ElemIteratorPtr volIt = myMesh_i->GetElements( elems, SMESH::VOLUME );
2065   while( volIt->more() )
2066     elemSet.insert( elemSet.end(), make_pair( volIt->next(), noneFacet ));
2067
2068   getEditor().SplitVolumes( elemSet, int( methodFlags ));
2069   declareMeshModified( /*isReComputeSafe=*/true ); // it does not influence Compute()
2070
2071   TPythonDump() << this << ".SplitVolumesIntoTetra( "
2072                 << elems << ", " << methodFlags << " )";
2073
2074   SMESH_CATCH( SMESH::throwCorbaException );
2075 }
2076
2077 //================================================================================
2078 /*!
2079  * \brief Split hexahedra into triangular prisms
2080  *  \param elems - elements to split
2081  *  \param facetToSplitNormal - normal used to find a facet of hexahedron
2082  *         to split into triangles
2083  *  \param methodFlags - flags passing splitting method:
2084  *         1 - split the hexahedron into 2 prisms
2085  *         2 - split the hexahedron into 4 prisms
2086  */
2087 //================================================================================
2088
2089 void SMESH_MeshEditor_i::SplitHexahedraIntoPrisms (SMESH::SMESH_IDSource_ptr  elems,
2090                                                    const SMESH::PointStruct & startHexPoint,
2091                                                    const SMESH::DirStruct&    facetToSplitNormal,
2092                                                    CORBA::Short               methodFlags,
2093                                                    CORBA::Boolean             allDomains)
2094   throw (SALOME::SALOME_Exception)
2095 {
2096   SMESH_TRY;
2097   initData();
2098   prepareIdSource( elems );
2099
2100   gp_Ax1 facetNorm( gp_Pnt( startHexPoint.x,
2101                             startHexPoint.y,
2102                             startHexPoint.z ),
2103                     gp_Dir( facetToSplitNormal.PS.x,
2104                             facetToSplitNormal.PS.y,
2105                             facetToSplitNormal.PS.z ));
2106   TIDSortedElemSet elemSet;
2107   SMESH::long_array_var anElementsId = elems->GetIDs();
2108   SMDS_MeshElement::GeomFilter filter( SMDSGeom_HEXA );
2109   arrayToSet( anElementsId, getMeshDS(), elemSet, SMDSAbs_Volume, &filter );
2110
2111   ::SMESH_MeshEditor::TFacetOfElem elemFacets;
2112   while ( !elemSet.empty() )
2113   {
2114     getEditor().GetHexaFacetsToSplit( elemSet, facetNorm, elemFacets );
2115     if ( !allDomains )
2116       break;
2117
2118     ::SMESH_MeshEditor::TFacetOfElem::iterator ef = elemFacets.begin();
2119     for ( ; ef != elemFacets.end(); ++ef )
2120       elemSet.erase( ef->first );
2121   }
2122
2123   if ( methodFlags == 2 )
2124     methodFlags = int( ::SMESH_MeshEditor::HEXA_TO_4_PRISMS );
2125   else
2126     methodFlags = int( ::SMESH_MeshEditor::HEXA_TO_2_PRISMS );
2127
2128   getEditor().SplitVolumes( elemFacets, int( methodFlags ));
2129   declareMeshModified( /*isReComputeSafe=*/true ); // it does not influence Compute()
2130
2131   TPythonDump() << this << ".SplitHexahedraIntoPrisms( "
2132                 << elems << ", "
2133                 << startHexPoint << ", "
2134                 << facetToSplitNormal<< ", "
2135                 << methodFlags<< ", "
2136                 << allDomains << " )";
2137
2138   SMESH_CATCH( SMESH::throwCorbaException );
2139 }
2140
2141 //=======================================================================
2142 //function : Smooth
2143 //purpose  :
2144 //=======================================================================
2145
2146 CORBA::Boolean
2147 SMESH_MeshEditor_i::Smooth(const SMESH::long_array &              IDsOfElements,
2148                            const SMESH::long_array &              IDsOfFixedNodes,
2149                            CORBA::Long                            MaxNbOfIterations,
2150                            CORBA::Double                          MaxAspectRatio,
2151                            SMESH::SMESH_MeshEditor::Smooth_Method Method)
2152   throw (SALOME::SALOME_Exception)
2153 {
2154   return smooth( IDsOfElements, IDsOfFixedNodes, MaxNbOfIterations,
2155                  MaxAspectRatio, Method, false );
2156 }
2157
2158
2159 //=======================================================================
2160 //function : SmoothParametric
2161 //purpose  :
2162 //=======================================================================
2163
2164 CORBA::Boolean
2165 SMESH_MeshEditor_i::SmoothParametric(const SMESH::long_array &              IDsOfElements,
2166                                      const SMESH::long_array &              IDsOfFixedNodes,
2167                                      CORBA::Long                            MaxNbOfIterations,
2168                                      CORBA::Double                          MaxAspectRatio,
2169                                      SMESH::SMESH_MeshEditor::Smooth_Method Method)
2170   throw (SALOME::SALOME_Exception)
2171 {
2172   return smooth( IDsOfElements, IDsOfFixedNodes, MaxNbOfIterations,
2173                  MaxAspectRatio, Method, true );
2174 }
2175
2176
2177 //=======================================================================
2178 //function : SmoothObject
2179 //purpose  :
2180 //=======================================================================
2181
2182 CORBA::Boolean
2183 SMESH_MeshEditor_i::SmoothObject(SMESH::SMESH_IDSource_ptr              theObject,
2184                                  const SMESH::long_array &              IDsOfFixedNodes,
2185                                  CORBA::Long                            MaxNbOfIterations,
2186                                  CORBA::Double                          MaxAspectRatio,
2187                                  SMESH::SMESH_MeshEditor::Smooth_Method Method)
2188   throw (SALOME::SALOME_Exception)
2189 {
2190   return smoothObject (theObject, IDsOfFixedNodes, MaxNbOfIterations,
2191                        MaxAspectRatio, Method, false);
2192 }
2193
2194
2195 //=======================================================================
2196 //function : SmoothParametricObject
2197 //purpose  :
2198 //=======================================================================
2199
2200 CORBA::Boolean
2201 SMESH_MeshEditor_i::SmoothParametricObject(SMESH::SMESH_IDSource_ptr              theObject,
2202                                            const SMESH::long_array &              IDsOfFixedNodes,
2203                                            CORBA::Long                            MaxNbOfIterations,
2204                                            CORBA::Double                          MaxAspectRatio,
2205                                            SMESH::SMESH_MeshEditor::Smooth_Method Method)
2206   throw (SALOME::SALOME_Exception)
2207 {
2208   return smoothObject (theObject, IDsOfFixedNodes, MaxNbOfIterations,
2209                        MaxAspectRatio, Method, true);
2210 }
2211
2212
2213 //=============================================================================
2214 /*!
2215  *
2216  */
2217 //=============================================================================
2218
2219 CORBA::Boolean
2220 SMESH_MeshEditor_i::smooth(const SMESH::long_array &              IDsOfElements,
2221                            const SMESH::long_array &              IDsOfFixedNodes,
2222                            CORBA::Long                            MaxNbOfIterations,
2223                            CORBA::Double                          MaxAspectRatio,
2224                            SMESH::SMESH_MeshEditor::Smooth_Method Method,
2225                            bool                                   IsParametric)
2226   throw (SALOME::SALOME_Exception)
2227 {
2228   SMESH_TRY;
2229   initData();
2230
2231   SMESHDS_Mesh* aMesh = getMeshDS();
2232
2233   TIDSortedElemSet elements;
2234   arrayToSet(IDsOfElements, aMesh, elements, SMDSAbs_Face);
2235
2236   set<const SMDS_MeshNode*> fixedNodes;
2237   for (int i = 0; i < IDsOfFixedNodes.length(); i++) {
2238     CORBA::Long index = IDsOfFixedNodes[i];
2239     const SMDS_MeshNode * node = aMesh->FindNode(index);
2240     if ( node )
2241       fixedNodes.insert( node );
2242   }
2243   ::SMESH_MeshEditor::SmoothMethod method = ::SMESH_MeshEditor::LAPLACIAN;
2244   if ( Method != SMESH::SMESH_MeshEditor::LAPLACIAN_SMOOTH )
2245     method = ::SMESH_MeshEditor::CENTROIDAL;
2246
2247   getEditor().Smooth(elements, fixedNodes, method,
2248                   MaxNbOfIterations, MaxAspectRatio, IsParametric );
2249
2250   declareMeshModified( /*isReComputeSafe=*/true ); // does not prevent re-compute
2251
2252   // Update Python script
2253   TPythonDump() << "isDone = " << this << "."
2254                 << (IsParametric ? "SmoothParametric( " : "Smooth( ")
2255                 << IDsOfElements << ", "     << IDsOfFixedNodes << ", "
2256                 << TVar( MaxNbOfIterations ) << ", " << TVar( MaxAspectRatio ) << ", "
2257                 << "SMESH.SMESH_MeshEditor."
2258                 << ( Method == SMESH::SMESH_MeshEditor::CENTROIDAL_SMOOTH ?
2259                      "CENTROIDAL_SMOOTH )" : "LAPLACIAN_SMOOTH )");
2260
2261   return true;
2262
2263   SMESH_CATCH( SMESH::throwCorbaException );
2264   return 0;
2265 }
2266
2267 //=============================================================================
2268 /*!
2269  *
2270  */
2271 //=============================================================================
2272
2273 CORBA::Boolean
2274 SMESH_MeshEditor_i::smoothObject(SMESH::SMESH_IDSource_ptr              theObject,
2275                                  const SMESH::long_array &              IDsOfFixedNodes,
2276                                  CORBA::Long                            MaxNbOfIterations,
2277                                  CORBA::Double                          MaxAspectRatio,
2278                                  SMESH::SMESH_MeshEditor::Smooth_Method Method,
2279                                  bool                                   IsParametric)
2280   throw (SALOME::SALOME_Exception)
2281 {
2282   SMESH_TRY;
2283   initData();
2284
2285   TPythonDump aTPythonDump;  // suppress dump in smooth()
2286
2287   prepareIdSource( theObject );
2288   SMESH::long_array_var anElementsId = theObject->GetIDs();
2289   CORBA::Boolean isDone = smooth (anElementsId, IDsOfFixedNodes, MaxNbOfIterations,
2290                                   MaxAspectRatio, Method, IsParametric);
2291
2292   // Update Python script
2293   aTPythonDump << "isDone = " << this << "."
2294                << (IsParametric ? "SmoothParametricObject( " : "SmoothObject( ")
2295                << theObject << ", " << IDsOfFixedNodes << ", "
2296                << TVar( MaxNbOfIterations ) << ", " << TVar( MaxAspectRatio ) << ", "
2297                << "SMESH.SMESH_MeshEditor."
2298                << ( Method == SMESH::SMESH_MeshEditor::CENTROIDAL_SMOOTH ?
2299                     "CENTROIDAL_SMOOTH )" : "LAPLACIAN_SMOOTH )");
2300
2301   return isDone;
2302
2303   SMESH_CATCH( SMESH::throwCorbaException );
2304   return 0;
2305 }
2306
2307 //=============================================================================
2308 /*!
2309  *
2310  */
2311 //=============================================================================
2312
2313 void SMESH_MeshEditor_i::RenumberNodes()
2314   throw (SALOME::SALOME_Exception)
2315 {
2316   SMESH_TRY;
2317   // Update Python script
2318   TPythonDump() << this << ".RenumberNodes()";
2319
2320   getMeshDS()->Renumber( true );
2321
2322   SMESH_CATCH( SMESH::throwCorbaException );
2323 }
2324
2325 //=============================================================================
2326 /*!
2327  *
2328  */
2329 //=============================================================================
2330
2331 void SMESH_MeshEditor_i::RenumberElements()
2332   throw (SALOME::SALOME_Exception)
2333 {
2334   SMESH_TRY;
2335   // Update Python script
2336   TPythonDump() << this << ".RenumberElements()";
2337
2338   getMeshDS()->Renumber( false );
2339
2340   SMESH_CATCH( SMESH::throwCorbaException );
2341 }
2342
2343 //=======================================================================
2344 /*!
2345  * \brief Return groups by their IDs
2346  */
2347 //=======================================================================
2348
2349 SMESH::ListOfGroups* SMESH_MeshEditor_i::getGroups(const std::list<int>* groupIDs)
2350   throw (SALOME::SALOME_Exception)
2351 {
2352   SMESH_TRY;
2353   if ( !groupIDs )
2354     return 0;
2355   myMesh_i->CreateGroupServants();
2356   return myMesh_i->GetGroups( *groupIDs );
2357
2358   SMESH_CATCH( SMESH::throwCorbaException );
2359   return 0;
2360 }
2361
2362 //=======================================================================
2363 //function : RotationSweepObjects
2364 //purpose  :
2365 //=======================================================================
2366
2367 SMESH::ListOfGroups*
2368 SMESH_MeshEditor_i::RotationSweepObjects(const SMESH::ListOfIDSources & theNodes,
2369                                          const SMESH::ListOfIDSources & theEdges,
2370                                          const SMESH::ListOfIDSources & theFaces,
2371                                          const SMESH::AxisStruct &      theAxis,
2372                                          CORBA::Double                  theAngleInRadians,
2373                                          CORBA::Long                    theNbOfSteps,
2374                                          CORBA::Double                  theTolerance,
2375                                          const bool                     theMakeGroups)
2376   throw (SALOME::SALOME_Exception)
2377 {
2378   SMESH_TRY;
2379   initData();
2380
2381   TIDSortedElemSet elemsNodes[2];
2382   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
2383     SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
2384     while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
2385   }
2386   for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
2387     idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
2388   for ( int i = 0, nb = theFaces.length(); i < nb; ++i )
2389     idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face );
2390
2391   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2392   bool              makeWalls=true;
2393   if ( myIsPreviewMode )
2394   {
2395     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2396     TPreviewMesh * tmpMesh = getPreviewMesh();
2397     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2398     tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid );
2399     workElements = & copyElements[0];
2400     //makeWalls = false; -- faces are needed for preview
2401   }
2402
2403   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2404
2405   gp_Ax1 Ax1 (gp_Pnt( theAxis.x,  theAxis.y,  theAxis.z ),
2406               gp_Vec( theAxis.vx, theAxis.vy, theAxis.vz ));
2407
2408   ::SMESH_MeshEditor::PGroupIDs groupIds =
2409       getEditor().RotationSweep (workElements, Ax1, theAngleInRadians,
2410                                  theNbOfSteps, theTolerance, theMakeGroups, makeWalls);
2411
2412   SMESH::ListOfGroups * aGroups = theMakeGroups ? getGroups( groupIds.get()) : 0;
2413
2414   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2415
2416   if ( !myIsPreviewMode )
2417   {
2418     dumpGroupsList( aPythonDump, aGroups );
2419     aPythonDump << this<< ".RotationSweepObjects( "
2420                 << theNodes                  << ", "
2421                 << theEdges                  << ", "
2422                 << theFaces                  << ", "
2423                 << theAxis                   << ", "
2424                 << TVar( theAngleInRadians ) << ", "
2425                 << TVar( theNbOfSteps      ) << ", "
2426                 << TVar( theTolerance      ) << ", "
2427                 << theMakeGroups             << " )";
2428   }
2429   else
2430   {
2431     getPreviewMesh()->Remove( SMDSAbs_Volume );
2432   }
2433
2434   return aGroups ? aGroups : new SMESH::ListOfGroups;
2435
2436   SMESH_CATCH( SMESH::throwCorbaException );
2437   return 0;
2438 }
2439
2440 namespace MeshEditor_I
2441 {
2442   /*!
2443    * \brief Structure used to pass extrusion parameters to ::SMESH_MeshEditor
2444    */
2445   struct ExtrusionParams : public ::SMESH_MeshEditor::ExtrusParam
2446   {
2447     bool myIsExtrusionByNormal;
2448
2449     static int makeFlags( CORBA::Boolean MakeGroups,
2450                           CORBA::Boolean ByAverageNormal = false,
2451                           CORBA::Boolean UseInputElemsOnly = false,
2452                           CORBA::Long    Flags = 0,
2453                           CORBA::Boolean MakeBoundary = true )
2454     {
2455       if ( MakeGroups       ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_GROUPS;
2456       if ( ByAverageNormal  ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_BY_AVG_NORMAL;
2457       if ( UseInputElemsOnly) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_USE_INPUT_ELEMS_ONLY;
2458       if ( MakeBoundary     ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_BOUNDARY;
2459       return Flags;
2460     }
2461     // standard params
2462     ExtrusionParams(const SMESH::DirStruct &  theDir,
2463                     CORBA::Long               theNbOfSteps,
2464                     CORBA::Boolean            theMakeGroups):
2465       ::SMESH_MeshEditor::ExtrusParam ( gp_Vec( theDir.PS.x,
2466                                                 theDir.PS.y,
2467                                                 theDir.PS.z ),
2468                                         theNbOfSteps,
2469                                         makeFlags( theMakeGroups )),
2470       myIsExtrusionByNormal( false )
2471     {
2472     }
2473     // advanced params
2474     ExtrusionParams(const SMESH::DirStruct &  theDir,
2475                     CORBA::Long               theNbOfSteps,
2476                     CORBA::Boolean            theMakeGroups,
2477                     CORBA::Long               theExtrFlags,
2478                     CORBA::Double             theSewTolerance):
2479       ::SMESH_MeshEditor::ExtrusParam ( gp_Vec( theDir.PS.x,
2480                                                 theDir.PS.y,
2481                                                 theDir.PS.z ),
2482                                         theNbOfSteps,
2483                                         makeFlags( theMakeGroups, false, false,
2484                                                    theExtrFlags, false ),
2485                                         theSewTolerance ),
2486       myIsExtrusionByNormal( false )
2487     {
2488     }
2489     // params for extrusion by normal
2490     ExtrusionParams(CORBA::Double  theStepSize,
2491                     CORBA::Long    theNbOfSteps,
2492                     CORBA::Short   theDim,
2493                     CORBA::Boolean theByAverageNormal,
2494                     CORBA::Boolean theUseInputElemsOnly,
2495                     CORBA::Boolean theMakeGroups ):
2496       ::SMESH_MeshEditor::ExtrusParam ( theStepSize, 
2497                                         theNbOfSteps,
2498                                         makeFlags( theMakeGroups,
2499                                                    theByAverageNormal, theUseInputElemsOnly ),
2500                                         theDim),
2501       myIsExtrusionByNormal( true )
2502     {
2503     }
2504
2505     void SetNoGroups()
2506     {
2507       Flags() &= ~(::SMESH_MeshEditor::EXTRUSION_FLAG_GROUPS);
2508     }
2509   };
2510 }
2511
2512 //=======================================================================
2513 /*!
2514  * \brief Generate dim+1 elements by extrusion of elements along vector
2515  *  \param [in] edges - edges to extrude: a list including groups, sub-meshes or a mesh
2516  *  \param [in] faces - faces to extrude: a list including groups, sub-meshes or a mesh
2517  *  \param [in] nodes - nodes to extrude: a list including groups, sub-meshes or a mesh
2518  *  \param [in] stepVector - vector giving direction and distance of an extrusion step
2519  *  \param [in] nbOfSteps - number of elements to generate from one element
2520  *  \param [in] toMakeGroups - if true, new elements will be included into new groups
2521  *              corresponding to groups the input elements included in.
2522  *  \return ListOfGroups - new groups craeted if \a toMakeGroups is true
2523  */
2524 //=======================================================================
2525
2526 SMESH::ListOfGroups*
2527 SMESH_MeshEditor_i::ExtrusionSweepObjects(const SMESH::ListOfIDSources & theNodes,
2528                                           const SMESH::ListOfIDSources & theEdges,
2529                                           const SMESH::ListOfIDSources & theFaces,
2530                                           const SMESH::DirStruct &       theStepVector,
2531                                           CORBA::Long                    theNbOfSteps,
2532                                           CORBA::Boolean                 theToMakeGroups)
2533   throw (SALOME::SALOME_Exception)
2534 {
2535   SMESH_TRY;
2536   initData();
2537
2538   ExtrusionParams params( theStepVector, theNbOfSteps, theToMakeGroups );
2539
2540   TIDSortedElemSet elemsNodes[2];
2541   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
2542     SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
2543     while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
2544   }
2545   for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
2546     idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
2547   for ( int i = 0, nb = theFaces.length(); i < nb; ++i )
2548     idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face );
2549
2550   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2551   SMDSAbs_ElementType previewType = SMDSAbs_All; //SMDSAbs_Face;
2552   if ( myIsPreviewMode )
2553   {
2554     // if ( (*elemsNodes.begin())->GetType() == SMDSAbs_Node )
2555     //   previewType = SMDSAbs_Edge;
2556
2557     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2558     TPreviewMesh * tmpMesh = getPreviewMesh( previewType );
2559     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2560     tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid );
2561     workElements = & copyElements[0];
2562
2563     params.SetNoGroups();
2564   }
2565   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2566
2567   ::SMESH_MeshEditor::TTElemOfElemListMap aHistory;
2568   ::SMESH_MeshEditor::PGroupIDs groupIds =
2569       getEditor().ExtrusionSweep( workElements, params, aHistory );
2570
2571   SMESH::ListOfGroups * aGroups = theToMakeGroups ? getGroups( groupIds.get()) : 0;
2572
2573   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2574
2575   if ( !myIsPreviewMode )
2576   {
2577     dumpGroupsList( aPythonDump, aGroups );
2578     aPythonDump << this<< ".ExtrusionSweepObjects( "
2579                 << theNodes             << ", "
2580                 << theEdges             << ", "
2581                 << theFaces             << ", "
2582                 << theStepVector        << ", "
2583                 << TVar( theNbOfSteps ) << ", "
2584                 << theToMakeGroups      << " )";
2585   }
2586   else
2587   {
2588     getPreviewMesh( previewType )->Remove( SMDSAbs_Volume );
2589   }
2590
2591   return aGroups ? aGroups : new SMESH::ListOfGroups;
2592
2593   SMESH_CATCH( SMESH::throwCorbaException );
2594   return 0;
2595 }
2596
2597 //=======================================================================
2598 //function : ExtrusionByNormal
2599 //purpose  :
2600 //=======================================================================
2601
2602 SMESH::ListOfGroups*
2603 SMESH_MeshEditor_i::ExtrusionByNormal(const SMESH::ListOfIDSources& objects,
2604                                       CORBA::Double                 stepSize,
2605                                       CORBA::Long                   nbOfSteps,
2606                                       CORBA::Boolean                byAverageNormal,
2607                                       CORBA::Boolean                useInputElemsOnly,
2608                                       CORBA::Boolean                makeGroups,
2609                                       CORBA::Short                  dim)
2610   throw (SALOME::SALOME_Exception)
2611 {
2612   SMESH_TRY;
2613   initData();
2614
2615   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
2616
2617   ExtrusionParams params( stepSize, nbOfSteps, dim,
2618                           byAverageNormal, useInputElemsOnly, makeGroups );
2619
2620   SMDSAbs_ElementType elemType = ( dim == 1 ? SMDSAbs_Edge : SMDSAbs_Face );
2621   if ( objects.length() > 0 && !SMESH::DownCast<SMESH_Mesh_i*>( objects[0] ))
2622   {
2623     SMESH::array_of_ElementType_var elemTypes = objects[0]->GetTypes();
2624     if (( elemTypes->length() == 1 ) &&
2625         ( elemTypes[0] == SMESH::EDGE || elemTypes[0] == SMESH::FACE ))
2626       elemType = ( SMDSAbs_ElementType ) elemTypes[0];
2627   }
2628
2629   TIDSortedElemSet elemsNodes[2];
2630   for ( int i = 0, nb = objects.length(); i < nb; ++i )
2631     idSourceToSet( objects[i], getMeshDS(), elemsNodes[0], elemType );
2632
2633   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2634   SMDSAbs_ElementType previewType = SMDSAbs_Face;
2635   if ( myIsPreviewMode )
2636   {
2637     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2638     TPreviewMesh * tmpMesh = getPreviewMesh( previewType );
2639     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2640     workElements = & copyElements[0];
2641
2642     params.SetNoGroups();
2643   }
2644
2645   ::SMESH_MeshEditor::TTElemOfElemListMap aHistory;
2646   ::SMESH_MeshEditor::PGroupIDs groupIds =
2647       getEditor().ExtrusionSweep( workElements, params, aHistory );
2648
2649   SMESH::ListOfGroups * aGroups = makeGroups ? getGroups( groupIds.get()) : 0;
2650
2651   if (!myIsPreviewMode) {
2652     dumpGroupsList(aPythonDump, aGroups);
2653     aPythonDump << this << ".ExtrusionByNormal( " << objects
2654                 << ", " << TVar( stepSize )
2655                 << ", " << TVar( nbOfSteps )
2656                 << ", " << byAverageNormal
2657                 << ", " << useInputElemsOnly
2658                 << ", " << makeGroups
2659                 << ", " << dim
2660                 << " )";
2661   }
2662   else
2663   {
2664     getPreviewMesh( previewType )->Remove( SMDSAbs_Volume );
2665   }
2666
2667   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2668
2669   return aGroups ? aGroups : new SMESH::ListOfGroups;
2670
2671   SMESH_CATCH( SMESH::throwCorbaException );
2672   return 0;
2673 }
2674
2675 //=======================================================================
2676 //function : AdvancedExtrusion
2677 //purpose  :
2678 //=======================================================================
2679
2680 SMESH::ListOfGroups*
2681 SMESH_MeshEditor_i::AdvancedExtrusion(const SMESH::long_array & theIDsOfElements,
2682                                       const SMESH::DirStruct &  theStepVector,
2683                                       CORBA::Long               theNbOfSteps,
2684                                       CORBA::Long               theExtrFlags,
2685                                       CORBA::Double             theSewTolerance,
2686                                       CORBA::Boolean            theMakeGroups)
2687   throw (SALOME::SALOME_Exception)
2688 {
2689   SMESH_TRY;
2690   initData();
2691
2692   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2693
2694   ExtrusionParams params( theStepVector, theNbOfSteps, theMakeGroups,
2695                           theExtrFlags, theSewTolerance );
2696
2697   TIDSortedElemSet elemsNodes[2];
2698   arrayToSet( theIDsOfElements, getMeshDS(), elemsNodes[0] );
2699
2700   ::SMESH_MeshEditor::TTElemOfElemListMap aHistory;
2701   ::SMESH_MeshEditor::PGroupIDs groupIds =
2702       getEditor().ExtrusionSweep( elemsNodes, params, aHistory );
2703
2704   SMESH::ListOfGroups * aGroups = theMakeGroups ? getGroups( groupIds.get()) : 0;
2705
2706   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2707
2708   if ( !myIsPreviewMode ) {
2709     dumpGroupsList(aPythonDump, aGroups);
2710     aPythonDump << this << ".AdvancedExtrusion( "
2711                 << theIDsOfElements << ", "
2712                 << theStepVector << ", "
2713                 << theNbOfSteps << ", "
2714                 << theExtrFlags << ", "
2715                 << theSewTolerance << ", "
2716                 << theMakeGroups << " )";
2717   }
2718   else
2719   {
2720     getPreviewMesh()->Remove( SMDSAbs_Volume );
2721   }
2722
2723   return aGroups ? aGroups : new SMESH::ListOfGroups;
2724
2725   SMESH_CATCH( SMESH::throwCorbaException );
2726   return 0;
2727 }
2728
2729 //================================================================================
2730 /*!
2731  * \brief Convert extrusion error to IDL enum
2732  */
2733 //================================================================================
2734
2735 namespace
2736 {
2737 #define RETCASE(enm) case ::SMESH_MeshEditor::enm: return SMESH::SMESH_MeshEditor::enm;
2738
2739   SMESH::SMESH_MeshEditor::Extrusion_Error convExtrError( ::SMESH_MeshEditor::Extrusion_Error e )
2740   {
2741     switch ( e ) {
2742       RETCASE( EXTR_OK );
2743       RETCASE( EXTR_NO_ELEMENTS );
2744       RETCASE( EXTR_PATH_NOT_EDGE );
2745       RETCASE( EXTR_BAD_PATH_SHAPE );
2746       RETCASE( EXTR_BAD_STARTING_NODE );
2747       RETCASE( EXTR_BAD_ANGLES_NUMBER );
2748       RETCASE( EXTR_CANT_GET_TANGENT );
2749     }
2750     return SMESH::SMESH_MeshEditor::EXTR_OK;
2751   }
2752 }
2753
2754 //=======================================================================
2755 //function : extrusionAlongPath
2756 //purpose  :
2757 //=======================================================================
2758 SMESH::ListOfGroups*
2759 SMESH_MeshEditor_i::ExtrusionAlongPathObjects(const SMESH::ListOfIDSources & theNodes,
2760                                               const SMESH::ListOfIDSources & theEdges,
2761                                               const SMESH::ListOfIDSources & theFaces,
2762                                               SMESH::SMESH_IDSource_ptr      thePathMesh,
2763                                               GEOM::GEOM_Object_ptr          thePathShape,
2764                                               CORBA::Long                    theNodeStart,
2765                                               CORBA::Boolean                 theHasAngles,
2766                                               const SMESH::double_array &    theAngles,
2767                                               CORBA::Boolean                 theLinearVariation,
2768                                               CORBA::Boolean                 theHasRefPoint,
2769                                               const SMESH::PointStruct &     theRefPoint,
2770                                               bool                           theMakeGroups,
2771                                               SMESH::SMESH_MeshEditor::Extrusion_Error& theError)
2772   throw (SALOME::SALOME_Exception)
2773 {
2774   SMESH_TRY;
2775   initData();
2776
2777   SMESH::ListOfGroups_var aGroups = new SMESH::ListOfGroups;
2778
2779   theError = SMESH::SMESH_MeshEditor::EXTR_BAD_PATH_SHAPE;
2780   if ( thePathMesh->_is_nil() )
2781     return aGroups._retn();
2782
2783   // get a sub-mesh
2784   SMESH_subMesh* aSubMesh = 0;
2785   SMESH_Mesh_i* aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( thePathMesh );
2786   if ( thePathShape->_is_nil() )
2787   {
2788     // thePathMesh should be either a sub-mesh or a mesh with 1D elements only
2789     if ( SMESH_subMesh_i* sm = SMESH::DownCast<SMESH_subMesh_i*>( thePathMesh ))
2790     {
2791       SMESH::SMESH_Mesh_var mesh = thePathMesh->GetMesh();
2792       aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
2793       if ( !aMeshImp ) return aGroups._retn();
2794       aSubMesh = aMeshImp->GetImpl().GetSubMeshContaining( sm->GetId() );
2795       if ( !aSubMesh ) return aGroups._retn();
2796     }
2797     else if ( !aMeshImp ||
2798               aMeshImp->NbEdges() != aMeshImp->NbElements() )
2799     {
2800       return aGroups._retn();
2801     }
2802   }
2803   else
2804   {
2805     if ( !aMeshImp ) return aGroups._retn();
2806     TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( thePathShape );
2807     aSubMesh = aMeshImp->GetImpl().GetSubMesh( aShape );
2808     if ( !aSubMesh || !aSubMesh->GetSubMeshDS() )
2809       return aGroups._retn();
2810   }
2811
2812   SMDS_MeshNode* nodeStart =
2813     (SMDS_MeshNode*)aMeshImp->GetImpl().GetMeshDS()->FindNode(theNodeStart);
2814   if ( !nodeStart ) {
2815     theError = SMESH::SMESH_MeshEditor::EXTR_BAD_STARTING_NODE;
2816     return aGroups._retn();
2817   }
2818
2819   TIDSortedElemSet elemsNodes[2];
2820   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
2821     SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
2822     while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
2823   }
2824   for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
2825     idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
2826   for ( int i = 0, nb = theFaces.length(); i < nb; ++i )
2827     idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face );
2828
2829   list<double> angles;
2830   for (int i = 0; i < theAngles.length(); i++) {
2831     angles.push_back( theAngles[i] );
2832   }
2833
2834   gp_Pnt refPnt( theRefPoint.x, theRefPoint.y, theRefPoint.z );
2835
2836   int nbOldGroups = myMesh->NbGroup();
2837
2838   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2839   if ( myIsPreviewMode )
2840   {
2841     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2842     TPreviewMesh * tmpMesh = getPreviewMesh();
2843     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2844     tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid );
2845     workElements = & copyElements[0];
2846     theMakeGroups = false;
2847   }
2848
2849   ::SMESH_MeshEditor::Extrusion_Error error;
2850   if ( !aSubMesh )
2851     error = getEditor().ExtrusionAlongTrack( workElements, &(aMeshImp->GetImpl()), nodeStart,
2852                                              theHasAngles, angles, theLinearVariation,
2853                                              theHasRefPoint, refPnt, theMakeGroups );
2854   else
2855     error = getEditor().ExtrusionAlongTrack( workElements, aSubMesh, nodeStart,
2856                                              theHasAngles, angles, theLinearVariation,
2857                                              theHasRefPoint, refPnt, theMakeGroups );
2858
2859   declareMeshModified( /*isReComputeSafe=*/true );
2860   theError = convExtrError( error );
2861
2862   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2863   if ( theMakeGroups ) {
2864     list<int> groupIDs = myMesh->GetGroupIds();
2865     list<int>::iterator newBegin = groupIDs.begin();
2866     std::advance( newBegin, nbOldGroups ); // skip old groups
2867     groupIDs.erase( groupIDs.begin(), newBegin );
2868     aGroups = getGroups( & groupIDs );
2869     if ( ! &aGroups.in() ) aGroups = new SMESH::ListOfGroups;
2870   }
2871
2872   if ( !myIsPreviewMode ) {
2873     aPythonDump << "(" << aGroups << ", error) = "
2874                 << this << ".ExtrusionAlongPathObjects( "
2875                 << theNodes            << ", "
2876                 << theEdges            << ", "
2877                 << theFaces            << ", "
2878                 << thePathMesh         << ", "
2879                 << thePathShape        << ", "
2880                 << theNodeStart        << ", "
2881                 << theHasAngles        << ", "
2882                 << theAngles           << ", "
2883                 << theLinearVariation  << ", "
2884                 << theHasRefPoint      << ", "
2885                 << "SMESH.PointStruct( "
2886                 << ( theHasRefPoint ? theRefPoint.x : 0 ) << ", "
2887                 << ( theHasRefPoint ? theRefPoint.y : 0 ) << ", "
2888                 << ( theHasRefPoint ? theRefPoint.z : 0 ) << " ), "
2889                 << theMakeGroups       << " )";
2890   }
2891   else
2892   {
2893     getPreviewMesh()->Remove( SMDSAbs_Volume );
2894   }
2895
2896   return aGroups._retn();
2897
2898   SMESH_CATCH( SMESH::throwCorbaException );
2899   return 0;
2900 }
2901
2902 //================================================================================
2903 /*!
2904  * \brief Compute rotation angles for ExtrusionAlongPath as linear variation
2905  * of given angles along path steps
2906  * \param PathMesh mesh containing a 1D sub-mesh on the edge, along
2907  *                which proceeds the extrusion
2908  * \param PathShape is shape(edge); as the mesh can be complex, the edge
2909  *                 is used to define the sub-mesh for the path
2910  */
2911 //================================================================================
2912
2913 SMESH::double_array*
2914 SMESH_MeshEditor_i::LinearAnglesVariation(SMESH::SMESH_Mesh_ptr       thePathMesh,
2915                                           GEOM::GEOM_Object_ptr       thePathShape,
2916                                           const SMESH::double_array & theAngles)
2917 {
2918   SMESH::double_array_var aResult = new SMESH::double_array();
2919   int nbAngles = theAngles.length();
2920   if ( nbAngles > 0 && !thePathMesh->_is_nil() && !thePathShape->_is_nil() )
2921   {
2922     SMESH_Mesh_i* aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( thePathMesh );
2923     TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( thePathShape );
2924     SMESH_subMesh* aSubMesh = aMeshImp->GetImpl().GetSubMesh( aShape );
2925     if ( !aSubMesh || !aSubMesh->GetSubMeshDS())
2926       return aResult._retn();
2927     int nbSteps = aSubMesh->GetSubMeshDS()->NbElements();
2928     if ( nbSteps == nbAngles )
2929     {
2930       aResult.inout() = theAngles;
2931     }
2932     else
2933     {
2934       aResult->length( nbSteps );
2935       double rAn2St = double( nbAngles ) / double( nbSteps );
2936       double angPrev = 0, angle;
2937       for ( int iSt = 0; iSt < nbSteps; ++iSt )
2938       {
2939         double angCur = rAn2St * ( iSt+1 );
2940         double angCurFloor  = floor( angCur );
2941         double angPrevFloor = floor( angPrev );
2942         if ( angPrevFloor == angCurFloor )
2943           angle = rAn2St * theAngles[ int( angCurFloor ) ];
2944         else
2945         {
2946           int iP = int( angPrevFloor );
2947           double angPrevCeil = ceil(angPrev);
2948           angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
2949
2950           int iC = int( angCurFloor );
2951           if ( iC < nbAngles )
2952             angle += ( angCur - angCurFloor ) * theAngles[ iC ];
2953
2954           iP = int( angPrevCeil );
2955           while ( iC-- > iP )
2956             angle += theAngles[ iC ];
2957         }
2958         aResult[ iSt ] = angle;
2959         angPrev = angCur;
2960       }
2961     }
2962   }
2963   // Update Python script
2964   TPythonDump() << "rotAngles = " << theAngles;
2965   TPythonDump() << "rotAngles = " << this << ".LinearAnglesVariation( "
2966                 << thePathMesh  << ", "
2967                 << thePathShape << ", "
2968                 << "rotAngles )";
2969
2970   return aResult._retn();
2971 }
2972
2973 //=======================================================================
2974 //function : mirror
2975 //purpose  :
2976 //=======================================================================
2977
2978 SMESH::ListOfGroups*
2979 SMESH_MeshEditor_i::mirror(TIDSortedElemSet &                  theElements,
2980                            const SMESH::AxisStruct &           theAxis,
2981                            SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
2982                            CORBA::Boolean                      theCopy,
2983                            bool                                theMakeGroups,
2984                            ::SMESH_Mesh*                       theTargetMesh)
2985   throw (SALOME::SALOME_Exception)
2986 {
2987   SMESH_TRY;
2988   initData();
2989
2990   gp_Pnt P ( theAxis.x, theAxis.y, theAxis.z );
2991   gp_Vec V ( theAxis.vx, theAxis.vy, theAxis.vz );
2992
2993   if ( theTargetMesh )
2994     theCopy = false;
2995
2996   gp_Trsf aTrsf;
2997   switch ( theMirrorType ) {
2998   case  SMESH::SMESH_MeshEditor::POINT:
2999     aTrsf.SetMirror( P );
3000     break;
3001   case  SMESH::SMESH_MeshEditor::AXIS:
3002     aTrsf.SetMirror( gp_Ax1( P, V ));
3003     break;
3004   default:
3005     aTrsf.SetMirror( gp_Ax2( P, V ));
3006   }
3007
3008   TIDSortedElemSet  copyElements;
3009   TIDSortedElemSet* workElements = & theElements;
3010
3011   if ( myIsPreviewMode )
3012   {
3013     TPreviewMesh * tmpMesh = getPreviewMesh();
3014     tmpMesh->Copy( theElements, copyElements);
3015     if ( !theCopy && !theTargetMesh )
3016     {
3017       TIDSortedElemSet elemsAround, elemsAroundCopy;
3018       getElementsAround( theElements, getMeshDS(), elemsAround );
3019       tmpMesh->Copy( elemsAround, elemsAroundCopy);
3020     }
3021     workElements = & copyElements;
3022     theMakeGroups = false;
3023   }
3024
3025   ::SMESH_MeshEditor::PGroupIDs groupIds =
3026       getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
3027
3028   if ( theCopy && !myIsPreviewMode)
3029   {
3030     if ( theTargetMesh )
3031     {
3032       theTargetMesh->GetMeshDS()->Modified();
3033     }
3034     else
3035     {
3036       declareMeshModified( /*isReComputeSafe=*/false );
3037     }
3038   }
3039   return theMakeGroups ? getGroups(groupIds.get()) : 0;
3040
3041   SMESH_CATCH( SMESH::throwCorbaException );
3042   return 0;
3043 }
3044
3045 //=======================================================================
3046 //function : Mirror
3047 //purpose  :
3048 //=======================================================================
3049
3050 void SMESH_MeshEditor_i::Mirror(const SMESH::long_array &           theIDsOfElements,
3051                                 const SMESH::AxisStruct &           theAxis,
3052                                 SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
3053                                 CORBA::Boolean                      theCopy)
3054   throw (SALOME::SALOME_Exception)
3055 {
3056   if ( !myIsPreviewMode ) {
3057     TPythonDump() << this << ".Mirror( "
3058                   << theIDsOfElements              << ", "
3059                   << theAxis                       << ", "
3060                   << mirrorTypeName(theMirrorType) << ", "
3061                   << theCopy                       << " )";
3062   }
3063   if ( theIDsOfElements.length() > 0 )
3064   {
3065     TIDSortedElemSet elements;
3066     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3067     mirror(elements, theAxis, theMirrorType, theCopy, false);
3068   }
3069 }
3070
3071
3072 //=======================================================================
3073 //function : MirrorObject
3074 //purpose  :
3075 //=======================================================================
3076
3077 void SMESH_MeshEditor_i::MirrorObject(SMESH::SMESH_IDSource_ptr           theObject,<