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