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