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