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