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