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