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