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