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