Salome HOME
Merge ASERIS development.
[modules/smesh.git] / src / SMESH_I / SMESH_MeshEditor_i.cxx
1 // Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //  File   : SMESH_MeshEditor_i.cxx
23 //  Author : Nicolas REJNERI
24 //  Module : SMESH
25
26 #ifdef WIN32
27 #define NOMINMAX
28 #endif
29
30 // A macro used in SMESH_TryCatch.hxx,
31 // it re-raises a CORBA SALOME exception thrown by SMESH_MeshEditor_i and caught by SMESH_CATCH
32 #define SMY_OWN_CATCH \
33   catch ( SALOME::SALOME_Exception & e ) { throw e; }
34
35 #include "SMESH_MeshEditor_i.hxx"
36
37 #include "SMDS_EdgePosition.hxx"
38 #include "SMDS_ElemIterator.hxx"
39 #include "SMDS_FacePosition.hxx"
40 #include "SMDS_IteratorOnIterators.hxx"
41 #include "SMDS_LinearEdge.hxx"
42 #include "SMDS_Mesh0DElement.hxx"
43 #include "SMDS_MeshFace.hxx"
44 #include "SMDS_MeshVolume.hxx"
45 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
46 #include "SMDS_SetIterator.hxx"
47 #include "SMDS_VolumeTool.hxx"
48 #include "SMESHDS_Group.hxx"
49 #include "SMESHDS_GroupOnGeom.hxx"
50 #include "SMESH_ControlsDef.hxx"
51 #include "SMESH_Filter_i.hxx"
52 #include "SMESH_Gen_i.hxx"
53 #include "SMESH_Group.hxx"
54 #include "SMESH_Group_i.hxx"
55 #include "SMESH_MeshAlgos.hxx"
56 #include "SMESH_MeshPartDS.hxx"
57 #include "SMESH_MesherHelper.hxx"
58 #include "SMESH_PythonDump.hxx"
59 #include "SMESH_subMeshEventListener.hxx"
60 #include "SMESH_subMesh_i.hxx"
61
62 #include <utilities.h>
63 #include <Utils_ExceptHandlers.hxx>
64 #include <Utils_CorbaException.hxx>
65 #include <SALOMEDS_wrap.hxx>
66 #include <SALOME_GenericObj_i.hh>
67
68 #include <BRepAdaptor_Surface.hxx>
69 #include <BRep_Tool.hxx>
70 #include <TopExp_Explorer.hxx>
71 #include <TopoDS.hxx>
72 #include <TopoDS_Edge.hxx>
73 #include <TopoDS_Face.hxx>
74 #include <gp_Ax1.hxx>
75 #include <gp_Ax2.hxx>
76 #include <gp_Vec.hxx>
77
78 #include <Standard_Failure.hxx>
79 #include <Standard_ErrorHandler.hxx>
80
81 #include <sstream>
82 #include <limits>
83
84 #include "SMESH_TryCatch.hxx" // include after OCCT headers!
85
86 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
87
88 using namespace std;
89 using SMESH::TPythonDump;
90 using SMESH::TVar;
91
92 namespace MeshEditor_I {
93
94   //=============================================================================
95   /*!
96    * \brief Mesh to apply modifications for preview purposes
97    */
98   //=============================================================================
99
100   struct TPreviewMesh: public SMESH_Mesh
101   {
102     SMDSAbs_ElementType myPreviewType; // type to show
103     //!< Constructor
104     TPreviewMesh(SMDSAbs_ElementType previewElements = SMDSAbs_All) {
105       _isShapeToMesh = (_id =_studyId = 0);
106       _myMeshDS  = new SMESHDS_Mesh( _id, true );
107       myPreviewType = previewElements;
108     }
109     //!< Copy a set of elements
110     void Copy(const TIDSortedElemSet & theElements,
111               TIDSortedElemSet&        theCopyElements,
112               SMDSAbs_ElementType      theSelectType = SMDSAbs_All,
113               SMDSAbs_ElementType      theAvoidType = SMDSAbs_All)
114     {
115       // loop on theIDsOfElements
116       TIDSortedElemSet::const_iterator eIt = theElements.begin();
117       for ( ; eIt != theElements.end(); ++eIt )
118       {
119         const SMDS_MeshElement* anElem = *eIt;
120         if ( !anElem ) continue;
121         SMDSAbs_ElementType type = anElem->GetType();
122         if ( type == theAvoidType ||
123              ( theSelectType != SMDSAbs_All && type != theSelectType ))
124           continue;
125         const SMDS_MeshElement* anElemCopy;
126         if ( type == SMDSAbs_Node)
127           anElemCopy = Copy( cast2Node(anElem) );
128         else
129           anElemCopy = Copy( anElem );
130         if ( anElemCopy )
131           theCopyElements.insert( theCopyElements.end(), anElemCopy );
132       }
133     }
134     //!< Copy an element
135     SMDS_MeshElement* Copy( const SMDS_MeshElement* anElem )
136     {
137       // copy element nodes
138       int anElemNbNodes = anElem->NbNodes();
139       vector< int > anElemNodesID( anElemNbNodes ) ;
140       SMDS_ElemIteratorPtr itElemNodes = anElem->nodesIterator();
141       for ( int i = 0; itElemNodes->more(); i++)
142       {
143         const SMDS_MeshNode* anElemNode = cast2Node( itElemNodes->next() );
144         Copy( anElemNode );
145         anElemNodesID[i] = anElemNode->GetID();
146       }
147
148       // creates a corresponding element on copied nodes
149       ::SMESH_MeshEditor::ElemFeatures elemType;
150       elemType.Init( anElem, /*basicOnly=*/false );
151       elemType.SetID( anElem->GetID() );
152       SMDS_MeshElement* anElemCopy =
153         ::SMESH_MeshEditor(this).AddElement( anElemNodesID, elemType );
154       return anElemCopy;
155     }
156     //!< Copy a node
157     SMDS_MeshNode* Copy( const SMDS_MeshNode* anElemNode )
158     {
159       return _myMeshDS->AddNodeWithID(anElemNode->X(), anElemNode->Y(), anElemNode->Z(),
160                                       anElemNode->GetID());
161     }
162     void RemoveAll()
163     {
164       GetMeshDS()->ClearMesh();
165     }
166     void Remove( SMDSAbs_ElementType type )
167     {
168       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 splitted.
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::Study_var     study = gen->GetCurrentStudy();
5399   SALOMEDS::SObject_wrap meshSO = gen->ObjectToSObject( study, mesh );
5400   gen->SetName( meshSO, theMeshName, "Mesh" );
5401   gen->SetPixMap( meshSO, "ICON_SMESH_TREE_MESH_IMPORTED");
5402
5403   return mesh._retn();
5404 }
5405
5406 //=======================================================================
5407 //function : dumpGroupsList
5408 //purpose  :
5409 //=======================================================================
5410
5411 void SMESH_MeshEditor_i::dumpGroupsList(TPythonDump &               theDumpPython,
5412                                         const SMESH::ListOfGroups * theGroupList)
5413 {
5414   bool isDumpGroupList = ( theGroupList && theGroupList->length() > 0 );
5415   if ( isDumpGroupList )
5416     theDumpPython << theGroupList << " = ";
5417 }
5418
5419 //================================================================================
5420 /*!
5421   \brief Generates the unique group name.
5422   \param thePrefix name prefix
5423   \return unique name
5424 */
5425 //================================================================================
5426
5427 std::string SMESH_MeshEditor_i::generateGroupName(const std::string& thePrefix)
5428 {
5429   SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
5430   set<std::string> groupNames;
5431
5432   // Get existing group names
5433   for (int i = 0, nbGroups = groups->length(); i < nbGroups; i++ ) {
5434     SMESH::SMESH_GroupBase_var aGroup = groups[i];
5435     if (CORBA::is_nil(aGroup))
5436       continue;
5437
5438     CORBA::String_var name = aGroup->GetName();
5439     groupNames.insert( name.in() );
5440   }
5441
5442   // Find new name
5443   std::string name = thePrefix;
5444   int index = 0;
5445
5446   while (!groupNames.insert(name).second)
5447     name = SMESH_Comment( thePrefix ) << "_" << index++;
5448
5449   return name;
5450 }
5451
5452 //================================================================================
5453 /*!
5454  * \brief Prepare SMESH_IDSource for work
5455  */
5456 //================================================================================
5457
5458 void SMESH_MeshEditor_i::prepareIdSource(SMESH::SMESH_IDSource_ptr theObject)
5459 {
5460   if ( SMESH::Filter_i* filter = SMESH::DownCast<SMESH::Filter_i*>( theObject ))
5461   {
5462     SMESH::SMESH_Mesh_var mesh = myMesh_i->_this();
5463     filter->SetMesh( mesh );
5464   }
5465 }
5466 //================================================================================
5467 /*!
5468  * \brief Retrieve elements of given type from SMESH_IDSource
5469  */
5470 //================================================================================
5471
5472 bool SMESH_MeshEditor_i::idSourceToSet(SMESH::SMESH_IDSource_ptr  theIDSource,
5473                                        const SMESHDS_Mesh*        theMeshDS,
5474                                        TIDSortedElemSet&          theElemSet,
5475                                        const SMDSAbs_ElementType  theType,
5476                                        const bool                 emptyIfIsMesh,
5477                                        IDSource_Error*            error)
5478
5479 {
5480   if ( error ) *error = IDSource_OK;
5481
5482   if ( CORBA::is_nil( theIDSource ))
5483   {
5484     if ( error ) *error = IDSource_INVALID;
5485     return false;
5486   }
5487   if ( emptyIfIsMesh && SMESH::DownCast<SMESH_Mesh_i*>( theIDSource ))
5488   {
5489     if ( error && getMeshDS()->GetMeshInfo().NbElements( theType ) == 0 )
5490       *error = IDSource_EMPTY;
5491     return true;
5492   }
5493   prepareIdSource( theIDSource );
5494   SMESH::long_array_var anIDs = theIDSource->GetIDs();
5495   if ( anIDs->length() == 0 )
5496   {
5497     if ( error ) *error = IDSource_EMPTY;
5498     return false;
5499   }
5500   SMESH::array_of_ElementType_var types = theIDSource->GetTypes();
5501   if ( types->length() == 1 && types[0] == SMESH::NODE ) // group of nodes
5502   {
5503     if ( theType == SMDSAbs_All || theType == SMDSAbs_Node )
5504     {
5505       arrayToSet( anIDs, getMeshDS(), theElemSet, SMDSAbs_Node );
5506     }
5507     else
5508     {
5509       if ( error ) *error = IDSource_INVALID;
5510       return false;
5511     }
5512   }
5513   else
5514   {
5515     arrayToSet( anIDs, getMeshDS(), theElemSet, theType);
5516     if ( bool(anIDs->length()) != bool(theElemSet.size()))
5517     {
5518       if ( error ) *error = IDSource_INVALID;
5519       return false;
5520     }
5521   }
5522   return true;
5523 }
5524
5525 //================================================================================
5526 /*!
5527  * \brief Duplicates given elements, i.e. creates new elements based on the
5528  *        same nodes as the given ones.
5529  * \param theElements - container of elements to duplicate.
5530  * \param theGroupName - a name of group to contain the generated elements.
5531  *                    If a group with such a name already exists, the new elements
5532  *                    are added to the existng group, else a new group is created.
5533  *                    If \a theGroupName is empty, new elements are not added 
5534  *                    in any group.
5535  * \return a group where the new elements are added. NULL if theGroupName == "".
5536  * \sa DoubleNode()
5537  */
5538 //================================================================================
5539
5540 SMESH::SMESH_Group_ptr
5541 SMESH_MeshEditor_i::DoubleElements(SMESH::SMESH_IDSource_ptr theElements,
5542                                    const char*               theGroupName)
5543   throw (SALOME::SALOME_Exception)
5544 {
5545   SMESH::SMESH_Group_var newGroup;
5546
5547   SMESH_TRY;
5548   initData();
5549
5550   TPythonDump pyDump;
5551
5552   TIDSortedElemSet elems;
5553   if ( idSourceToSet( theElements, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true))
5554   {
5555     getEditor().DoubleElements( elems );
5556
5557     if ( strlen( theGroupName ) && !getEditor().GetLastCreatedElems().IsEmpty() )
5558     {
5559       // group type
5560       SMESH::ElementType type =
5561         SMESH::ElementType( getEditor().GetLastCreatedElems().Value(1)->GetType() );
5562       // find existing group
5563       SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
5564       for ( size_t i = 0; i < groups->length(); ++i )
5565         if ( groups[i]->GetType() == type )
5566         {
5567           CORBA::String_var name = groups[i]->GetName();
5568           if ( strcmp( name, theGroupName ) == 0 ) {
5569             newGroup = SMESH::SMESH_Group::_narrow( groups[i] );
5570             break;
5571           }
5572         }
5573       // create a new group
5574       if ( newGroup->_is_nil() )
5575         newGroup = myMesh_i->CreateGroup( type, theGroupName );
5576       // fill newGroup
5577       if ( SMESH_Group_i* group_i = SMESH::DownCast< SMESH_Group_i* >( newGroup ))
5578       {
5579         SMESHDS_Group* groupDS = static_cast< SMESHDS_Group* >( group_i->GetGroupDS() );
5580         const SMESH_SequenceOfElemPtr& aSeq = getEditor().GetLastCreatedElems();
5581         for ( int i = 1; i <= aSeq.Length(); i++ )
5582           groupDS->SMDSGroup().Add( aSeq(i) );
5583       }
5584     }
5585   }
5586   // python dump
5587   if ( !newGroup->_is_nil() )
5588     pyDump << newGroup << " = ";
5589   pyDump << this << ".DoubleElements( "
5590          << theElements << ", " << "'" << theGroupName <<"')";
5591
5592   SMESH_CATCH( SMESH::throwCorbaException );
5593
5594   return newGroup._retn();
5595 }
5596
5597 //================================================================================
5598 /*!
5599   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5600   \param theNodes - identifiers of nodes to be doubled
5601   \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
5602          nodes. If list of element identifiers is empty then nodes are doubled but
5603          they not assigned to elements
5604   \return TRUE if operation has been completed successfully, FALSE otherwise
5605   \sa DoubleNode(), DoubleNodeGroup(), DoubleNodeGroups()
5606 */
5607 //================================================================================
5608
5609 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodes( const SMESH::long_array& theNodes,
5610                                                 const SMESH::long_array& theModifiedElems )
5611   throw (SALOME::SALOME_Exception)
5612 {
5613   SMESH_TRY;
5614   initData();
5615
5616   list< int > aListOfNodes;
5617   int i, n;
5618   for ( i = 0, n = theNodes.length(); i < n; i++ )
5619     aListOfNodes.push_back( theNodes[ i ] );
5620
5621   list< int > aListOfElems;
5622   for ( i = 0, n = theModifiedElems.length(); i < n; i++ )
5623     aListOfElems.push_back( theModifiedElems[ i ] );
5624
5625   bool aResult = getEditor().DoubleNodes( aListOfNodes, aListOfElems );
5626
5627   declareMeshModified( /*isReComputeSafe=*/ !aResult );
5628
5629   // Update Python script
5630   TPythonDump() << this << ".DoubleNodes( " << theNodes << ", "<< theModifiedElems << " )";
5631
5632   return aResult;
5633
5634   SMESH_CATCH( SMESH::throwCorbaException );
5635   return 0;
5636 }
5637
5638 //================================================================================
5639 /*!
5640   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5641   This method provided for convenience works as DoubleNodes() described above.
5642   \param theNodeId - identifier of node to be doubled.
5643   \param theModifiedElems - identifiers of elements to be updated.
5644   \return TRUE if operation has been completed successfully, FALSE otherwise
5645   \sa DoubleNodes(), DoubleNodeGroup(), DoubleNodeGroups()
5646 */
5647 //================================================================================
5648
5649 CORBA::Boolean SMESH_MeshEditor_i::DoubleNode( CORBA::Long              theNodeId,
5650                                                const SMESH::long_array& theModifiedElems )
5651   throw (SALOME::SALOME_Exception)
5652 {
5653   SMESH_TRY;
5654   SMESH::long_array_var aNodes = new SMESH::long_array;
5655   aNodes->length( 1 );
5656   aNodes[ 0 ] = theNodeId;
5657
5658   TPythonDump pyDump; // suppress dump by the next line
5659
5660   CORBA::Boolean done = DoubleNodes( aNodes, theModifiedElems );
5661
5662   pyDump << this << ".DoubleNode( " << theNodeId << ", " << theModifiedElems << " )";
5663
5664   return done;
5665
5666   SMESH_CATCH( SMESH::throwCorbaException );
5667   return 0;
5668 }
5669
5670 //================================================================================
5671 /*!
5672   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5673   This method provided for convenience works as DoubleNodes() described above.
5674   \param theNodes - group of nodes to be doubled.
5675   \param theModifiedElems - group of elements to be updated.
5676   \return TRUE if operation has been completed successfully, FALSE otherwise
5677   \sa DoubleNode(), DoubleNodes(), DoubleNodeGroups()
5678 */
5679 //================================================================================
5680
5681 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroup(SMESH::SMESH_GroupBase_ptr theNodes,
5682                                                    SMESH::SMESH_GroupBase_ptr theModifiedElems )
5683   throw (SALOME::SALOME_Exception)
5684 {
5685   SMESH_TRY;
5686   if ( CORBA::is_nil( theNodes ) && theNodes->GetType() != SMESH::NODE )
5687     return false;
5688
5689   SMESH::long_array_var aNodes = theNodes->GetListOfID();
5690   SMESH::long_array_var aModifiedElems;
5691   if ( !CORBA::is_nil( theModifiedElems ) )
5692     aModifiedElems = theModifiedElems->GetListOfID();
5693   else
5694   {
5695     aModifiedElems = new SMESH::long_array;
5696     aModifiedElems->length( 0 );
5697   }
5698
5699   TPythonDump pyDump; // suppress dump by the next line
5700
5701   bool done = DoubleNodes( aNodes, aModifiedElems );
5702
5703   pyDump << this << ".DoubleNodeGroup( " << theNodes << ", " << theModifiedElems << " )";
5704
5705   return done;
5706
5707   SMESH_CATCH( SMESH::throwCorbaException );
5708   return 0;
5709 }
5710
5711 //================================================================================
5712 /*!
5713  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
5714  * Works as DoubleNodeGroup(), but returns a new group with newly created nodes.
5715  * \param theNodes - group of nodes to be doubled.
5716  * \param theModifiedElems - group of elements to be updated.
5717  * \return a new group with newly created nodes
5718  * \sa DoubleNodeGroup()
5719  */
5720 //================================================================================
5721
5722 SMESH::SMESH_Group_ptr
5723 SMESH_MeshEditor_i::DoubleNodeGroupNew( SMESH::SMESH_GroupBase_ptr theNodes,
5724                                         SMESH::SMESH_GroupBase_ptr theModifiedElems )
5725   throw (SALOME::SALOME_Exception)
5726 {
5727   SMESH_TRY;
5728   SMESH::SMESH_Group_var aNewGroup;
5729
5730   if ( CORBA::is_nil( theNodes ) && theNodes->GetType() != SMESH::NODE )
5731     return aNewGroup._retn();
5732
5733   // Duplicate nodes
5734   SMESH::long_array_var aNodes = theNodes->GetListOfID();
5735   SMESH::long_array_var aModifiedElems;
5736   if ( !CORBA::is_nil( theModifiedElems ) )
5737     aModifiedElems = theModifiedElems->GetListOfID();
5738   else {
5739     aModifiedElems = new SMESH::long_array;
5740     aModifiedElems->length( 0 );
5741   }
5742
5743   TPythonDump pyDump; // suppress dump by the next line
5744
5745   bool aResult = DoubleNodes( aNodes, aModifiedElems );
5746   if ( aResult )
5747   {
5748     // Create group with newly created nodes
5749     SMESH::long_array_var anIds = GetLastCreatedNodes();
5750     if (anIds->length() > 0) {
5751       std::string anUnindexedName (theNodes->GetName());
5752       std::string aNewName = generateGroupName(anUnindexedName + "_double");
5753       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
5754       aNewGroup->Add(anIds);
5755       pyDump << aNewGroup << " = ";
5756     }
5757   }
5758
5759   pyDump << this << ".DoubleNodeGroupNew( " << theNodes << ", "
5760          << theModifiedElems << " )";
5761
5762   return aNewGroup._retn();
5763
5764   SMESH_CATCH( SMESH::throwCorbaException );
5765   return 0;
5766 }
5767
5768 //================================================================================
5769 /*!
5770   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5771   This method provided for convenience works as DoubleNodes() described above.
5772   \param theNodes - list of groups of nodes to be doubled
5773   \param theModifiedElems - list of groups of elements to be updated.
5774   \return TRUE if operation has been completed successfully, FALSE otherwise
5775   \sa DoubleNode(), DoubleNodeGroup(), DoubleNodes()
5776 */
5777 //================================================================================
5778
5779 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroups(const SMESH::ListOfGroups& theNodes,
5780                                                     const SMESH::ListOfGroups& theModifiedElems )
5781   throw (SALOME::SALOME_Exception)
5782 {
5783   SMESH_TRY;
5784   initData();
5785
5786   std::list< int > aNodes;
5787   int i, n, j, m;
5788   for ( i = 0, n = theNodes.length(); i < n; i++ )
5789   {
5790     SMESH::SMESH_GroupBase_var aGrp = theNodes[ i ];
5791     if ( !CORBA::is_nil( aGrp ) && aGrp->GetType() == SMESH::NODE )
5792     {
5793       SMESH::long_array_var aCurr = aGrp->GetListOfID();
5794       for ( j = 0, m = aCurr->length(); j < m; j++ )
5795         aNodes.push_back( aCurr[ j ] );
5796     }
5797   }
5798
5799   std::list< int > anElems;
5800   for ( i = 0, n = theModifiedElems.length(); i < n; i++ )
5801   {
5802     SMESH::SMESH_GroupBase_var aGrp = theModifiedElems[ i ];
5803     if ( !CORBA::is_nil( aGrp ) && aGrp->GetType() != SMESH::NODE )
5804     {
5805       SMESH::long_array_var aCurr = aGrp->GetListOfID();
5806       for ( j = 0, m = aCurr->length(); j < m; j++ )
5807         anElems.push_back( aCurr[ j ] );
5808     }
5809   }
5810
5811   bool aResult = getEditor().DoubleNodes( aNodes, anElems );
5812
5813   declareMeshModified( /*isReComputeSafe=*/false );
5814
5815   TPythonDump() << this << ".DoubleNodeGroups( " << theNodes << ", " << theModifiedElems << " )";
5816
5817   return aResult;
5818
5819   SMESH_CATCH( SMESH::throwCorbaException );
5820   return 0;
5821 }
5822
5823 //================================================================================
5824 /*!
5825  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
5826  * Works as DoubleNodeGroups(), but returns a new group with newly created nodes.
5827  * \param theNodes - group of nodes to be doubled.
5828  * \param theModifiedElems - group of elements to be updated.
5829  * \return a new group with newly created nodes
5830  * \sa DoubleNodeGroups()
5831  */
5832 //================================================================================
5833
5834 SMESH::SMESH_Group_ptr
5835 SMESH_MeshEditor_i::DoubleNodeGroupsNew( const SMESH::ListOfGroups& theNodes,
5836                                          const SMESH::ListOfGroups& theModifiedElems )
5837   throw (SALOME::SALOME_Exception)
5838 {
5839   SMESH::SMESH_Group_var aNewGroup;
5840
5841   TPythonDump pyDump; // suppress dump by the next line
5842
5843   bool aResult = DoubleNodeGroups( theNodes, theModifiedElems );
5844
5845   if ( aResult )
5846   {
5847     // Create group with newly created nodes
5848     SMESH::long_array_var anIds = GetLastCreatedNodes();
5849     if (anIds->length() > 0) {
5850       std::string anUnindexedName (theNodes[0]->GetName());
5851       std::string aNewName = generateGroupName(anUnindexedName + "_double");
5852       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
5853       aNewGroup->Add(anIds);
5854       pyDump << aNewGroup << " = ";
5855     }
5856   }
5857
5858   pyDump << this << ".DoubleNodeGroupsNew( " << theNodes << ", "
5859          << theModifiedElems << " )";
5860
5861   return aNewGroup._retn();
5862 }
5863
5864
5865 //================================================================================
5866 /*!
5867   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5868   \param theElems - the list of elements (edges or faces) to be replicated
5869   The nodes for duplication could be found from these elements
5870   \param theNodesNot - list of nodes to NOT replicate
5871   \param theAffectedElems - the list of elements (cells and edges) to which the
5872   replicated nodes should be associated to.
5873   \return TRUE if operation has been completed successfully, FALSE otherwise
5874   \sa DoubleNodeGroup(), DoubleNodeGroups()
5875 */
5876 //================================================================================
5877
5878 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElem( const SMESH::long_array& theElems,
5879                                                    const SMESH::long_array& theNodesNot,
5880                                                    const SMESH::long_array& theAffectedElems )
5881   throw (SALOME::SALOME_Exception)
5882 {
5883   SMESH_TRY;
5884   initData();
5885
5886   SMESHDS_Mesh* aMeshDS = getMeshDS();
5887   TIDSortedElemSet anElems, aNodes, anAffected;
5888   arrayToSet(theElems, aMeshDS, anElems, SMDSAbs_All);
5889   arrayToSet(theNodesNot, aMeshDS, aNodes, SMDSAbs_Node);
5890   arrayToSet(theAffectedElems, aMeshDS, anAffected, SMDSAbs_All);
5891
5892   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5893
5894   // Update Python script
5895   TPythonDump() << this << ".DoubleNodeElem( " << theElems << ", "
5896                 << theNodesNot << ", " << theAffectedElems << " )";
5897
5898   declareMeshModified( /*isReComputeSafe=*/false );
5899   return aResult;
5900
5901   SMESH_CATCH( SMESH::throwCorbaException );
5902   return 0;
5903 }
5904
5905 //================================================================================
5906 /*!
5907   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5908   \param theElems - the list of elements (edges or faces) to be replicated
5909   The nodes for duplication could be found from these elements
5910   \param theNodesNot - list of nodes to NOT replicate
5911   \param theShape - shape to detect affected elements (element which geometric center
5912   located on or inside shape).
5913   The replicated nodes should be associated to affected elements.
5914   \return TRUE if operation has been completed successfully, FALSE otherwise
5915   \sa DoubleNodeGroupInRegion(), DoubleNodeGroupsInRegion()
5916 */
5917 //================================================================================
5918
5919 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemInRegion ( const SMESH::long_array& theElems,
5920                                                             const SMESH::long_array& theNodesNot,
5921                                                             GEOM::GEOM_Object_ptr    theShape )
5922   throw (SALOME::SALOME_Exception)
5923 {
5924   SMESH_TRY;
5925   initData();
5926
5927
5928   SMESHDS_Mesh* aMeshDS = getMeshDS();
5929   TIDSortedElemSet anElems, aNodes;
5930   arrayToSet(theElems, aMeshDS, anElems, SMDSAbs_All);
5931   arrayToSet(theNodesNot, aMeshDS, aNodes, SMDSAbs_Node);
5932
5933   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
5934   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
5935
5936   // Update Python script
5937   TPythonDump() << "isDone = " << this << ".DoubleNodeElemInRegion( " << theElems << ", "
5938                 << theNodesNot << ", " << theShape << " )";
5939
5940   declareMeshModified( /*isReComputeSafe=*/false );
5941   return aResult;
5942
5943   SMESH_CATCH( SMESH::throwCorbaException );
5944   return 0;
5945 }
5946
5947 //================================================================================
5948 /*!
5949   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5950   \param theElems - group of of elements (edges or faces) to be replicated
5951   \param theNodesNot - group of nodes not to replicated
5952   \param theAffectedElems - group of elements to which the replicated nodes
5953   should be associated to.
5954   \return TRUE if operation has been completed successfully, FALSE otherwise
5955   \sa DoubleNodes(), DoubleNodeGroups()
5956 */
5957 //================================================================================
5958
5959 CORBA::Boolean
5960 SMESH_MeshEditor_i::DoubleNodeElemGroup(SMESH::SMESH_GroupBase_ptr theElems,
5961                                         SMESH::SMESH_GroupBase_ptr theNodesNot,
5962                                         SMESH::SMESH_GroupBase_ptr theAffectedElems)
5963   throw (SALOME::SALOME_Exception)
5964 {
5965   SMESH_TRY;
5966   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
5967     return false;
5968
5969   initData();
5970
5971
5972   SMESHDS_Mesh* aMeshDS = getMeshDS();
5973   TIDSortedElemSet anElems, aNodes, anAffected;
5974   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
5975   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
5976   idSourceToSet( theAffectedElems, aMeshDS, anAffected, SMDSAbs_All );
5977
5978   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5979
5980   // Update Python script
5981   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroup( " << theElems << ", "
5982                 << theNodesNot << ", " << theAffectedElems << " )";
5983
5984   declareMeshModified( /*isReComputeSafe=*/false );
5985   return aResult;
5986
5987   SMESH_CATCH( SMESH::throwCorbaException );
5988   return 0;
5989 }
5990
5991 //================================================================================
5992 /*!
5993  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5994  * Works as DoubleNodeElemGroup(), but returns a new group with newly created elements.
5995  * \param theElems - group of of elements (edges or faces) to be replicated
5996  * \param theNodesNot - group of nodes not to replicated
5997  * \param theAffectedElems - group of elements to which the replicated nodes
5998  *        should be associated to.
5999  * \return a new group with newly created elements
6000  * \sa DoubleNodeElemGroup()
6001  */
6002 //================================================================================
6003
6004 SMESH::SMESH_Group_ptr
6005 SMESH_MeshEditor_i::DoubleNodeElemGroupNew(SMESH::SMESH_GroupBase_ptr theElems,
6006                                            SMESH::SMESH_GroupBase_ptr theNodesNot,
6007                                            SMESH::SMESH_GroupBase_ptr theAffectedElems)
6008   throw (SALOME::SALOME_Exception)
6009 {
6010   TPythonDump pyDump;
6011   SMESH::ListOfGroups_var twoGroups = DoubleNodeElemGroup2New( theElems,
6012                                                                theNodesNot,
6013                                                                theAffectedElems,
6014                                                                true, false );
6015   SMESH::SMESH_GroupBase_var baseGroup = twoGroups[0].in();
6016   SMESH::SMESH_Group_var     elemGroup = SMESH::SMESH_Group::_narrow( baseGroup );
6017
6018   pyDump << elemGroup << " = " << this << ".DoubleNodeElemGroupNew( "
6019          << theElems         << ", "
6020          << theNodesNot      << ", "
6021          << theAffectedElems << " )";
6022
6023   return elemGroup._retn();
6024 }
6025
6026 //================================================================================
6027 /*!
6028  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6029  * Works as DoubleNodeElemGroup(), but returns a new group with newly created elements.
6030  * \param theElems - group of of elements (edges or faces) to be replicated
6031  * \param theNodesNot - group of nodes not to replicated
6032  * \param theAffectedElems - group of elements to which the replicated nodes
6033  *        should be associated to.
6034  * \return a new group with newly created elements
6035  * \sa DoubleNodeElemGroup()
6036  */
6037 //================================================================================
6038
6039 SMESH::ListOfGroups*
6040 SMESH_MeshEditor_i::DoubleNodeElemGroup2New(SMESH::SMESH_GroupBase_ptr theElems,
6041                                             SMESH::SMESH_GroupBase_ptr theNodesNot,
6042                                             SMESH::SMESH_GroupBase_ptr theAffectedElems,
6043                                             CORBA::Boolean             theElemGroupNeeded,
6044                                             CORBA::Boolean             theNodeGroupNeeded)
6045   throw (SALOME::SALOME_Exception)
6046 {
6047   SMESH_TRY;
6048   SMESH::SMESH_Group_var aNewElemGroup, aNewNodeGroup;
6049   SMESH::ListOfGroups_var aTwoGroups = new SMESH::ListOfGroups();
6050   aTwoGroups->length( 2 );
6051
6052   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
6053     return aTwoGroups._retn();
6054
6055   initData();
6056
6057
6058   SMESHDS_Mesh* aMeshDS = getMeshDS();
6059   TIDSortedElemSet anElems, aNodes, anAffected;
6060   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
6061   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
6062   idSourceToSet( theAffectedElems, aMeshDS, anAffected, SMDSAbs_All );
6063
6064
6065   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
6066
6067   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6068
6069   TPythonDump pyDump;
6070
6071   if ( aResult )
6072   {
6073     // Create group with newly created elements
6074     CORBA::String_var elemGroupName = theElems->GetName();
6075     std::string aNewName = generateGroupName( std::string(elemGroupName.in()) + "_double");
6076     if ( !getEditor().GetLastCreatedElems().IsEmpty() && theElemGroupNeeded )
6077     {
6078       SMESH::long_array_var anIds = GetLastCreatedElems();
6079       SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true);
6080       aNewElemGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str());
6081       aNewElemGroup->Add(anIds);
6082     }
6083     if ( !getEditor().GetLastCreatedNodes().IsEmpty() && theNodeGroupNeeded )
6084     {
6085       SMESH::long_array_var anIds = GetLastCreatedNodes();
6086       aNewNodeGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
6087       aNewNodeGroup->Add(anIds);
6088     }
6089   }
6090
6091   // Update Python script
6092
6093   pyDump << "[ ";
6094   if ( aNewElemGroup->_is_nil() ) pyDump << "nothing, ";
6095   else                            pyDump << aNewElemGroup << ", ";
6096   if ( aNewNodeGroup->_is_nil() ) pyDump << "nothing ] = ";
6097   else                            pyDump << aNewNodeGroup << " ] = ";
6098
6099   pyDump << this << ".DoubleNodeElemGroup2New( " << theElems << ", "
6100          << theNodesNot        << ", "
6101          << theAffectedElems   << ", "
6102          << theElemGroupNeeded << ", "
6103          << theNodeGroupNeeded <<" )";
6104
6105   aTwoGroups[0] = aNewElemGroup._retn();
6106   aTwoGroups[1] = aNewNodeGroup._retn();
6107   return aTwoGroups._retn();
6108
6109   SMESH_CATCH( SMESH::throwCorbaException );
6110   return 0;
6111 }
6112
6113 //================================================================================
6114 /*!
6115   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6116   \param theElems - group of of elements (edges or faces) to be replicated
6117   \param theNodesNot - group of nodes not to replicated
6118   \param theShape - shape to detect affected elements (element which geometric center
6119   located on or inside shape).
6120   The replicated nodes should be associated to affected elements.
6121   \return TRUE if operation has been completed successfully, FALSE otherwise
6122   \sa DoubleNodesInRegion(), DoubleNodeGroupsInRegion()
6123 */
6124 //================================================================================
6125
6126 CORBA::Boolean
6127 SMESH_MeshEditor_i::DoubleNodeElemGroupInRegion(SMESH::SMESH_GroupBase_ptr theElems,
6128                                                 SMESH::SMESH_GroupBase_ptr theNodesNot,
6129                                                 GEOM::GEOM_Object_ptr      theShape )
6130   throw (SALOME::SALOME_Exception)
6131 {
6132   SMESH_TRY;
6133   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
6134     return false;
6135
6136   initData();
6137
6138
6139   SMESHDS_Mesh* aMeshDS = getMeshDS();
6140   TIDSortedElemSet anElems, aNodes, anAffected;
6141   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
6142   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
6143
6144   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
6145   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
6146
6147
6148   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6149
6150   // Update Python script
6151   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroupInRegion( " << theElems << ", "
6152                 << theNodesNot << ", " << theShape << " )";
6153   return aResult;
6154
6155   SMESH_CATCH( SMESH::throwCorbaException );
6156   return 0;
6157 }
6158
6159 //================================================================================
6160 /*!
6161  * \brief Re-load elements from a list of groups into a TIDSortedElemSet
6162  *  \param [in] theGrpList - groups
6163  *  \param [in] theMeshDS -  mesh
6164  *  \param [out] theElemSet - set of elements
6165  *  \param [in] theIsNodeGrp - is \a theGrpList includes goups of nodes
6166  */
6167 //================================================================================
6168
6169 static void listOfGroupToSet(const SMESH::ListOfGroups& theGrpList,
6170                              SMESHDS_Mesh*              theMeshDS,
6171                              TIDSortedElemSet&          theElemSet,
6172                              const bool                 theIsNodeGrp)
6173 {
6174   for ( int i = 0, n = theGrpList.length(); i < n; i++ )
6175   {
6176     SMESH::SMESH_GroupBase_var aGrp = theGrpList[ i ];
6177     if ( !CORBA::is_nil( aGrp ) && (theIsNodeGrp ? aGrp->GetType() == SMESH::NODE
6178                                     : aGrp->GetType() != SMESH::NODE ) )
6179     {
6180       SMESH::long_array_var anIDs = aGrp->GetIDs();
6181       arrayToSet( anIDs, theMeshDS, theElemSet, theIsNodeGrp ? SMDSAbs_Node : SMDSAbs_All );
6182     }
6183   }
6184 }
6185
6186 //================================================================================
6187 /*!
6188   \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
6189   This method provided for convenience works as DoubleNodes() described above.
6190   \param theElems - list of groups of elements (edges or faces) to be replicated
6191   \param theNodesNot - list of groups of nodes not to replicated
6192   \param theAffectedElems - group of elements to which the replicated nodes
6193   should be associated to.
6194   \return TRUE if operation has been completed successfully, FALSE otherwise
6195   \sa DoubleNodeGroup(), DoubleNodes(), DoubleNodeElemGroupsNew()
6196 */
6197 //================================================================================
6198
6199 CORBA::Boolean
6200 SMESH_MeshEditor_i::DoubleNodeElemGroups(const SMESH::ListOfGroups& theElems,
6201                                          const SMESH::ListOfGroups& theNodesNot,
6202                                          const SMESH::ListOfGroups& theAffectedElems)
6203   throw (SALOME::SALOME_Exception)
6204 {
6205   SMESH_TRY;
6206   initData();
6207
6208
6209   SMESHDS_Mesh* aMeshDS = getMeshDS();
6210   TIDSortedElemSet anElems, aNodes, anAffected;
6211   listOfGroupToSet(theElems, aMeshDS, anElems, false );
6212   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
6213   listOfGroupToSet(theAffectedElems, aMeshDS, anAffected, false );
6214
6215   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
6216
6217   // Update Python script
6218   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroups( " << &theElems << ", "
6219                 << &theNodesNot << ", " << &theAffectedElems << " )";
6220
6221   declareMeshModified( /*isReComputeSafe=*/false );
6222   return aResult;
6223
6224   SMESH_CATCH( SMESH::throwCorbaException );
6225   return 0;
6226 }
6227
6228 //================================================================================
6229 /*!
6230  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6231  * Works as DoubleNodeElemGroups(), but returns a new group with newly created elements.
6232   \param theElems - list of groups of elements (edges or faces) to be replicated
6233   \param theNodesNot - list of groups of nodes not to replicated
6234   \param theAffectedElems - group of elements to which the replicated nodes
6235   should be associated to.
6236  * \return a new group with newly created elements
6237  * \sa DoubleNodeElemGroups()
6238  */
6239 //================================================================================
6240
6241 SMESH::SMESH_Group_ptr
6242 SMESH_MeshEditor_i::DoubleNodeElemGroupsNew(const SMESH::ListOfGroups& theElems,
6243                                             const SMESH::ListOfGroups& theNodesNot,
6244                                             const SMESH::ListOfGroups& theAffectedElems)
6245   throw (SALOME::SALOME_Exception)
6246 {
6247   TPythonDump pyDump;
6248   SMESH::ListOfGroups_var twoGroups = DoubleNodeElemGroups2New( theElems,
6249                                                                 theNodesNot,
6250                                                                 theAffectedElems,
6251                                                                 true, false );
6252   SMESH::SMESH_GroupBase_var baseGroup = twoGroups[0].in();
6253   SMESH::SMESH_Group_var     elemGroup = SMESH::SMESH_Group::_narrow( baseGroup );
6254
6255   pyDump << elemGroup << " = " << this << ".DoubleNodeElemGroupsNew( "
6256          << theElems         << ", "
6257          << theNodesNot      << ", "
6258          << theAffectedElems << " )";
6259
6260   return elemGroup._retn();
6261 }
6262
6263 //================================================================================
6264 /*!
6265  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6266  * Works as DoubleNodeElemGroups(), but returns a new group with newly created elements.
6267   \param theElems - list of groups of elements (edges or faces) to be replicated
6268   \param theNodesNot - list of groups of nodes not to replicated
6269   \param theAffectedElems - group of elements to which the replicated nodes
6270   should be associated to.
6271  * \return a new group with newly created elements
6272  * \sa DoubleNodeElemGroups()
6273  */
6274 //================================================================================
6275
6276 SMESH::ListOfGroups*
6277 SMESH_MeshEditor_i::DoubleNodeElemGroups2New(const SMESH::ListOfGroups& theElems,
6278                                              const SMESH::ListOfGroups& theNodesNot,
6279                                              const SMESH::ListOfGroups& theAffectedElems,
6280                                              CORBA::Boolean             theElemGroupNeeded,
6281                                              CORBA::Boolean             theNodeGroupNeeded)
6282   throw (SALOME::SALOME_Exception)
6283 {
6284   SMESH_TRY;
6285   SMESH::SMESH_Group_var aNewElemGroup, aNewNodeGroup;
6286   SMESH::ListOfGroups_var aTwoGroups = new SMESH::ListOfGroups();
6287   aTwoGroups->length( 2 );
6288   
6289   initData();
6290
6291
6292   SMESHDS_Mesh* aMeshDS = getMeshDS();
6293   TIDSortedElemSet anElems, aNodes, anAffected;
6294   listOfGroupToSet(theElems, aMeshDS, anElems, false );
6295   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
6296   listOfGroupToSet(theAffectedElems, aMeshDS, anAffected, false );
6297
6298   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
6299
6300   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6301
6302   TPythonDump pyDump;
6303   if ( aResult )
6304   {
6305     // Create group with newly created elements
6306     CORBA::String_var elemGroupName = theElems[0]->GetName();
6307     std::string aNewName = generateGroupName( std::string(elemGroupName.in()) + "_double");
6308     if ( !getEditor().GetLastCreatedElems().IsEmpty() && theElemGroupNeeded )
6309     {
6310       SMESH::long_array_var anIds = GetLastCreatedElems();
6311       SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true);
6312       aNewElemGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str());
6313       aNewElemGroup->Add(anIds);
6314     }
6315     if ( !getEditor().GetLastCreatedNodes().IsEmpty() && theNodeGroupNeeded )
6316     {
6317       SMESH::long_array_var anIds = GetLastCreatedNodes();
6318       aNewNodeGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
6319       aNewNodeGroup->Add(anIds);
6320     }
6321   }
6322
6323   // Update Python script
6324
6325   pyDump << "[ ";
6326   if ( aNewElemGroup->_is_nil() ) pyDump << "nothing, ";
6327   else                            pyDump << aNewElemGroup << ", ";
6328   if ( aNewNodeGroup->_is_nil() ) pyDump << "nothing ] = ";
6329   else                            pyDump << aNewNodeGroup << " ] = ";
6330
6331   pyDump << this << ".DoubleNodeElemGroups2New( " << &theElems << ", "
6332          << &theNodesNot       << ", "
6333          << &theAffectedElems  << ", "
6334          << theElemGroupNeeded << ", "
6335          << theNodeGroupNeeded << " )";
6336
6337   aTwoGroups[0] = aNewElemGroup._retn();
6338   aTwoGroups[1] = aNewNodeGroup._retn();
6339   return aTwoGroups._retn();
6340
6341   SMESH_CATCH( SMESH::throwCorbaException );
6342   return 0;
6343 }
6344
6345 //================================================================================
6346 /*!
6347   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6348   This method provided for convenience works as DoubleNodes() described above.
6349   \param theElems - list of groups of elements (edges or faces) to be replicated
6350   \param theNodesNot - list of groups of nodes not to replicated
6351   \param theShape - shape to detect affected elements (element which geometric center
6352   located on or inside shape).
6353   The replicated nodes should be associated to affected elements.
6354   \return TRUE if operation has been completed successfully, FALSE otherwise
6355   \sa DoubleNodeGroupInRegion(), DoubleNodesInRegion()
6356 */
6357 //================================================================================
6358
6359 CORBA::Boolean
6360 SMESH_MeshEditor_i::DoubleNodeElemGroupsInRegion(const SMESH::ListOfGroups& theElems,
6361                                                  const SMESH::ListOfGroups& theNodesNot,
6362                                                  GEOM::GEOM_Object_ptr      theShape )
6363   throw (SALOME::SALOME_Exception)
6364 {
6365   SMESH_TRY;
6366   initData();
6367
6368
6369   SMESHDS_Mesh* aMeshDS = getMeshDS();
6370   TIDSortedElemSet anElems, aNodes;
6371   listOfGroupToSet(theElems, aMeshDS, anElems,false );
6372   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
6373
6374   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
6375   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
6376
6377   // Update Python script
6378   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroupsInRegion( " << &theElems << ", "
6379                 << &theNodesNot << ", " << theShape << " )";
6380
6381   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6382   return aResult;
6383
6384   SMESH_CATCH( SMESH::throwCorbaException );
6385   return 0;
6386 }
6387
6388 //================================================================================
6389 /*!
6390   \brief Identify the elements that will be affected by node duplication (actual
6391          duplication is not performed.
6392   This method is the first step of DoubleNodeElemGroupsInRegion.
6393   \param theElems - list of groups of elements (edges or faces) to be replicated
6394   \param theNodesNot - list of groups of nodes not to replicated
6395   \param theShape - shape to detect affected elements (element which geometric center
6396          located on or inside shape).
6397          The replicated nodes should be associated to affected elements.
6398   \return groups of affected elements
6399   \sa DoubleNodeElemGroupsInRegion()
6400 */
6401 //================================================================================
6402 SMESH::ListOfGroups*
6403 SMESH_MeshEditor_i::AffectedElemGroupsInRegion( const SMESH::ListOfGroups& theElems,
6404                                                 const SMESH::ListOfGroups& theNodesNot,
6405                                                 GEOM::GEOM_Object_ptr      theShape )
6406   throw (SALOME::SALOME_Exception)
6407 {
6408   SMESH_TRY;
6409   SMESH::ListOfGroups_var aListOfGroups = new SMESH::ListOfGroups();
6410   bool isEdgeGroup = false;
6411   bool isFaceGroup = false;
6412   bool isVolumeGroup = false;
6413   SMESH::SMESH_Group_var aNewEdgeGroup = myMesh_i->CreateGroup(SMESH::EDGE, "affectedEdges");
6414   SMESH::SMESH_Group_var aNewFaceGroup = myMesh_i->CreateGroup(SMESH::FACE, "affectedFaces");
6415   SMESH::SMESH_Group_var aNewVolumeGroup = myMesh_i->CreateGroup(SMESH::VOLUME, "affectedVolumes");
6416
6417   initData();
6418
6419   ::SMESH_MeshEditor aMeshEditor(myMesh);
6420
6421   SMESHDS_Mesh* aMeshDS = getMeshDS();
6422   TIDSortedElemSet anElems, aNodes;
6423   listOfGroupToSet(theElems, aMeshDS, anElems, false);
6424   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true);
6425
6426   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape(theShape);
6427   TIDSortedElemSet anAffected;
6428   bool aResult = aMeshEditor.AffectedElemGroupsInRegion(anElems, aNodes, aShape, anAffected);
6429
6430
6431   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6432
6433   TPythonDump pyDump;
6434   if (aResult)
6435   {
6436     int lg = anAffected.size();
6437     SMESH::long_array_var volumeIds = new SMESH::long_array;
6438     volumeIds->length(lg);
6439     SMESH::long_array_var faceIds = new SMESH::long_array;
6440     faceIds->length(lg);
6441     SMESH::long_array_var edgeIds = new SMESH::long_array;
6442     edgeIds->length(lg);
6443     int ivol = 0;
6444     int iface = 0;
6445     int iedge = 0;
6446
6447     TIDSortedElemSet::const_iterator eIt = anAffected.begin();
6448     for (; eIt != anAffected.end(); ++eIt)
6449     {
6450       const SMDS_MeshElement* anElem = *eIt;
6451       if (!anElem)
6452         continue;
6453       int elemId = anElem->GetID();
6454       if (myMesh->GetElementType(elemId, true) == SMDSAbs_Volume)
6455         volumeIds[ivol++] = elemId;
6456       else if (myMesh->GetElementType(elemId, true) == SMDSAbs_Face)
6457         faceIds[iface++] = elemId;
6458       else if (myMesh->GetElementType(elemId, true) == SMDSAbs_Edge)
6459         edgeIds[iedge++] = elemId;
6460     }
6461     volumeIds->length(ivol);
6462     faceIds->length(iface);
6463     edgeIds->length(iedge);
6464
6465     aNewVolumeGroup->Add(volumeIds);
6466     aNewFaceGroup->Add(faceIds);
6467     aNewEdgeGroup->Add(edgeIds);
6468     isVolumeGroup = (aNewVolumeGroup->Size() > 0);
6469     isFaceGroup = (aNewFaceGroup->Size() > 0);
6470     isEdgeGroup = (aNewEdgeGroup->Size() > 0);
6471   }
6472
6473   int nbGroups = 0;
6474   if (isEdgeGroup)   nbGroups++;
6475   if (isFaceGroup)   nbGroups++;
6476   if (isVolumeGroup) nbGroups++;
6477   aListOfGroups->length(nbGroups);
6478
6479   int i = 0;
6480   if (isEdgeGroup)   aListOfGroups[i++] = aNewEdgeGroup._retn();
6481   if (isFaceGroup)   aListOfGroups[i++] = aNewFaceGroup._retn();
6482   if (isVolumeGroup) aListOfGroups[i++] = aNewVolumeGroup._retn();
6483
6484   // Update Python script
6485
6486   pyDump << "[ ";
6487   if (isEdgeGroup)   pyDump << aNewEdgeGroup << ", ";
6488   if (isFaceGroup)   pyDump << aNewFaceGroup << ", ";
6489   if (isVolumeGroup) pyDump << aNewVolumeGroup << ", ";
6490   pyDump << "] = ";
6491   pyDump << this << ".AffectedElemGroupsInRegion( "
6492          << &theElems << ", " << &theNodesNot << ", " << theShape << " )";
6493
6494   return aListOfGroups._retn();
6495
6496   SMESH_CATCH( SMESH::throwCorbaException );
6497   return 0;
6498 }
6499
6500 //================================================================================
6501 /*!
6502   \brief Generated skin mesh (containing 2D cells) from 3D mesh
6503    The created 2D mesh elements based on nodes of free faces of boundary volumes
6504   \return TRUE if operation has been completed successfully, FALSE otherwise
6505 */
6506 //================================================================================
6507
6508 CORBA::Boolean SMESH_MeshEditor_i::Make2DMeshFrom3D()
6509   throw (SALOME::SALOME_Exception)
6510 {
6511   SMESH_TRY;
6512   initData();
6513
6514   bool aResult = getEditor().Make2DMeshFrom3D();
6515
6516   TPythonDump() << "isDone = " << this << ".Make2DMeshFrom3D()";
6517
6518   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6519   return aResult;
6520
6521   SMESH_CATCH( SMESH::throwCorbaException );
6522   return false;
6523 }
6524
6525 //================================================================================
6526 /*!
6527  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
6528  * The list of groups must contain at least two groups. The groups have to be disjoint:
6529  * no common element into two different groups.
6530  * The nodes of the internal faces at the boundaries of the groups are doubled.
6531  * Optionally, the internal faces are replaced by flat elements.
6532  * Triangles are transformed into prisms, and quadrangles into hexahedrons.
6533  * The flat elements are stored in groups of volumes.
6534  * These groups are named according to the position of the group in the list:
6535  * 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.
6536  * 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.
6537  * All the flat elements are gathered into the group named "joints3D" (or "joints2D" in 2D situation).
6538  * The flat element of the multiple junctions between the simple junction are stored in a group named "jointsMultiples".
6539  * \param theDomains - list of groups of volumes
6540  * \param createJointElems - if TRUE, create the elements
6541  * \param onAllBoundaries - if TRUE, the nodes and elements are also created on
6542  *        the boundary between \a theDomains and the rest mesh
6543  * \return TRUE if operation has been completed successfully, FALSE otherwise
6544  */
6545 //================================================================================
6546
6547 CORBA::Boolean
6548 SMESH_MeshEditor_i::DoubleNodesOnGroupBoundaries( const SMESH::ListOfGroups& theDomains,
6549                                                   CORBA::Boolean             createJointElems,
6550                                                   CORBA::Boolean             onAllBoundaries )
6551   throw (SALOME::SALOME_Exception)
6552 {
6553   bool isOK = false;
6554
6555   SMESH_TRY;
6556   initData();
6557
6558   SMESHDS_Mesh* aMeshDS = getMeshDS();
6559
6560   // MESSAGE("theDomains.length = "<<theDomains.length());
6561   if ( theDomains.length() <= 1 && !onAllBoundaries )
6562     THROW_SALOME_CORBA_EXCEPTION("At least 2 groups are required.", SALOME::BAD_PARAM);
6563
6564   vector<TIDSortedElemSet> domains;
6565   domains.resize( theDomains.length() );
6566
6567   for ( int i = 0, n = theDomains.length(); i < n; i++ )
6568   {
6569     SMESH::SMESH_GroupBase_var aGrp = theDomains[ i ];
6570     if ( !CORBA::is_nil( aGrp ) /*&& ( aGrp->GetType() != SMESH::NODE )*/ )
6571     {
6572 //      if ( aGrp->GetType() != SMESH::VOLUME )
6573 //        THROW_SALOME_CORBA_EXCEPTION("Not a volume group", SALOME::BAD_PARAM);
6574       SMESH::long_array_var anIDs = aGrp->GetIDs();
6575       arrayToSet( anIDs, aMeshDS, domains[ i ], SMDSAbs_All );
6576     }
6577   }
6578
6579   isOK = getEditor().DoubleNodesOnGroupBoundaries( domains, createJointElems, onAllBoundaries );
6580   // TODO publish the groups of flat elements in study
6581
6582   declareMeshModified( /*isReComputeSafe=*/ !isOK );
6583
6584   // Update Python script
6585   TPythonDump() << "isDone = " << this << ".DoubleNodesOnGroupBoundaries( " << &theDomains
6586                 << ", " << createJointElems << ", " << onAllBoundaries << " )";
6587
6588   SMESH_CATCH( SMESH::throwCorbaException );
6589
6590   myMesh_i->CreateGroupServants(); // publish created groups if any
6591
6592   return isOK;
6593 }
6594
6595 //================================================================================
6596 /*!
6597  * \brief Double nodes on some external faces and create flat elements.
6598  * Flat elements are mainly used by some types of mechanic calculations.
6599  *
6600  * Each group of the list must be constituted of faces.
6601  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
6602  * @param theGroupsOfFaces - list of groups of faces
6603  * @return TRUE if operation has been completed successfully, FALSE otherwise
6604  */
6605 //================================================================================
6606
6607 CORBA::Boolean
6608 SMESH_MeshEditor_i::CreateFlatElementsOnFacesGroups( const SMESH::ListOfGroups& theGroupsOfFaces )
6609   throw (SALOME::SALOME_Exception)
6610 {
6611   SMESH_TRY;
6612   initData();
6613
6614   SMESHDS_Mesh* aMeshDS = getMeshDS();
6615
6616   vector<TIDSortedElemSet> faceGroups;
6617   faceGroups.clear();
6618
6619   for ( int i = 0, n = theGroupsOfFaces.length(); i < n; i++ )
6620   {
6621     SMESH::SMESH_GroupBase_var aGrp = theGroupsOfFaces[ i ];
6622     if ( !CORBA::is_nil( aGrp ) && ( aGrp->GetType() != SMESH::NODE ) )
6623     {
6624       TIDSortedElemSet faceGroup;
6625       faceGroup.clear();
6626       faceGroups.push_back(faceGroup);
6627       SMESH::long_array_var anIDs = aGrp->GetIDs();
6628       arrayToSet( anIDs, aMeshDS, faceGroups[ i ], SMDSAbs_All );
6629     }
6630   }
6631
6632   bool aResult = getEditor().CreateFlatElementsOnFacesGroups( faceGroups );
6633   // TODO publish the groups of flat elements in study
6634
6635   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6636
6637   // Update Python script
6638   TPythonDump() << this << ".CreateFlatElementsOnFacesGroups( " << &theGroupsOfFaces << " )";
6639   return aResult;
6640
6641   SMESH_CATCH( SMESH::throwCorbaException );
6642   return false;
6643 }
6644
6645 //================================================================================
6646 /*!
6647  *  \brief Identify all the elements around a geom shape, get the faces delimiting
6648  *         the hole.
6649  *
6650  *  Build groups of volume to remove, groups of faces to replace on the skin of the
6651  *  object, groups of faces to remove inside the object, (idem edges).
6652  *  Build ordered list of nodes at the border of each group of faces to replace
6653  *  (to be used to build a geom subshape).
6654  */
6655 //================================================================================
6656
6657 void SMESH_MeshEditor_i::CreateHoleSkin(CORBA::Double                  radius,
6658                                         GEOM::GEOM_Object_ptr          theShape,
6659                                         const char*                    groupName,
6660                                         const SMESH::double_array&     theNodesCoords,
6661                                         SMESH::array_of_long_array_out GroupsOfNodes)
6662   throw (SALOME::SALOME_Exception)
6663 {
6664   SMESH_TRY;
6665
6666   initData();
6667   std::vector<std::vector<int> > aListOfListOfNodes;
6668   ::SMESH_MeshEditor aMeshEditor( myMesh );
6669
6670   theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
6671   if ( !theNodeSearcher )
6672     theNodeSearcher = SMESH_MeshAlgos::GetNodeSearcher( *getMeshDS() );
6673
6674   vector<double> nodesCoords;
6675   for ( CORBA::ULong i = 0; i < theNodesCoords.length(); i++)
6676   {
6677     nodesCoords.push_back( theNodesCoords[i] );
6678   }
6679
6680   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
6681   aMeshEditor.CreateHoleSkin(radius, aShape, theNodeSearcher, groupName,
6682                              nodesCoords, aListOfListOfNodes);
6683
6684   GroupsOfNodes = new SMESH::array_of_long_array;
6685   GroupsOfNodes->length( aListOfListOfNodes.size() );
6686   std::vector<std::vector<int> >::iterator llIt = aListOfListOfNodes.begin();
6687   for ( CORBA::Long i = 0; llIt != aListOfListOfNodes.end(); llIt++, i++ )
6688   {
6689     vector<int>& aListOfNodes = *llIt;
6690     vector<int>::iterator lIt = aListOfNodes.begin();;
6691     SMESH::long_array& aGroup = (*GroupsOfNodes)[ i ];
6692     aGroup.length( aListOfNodes.size() );
6693     for ( int j = 0; lIt != aListOfNodes.end(); lIt++, j++ )
6694       aGroup[ j ] = (*lIt);
6695   }
6696   TPythonDump() << "lists_nodes = " << this << ".CreateHoleSkin( "
6697                 << radius << ", "
6698                 << theShape
6699                 << ", '" << groupName << "', "
6700                 << theNodesCoords << " )";
6701
6702   SMESH_CATCH( SMESH::throwCorbaException );
6703 }
6704
6705 // issue 20749 ===================================================================
6706 /*!
6707  * \brief Creates missing boundary elements
6708  *  \param elements - elements whose boundary is to be checked
6709  *  \param dimension - defines type of boundary elements to create
6710  *  \param groupName - a name of group to store created boundary elements in,
6711  *                     "" means not to create the group
6712  *  \param meshName - a name of new mesh to store created boundary elements in,
6713  *                     "" means not to create the new mesh
6714  *  \param toCopyElements - if true, the checked elements will be copied into the new mesh
6715  *  \param toCopyExistingBondary - if true, not only new but also pre-existing
6716  *                                boundary elements will be copied into the new mesh
6717  *  \param group - returns the create group, if any
6718  *  \retval SMESH::SMESH_Mesh - the mesh where elements were added to
6719  */
6720 // ================================================================================
6721
6722 SMESH::SMESH_Mesh_ptr
6723 SMESH_MeshEditor_i::MakeBoundaryMesh(SMESH::SMESH_IDSource_ptr idSource,
6724                                      SMESH::Bnd_Dimension      dim,
6725                                      const char*               groupName,
6726                                      const char*               meshName,
6727                                      CORBA::Boolean            toCopyElements,
6728                                      CORBA::Boolean            toCopyExistingBondary,
6729                                      SMESH::SMESH_Group_out    group)
6730   throw (SALOME::SALOME_Exception)
6731 {
6732   SMESH_TRY;
6733   initData();
6734
6735   if ( dim > SMESH::BND_1DFROM2D )
6736     THROW_SALOME_CORBA_EXCEPTION("Invalid boundary dimension", SALOME::BAD_PARAM);
6737
6738   SMESHDS_Mesh* aMeshDS = getMeshDS();
6739
6740   SMESH::SMESH_Mesh_var mesh_var;
6741   SMESH::SMESH_Group_var group_var;
6742
6743   TPythonDump pyDump;
6744
6745   TIDSortedElemSet elements;
6746   SMDSAbs_ElementType elemType = (dim == SMESH::BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
6747   if ( idSourceToSet( idSource, aMeshDS, elements, elemType,/*emptyIfIsMesh=*/true ))
6748   {
6749     // mesh to fill in
6750     mesh_var =
6751       strlen(meshName) ? makeMesh(meshName) : SMESH::SMESH_Mesh::_duplicate(myMesh_i->_this());
6752     SMESH_Mesh_i* mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh_var );
6753     // other mesh
6754     SMESH_Mesh* smesh_mesh = (mesh_i==myMesh_i) ? (SMESH_Mesh*)0 : &mesh_i->GetImpl();
6755
6756     // group of new boundary elements
6757     SMESH_Group* smesh_group = 0;
6758     if ( strlen(groupName) )
6759     {
6760       group_var = mesh_i->CreateGroup( SMESH::ElementType(int(elemType)-1),groupName);
6761       if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( group_var ))
6762         smesh_group = group_i->GetSmeshGroup();
6763     }
6764
6765     // do it
6766     getEditor().MakeBoundaryMesh( elements,
6767                                   ::SMESH_MeshEditor::Bnd_Dimension(dim),
6768                                   smesh_group,
6769                                   smesh_mesh,
6770                                   toCopyElements,
6771                                   toCopyExistingBondary);
6772
6773     if ( smesh_mesh )
6774       smesh_mesh->GetMeshDS()->Modified();
6775   }
6776
6777   const char* dimName[] = { "BND_2DFROM3D", "BND_1DFROM3D", "BND_1DFROM2D" };
6778
6779   // result of MakeBoundaryMesh() is a tuple (mesh, group)
6780   if ( mesh_var->_is_nil() )
6781     pyDump << myMesh_i->_this() << ", ";
6782   else
6783     pyDump << mesh_var << ", ";
6784   if ( group_var->_is_nil() )
6785     pyDump << "_NoneGroup = "; // assignment to None is forbidden
6786   else
6787     pyDump << group_var << " = ";
6788   pyDump << this << ".MakeBoundaryMesh( "
6789          << idSource << ", "
6790          << "SMESH." << dimName[int(dim)] << ", "
6791          << "'" << groupName << "', "
6792          << "'" << meshName<< "', "
6793          << toCopyElements << ", "
6794          << toCopyExistingBondary << ")";
6795
6796   group = group_var._retn();
6797   return mesh_var._retn();
6798
6799   SMESH_CATCH( SMESH::throwCorbaException );
6800   return SMESH::SMESH_Mesh::_nil();
6801 }
6802
6803 //================================================================================
6804 /*!
6805  * \brief Creates missing boundary elements
6806  *  \param dimension - defines type of boundary elements to create
6807  *  \param groupName - a name of group to store all boundary elements in,
6808  *    "" means not to create the group
6809  *  \param meshName - a name of a new mesh, which is a copy of the initial 
6810  *    mesh + created boundary elements; "" means not to create the new mesh
6811  *  \param toCopyAll - if true, the whole initial mesh will be copied into
6812  *    the new mesh else only boundary elements will be copied into the new mesh
6813  *  \param groups - optional groups of elements to make boundary around
6814  *  \param mesh - returns the mesh where elements were added to
6815  *  \param group - returns the created group, if any
6816  *  \retval long - number of added boundary elements
6817  */
6818 //================================================================================
6819
6820 CORBA::Long SMESH_MeshEditor_i::MakeBoundaryElements(SMESH::Bnd_Dimension dim,
6821                                                      const char* groupName,
6822                                                      const char* meshName,
6823                                                      CORBA::Boolean toCopyAll,
6824                                                      const SMESH::ListOfIDSources& groups,
6825                                                      SMESH::SMESH_Mesh_out mesh,
6826                                                      SMESH::SMESH_Group_out group)
6827   throw (SALOME::SALOME_Exception)
6828 {
6829   SMESH_TRY;
6830   initData();
6831
6832   if ( dim > SMESH::BND_1DFROM2D )
6833     THROW_SALOME_CORBA_EXCEPTION("Invalid boundary dimension", SALOME::BAD_PARAM);
6834
6835   // separate groups belonging to this and other mesh
6836   SMESH::ListOfIDSources_var groupsOfThisMesh  = new SMESH::ListOfIDSources;
6837   SMESH::ListOfIDSources_var groupsOfOtherMesh = new SMESH::ListOfIDSources;
6838   groupsOfThisMesh ->length( groups.length() );
6839   groupsOfOtherMesh->length( groups.length() );
6840   int nbGroups = 0, nbGroupsOfOtherMesh = 0;
6841   for ( CORBA::ULong i = 0; i < groups.length(); ++i )
6842   {
6843     SMESH::SMESH_Mesh_var m = groups[i]->GetMesh();
6844     if ( myMesh_i != SMESH::DownCast<SMESH_Mesh_i*>( m ))
6845       groupsOfOtherMesh[ nbGroupsOfOtherMesh++ ] = groups[i];
6846     else
6847       groupsOfThisMesh[ nbGroups++ ] = groups[i];
6848     if ( SMESH::DownCast<SMESH_Mesh_i*>( groups[i] ))
6849       THROW_SALOME_CORBA_EXCEPTION("expected a group but received a mesh", SALOME::BAD_PARAM);
6850   }
6851   groupsOfThisMesh->length( nbGroups );
6852   groupsOfOtherMesh->length( nbGroupsOfOtherMesh );
6853
6854   int nbAdded = 0;
6855   TPythonDump pyDump;
6856
6857   if ( nbGroupsOfOtherMesh > 0 )
6858   {
6859     // process groups belonging to another mesh
6860     SMESH::SMESH_Mesh_var    otherMesh = groupsOfOtherMesh[0]->GetMesh();
6861     SMESH::SMESH_MeshEditor_var editor = otherMesh->GetMeshEditor();
6862     nbAdded += editor->MakeBoundaryElements( dim, groupName, meshName, toCopyAll,
6863                                              groupsOfOtherMesh, mesh, group );
6864   }
6865
6866   SMESH::SMESH_Mesh_var mesh_var;
6867   SMESH::SMESH_Group_var group_var;
6868
6869   // get mesh to fill
6870   mesh_var = SMESH::SMESH_Mesh::_duplicate( myMesh_i->_this() );
6871   const bool toCopyMesh = ( strlen( meshName ) > 0 );
6872   if ( toCopyMesh )
6873   {
6874     if ( toCopyAll )
6875       mesh_var = SMESH_Gen_i::GetSMESHGen()->CopyMesh(mesh_var,
6876                                                       meshName,
6877                                                       /*toCopyGroups=*/false,
6878                                                       /*toKeepIDs=*/true);
6879     else
6880       mesh_var = makeMesh(meshName);
6881   }
6882   SMESH_Mesh_i* mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh_var );
6883   SMESH_Mesh*  tgtMesh = &mesh_i->GetImpl();
6884
6885   // source mesh
6886   SMESH_Mesh*     srcMesh = ( toCopyMesh && !toCopyAll ) ? myMesh : tgtMesh;
6887   SMESHDS_Mesh* srcMeshDS = srcMesh->GetMeshDS();
6888
6889   // group of boundary elements
6890   SMESH_Group* smesh_group = 0;
6891   SMDSAbs_ElementType elemType = (dim == SMESH::BND_2DFROM3D) ? SMDSAbs_Volume : SMDSAbs_Face;
6892   if ( strlen(groupName) )
6893   {
6894     SMESH::ElementType groupType = SMESH::ElementType( int(elemType)-1 );
6895     group_var = mesh_i->CreateGroup( groupType, groupName );
6896     if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( group_var ))
6897       smesh_group = group_i->GetSmeshGroup();
6898   }
6899
6900   TIDSortedElemSet elements;
6901
6902   if ( groups.length() > 0 )
6903   {
6904     for ( int i = 0; i < nbGroups; ++i )
6905     {
6906       elements.clear();
6907       if ( idSourceToSet( groupsOfThisMesh[i], srcMeshDS, elements, elemType,/*emptyIfIsMesh=*/0 ))
6908       {
6909         SMESH::Bnd_Dimension bdim = 
6910           ( elemType == SMDSAbs_Volume ) ? SMESH::BND_2DFROM3D : SMESH::BND_1DFROM2D;
6911         nbAdded += getEditor().MakeBoundaryMesh( elements,
6912                                                  ::SMESH_MeshEditor::Bnd_Dimension(bdim),
6913                                                  smesh_group,
6914                                                  tgtMesh,
6915                                                  /*toCopyElements=*/false,
6916                                                  /*toCopyExistingBondary=*/srcMesh != tgtMesh,
6917                                                  /*toAddExistingBondary=*/true,
6918                                                  /*aroundElements=*/true);
6919       }
6920     }
6921   }
6922   else
6923   {
6924     nbAdded += getEditor().MakeBoundaryMesh( elements,
6925                                              ::SMESH_MeshEditor::Bnd_Dimension(dim),
6926                                              smesh_group,
6927                                              tgtMesh,
6928                                              /*toCopyElements=*/false,
6929                                              /*toCopyExistingBondary=*/srcMesh != tgtMesh,
6930                                              /*toAddExistingBondary=*/true);
6931   }
6932   tgtMesh->GetMeshDS()->Modified();
6933
6934   const char* dimName[] = { "BND_2DFROM3D", "BND_1DFROM3D", "BND_1DFROM2D" };
6935
6936   // result of MakeBoundaryElements() is a tuple (nb, mesh, group)
6937   pyDump << "nbAdded, ";
6938   if ( mesh_var->_is_nil() )
6939     pyDump << myMesh_i->_this() << ", ";
6940   else
6941     pyDump << mesh_var << ", ";
6942   if ( group_var->_is_nil() )
6943     pyDump << "_NoneGroup = "; // assignment to None is forbidden
6944   else
6945     pyDump << group_var << " = ";
6946   pyDump << this << ".MakeBoundaryElements( "
6947          << "SMESH." << dimName[int(dim)] << ", "
6948          << "'" << groupName << "', "
6949          << "'" << meshName<< "', "
6950          << toCopyAll << ", "
6951          << groups << ")";
6952
6953   mesh  = mesh_var._retn();
6954   group = group_var._retn();
6955   return nbAdded;
6956
6957   SMESH_CATCH( SMESH::throwCorbaException );
6958   return 0;
6959 }
6960
6961 //================================================================================
6962 /*!
6963  * \brief Create a polyline consisting of 1D mesh elements each lying on a 2D element of
6964  *        the initial mesh. Positions of new nodes are found by cutting the mesh by the
6965  *        plane passing through pairs of points specified by each PolySegment structure.
6966  *        If there are several paths connecting a pair of points, the shortest path is
6967  *        selected by the module. Position of the cutting plane is defined by the two
6968  *        points and an optional vector lying on the plane specified by a PolySegment.
6969  *        By default the vector is defined by Mesh module as following. A middle point
6970  *        of the two given points is computed. The middle point is projected to the mesh.
6971  *        The vector goes from the middle point to the projection point. In case of planar
6972  *        mesh, the vector is normal to the mesh.
6973  *  \param [inout] segments - PolySegment's defining positions of cutting planes.
6974  *        Return the used vector and position of the middle point.
6975  *  \param [in] groupName - optional name of a group where created mesh segments will
6976  *        be added.
6977  */
6978 //================================================================================
6979
6980 void SMESH_MeshEditor_i::MakePolyLine(SMESH::ListOfPolySegments& theSegments,
6981                                       const char*                theGroupName)
6982   throw (SALOME::SALOME_Exception)
6983 {
6984   if ( theSegments.length() == 0 )
6985     THROW_SALOME_CORBA_EXCEPTION("No segments given", SALOME::BAD_PARAM );
6986   if ( myMesh->NbFaces() == 0 )
6987     THROW_SALOME_CORBA_EXCEPTION("No faces in the mesh", SALOME::BAD_PARAM );
6988
6989   SMESH_TRY;
6990   initData(/*deleteSearchers=*/false);
6991
6992   SMESHDS_Group* groupDS = 0;
6993   SMESHDS_Mesh*   meshDS = getMeshDS();
6994   if ( myIsPreviewMode ) // copy faces to the tmp mesh
6995   {
6996     TPreviewMesh * tmpMesh = getPreviewMesh( SMDSAbs_Edge );
6997     SMDS_ElemIteratorPtr faceIt = getMeshDS()->elementsIterator( SMDSAbs_Face );
6998     while ( faceIt->more() )
6999       tmpMesh->Copy( faceIt->next() );
7000     meshDS = tmpMesh->GetMeshDS();
7001   }
7002   else if ( theGroupName[0] ) // find/create a group of segments
7003   {
7004     SMESH_Mesh::GroupIteratorPtr grpIt = myMesh->GetGroups();
7005     while ( !groupDS && grpIt->more() )
7006     {
7007       SMESH_Group* group = grpIt->next();
7008       if ( group->GetGroupDS()->GetType() == SMDSAbs_Edge &&
7009            strcmp( group->GetName(), theGroupName ) == 0 )
7010       {
7011         groupDS = dynamic_cast< SMESHDS_Group* >( group->GetGroupDS() );
7012       }
7013     }
7014     if ( !groupDS )
7015     {
7016       SMESH::SMESH_Group_var groupVar = myMesh_i->CreateGroup( SMESH::EDGE, theGroupName );
7017
7018       if ( SMESH_Group_i* groupImpl = SMESH::DownCast<SMESH_Group_i*>( groupVar ))
7019         groupDS = dynamic_cast< SMESHDS_Group* >( groupImpl->GetGroupDS() );
7020     }
7021   }
7022
7023   // convert input polySegments
7024   ::SMESH_MeshEditor::TListOfPolySegments segments( theSegments.length() );
7025   for ( CORBA::ULong i = 0; i < theSegments.length(); ++i )
7026   {
7027     SMESH::PolySegment&               segIn = theSegments[ i ];
7028     ::SMESH_MeshEditor::PolySegment& segOut = segments[ i ];
7029     segOut.myNode1[0] = meshDS->FindNode( segIn.node1ID1 );
7030     segOut.myNode2[0] = meshDS->FindNode( segIn.node1ID2 );
7031     segOut.myNode1[1] = meshDS->FindNode( segIn.node2ID1 );
7032     segOut.myNode2[1] = meshDS->FindNode( segIn.node2ID2 );
7033     segOut.myVector.SetCoord( segIn.vector.PS.x,
7034                               segIn.vector.PS.y,
7035                               segIn.vector.PS.z );
7036     if ( !segOut.myNode1[0] )
7037       THROW_SALOME_CORBA_EXCEPTION( SMESH_Comment( "Invalid node ID: ") << segIn.node1ID1,
7038                                     SALOME::BAD_PARAM );
7039     if ( !segOut.myNode1[1] )
7040       THROW_SALOME_CORBA_EXCEPTION( SMESH_Comment( "Invalid node ID: ") << segIn.node2ID1,
7041                                     SALOME::BAD_PARAM );
7042   }
7043
7044   // get a static ElementSearcher
7045   SMESH::SMESH_IDSource_var idSource = SMESH::SMESH_IDSource::_narrow( myMesh_i->_this() );
7046   theSearchersDeleter.Set( myMesh, getPartIOR( idSource, SMESH::FACE ));
7047   if ( !theElementSearcher )
7048     theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() );
7049
7050   // compute
7051   getEditor().MakePolyLine( segments, groupDS, theElementSearcher );
7052
7053   // return vectors
7054   if ( myIsPreviewMode )
7055   {
7056     for ( CORBA::ULong i = 0; i < theSegments.length(); ++i )
7057     {
7058       SMESH::PolySegment&             segOut = theSegments[ i ];
7059       ::SMESH_MeshEditor::PolySegment& segIn = segments[ i ];
7060       segOut.vector.PS.x = segIn.myVector.X();
7061       segOut.vector.PS.y = segIn.myVector.Y();
7062       segOut.vector.PS.z = segIn.myVector.Z();
7063     }
7064   }
7065   else
7066   {
7067     TPythonDump() << "_segments = []";
7068     for ( CORBA::ULong i = 0; i < theSegments.length(); ++i )
7069     {
7070       SMESH::PolySegment& segIn = theSegments[ i ];
7071       TPythonDump() << "_segments.append( SMESH.PolySegment( "
7072                     << segIn.node1ID1 << ", "
7073                     << segIn.node1ID2 << ", "
7074                     << segIn.node2ID1 << ", "
7075                     << segIn.node2ID2 << ", "
7076                     << "smeshBuilder.MakeDirStruct( "
7077                     << segIn.vector.PS.x << ", "
7078                     << segIn.vector.PS.y << ", "
7079                     << segIn.vector.PS.z << ")))";
7080     }
7081     TPythonDump() << this << ".MakePolyLine( _segments, '" << theGroupName << "')";
7082   }
7083   meshDS->Modified();
7084   SMESH_CATCH( SMESH::throwCorbaException );
7085   return;
7086 }