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