Salome HOME
IPAL52868: Confusing error message when computing an imported mesh w/o algo assigned
[modules/smesh.git] / src / SMESH_I / SMESH_MeshEditor_i.cxx
1 // Copyright (C) 2007-2015  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 #include <Basics_OCCTVersion.hxx>
68
69 #include <BRepAdaptor_Surface.hxx>
70 #include <BRep_Tool.hxx>
71 #include <TopExp_Explorer.hxx>
72 #include <TopoDS.hxx>
73 #include <TopoDS_Edge.hxx>
74 #include <TopoDS_Face.hxx>
75 #include <gp_Ax1.hxx>
76 #include <gp_Ax2.hxx>
77 #include <gp_Vec.hxx>
78
79 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
80 #define NO_CAS_CATCH
81 #endif
82
83 #include <Standard_Failure.hxx>
84
85 #ifdef NO_CAS_CATCH
86 #include <Standard_ErrorHandler.hxx>
87 #endif
88
89 #include <sstream>
90 #include <limits>
91
92 #include "SMESH_TryCatch.hxx" // include after OCCT headers!
93
94 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
95
96 using namespace std;
97 using SMESH::TPythonDump;
98 using SMESH::TVar;
99
100 namespace MeshEditor_I {
101
102   //=============================================================================
103   /*!
104    * \brief Mesh to apply modifications for preview purposes
105    */
106   //=============================================================================
107
108   struct TPreviewMesh: public SMESH_Mesh
109   {
110     SMDSAbs_ElementType myPreviewType; // type to show
111     //!< Constructor
112     TPreviewMesh(SMDSAbs_ElementType previewElements = SMDSAbs_All) {
113       _isShapeToMesh = (_id =_studyId = 0);
114       _myMeshDS  = new SMESHDS_Mesh( _id, true );
115       myPreviewType = previewElements;
116     }
117     //!< Copy a set of elements
118     void Copy(const TIDSortedElemSet & theElements,
119               TIDSortedElemSet&        theCopyElements,
120               SMDSAbs_ElementType      theSelectType = SMDSAbs_All,
121               SMDSAbs_ElementType      theAvoidType = SMDSAbs_All)
122     {
123       // loop on theIDsOfElements
124       TIDSortedElemSet::const_iterator eIt = theElements.begin();
125       for ( ; eIt != theElements.end(); ++eIt )
126       {
127         const SMDS_MeshElement* anElem = *eIt;
128         if ( !anElem ) continue;
129         SMDSAbs_ElementType type = anElem->GetType();
130         if ( type == theAvoidType ||
131              ( theSelectType != SMDSAbs_All && type != theSelectType ))
132           continue;
133         const SMDS_MeshElement* anElemCopy;
134         if ( type == SMDSAbs_Node)
135           anElemCopy = Copy( cast2Node(anElem) );
136         else
137           anElemCopy = Copy( anElem );
138         if ( anElemCopy )
139           theCopyElements.insert( theCopyElements.end(), anElemCopy );
140       }
141     }
142     //!< Copy an element
143     SMDS_MeshElement* Copy( const SMDS_MeshElement* anElem )
144     {
145       // copy element nodes
146       int anElemNbNodes = anElem->NbNodes();
147       vector< int > anElemNodesID( anElemNbNodes ) ;
148       SMDS_ElemIteratorPtr itElemNodes = anElem->nodesIterator();
149       for ( int i = 0; itElemNodes->more(); i++)
150       {
151         const SMDS_MeshNode* anElemNode = cast2Node( itElemNodes->next() );
152         Copy( anElemNode );
153         anElemNodesID[i] = anElemNode->GetID();
154       }
155
156       // creates a corresponding element on copied nodes
157       ::SMESH_MeshEditor::ElemFeatures elemType;
158       elemType.Init( anElem, /*basicOnly=*/false );
159       elemType.SetID( anElem->GetID() );
160       SMDS_MeshElement* anElemCopy =
161         ::SMESH_MeshEditor(this).AddElement( anElemNodesID, elemType );
162       return anElemCopy;
163     }
164     //!< Copy a node
165     SMDS_MeshNode* Copy( const SMDS_MeshNode* anElemNode )
166     {
167       return _myMeshDS->AddNodeWithID(anElemNode->X(), anElemNode->Y(), anElemNode->Z(),
168                                       anElemNode->GetID());
169     }
170     void RemoveAll()
171     {
172       GetMeshDS()->ClearMesh();
173     }
174     void Remove( SMDSAbs_ElementType type )
175     {
176       SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator( type );
177       while ( eIt->more() )
178         GetMeshDS()->RemoveFreeElement( eIt->next(), /*sm=*/0, /*fromGroups=*/false );
179     }
180   };// struct TPreviewMesh
181
182   static SMESH_NodeSearcher *    theNodeSearcher    = 0;
183   static SMESH_ElementSearcher * theElementSearcher = 0;
184
185   //=============================================================================
186   /*!
187    * \brief Deleter of theNodeSearcher at any compute event occured
188    */
189   //=============================================================================
190
191   struct TSearchersDeleter : public SMESH_subMeshEventListener
192   {
193     SMESH_Mesh* myMesh;
194     string      myMeshPartIOR;
195     //!< Constructor
196     TSearchersDeleter(): SMESH_subMeshEventListener( false, // won't be deleted by submesh
197                                                      "SMESH_MeshEditor_i::TSearchersDeleter"),
198                          myMesh(0) {}
199     //!< Delete theNodeSearcher
200     static void Delete()
201     {
202       if ( theNodeSearcher )    delete theNodeSearcher;    theNodeSearcher    = 0;
203       if ( theElementSearcher ) delete theElementSearcher; theElementSearcher = 0;
204     }
205     typedef map < int, SMESH_subMesh * > TDependsOnMap;
206     //!< The meshod called by submesh: do my main job
207     void ProcessEvent(const int, const int eventType, SMESH_subMesh* sm,
208                       SMESH_subMeshEventListenerData*,const SMESH_Hypothesis*)
209     {
210       if ( eventType == SMESH_subMesh::COMPUTE_EVENT ) {
211         Delete();
212         Unset( sm->GetFather() );
213       }
214     }
215     //!< set self on all submeshes and delete theNodeSearcher if other mesh is set
216     void Set(SMESH_Mesh* mesh, const string& meshPartIOR = string())
217     {
218       if ( myMesh != mesh || myMeshPartIOR != meshPartIOR)
219       {
220         if ( myMesh ) {
221           Delete();
222           Unset( myMesh );
223         }
224         myMesh = mesh;
225         myMeshPartIOR = meshPartIOR;
226         SMESH_subMesh* sm = mesh->GetSubMesh( mesh->GetShapeToMesh() );
227         SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator( /*includeSelf=*/true );
228         while ( smIt->more() )
229         {
230           sm = smIt->next();
231           sm->SetEventListener( this, 0, sm );
232         }
233       }
234     }
235     //!<  delete self from all submeshes
236     void Unset(SMESH_Mesh* mesh)
237     {
238       if ( SMESH_subMesh* sm = mesh->GetSubMeshContaining(1) ) {
239         SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator( /*includeSelf=*/true );
240         while ( smIt->more() )
241           smIt->next()->DeleteEventListener( this );
242       }
243       myMesh = 0;
244     }
245
246   } theSearchersDeleter;
247
248   TCollection_AsciiString mirrorTypeName( SMESH::SMESH_MeshEditor::MirrorType theMirrorType )
249   {
250     TCollection_AsciiString typeStr;
251     switch ( theMirrorType ) {
252     case  SMESH::SMESH_MeshEditor::POINT:
253       typeStr = "SMESH.SMESH_MeshEditor.POINT";
254       break;
255     case  SMESH::SMESH_MeshEditor::AXIS:
256       typeStr = "SMESH.SMESH_MeshEditor.AXIS";
257       break;
258     default:
259       typeStr = "SMESH.SMESH_MeshEditor.PLANE";
260     }
261     return typeStr;
262   }
263   //================================================================================
264   /*!
265    * \brief function for conversion of long_array to TIDSortedElemSet
266    * \param IDs - array of IDs
267    * \param aMesh - mesh
268    * \param aMap - collection to fill
269    * \param aType - element type
270    */
271   //================================================================================
272
273   void arrayToSet(const SMESH::long_array & IDs,
274                   const SMESHDS_Mesh*       aMesh,
275                   TIDSortedElemSet&         aMap,
276                   const SMDSAbs_ElementType aType = SMDSAbs_All,
277                   SMDS_MeshElement::Filter* aFilter = NULL)
278   {
279     SMDS_MeshElement::NonNullFilter filter1;
280     SMDS_MeshElement::TypeFilter    filter2( aType );
281
282     if ( aFilter == NULL )
283       aFilter = ( aType == SMDSAbs_All ) ? (SMDS_MeshElement::Filter*) &filter1 : (SMDS_MeshElement::Filter*) &filter2;
284     
285     SMDS_MeshElement::Filter & filter = *aFilter;
286
287     if ( aType == SMDSAbs_Node )
288       for (int i=0; i<IDs.length(); i++) {
289         const SMDS_MeshElement * elem = aMesh->FindNode( IDs[i] );
290         if ( filter( elem ))
291           aMap.insert( aMap.end(), elem );
292       }
293     else
294       for (int i=0; i<IDs.length(); i++) {
295         const SMDS_MeshElement * elem = aMesh->FindElement( IDs[i] );
296         if ( filter( elem ))
297           aMap.insert( aMap.end(), elem );
298       }
299   }
300
301   //================================================================================
302   /*!
303    * \brief Retrieve nodes from SMESH_IDSource
304    */
305   //================================================================================
306
307   void idSourceToNodeSet(SMESH::SMESH_IDSource_ptr  theObject,
308                          const SMESHDS_Mesh*        theMeshDS,
309                          TIDSortedNodeSet&          theNodeSet)
310
311   {
312     if ( CORBA::is_nil( theObject ) )
313       return;
314     SMESH::array_of_ElementType_var types = theObject->GetTypes();
315     SMESH::long_array_var     aElementsId = theObject->GetIDs();
316     if ( types->length() == 1 && types[0] == SMESH::NODE)
317     {
318       for(int i = 0; i < aElementsId->length(); i++)
319         if ( const SMDS_MeshNode * n = theMeshDS->FindNode( aElementsId[i] ))
320           theNodeSet.insert( theNodeSet.end(), n);
321     }
322     else if ( SMESH::DownCast<SMESH_Mesh_i*>( theObject ))
323     {
324       SMDS_NodeIteratorPtr nIt = theMeshDS->nodesIterator();
325       while ( nIt->more( ))
326         if( const SMDS_MeshElement * elem = nIt->next() )
327           theNodeSet.insert( elem->begin_nodes(), elem->end_nodes());
328     }
329     else
330     {
331       for(int i = 0; i < aElementsId->length(); i++)
332         if( const SMDS_MeshElement * elem = theMeshDS->FindElement( aElementsId[i] ))
333           theNodeSet.insert( elem->begin_nodes(), elem->end_nodes());
334     }
335   }
336
337   //================================================================================
338   /*!
339    * \brief Returns elements connected to the given elements
340    */
341   //================================================================================
342
343   void getElementsAround(const TIDSortedElemSet& theElements,
344                          const SMESHDS_Mesh*     theMeshDS,
345                          TIDSortedElemSet&       theElementsAround)
346   {
347     if ( theElements.empty() ) return;
348
349     SMDSAbs_ElementType elemType    = (*theElements.begin())->GetType();
350     bool sameElemType = ( elemType == (*theElements.rbegin())->GetType() );
351     if ( sameElemType &&
352          theMeshDS->GetMeshInfo().NbElements( elemType ) == theElements.size() )
353       return; // all the elements are in theElements
354
355     if ( !sameElemType )
356       elemType = SMDSAbs_All;
357
358     vector<bool> isNodeChecked( theMeshDS->NbNodes(), false );
359
360     TIDSortedElemSet::const_iterator elemIt = theElements.begin();
361     for ( ; elemIt != theElements.end(); ++elemIt )
362     {
363       const SMDS_MeshElement* e = *elemIt;
364       int i = e->NbCornerNodes();
365       while ( --i != -1 )
366       {
367         const SMDS_MeshNode* n = e->GetNode( i );
368         if ( !isNodeChecked[ n->GetID() ])
369         {
370           isNodeChecked[ n->GetID() ] = true;
371           SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator(elemType);
372           while ( invIt->more() )
373           {
374             const SMDS_MeshElement* elemAround = invIt->next();
375             if ( !theElements.count( elemAround ))
376               theElementsAround.insert( elemAround );
377           }
378         }
379       }
380     }
381   }
382
383   //================================================================================
384   /*!
385    * \brief Return a string used to detect change of mesh part on which theElementSearcher
386    * is going to be used
387    */
388   //================================================================================
389
390   string getPartIOR( SMESH::SMESH_IDSource_ptr theMeshPart, SMESH::ElementType type)
391   {
392     string partIOR = SMESH_Gen_i::GetORB()->object_to_string( theMeshPart );
393     if ( SMESH_Group_i* group_i = SMESH::DownCast<SMESH_Group_i*>( theMeshPart ))
394       // take into account passible group modification
395       partIOR += SMESH_Comment( ((SMESHDS_Group*)group_i->GetGroupDS())->SMDSGroup().Tic() );
396     partIOR += SMESH_Comment( type );
397     return partIOR;
398   }
399
400 } // namespace MeshEditor_I
401
402 using namespace MeshEditor_I;
403
404 //=============================================================================
405 /*!
406  *
407  */
408 //=============================================================================
409
410 SMESH_MeshEditor_i::SMESH_MeshEditor_i(SMESH_Mesh_i* theMesh, bool isPreview):
411   myMesh_i( theMesh ),
412   myMesh( &theMesh->GetImpl() ),
413   myEditor( myMesh ),
414   myIsPreviewMode ( isPreview ),
415   myPreviewMesh( 0 ),
416   myPreviewEditor( 0 )
417 {
418 }
419
420 //================================================================================
421 /*!
422  * \brief Destructor
423  */
424 //================================================================================
425
426 SMESH_MeshEditor_i::~SMESH_MeshEditor_i()
427 {
428   PortableServer::POA_var poa = SMESH_Gen_i::GetPOA();
429   PortableServer::ObjectId_var anObjectId = poa->servant_to_id(this);
430   poa->deactivate_object(anObjectId.in());
431
432   //deleteAuxIDSources();
433   delete myPreviewMesh;   myPreviewMesh = 0;
434   delete myPreviewEditor; myPreviewEditor = 0;
435 }
436
437 //================================================================================
438 /*!
439  * \brief Returns the mesh
440  */
441 //================================================================================
442
443 SMESH::SMESH_Mesh_ptr SMESH_MeshEditor_i::GetMesh()
444 {
445   return myMesh_i->_this();
446 }
447
448 //================================================================================
449 /*!
450  * \brief Clear members
451  */
452 //================================================================================
453
454 void SMESH_MeshEditor_i::initData(bool deleteSearchers)
455 {
456   if ( myIsPreviewMode ) {
457     if ( myPreviewMesh ) myPreviewMesh->RemoveAll();
458   }
459   else {
460     if ( deleteSearchers )
461       TSearchersDeleter::Delete();
462   }
463   getEditor().GetError().reset();
464   getEditor().ClearLastCreated();
465 }
466
467 //================================================================================
468 /*!
469  * \brief Increment mesh modif time and optionally record that the performed
470  *        modification may influence futher mesh re-compute.
471  *  \param [in] isReComputeSafe - true if the modification does not influence
472  *              futher mesh re-compute
473  */
474 //================================================================================
475
476 void SMESH_MeshEditor_i::declareMeshModified( bool isReComputeSafe )
477 {
478   myMesh->GetMeshDS()->Modified();
479   if ( !isReComputeSafe )
480     myMesh->SetIsModified( true );
481 }
482
483 //================================================================================
484 /*!
485  * \brief Return either myEditor or myPreviewEditor depending on myIsPreviewMode.
486  *        WARNING: in preview mode call getPreviewMesh() before getEditor()!
487  */
488 //================================================================================
489
490 ::SMESH_MeshEditor& SMESH_MeshEditor_i::getEditor()
491 {
492   if ( myIsPreviewMode && !myPreviewEditor ) {
493     if ( !myPreviewMesh ) getPreviewMesh();
494     myPreviewEditor = new ::SMESH_MeshEditor( myPreviewMesh );
495   }
496   return myIsPreviewMode ? *myPreviewEditor : myEditor;
497 }
498
499 //================================================================================
500 /*!
501  * \brief Initialize and return myPreviewMesh
502  *  \param previewElements - type of elements to show in preview
503  *
504  *  WARNING: call it once par a method!
505  */
506 //================================================================================
507
508 TPreviewMesh * SMESH_MeshEditor_i::getPreviewMesh(SMDSAbs_ElementType previewElements)
509 {
510   if ( !myPreviewMesh || myPreviewMesh->myPreviewType != previewElements )
511   {
512     delete myPreviewEditor;
513     myPreviewEditor = 0;
514     delete myPreviewMesh;
515     myPreviewMesh = new TPreviewMesh( previewElements );
516   }
517   myPreviewMesh->Clear();
518   return myPreviewMesh;
519 }
520
521 //================================================================================
522 /*!
523  * Return data of mesh edition preview
524  */
525 //================================================================================
526
527 SMESH::MeshPreviewStruct* SMESH_MeshEditor_i::GetPreviewData()
528   throw (SALOME::SALOME_Exception)
529 {
530   SMESH_TRY;
531   const bool hasBadElems = ( getEditor().GetError() && getEditor().GetError()->HasBadElems() );
532
533   if ( myIsPreviewMode || hasBadElems ) { // --- MeshPreviewStruct filling ---
534
535     list<int> aNodesConnectivity;
536     typedef map<int, int> TNodesMap;
537     TNodesMap nodesMap;
538
539     SMESHDS_Mesh* aMeshDS;
540     std::auto_ptr< SMESH_MeshPartDS > aMeshPartDS;
541     if ( hasBadElems ) {
542       aMeshPartDS.reset( new SMESH_MeshPartDS( getEditor().GetError()->myBadElements ));
543       aMeshDS = aMeshPartDS.get();
544     }
545     else {
546       aMeshDS = getEditor().GetMeshDS();
547     }
548     myPreviewData = new SMESH::MeshPreviewStruct();
549     myPreviewData->nodesXYZ.length(aMeshDS->NbNodes());
550
551
552     SMDSAbs_ElementType previewType = SMDSAbs_All;
553     if ( !hasBadElems )
554       if (TPreviewMesh * aPreviewMesh = dynamic_cast< TPreviewMesh* >( getEditor().GetMesh() )) {
555         previewType = aPreviewMesh->myPreviewType;
556         switch ( previewType ) {
557         case SMDSAbs_Edge  : break;
558         case SMDSAbs_Face  : break;
559         case SMDSAbs_Volume: break;
560         default:;
561           if ( aMeshDS->GetMeshInfo().NbElements() == 0 ) previewType = SMDSAbs_Node;
562         }
563       }
564
565     myPreviewData->elementTypes.length( aMeshDS->GetMeshInfo().NbElements( previewType ));
566     int i = 0, j = 0;
567     SMDS_ElemIteratorPtr itMeshElems = aMeshDS->elementsIterator(previewType);
568
569     while ( itMeshElems->more() ) {
570       const SMDS_MeshElement* aMeshElem = itMeshElems->next();
571       SMDS_NodeIteratorPtr itElemNodes = 
572         (( aMeshElem->GetEntityType() == SMDSEntity_Quad_Polygon ) ?
573          aMeshElem->interlacedNodesIterator() :
574          aMeshElem->nodeIterator() );
575       while ( itElemNodes->more() ) {
576         const SMDS_MeshNode* aMeshNode = itElemNodes->next();
577         int aNodeID = aMeshNode->GetID();
578         TNodesMap::iterator anIter = nodesMap.find(aNodeID);
579         if ( anIter == nodesMap.end() ) {
580           // filling the nodes coordinates
581           myPreviewData->nodesXYZ[j].x = aMeshNode->X();
582           myPreviewData->nodesXYZ[j].y = aMeshNode->Y();
583           myPreviewData->nodesXYZ[j].z = aMeshNode->Z();
584           anIter = nodesMap.insert( make_pair(aNodeID, j) ).first;
585           j++;
586         }
587         aNodesConnectivity.push_back(anIter->second);
588       }
589
590       // filling the elements types
591       SMDSAbs_ElementType aType = aMeshElem->GetType();
592       bool               isPoly = aMeshElem->IsPoly();
593       myPreviewData->elementTypes[i].SMDS_ElementType = (SMESH::ElementType) aType;
594       myPreviewData->elementTypes[i].isPoly           = isPoly;
595       myPreviewData->elementTypes[i].nbNodesInElement = aMeshElem->NbNodes();
596       i++;
597     }
598     myPreviewData->nodesXYZ.length( j );
599
600     // filling the elements connectivities
601     list<int>::iterator aConnIter = aNodesConnectivity.begin();
602     myPreviewData->elementConnectivities.length(aNodesConnectivity.size());
603     for( int i = 0; aConnIter != aNodesConnectivity.end(); aConnIter++, i++ )
604       myPreviewData->elementConnectivities[i] = *aConnIter;
605   }
606   return myPreviewData._retn();
607
608   SMESH_CATCH( SMESH::throwCorbaException );
609   return 0;
610 }
611
612 //================================================================================
613 /*!
614  * \brief Returns list of it's IDs of created nodes
615  * \retval SMESH::long_array* - list of node ID
616  */
617 //================================================================================
618
619 SMESH::long_array* SMESH_MeshEditor_i::GetLastCreatedNodes()
620   throw (SALOME::SALOME_Exception)
621 {
622   SMESH_TRY;
623   SMESH::long_array_var myLastCreatedNodes = new SMESH::long_array();
624
625   const SMESH_SequenceOfElemPtr& aSeq = getEditor().GetLastCreatedNodes();
626   myLastCreatedNodes->length( aSeq.Length() );
627   for (int i = 1; i <= aSeq.Length(); i++)
628     myLastCreatedNodes[i-1] = aSeq.Value(i)->GetID();
629
630   return myLastCreatedNodes._retn();
631   SMESH_CATCH( SMESH::throwCorbaException );
632   return 0;
633 }
634
635 //================================================================================
636 /*!
637  * \brief Returns list of it's IDs of created elements
638  * \retval SMESH::long_array* - list of elements' ID
639  */
640 //================================================================================
641
642 SMESH::long_array* SMESH_MeshEditor_i::GetLastCreatedElems()
643   throw (SALOME::SALOME_Exception)
644 {
645   SMESH_TRY;
646   SMESH::long_array_var myLastCreatedElems = new SMESH::long_array();
647
648   const SMESH_SequenceOfElemPtr& aSeq = getEditor().GetLastCreatedElems();
649   myLastCreatedElems->length( aSeq.Length() );
650   for ( int i = 1; i <= aSeq.Length(); i++ )
651     myLastCreatedElems[i-1] = aSeq.Value(i)->GetID();
652
653   return myLastCreatedElems._retn();
654   SMESH_CATCH( SMESH::throwCorbaException );
655   return 0;
656 }
657
658 //=======================================================================
659 //function : ClearLastCreated
660 //purpose  : Clears sequences of last created elements and nodes 
661 //=======================================================================
662
663 void SMESH_MeshEditor_i::ClearLastCreated() throw (SALOME::SALOME_Exception)
664 {
665   SMESH_TRY;
666   getEditor().ClearLastCreated();
667   SMESH_CATCH( SMESH::throwCorbaException );
668 }
669
670 //=======================================================================
671 /*
672  * Returns description of an error/warning occured during the last operation
673  * WARNING: ComputeError.code >= 100 and no corresponding enum in IDL API
674  */
675 //=======================================================================
676
677 SMESH::ComputeError* SMESH_MeshEditor_i::GetLastError()
678   throw (SALOME::SALOME_Exception)
679 {
680   SMESH_TRY;
681   SMESH::ComputeError_var errOut = new SMESH::ComputeError;
682   SMESH_ComputeErrorPtr&  errIn  = getEditor().GetError();
683   if ( errIn && !errIn->IsOK() )
684   {
685     errOut->code       = -( errIn->myName < 0 ? errIn->myName + 1: errIn->myName ); // -1 -> 0
686     errOut->comment    = errIn->myComment.c_str();
687     errOut->subShapeID = -1;
688     errOut->hasBadMesh = !errIn->myBadElements.empty();
689   }
690   else
691   {
692     errOut->code       = 0;
693     errOut->subShapeID = -1;
694     errOut->hasBadMesh = false;
695   }
696
697   return errOut._retn();
698   SMESH_CATCH( SMESH::throwCorbaException );
699   return 0;
700 }
701
702 //=======================================================================
703 //function : MakeIDSource
704 //purpose  : Wrap a sequence of ids in a SMESH_IDSource.
705 //           Call UnRegister() as you fininsh using it!!
706 //=======================================================================
707
708 struct SMESH_MeshEditor_i::_IDSource : public virtual POA_SMESH::SMESH_IDSource,
709                                        public virtual SALOME::GenericObj_i
710 {
711   SMESH::long_array     _ids;
712   SMESH::ElementType    _type;
713   SMESH::SMESH_Mesh_ptr _mesh;
714   SMESH::long_array* GetIDs()      { return new SMESH::long_array( _ids ); }
715   SMESH::long_array* GetMeshInfo() { return 0; }
716   SMESH::long_array* GetNbElementsByType()
717   {
718     SMESH::long_array_var aRes = new SMESH::long_array();
719     aRes->length(SMESH::NB_ELEMENT_TYPES);
720     for (int i = 0; i < SMESH::NB_ELEMENT_TYPES; i++)
721       aRes[ i ] = ( i == _type ) ? _ids.length() : 0;
722     return aRes._retn();  
723   }
724   SMESH::SMESH_Mesh_ptr GetMesh()  { return SMESH::SMESH_Mesh::_duplicate( _mesh ); }
725   bool IsMeshInfoCorrect()         { return true; }
726   SMESH::array_of_ElementType* GetTypes()
727   {
728     SMESH::array_of_ElementType_var types = new SMESH::array_of_ElementType;
729     if ( _ids.length() > 0 ) {
730       types->length( 1 );
731       types[0] = _type;
732     }
733     return types._retn();
734   }
735   SALOMEDS::TMPFile* GetVtkUgStream()
736   {
737     SALOMEDS::TMPFile_var SeqFile;
738     return SeqFile._retn();
739   }
740 };
741
742 SMESH::SMESH_IDSource_ptr SMESH_MeshEditor_i::MakeIDSource(const SMESH::long_array& ids,
743                                                            SMESH::ElementType       type)
744 {
745   _IDSource* idSrc = new _IDSource;
746   idSrc->_mesh = myMesh_i->_this();
747   idSrc->_ids  = ids;
748   idSrc->_type = type;
749   if ( type == SMESH::ALL && ids.length() > 0 )
750     idSrc->_type = myMesh_i->GetElementType( ids[0], true );
751
752   SMESH::SMESH_IDSource_var anIDSourceVar = idSrc->_this();
753
754   return anIDSourceVar._retn();
755 }
756
757 bool SMESH_MeshEditor_i::IsTemporaryIDSource( SMESH::SMESH_IDSource_ptr& idSource )
758 {
759   return SMESH::DownCast<SMESH_MeshEditor_i::_IDSource*>( idSource );
760 }
761
762 CORBA::Long* SMESH_MeshEditor_i::GetTemporaryIDs( SMESH::SMESH_IDSource_ptr& idSource,
763                                                   int&                       nbIds)
764 {
765   if ( _IDSource* tmpIdSource = SMESH::DownCast<SMESH_MeshEditor_i::_IDSource*>( idSource ))
766   {
767     nbIds = (int) tmpIdSource->_ids.length();
768     return & tmpIdSource->_ids[0];
769   }
770   nbIds = 0;
771   return 0;
772 }
773
774 // void SMESH_MeshEditor_i::deleteAuxIDSources()
775 // {
776 //   std::list< _IDSource* >::iterator idSrcIt = myAuxIDSources.begin();
777 //   for ( ; idSrcIt != myAuxIDSources.end(); ++idSrcIt )
778 //     delete *idSrcIt;
779 //   myAuxIDSources.clear();
780 // }
781
782 //=============================================================================
783 /*!
784  *
785  */
786 //=============================================================================
787
788 CORBA::Boolean
789 SMESH_MeshEditor_i::RemoveElements(const SMESH::long_array & IDsOfElements)
790   throw (SALOME::SALOME_Exception)
791 {
792   SMESH_TRY;
793   initData();
794
795   list< int > IdList;
796
797   for (int i = 0; i < IDsOfElements.length(); i++)
798     IdList.push_back( IDsOfElements[i] );
799
800   // Update Python script
801   TPythonDump() << "isDone = " << this << ".RemoveElements( " << IDsOfElements << " )";
802
803   // Remove Elements
804   bool ret = getEditor().Remove( IdList, false );
805
806   declareMeshModified( /*isReComputeSafe=*/ IDsOfElements.length() == 0 ); // issue 0020693
807   return ret;
808
809   SMESH_CATCH( SMESH::throwCorbaException );
810   return 0;
811 }
812
813 //=============================================================================
814 /*!
815  *
816  */
817 //=============================================================================
818
819 CORBA::Boolean SMESH_MeshEditor_i::RemoveNodes(const SMESH::long_array & IDsOfNodes)
820   throw (SALOME::SALOME_Exception)
821 {
822   SMESH_TRY;
823   initData();
824
825   list< int > IdList;
826   for (int i = 0; i < IDsOfNodes.length(); i++)
827     IdList.push_back( IDsOfNodes[i] );
828
829   // Update Python script
830   TPythonDump() << "isDone = " << this << ".RemoveNodes( " << IDsOfNodes << " )";
831
832   bool ret = getEditor().Remove( IdList, true );
833
834   declareMeshModified( /*isReComputeSafe=*/ !ret ); // issue 0020693
835   return ret;
836
837   SMESH_CATCH( SMESH::throwCorbaException );
838   return 0;
839 }
840
841 //=============================================================================
842 /*!
843  *
844  */
845 //=============================================================================
846
847 CORBA::Long SMESH_MeshEditor_i::RemoveOrphanNodes()
848   throw (SALOME::SALOME_Exception)
849 {
850   SMESH_TRY;
851   initData();
852
853   // Update Python script
854   TPythonDump() << "nbRemoved = " << this << ".RemoveOrphanNodes()";
855
856   // Create filter to find all orphan nodes
857   SMESH::Controls::Filter::TIdSequence seq;
858   SMESH::Controls::PredicatePtr predicate( new SMESH::Controls::FreeNodes() );
859   SMESH::Controls::Filter::GetElementsId( getMeshDS(), predicate, seq );
860
861   // remove orphan nodes (if there are any)
862   list< int > IdList;
863   for ( int i = 0; i < seq.size(); i++ )
864     IdList.push_back( seq[i] );
865
866   int nbNodesBefore = myMesh->NbNodes();
867   getEditor().Remove( IdList, true );
868   int nbNodesAfter = myMesh->NbNodes();
869
870   declareMeshModified( /*isReComputeSafe=*/ IdList.size() == 0 ); // issue 0020693
871   return nbNodesBefore - nbNodesAfter;
872
873   SMESH_CATCH( SMESH::throwCorbaException );
874   return 0;
875 }
876
877 //=============================================================================
878 /*!
879  * Add a new node.
880  */
881 //=============================================================================
882
883 CORBA::Long SMESH_MeshEditor_i::AddNode(CORBA::Double x,CORBA::Double y, CORBA::Double z)
884   throw (SALOME::SALOME_Exception)
885 {
886   SMESH_TRY;
887   initData();
888
889   const SMDS_MeshNode* N = getMeshDS()->AddNode(x, y, z);
890
891   // Update Python script
892   TPythonDump() << "nodeID = " << this << ".AddNode( "
893                 << TVar( x ) << ", " << TVar( y ) << ", " << TVar( z )<< " )";
894
895   declareMeshModified( /*isReComputeSafe=*/false );
896   return N->GetID();
897
898   SMESH_CATCH( SMESH::throwCorbaException );
899   return 0;
900 }
901
902 //=============================================================================
903 /*!
904  * Create 0D element on the given node.
905  */
906 //=============================================================================
907
908 CORBA::Long SMESH_MeshEditor_i::Add0DElement(CORBA::Long IDOfNode)
909   throw (SALOME::SALOME_Exception)
910 {
911   SMESH_TRY;
912   initData();
913
914   const SMDS_MeshNode* aNode = getMeshDS()->FindNode(IDOfNode);
915   SMDS_MeshElement* elem = getMeshDS()->Add0DElement(aNode);
916
917   // Update Python script
918   TPythonDump() << "elem0d = " << this << ".Add0DElement( " << IDOfNode <<" )";
919
920   declareMeshModified( /*isReComputeSafe=*/false );
921
922   return elem ? elem->GetID() : 0;
923
924   SMESH_CATCH( SMESH::throwCorbaException );
925   return 0;
926 }
927
928 //=============================================================================
929 /*!
930  * Create a ball element on the given node.
931  */
932 //=============================================================================
933
934 CORBA::Long SMESH_MeshEditor_i::AddBall(CORBA::Long IDOfNode, CORBA::Double diameter)
935   throw (SALOME::SALOME_Exception)
936 {
937   SMESH_TRY;
938   initData();
939
940   if ( diameter < std::numeric_limits<double>::min() )
941     THROW_SALOME_CORBA_EXCEPTION("Invalid diameter", SALOME::BAD_PARAM);
942
943   const SMDS_MeshNode* aNode = getMeshDS()->FindNode(IDOfNode);
944   SMDS_MeshElement* elem = getMeshDS()->AddBall(aNode, diameter);
945
946   // Update Python script
947   TPythonDump() << "ballElem = "
948                 << this << ".AddBall( " << IDOfNode << ", " << diameter <<" )";
949
950   declareMeshModified( /*isReComputeSafe=*/false );
951   return elem ? elem->GetID() : 0;
952
953   SMESH_CATCH( SMESH::throwCorbaException );
954   return 0;
955 }
956
957 //=============================================================================
958 /*!
959  * Create an edge, either linear and quadratic (this is determed
960  *  by number of given nodes, two or three)
961  */
962 //=============================================================================
963
964 CORBA::Long SMESH_MeshEditor_i::AddEdge(const SMESH::long_array & IDsOfNodes)
965   throw (SALOME::SALOME_Exception)
966 {
967   SMESH_TRY;
968   initData();
969
970   int NbNodes = IDsOfNodes.length();
971   SMDS_MeshElement* elem = 0;
972   if (NbNodes == 2)
973   {
974     CORBA::Long index1 = IDsOfNodes[0];
975     CORBA::Long index2 = IDsOfNodes[1];
976     elem = getMeshDS()->AddEdge( getMeshDS()->FindNode(index1),
977                                  getMeshDS()->FindNode(index2));
978
979     // Update Python script
980     TPythonDump() << "edge = " << this << ".AddEdge([ "
981                   << index1 << ", " << index2 <<" ])";
982   }
983   if (NbNodes == 3) {
984     CORBA::Long n1 = IDsOfNodes[0];
985     CORBA::Long n2 = IDsOfNodes[1];
986     CORBA::Long n12 = IDsOfNodes[2];
987     elem = getMeshDS()->AddEdge( getMeshDS()->FindNode(n1),
988                                  getMeshDS()->FindNode(n2),
989                                  getMeshDS()->FindNode(n12));
990     // Update Python script
991     TPythonDump() << "edgeID = " << this << ".AddEdge([ "
992                   <<n1<<", "<<n2<<", "<<n12<<" ])";
993   }
994
995   declareMeshModified( /*isReComputeSafe=*/false );
996   return elem ? elem->GetID() : 0;
997
998   SMESH_CATCH( SMESH::throwCorbaException );
999   return 0;
1000 }
1001
1002 //=============================================================================
1003 /*!
1004  *  AddFace
1005  */
1006 //=============================================================================
1007
1008 CORBA::Long SMESH_MeshEditor_i::AddFace(const SMESH::long_array & IDsOfNodes)
1009   throw (SALOME::SALOME_Exception)
1010 {
1011   SMESH_TRY;
1012   initData();
1013
1014   int NbNodes = IDsOfNodes.length();
1015   if (NbNodes < 3)
1016   {
1017     return 0;
1018   }
1019
1020   std::vector<const SMDS_MeshNode*> nodes (NbNodes);
1021   for (int i = 0; i < NbNodes; i++)
1022     nodes[i] = getMeshDS()->FindNode(IDsOfNodes[i]);
1023
1024   SMDS_MeshElement* elem = 0;
1025   switch (NbNodes) {
1026   case 3: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2]); break;
1027   case 4: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3]); break;
1028   case 6: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
1029                                       nodes[4], nodes[5]); break;
1030   case 7: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
1031                                       nodes[4], nodes[5], nodes[6]); break;
1032   case 8: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
1033                                       nodes[4], nodes[5], nodes[6], nodes[7]); break;
1034   case 9: elem = getMeshDS()->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
1035                                       nodes[4], nodes[5], nodes[6], nodes[7],
1036                                       nodes[8] ); break;
1037   default: elem = getMeshDS()->AddPolygonalFace(nodes);
1038   }
1039
1040   // Update Python script
1041   TPythonDump() << "faceID = " << this << ".AddFace( " << IDsOfNodes << " )";
1042
1043   declareMeshModified( /*isReComputeSafe=*/false );
1044
1045   return elem ? elem->GetID() : 0;
1046
1047   SMESH_CATCH( SMESH::throwCorbaException );
1048   return 0;
1049 }
1050
1051 //=============================================================================
1052 /*!
1053  *  AddPolygonalFace
1054  */
1055 //=============================================================================
1056
1057 CORBA::Long SMESH_MeshEditor_i::AddPolygonalFace (const SMESH::long_array & IDsOfNodes)
1058   throw (SALOME::SALOME_Exception)
1059 {
1060   SMESH_TRY;
1061   initData();
1062
1063   int NbNodes = IDsOfNodes.length();
1064   std::vector<const SMDS_MeshNode*> nodes (NbNodes);
1065   for (int i = 0; i < NbNodes; i++)
1066     if ( ! ( nodes[i] = getMeshDS()->FindNode( IDsOfNodes[i] )))
1067       return 0;
1068
1069   const SMDS_MeshElement* elem = getMeshDS()->AddPolygonalFace(nodes);
1070
1071   // Update Python script
1072   TPythonDump() <<"faceID = "<<this<<".AddPolygonalFace( "<<IDsOfNodes<<" )";
1073
1074   declareMeshModified( /*isReComputeSafe=*/false );
1075   return elem ? elem->GetID() : 0;
1076
1077   SMESH_CATCH( SMESH::throwCorbaException );
1078   return 0;
1079 }
1080
1081 //=============================================================================
1082 /*!
1083  *  AddQuadPolygonalFace
1084  */
1085 //=============================================================================
1086
1087 CORBA::Long SMESH_MeshEditor_i::AddQuadPolygonalFace (const SMESH::long_array & IDsOfNodes)
1088   throw (SALOME::SALOME_Exception)
1089 {
1090   SMESH_TRY;
1091   initData();
1092
1093   int NbNodes = IDsOfNodes.length();
1094   std::vector<const SMDS_MeshNode*> nodes (NbNodes);
1095   for (int i = 0; i < NbNodes; i++)
1096     nodes[i] = getMeshDS()->FindNode(IDsOfNodes[i]);
1097
1098   const SMDS_MeshElement* elem = getMeshDS()->AddQuadPolygonalFace(nodes);
1099
1100   // Update Python script
1101   TPythonDump() <<"faceID = "<<this<<".AddPolygonalFace( "<<IDsOfNodes<<" )";
1102
1103   declareMeshModified( /*isReComputeSafe=*/false );
1104   return elem ? elem->GetID() : 0;
1105
1106   SMESH_CATCH( SMESH::throwCorbaException );
1107   return 0;
1108 }
1109
1110 //=============================================================================
1111 /*!
1112  * Create volume, either linear and quadratic (this is determed
1113  *  by number of given nodes)
1114  */
1115 //=============================================================================
1116
1117 CORBA::Long SMESH_MeshEditor_i::AddVolume(const SMESH::long_array & IDsOfNodes)
1118   throw (SALOME::SALOME_Exception)
1119 {
1120   SMESH_TRY;
1121   initData();
1122
1123   int NbNodes = IDsOfNodes.length();
1124   vector< const SMDS_MeshNode*> n(NbNodes);
1125   for(int i=0;i<NbNodes;i++)
1126     n[i]= getMeshDS()->FindNode(IDsOfNodes[i]);
1127
1128   SMDS_MeshElement* elem = 0;
1129   switch(NbNodes)
1130   {
1131   case 4 :elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3]); break;
1132   case 5 :elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4]); break;
1133   case 6 :elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5]); break;
1134   case 8 :elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7]); break;
1135   case 10:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],
1136                                         n[6],n[7],n[8],n[9]);
1137     break;
1138   case 12:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],
1139                                         n[6],n[7],n[8],n[9],n[10],n[11]);
1140     break;
1141   case 13:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],
1142                                         n[7],n[8],n[9],n[10],n[11],n[12]);
1143     break;
1144   case 15:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7],n[8],
1145                                         n[9],n[10],n[11],n[12],n[13],n[14]);
1146     break;
1147   case 20:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7],
1148                                         n[8],n[9],n[10],n[11],n[12],n[13],n[14],
1149                                         n[15],n[16],n[17],n[18],n[19]);
1150     break;
1151   case 27:elem = getMeshDS()->AddVolume(n[0],n[1],n[2],n[3],n[4],n[5],n[6],n[7],
1152                                         n[8],n[9],n[10],n[11],n[12],n[13],n[14],
1153                                         n[15],n[16],n[17],n[18],n[19],
1154                                         n[20],n[21],n[22],n[23],n[24],n[25],n[26]);
1155     break;
1156   }
1157
1158   // Update Python script
1159   TPythonDump() << "volID = " << this << ".AddVolume( " << IDsOfNodes << " )";
1160
1161   declareMeshModified( /*isReComputeSafe=*/false );
1162   return elem ? elem->GetID() : 0;
1163
1164   SMESH_CATCH( SMESH::throwCorbaException );
1165   return 0;
1166 }
1167
1168 //=============================================================================
1169 /*!
1170  *  AddPolyhedralVolume
1171  */
1172 //=============================================================================
1173 CORBA::Long SMESH_MeshEditor_i::AddPolyhedralVolume (const SMESH::long_array & IDsOfNodes,
1174                                                      const SMESH::long_array & Quantities)
1175   throw (SALOME::SALOME_Exception)
1176 {
1177   SMESH_TRY;
1178   initData();
1179
1180   int NbNodes = IDsOfNodes.length();
1181   std::vector<const SMDS_MeshNode*> n (NbNodes);
1182   for (int i = 0; i < NbNodes; i++)
1183     {
1184       const SMDS_MeshNode* aNode = getMeshDS()->FindNode(IDsOfNodes[i]);
1185       if (!aNode) return 0;
1186       n[i] = aNode;
1187     }
1188
1189   int NbFaces = Quantities.length();
1190   std::vector<int> q (NbFaces);
1191   for (int j = 0; j < NbFaces; j++)
1192     q[j] = Quantities[j];
1193
1194   const SMDS_MeshElement* elem = getMeshDS()->AddPolyhedralVolume(n, q);
1195
1196   // Update Python script
1197   TPythonDump() << "volID = " << this << ".AddPolyhedralVolume( "
1198                 << IDsOfNodes << ", " << Quantities << " )";
1199
1200   declareMeshModified( /*isReComputeSafe=*/false );
1201   return elem ? elem->GetID() : 0;
1202
1203   SMESH_CATCH( SMESH::throwCorbaException );
1204   return 0;
1205 }
1206
1207 //=============================================================================
1208 /*!
1209  *  AddPolyhedralVolumeByFaces
1210  */
1211 //=============================================================================
1212
1213 CORBA::Long SMESH_MeshEditor_i::AddPolyhedralVolumeByFaces (const SMESH::long_array & IdsOfFaces)
1214   throw (SALOME::SALOME_Exception)
1215 {
1216   SMESH_TRY;
1217   initData();
1218
1219   int NbFaces = IdsOfFaces.length();
1220   std::vector<const SMDS_MeshNode*> poly_nodes;
1221   std::vector<int> quantities (NbFaces);
1222
1223   for (int i = 0; i < NbFaces; i++) {
1224     const SMDS_MeshElement* aFace = getMeshDS()->FindElement(IdsOfFaces[i]);
1225     quantities[i] = aFace->NbNodes();
1226
1227     SMDS_ElemIteratorPtr It = aFace->nodesIterator();
1228     while (It->more()) {
1229       poly_nodes.push_back(static_cast<const SMDS_MeshNode *>(It->next()));
1230     }
1231   }
1232
1233   const SMDS_MeshElement* elem = getMeshDS()->AddPolyhedralVolume(poly_nodes, quantities);
1234
1235   // Update Python script
1236   TPythonDump() << "volID = " << this << ".AddPolyhedralVolumeByFaces( "
1237                 << IdsOfFaces << " )";
1238
1239   declareMeshModified( /*isReComputeSafe=*/false );
1240   return elem ? elem->GetID() : 0;
1241
1242   SMESH_CATCH( SMESH::throwCorbaException );
1243   return 0;
1244 }
1245
1246 //=============================================================================
1247 //
1248 // \brief Create 0D elements on all nodes of the given object except those 
1249 //        nodes on which a 0D element already exists.
1250 //  \param theObject object on whose nodes 0D elements will be created.
1251 //  \param theGroupName optional name of a group to add 0D elements created
1252 //         and/or found on nodes of \a theObject.
1253 //  \return an object (a new group or a temporary SMESH_IDSource) holding
1254 //          ids of new and/or found 0D elements.
1255 //
1256 //=============================================================================
1257
1258 SMESH::SMESH_IDSource_ptr
1259 SMESH_MeshEditor_i::Create0DElementsOnAllNodes(SMESH::SMESH_IDSource_ptr theObject,
1260                                                const char*               theGroupName)
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 );
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 (int 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 (int 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 ByAverageNormal = false,
2490                           CORBA::Boolean UseInputElemsOnly = false,
2491                           CORBA::Long    Flags = 0,
2492                           CORBA::Boolean MakeBoundary = true )
2493     {
2494       if ( MakeGroups       ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_GROUPS;
2495       if ( ByAverageNormal  ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_BY_AVG_NORMAL;
2496       if ( UseInputElemsOnly) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_USE_INPUT_ELEMS_ONLY;
2497       if ( MakeBoundary     ) Flags |= ::SMESH_MeshEditor::EXTRUSION_FLAG_BOUNDARY;
2498       return Flags;
2499     }
2500     // standard params
2501     ExtrusionParams(const SMESH::DirStruct &  theDir,
2502                     CORBA::Long               theNbOfSteps,
2503                     CORBA::Boolean            theMakeGroups):
2504       ::SMESH_MeshEditor::ExtrusParam ( gp_Vec( theDir.PS.x,
2505                                                 theDir.PS.y,
2506                                                 theDir.PS.z ),
2507                                         theNbOfSteps,
2508                                         makeFlags( theMakeGroups )),
2509       myIsExtrusionByNormal( false )
2510     {
2511     }
2512     // advanced params
2513     ExtrusionParams(const SMESH::DirStruct &  theDir,
2514                     CORBA::Long               theNbOfSteps,
2515                     CORBA::Boolean            theMakeGroups,
2516                     CORBA::Long               theExtrFlags,
2517                     CORBA::Double             theSewTolerance):
2518       ::SMESH_MeshEditor::ExtrusParam ( gp_Vec( theDir.PS.x,
2519                                                 theDir.PS.y,
2520                                                 theDir.PS.z ),
2521                                         theNbOfSteps,
2522                                         makeFlags( theMakeGroups, false, false,
2523                                                    theExtrFlags, false ),
2524                                         theSewTolerance ),
2525       myIsExtrusionByNormal( false )
2526     {
2527     }
2528     // params for extrusion by normal
2529     ExtrusionParams(CORBA::Double  theStepSize,
2530                     CORBA::Long    theNbOfSteps,
2531                     CORBA::Short   theDim,
2532                     CORBA::Boolean theByAverageNormal,
2533                     CORBA::Boolean theUseInputElemsOnly,
2534                     CORBA::Boolean theMakeGroups ):
2535       ::SMESH_MeshEditor::ExtrusParam ( theStepSize, 
2536                                         theNbOfSteps,
2537                                         makeFlags( theMakeGroups,
2538                                                    theByAverageNormal, theUseInputElemsOnly ),
2539                                         theDim),
2540       myIsExtrusionByNormal( true )
2541     {
2542     }
2543
2544     void SetNoGroups()
2545     {
2546       Flags() &= ~(::SMESH_MeshEditor::EXTRUSION_FLAG_GROUPS);
2547     }
2548   };
2549 }
2550
2551 //=======================================================================
2552 /*!
2553  * \brief Generate dim+1 elements by extrusion of elements along vector
2554  *  \param [in] edges - edges to extrude: a list including groups, sub-meshes or a mesh
2555  *  \param [in] faces - faces to extrude: a list including groups, sub-meshes or a mesh
2556  *  \param [in] nodes - nodes to extrude: a list including groups, sub-meshes or a mesh
2557  *  \param [in] stepVector - vector giving direction and distance of an extrusion step
2558  *  \param [in] nbOfSteps - number of elements to generate from one element
2559  *  \param [in] toMakeGroups - if true, new elements will be included into new groups
2560  *              corresponding to groups the input elements included in.
2561  *  \return ListOfGroups - new groups craeted if \a toMakeGroups is true
2562  */
2563 //=======================================================================
2564
2565 SMESH::ListOfGroups*
2566 SMESH_MeshEditor_i::ExtrusionSweepObjects(const SMESH::ListOfIDSources & theNodes,
2567                                           const SMESH::ListOfIDSources & theEdges,
2568                                           const SMESH::ListOfIDSources & theFaces,
2569                                           const SMESH::DirStruct &       theStepVector,
2570                                           CORBA::Long                    theNbOfSteps,
2571                                           CORBA::Boolean                 theToMakeGroups)
2572   throw (SALOME::SALOME_Exception)
2573 {
2574   SMESH_TRY;
2575   initData();
2576
2577   ExtrusionParams params( theStepVector, theNbOfSteps, theToMakeGroups );
2578
2579   TIDSortedElemSet elemsNodes[2];
2580   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
2581     SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
2582     while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
2583   }
2584   for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
2585     idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
2586   for ( int i = 0, nb = theFaces.length(); i < nb; ++i )
2587     idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face );
2588
2589   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2590   SMDSAbs_ElementType previewType = SMDSAbs_All; //SMDSAbs_Face;
2591   if ( myIsPreviewMode )
2592   {
2593     // if ( (*elemsNodes.begin())->GetType() == SMDSAbs_Node )
2594     //   previewType = SMDSAbs_Edge;
2595
2596     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2597     TPreviewMesh * tmpMesh = getPreviewMesh( previewType );
2598     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2599     tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid );
2600     workElements = & copyElements[0];
2601
2602     params.SetNoGroups();
2603   }
2604   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2605
2606   ::SMESH_MeshEditor::TTElemOfElemListMap aHistory;
2607   ::SMESH_MeshEditor::PGroupIDs groupIds =
2608       getEditor().ExtrusionSweep( workElements, params, aHistory );
2609
2610   SMESH::ListOfGroups * aGroups = theToMakeGroups ? getGroups( groupIds.get()) : 0;
2611
2612   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2613
2614   if ( !myIsPreviewMode )
2615   {
2616     dumpGroupsList( aPythonDump, aGroups );
2617     aPythonDump << this<< ".ExtrusionSweepObjects( "
2618                 << theNodes             << ", "
2619                 << theEdges             << ", "
2620                 << theFaces             << ", "
2621                 << theStepVector        << ", "
2622                 << TVar( theNbOfSteps ) << ", "
2623                 << theToMakeGroups      << " )";
2624   }
2625   else
2626   {
2627     getPreviewMesh( previewType )->Remove( SMDSAbs_Volume );
2628   }
2629
2630   return aGroups ? aGroups : new SMESH::ListOfGroups;
2631
2632   SMESH_CATCH( SMESH::throwCorbaException );
2633   return 0;
2634 }
2635
2636 //=======================================================================
2637 //function : ExtrusionByNormal
2638 //purpose  :
2639 //=======================================================================
2640
2641 SMESH::ListOfGroups*
2642 SMESH_MeshEditor_i::ExtrusionByNormal(const SMESH::ListOfIDSources& objects,
2643                                       CORBA::Double                 stepSize,
2644                                       CORBA::Long                   nbOfSteps,
2645                                       CORBA::Boolean                byAverageNormal,
2646                                       CORBA::Boolean                useInputElemsOnly,
2647                                       CORBA::Boolean                makeGroups,
2648                                       CORBA::Short                  dim)
2649   throw (SALOME::SALOME_Exception)
2650 {
2651   SMESH_TRY;
2652   initData();
2653
2654   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
2655
2656   ExtrusionParams params( stepSize, nbOfSteps, dim,
2657                           byAverageNormal, useInputElemsOnly, makeGroups );
2658
2659   SMDSAbs_ElementType elemType = ( dim == 1 ? SMDSAbs_Edge : SMDSAbs_Face );
2660   if ( objects.length() > 0 && !SMESH::DownCast<SMESH_Mesh_i*>( objects[0] ))
2661   {
2662     SMESH::array_of_ElementType_var elemTypes = objects[0]->GetTypes();
2663     if (( elemTypes->length() == 1 ) &&
2664         ( elemTypes[0] == SMESH::EDGE || elemTypes[0] == SMESH::FACE ))
2665       elemType = ( SMDSAbs_ElementType ) elemTypes[0];
2666   }
2667
2668   TIDSortedElemSet elemsNodes[2];
2669   for ( int i = 0, nb = objects.length(); i < nb; ++i )
2670     idSourceToSet( objects[i], getMeshDS(), elemsNodes[0], elemType );
2671
2672   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2673   SMDSAbs_ElementType previewType = SMDSAbs_Face;
2674   if ( myIsPreviewMode )
2675   {
2676     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2677     TPreviewMesh * tmpMesh = getPreviewMesh( previewType );
2678     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2679     workElements = & copyElements[0];
2680
2681     params.SetNoGroups();
2682   }
2683
2684   ::SMESH_MeshEditor::TTElemOfElemListMap aHistory;
2685   ::SMESH_MeshEditor::PGroupIDs groupIds =
2686       getEditor().ExtrusionSweep( workElements, params, aHistory );
2687
2688   SMESH::ListOfGroups * aGroups = makeGroups ? getGroups( groupIds.get()) : 0;
2689
2690   if (!myIsPreviewMode) {
2691     dumpGroupsList(aPythonDump, aGroups);
2692     aPythonDump << this << ".ExtrusionByNormal( " << objects
2693                 << ", " << TVar( stepSize )
2694                 << ", " << TVar( nbOfSteps )
2695                 << ", " << byAverageNormal
2696                 << ", " << useInputElemsOnly
2697                 << ", " << makeGroups
2698                 << ", " << dim
2699                 << " )";
2700   }
2701   else
2702   {
2703     getPreviewMesh( previewType )->Remove( SMDSAbs_Volume );
2704   }
2705
2706   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2707
2708   return aGroups ? aGroups : new SMESH::ListOfGroups;
2709
2710   SMESH_CATCH( SMESH::throwCorbaException );
2711   return 0;
2712 }
2713
2714 //=======================================================================
2715 //function : AdvancedExtrusion
2716 //purpose  :
2717 //=======================================================================
2718
2719 SMESH::ListOfGroups*
2720 SMESH_MeshEditor_i::AdvancedExtrusion(const SMESH::long_array & theIDsOfElements,
2721                                       const SMESH::DirStruct &  theStepVector,
2722                                       CORBA::Long               theNbOfSteps,
2723                                       CORBA::Long               theExtrFlags,
2724                                       CORBA::Double             theSewTolerance,
2725                                       CORBA::Boolean            theMakeGroups)
2726   throw (SALOME::SALOME_Exception)
2727 {
2728   SMESH_TRY;
2729   initData();
2730
2731   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2732
2733   ExtrusionParams params( theStepVector, theNbOfSteps, theMakeGroups,
2734                           theExtrFlags, theSewTolerance );
2735
2736   TIDSortedElemSet elemsNodes[2];
2737   arrayToSet( theIDsOfElements, getMeshDS(), elemsNodes[0] );
2738
2739   ::SMESH_MeshEditor::TTElemOfElemListMap aHistory;
2740   ::SMESH_MeshEditor::PGroupIDs groupIds =
2741       getEditor().ExtrusionSweep( elemsNodes, params, aHistory );
2742
2743   SMESH::ListOfGroups * aGroups = theMakeGroups ? getGroups( groupIds.get()) : 0;
2744
2745   declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute()
2746
2747   if ( !myIsPreviewMode ) {
2748     dumpGroupsList(aPythonDump, aGroups);
2749     aPythonDump << this << ".AdvancedExtrusion( "
2750                 << theIDsOfElements << ", "
2751                 << theStepVector << ", "
2752                 << theNbOfSteps << ", "
2753                 << theExtrFlags << ", "
2754                 << theSewTolerance << ", "
2755                 << theMakeGroups << " )";
2756   }
2757   else
2758   {
2759     getPreviewMesh()->Remove( SMDSAbs_Volume );
2760   }
2761
2762   return aGroups ? aGroups : new SMESH::ListOfGroups;
2763
2764   SMESH_CATCH( SMESH::throwCorbaException );
2765   return 0;
2766 }
2767
2768 //================================================================================
2769 /*!
2770  * \brief Convert extrusion error to IDL enum
2771  */
2772 //================================================================================
2773
2774 namespace
2775 {
2776 #define RETCASE(enm) case ::SMESH_MeshEditor::enm: return SMESH::SMESH_MeshEditor::enm;
2777
2778   SMESH::SMESH_MeshEditor::Extrusion_Error convExtrError( ::SMESH_MeshEditor::Extrusion_Error e )
2779   {
2780     switch ( e ) {
2781       RETCASE( EXTR_OK );
2782       RETCASE( EXTR_NO_ELEMENTS );
2783       RETCASE( EXTR_PATH_NOT_EDGE );
2784       RETCASE( EXTR_BAD_PATH_SHAPE );
2785       RETCASE( EXTR_BAD_STARTING_NODE );
2786       RETCASE( EXTR_BAD_ANGLES_NUMBER );
2787       RETCASE( EXTR_CANT_GET_TANGENT );
2788     }
2789     return SMESH::SMESH_MeshEditor::EXTR_OK;
2790   }
2791 }
2792
2793 //=======================================================================
2794 //function : extrusionAlongPath
2795 //purpose  :
2796 //=======================================================================
2797 SMESH::ListOfGroups*
2798 SMESH_MeshEditor_i::ExtrusionAlongPathObjects(const SMESH::ListOfIDSources & theNodes,
2799                                               const SMESH::ListOfIDSources & theEdges,
2800                                               const SMESH::ListOfIDSources & theFaces,
2801                                               SMESH::SMESH_IDSource_ptr      thePathMesh,
2802                                               GEOM::GEOM_Object_ptr          thePathShape,
2803                                               CORBA::Long                    theNodeStart,
2804                                               CORBA::Boolean                 theHasAngles,
2805                                               const SMESH::double_array &    theAngles,
2806                                               CORBA::Boolean                 theLinearVariation,
2807                                               CORBA::Boolean                 theHasRefPoint,
2808                                               const SMESH::PointStruct &     theRefPoint,
2809                                               bool                           theMakeGroups,
2810                                               SMESH::SMESH_MeshEditor::Extrusion_Error& theError)
2811   throw (SALOME::SALOME_Exception)
2812 {
2813   SMESH_TRY;
2814   initData();
2815
2816   SMESH::ListOfGroups_var aGroups = new SMESH::ListOfGroups;
2817
2818   theError = SMESH::SMESH_MeshEditor::EXTR_BAD_PATH_SHAPE;
2819   if ( thePathMesh->_is_nil() )
2820     return aGroups._retn();
2821
2822   // get a sub-mesh
2823   SMESH_subMesh* aSubMesh = 0;
2824   SMESH_Mesh_i* aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( thePathMesh );
2825   if ( thePathShape->_is_nil() )
2826   {
2827     // thePathMesh should be either a sub-mesh or a mesh with 1D elements only
2828     if ( SMESH_subMesh_i* sm = SMESH::DownCast<SMESH_subMesh_i*>( thePathMesh ))
2829     {
2830       SMESH::SMESH_Mesh_var mesh = thePathMesh->GetMesh();
2831       aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
2832       if ( !aMeshImp ) return aGroups._retn();
2833       aSubMesh = aMeshImp->GetImpl().GetSubMeshContaining( sm->GetId() );
2834       if ( !aSubMesh ) return aGroups._retn();
2835     }
2836     else if ( !aMeshImp ||
2837               aMeshImp->NbEdges() != aMeshImp->NbElements() )
2838     {
2839       return aGroups._retn();
2840     }
2841   }
2842   else
2843   {
2844     if ( !aMeshImp ) return aGroups._retn();
2845     TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( thePathShape );
2846     aSubMesh = aMeshImp->GetImpl().GetSubMesh( aShape );
2847     if ( !aSubMesh || !aSubMesh->GetSubMeshDS() )
2848       return aGroups._retn();
2849   }
2850
2851   SMDS_MeshNode* nodeStart =
2852     (SMDS_MeshNode*)aMeshImp->GetImpl().GetMeshDS()->FindNode(theNodeStart);
2853   if ( !nodeStart ) {
2854     theError = SMESH::SMESH_MeshEditor::EXTR_BAD_STARTING_NODE;
2855     return aGroups._retn();
2856   }
2857
2858   TIDSortedElemSet elemsNodes[2];
2859   for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
2860     SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
2861     while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
2862   }
2863   for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
2864     idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
2865   for ( int i = 0, nb = theFaces.length(); i < nb; ++i )
2866     idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face );
2867
2868   list<double> angles;
2869   for (int i = 0; i < theAngles.length(); i++) {
2870     angles.push_back( theAngles[i] );
2871   }
2872
2873   gp_Pnt refPnt( theRefPoint.x, theRefPoint.y, theRefPoint.z );
2874
2875   int nbOldGroups = myMesh->NbGroup();
2876
2877   TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2];
2878   if ( myIsPreviewMode )
2879   {
2880     SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
2881     TPreviewMesh * tmpMesh = getPreviewMesh();
2882     tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid );
2883     tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid );
2884     workElements = & copyElements[0];
2885     theMakeGroups = false;
2886   }
2887
2888   ::SMESH_MeshEditor::Extrusion_Error error;
2889   if ( !aSubMesh )
2890     error = getEditor().ExtrusionAlongTrack( workElements, &(aMeshImp->GetImpl()), nodeStart,
2891                                              theHasAngles, angles, theLinearVariation,
2892                                              theHasRefPoint, refPnt, theMakeGroups );
2893   else
2894     error = getEditor().ExtrusionAlongTrack( workElements, aSubMesh, nodeStart,
2895                                              theHasAngles, angles, theLinearVariation,
2896                                              theHasRefPoint, refPnt, theMakeGroups );
2897
2898   declareMeshModified( /*isReComputeSafe=*/true );
2899   theError = convExtrError( error );
2900
2901   TPythonDump aPythonDump; // it is here to prevent dump of getGroups()
2902   if ( theMakeGroups ) {
2903     list<int> groupIDs = myMesh->GetGroupIds();
2904     list<int>::iterator newBegin = groupIDs.begin();
2905     std::advance( newBegin, nbOldGroups ); // skip old groups
2906     groupIDs.erase( groupIDs.begin(), newBegin );
2907     aGroups = getGroups( & groupIDs );
2908     if ( ! &aGroups.in() ) aGroups = new SMESH::ListOfGroups;
2909   }
2910
2911   if ( !myIsPreviewMode ) {
2912     aPythonDump << "(" << aGroups << ", error) = "
2913                 << this << ".ExtrusionAlongPathObjects( "
2914                 << theNodes            << ", "
2915                 << theEdges            << ", "
2916                 << theFaces            << ", "
2917                 << thePathMesh         << ", "
2918                 << thePathShape        << ", "
2919                 << theNodeStart        << ", "
2920                 << theHasAngles        << ", "
2921                 << theAngles           << ", "
2922                 << theLinearVariation  << ", "
2923                 << theHasRefPoint      << ", "
2924                 << "SMESH.PointStruct( "
2925                 << ( theHasRefPoint ? theRefPoint.x : 0 ) << ", "
2926                 << ( theHasRefPoint ? theRefPoint.y : 0 ) << ", "
2927                 << ( theHasRefPoint ? theRefPoint.z : 0 ) << " ), "
2928                 << theMakeGroups       << " )";
2929   }
2930   else
2931   {
2932     getPreviewMesh()->Remove( SMDSAbs_Volume );
2933   }
2934
2935   return aGroups._retn();
2936
2937   SMESH_CATCH( SMESH::throwCorbaException );
2938   return 0;
2939 }
2940
2941 //================================================================================
2942 /*!
2943  * \brief Compute rotation angles for ExtrusionAlongPath as linear variation
2944  * of given angles along path steps
2945  * \param PathMesh mesh containing a 1D sub-mesh on the edge, along
2946  *                which proceeds the extrusion
2947  * \param PathShape is shape(edge); as the mesh can be complex, the edge
2948  *                 is used to define the sub-mesh for the path
2949  */
2950 //================================================================================
2951
2952 SMESH::double_array*
2953 SMESH_MeshEditor_i::LinearAnglesVariation(SMESH::SMESH_Mesh_ptr       thePathMesh,
2954                                           GEOM::GEOM_Object_ptr       thePathShape,
2955                                           const SMESH::double_array & theAngles)
2956 {
2957   SMESH::double_array_var aResult = new SMESH::double_array();
2958   int nbAngles = theAngles.length();
2959   if ( nbAngles > 0 && !thePathMesh->_is_nil() && !thePathShape->_is_nil() )
2960   {
2961     SMESH_Mesh_i* aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( thePathMesh );
2962     TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( thePathShape );
2963     SMESH_subMesh* aSubMesh = aMeshImp->GetImpl().GetSubMesh( aShape );
2964     if ( !aSubMesh || !aSubMesh->GetSubMeshDS())
2965       return aResult._retn();
2966     int nbSteps = aSubMesh->GetSubMeshDS()->NbElements();
2967     if ( nbSteps == nbAngles )
2968     {
2969       aResult.inout() = theAngles;
2970     }
2971     else
2972     {
2973       aResult->length( nbSteps );
2974       double rAn2St = double( nbAngles ) / double( nbSteps );
2975       double angPrev = 0, angle;
2976       for ( int iSt = 0; iSt < nbSteps; ++iSt )
2977       {
2978         double angCur = rAn2St * ( iSt+1 );
2979         double angCurFloor  = floor( angCur );
2980         double angPrevFloor = floor( angPrev );
2981         if ( angPrevFloor == angCurFloor )
2982           angle = rAn2St * theAngles[ int( angCurFloor ) ];
2983         else
2984         {
2985           int iP = int( angPrevFloor );
2986           double angPrevCeil = ceil(angPrev);
2987           angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
2988
2989           int iC = int( angCurFloor );
2990           if ( iC < nbAngles )
2991             angle += ( angCur - angCurFloor ) * theAngles[ iC ];
2992
2993           iP = int( angPrevCeil );
2994           while ( iC-- > iP )
2995             angle += theAngles[ iC ];
2996         }
2997         aResult[ iSt ] = angle;
2998         angPrev = angCur;
2999       }
3000     }
3001   }
3002   // Update Python script
3003   TPythonDump() << "rotAngles = " << theAngles;
3004   TPythonDump() << "rotAngles = " << this << ".LinearAnglesVariation( "
3005                 << thePathMesh  << ", "
3006                 << thePathShape << ", "
3007                 << "rotAngles )";
3008
3009   return aResult._retn();
3010 }
3011
3012 //=======================================================================
3013 //function : mirror
3014 //purpose  :
3015 //=======================================================================
3016
3017 SMESH::ListOfGroups*
3018 SMESH_MeshEditor_i::mirror(TIDSortedElemSet &                  theElements,
3019                            const SMESH::AxisStruct &           theAxis,
3020                            SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
3021                            CORBA::Boolean                      theCopy,
3022                            bool                                theMakeGroups,
3023                            ::SMESH_Mesh*                       theTargetMesh)
3024   throw (SALOME::SALOME_Exception)
3025 {
3026   SMESH_TRY;
3027   initData();
3028
3029   gp_Pnt P ( theAxis.x, theAxis.y, theAxis.z );
3030   gp_Vec V ( theAxis.vx, theAxis.vy, theAxis.vz );
3031
3032   if ( theTargetMesh )
3033     theCopy = false;
3034
3035   gp_Trsf aTrsf;
3036   switch ( theMirrorType ) {
3037   case  SMESH::SMESH_MeshEditor::POINT:
3038     aTrsf.SetMirror( P );
3039     break;
3040   case  SMESH::SMESH_MeshEditor::AXIS:
3041     aTrsf.SetMirror( gp_Ax1( P, V ));
3042     break;
3043   default:
3044     aTrsf.SetMirror( gp_Ax2( P, V ));
3045   }
3046
3047   TIDSortedElemSet  copyElements;
3048   TIDSortedElemSet* workElements = & theElements;
3049
3050   if ( myIsPreviewMode )
3051   {
3052     TPreviewMesh * tmpMesh = getPreviewMesh();
3053     tmpMesh->Copy( theElements, copyElements);
3054     if ( !theCopy && !theTargetMesh )
3055     {
3056       TIDSortedElemSet elemsAround, elemsAroundCopy;
3057       getElementsAround( theElements, getMeshDS(), elemsAround );
3058       tmpMesh->Copy( elemsAround, elemsAroundCopy);
3059     }
3060     workElements = & copyElements;
3061     theMakeGroups = false;
3062   }
3063
3064   ::SMESH_MeshEditor::PGroupIDs groupIds =
3065       getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
3066
3067   if ( theCopy && !myIsPreviewMode)
3068   {
3069     if ( theTargetMesh )
3070     {
3071       theTargetMesh->GetMeshDS()->Modified();
3072     }
3073     else
3074     {
3075       declareMeshModified( /*isReComputeSafe=*/false );
3076     }
3077   }
3078   return theMakeGroups ? getGroups(groupIds.get()) : 0;
3079
3080   SMESH_CATCH( SMESH::throwCorbaException );
3081   return 0;
3082 }
3083
3084 //=======================================================================
3085 //function : Mirror
3086 //purpose  :
3087 //=======================================================================
3088
3089 void SMESH_MeshEditor_i::Mirror(const SMESH::long_array &           theIDsOfElements,
3090                                 const SMESH::AxisStruct &           theAxis,
3091                                 SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
3092                                 CORBA::Boolean                      theCopy)
3093   throw (SALOME::SALOME_Exception)
3094 {
3095   if ( !myIsPreviewMode ) {
3096     TPythonDump() << this << ".Mirror( "
3097                   << theIDsOfElements              << ", "
3098                   << theAxis                       << ", "
3099                   << mirrorTypeName(theMirrorType) << ", "
3100                   << theCopy                       << " )";
3101   }
3102   if ( theIDsOfElements.length() > 0 )
3103   {
3104     TIDSortedElemSet elements;
3105     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3106     mirror(elements, theAxis, theMirrorType, theCopy, false);
3107   }
3108 }
3109
3110
3111 //=======================================================================
3112 //function : MirrorObject
3113 //purpose  :
3114 //=======================================================================
3115
3116 void SMESH_MeshEditor_i::MirrorObject(SMESH::SMESH_IDSource_ptr           theObject,
3117                                       const SMESH::AxisStruct &           theAxis,
3118                                       SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
3119                                       CORBA::Boolean                      theCopy)
3120   throw (SALOME::SALOME_Exception)
3121 {
3122   if ( !myIsPreviewMode ) {
3123     TPythonDump() << this << ".MirrorObject( "
3124                   << theObject                     << ", "
3125                   << theAxis                       << ", "
3126                   << mirrorTypeName(theMirrorType) << ", "
3127                   << theCopy                       << " )";
3128   }
3129   TIDSortedElemSet elements;
3130
3131   bool emptyIfIsMesh = myIsPreviewMode ? false : true;
3132
3133   if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
3134     mirror(elements, theAxis, theMirrorType, theCopy, false);
3135 }
3136
3137 //=======================================================================
3138 //function : MirrorMakeGroups
3139 //purpose  :
3140 //=======================================================================
3141
3142 SMESH::ListOfGroups*
3143 SMESH_MeshEditor_i::MirrorMakeGroups(const SMESH::long_array&            theIDsOfElements,
3144                                      const SMESH::AxisStruct&            theMirror,
3145                                      SMESH::SMESH_MeshEditor::MirrorType theMirrorType)
3146   throw (SALOME::SALOME_Exception)
3147 {
3148   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3149
3150   SMESH::ListOfGroups * aGroups = 0;
3151   if ( theIDsOfElements.length() > 0 )
3152   {
3153     TIDSortedElemSet elements;
3154     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3155     aGroups = mirror(elements, theMirror, theMirrorType, true, true);
3156   }
3157   if (!myIsPreviewMode) {
3158     dumpGroupsList(aPythonDump, aGroups);
3159     aPythonDump << this << ".MirrorMakeGroups( "
3160                 << theIDsOfElements              << ", "
3161                 << theMirror                     << ", "
3162                 << mirrorTypeName(theMirrorType) << " )";
3163   }
3164   return aGroups;
3165 }
3166
3167 //=======================================================================
3168 //function : MirrorObjectMakeGroups
3169 //purpose  :
3170 //=======================================================================
3171
3172 SMESH::ListOfGroups*
3173 SMESH_MeshEditor_i::MirrorObjectMakeGroups(SMESH::SMESH_IDSource_ptr           theObject,
3174                                            const SMESH::AxisStruct&            theMirror,
3175                                            SMESH::SMESH_MeshEditor::MirrorType theMirrorType)
3176   throw (SALOME::SALOME_Exception)
3177 {
3178   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3179
3180   SMESH::ListOfGroups * aGroups = 0;
3181   TIDSortedElemSet elements;
3182   if ( idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3183     aGroups = mirror(elements, theMirror, theMirrorType, true, true);
3184
3185   if (!myIsPreviewMode)
3186   {
3187     dumpGroupsList(aPythonDump,aGroups);
3188     aPythonDump << this << ".MirrorObjectMakeGroups( "
3189                 << theObject                     << ", "
3190                 << theMirror                     << ", "
3191                 << mirrorTypeName(theMirrorType) << " )";
3192   }
3193   return aGroups;
3194 }
3195
3196 //=======================================================================
3197 //function : MirrorMakeMesh
3198 //purpose  :
3199 //=======================================================================
3200
3201 SMESH::SMESH_Mesh_ptr
3202 SMESH_MeshEditor_i::MirrorMakeMesh(const SMESH::long_array&            theIDsOfElements,
3203                                    const SMESH::AxisStruct&            theMirror,
3204                                    SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
3205                                    CORBA::Boolean                      theCopyGroups,
3206                                    const char*                         theMeshName)
3207   throw (SALOME::SALOME_Exception)
3208 {
3209   SMESH_Mesh_i* mesh_i;
3210   SMESH::SMESH_Mesh_var mesh;
3211   { // open new scope to dump "MakeMesh" command
3212     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3213
3214     TPythonDump pydump; // to prevent dump at mesh creation
3215
3216     mesh = makeMesh( theMeshName );
3217     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3218     if (mesh_i && theIDsOfElements.length() > 0 )
3219     {
3220       TIDSortedElemSet elements;
3221       arrayToSet(theIDsOfElements, getMeshDS(), elements);
3222       mirror(elements, theMirror, theMirrorType,
3223              false, theCopyGroups, & mesh_i->GetImpl());
3224       mesh_i->CreateGroupServants();
3225     }
3226
3227     if (!myIsPreviewMode) {
3228       pydump << mesh << " = " << this << ".MirrorMakeMesh( "
3229              << theIDsOfElements              << ", "
3230              << theMirror                     << ", "
3231              << mirrorTypeName(theMirrorType) << ", "
3232              << theCopyGroups                 << ", '"
3233              << theMeshName                   << "' )";
3234     }
3235   }
3236
3237   //dump "GetGroups"
3238   if (!myIsPreviewMode && mesh_i)
3239     mesh_i->GetGroups();
3240
3241   return mesh._retn();
3242 }
3243
3244 //=======================================================================
3245 //function : MirrorObjectMakeMesh
3246 //purpose  :
3247 //=======================================================================
3248
3249 SMESH::SMESH_Mesh_ptr
3250 SMESH_MeshEditor_i::MirrorObjectMakeMesh(SMESH::SMESH_IDSource_ptr           theObject,
3251                                          const SMESH::AxisStruct&            theMirror,
3252                                          SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
3253                                          CORBA::Boolean                      theCopyGroups,
3254                                          const char*                         theMeshName)
3255   throw (SALOME::SALOME_Exception)
3256 {
3257   SMESH_Mesh_i* mesh_i;
3258   SMESH::SMESH_Mesh_var mesh;
3259   { // open new scope to dump "MakeMesh" command
3260     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3261
3262     TPythonDump pydump; // to prevent dump at mesh creation
3263
3264     mesh = makeMesh( theMeshName );
3265     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3266     TIDSortedElemSet elements;
3267     if ( mesh_i &&
3268          idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3269     {
3270       mirror(elements, theMirror, theMirrorType,
3271              false, theCopyGroups, & mesh_i->GetImpl());
3272       mesh_i->CreateGroupServants();
3273     }
3274     if (!myIsPreviewMode) {
3275       pydump << mesh << " = " << this << ".MirrorObjectMakeMesh( "
3276              << theObject                     << ", "
3277              << theMirror                     << ", "
3278              << mirrorTypeName(theMirrorType) << ", "
3279              << theCopyGroups                 << ", '"
3280              << theMeshName                   << "' )";
3281     }
3282   }
3283
3284   //dump "GetGroups"
3285   if (!myIsPreviewMode && mesh_i)
3286     mesh_i->GetGroups();
3287
3288   return mesh._retn();
3289 }
3290
3291 //=======================================================================
3292 //function : translate
3293 //purpose  :
3294 //=======================================================================
3295
3296 SMESH::ListOfGroups*
3297 SMESH_MeshEditor_i::translate(TIDSortedElemSet        & theElements,
3298                               const SMESH::DirStruct &  theVector,
3299                               CORBA::Boolean            theCopy,
3300                               bool                      theMakeGroups,
3301                               ::SMESH_Mesh*             theTargetMesh)
3302   throw (SALOME::SALOME_Exception)
3303 {
3304   SMESH_TRY;
3305   initData();
3306
3307   if ( theTargetMesh )
3308     theCopy = false;
3309
3310   gp_Trsf aTrsf;
3311   const SMESH::PointStruct * P = &theVector.PS;
3312   aTrsf.SetTranslation( gp_Vec( P->x, P->y, P->z ));
3313
3314   TIDSortedElemSet  copyElements;
3315   TIDSortedElemSet* workElements = &theElements;
3316
3317   if ( myIsPreviewMode )
3318   {
3319     TPreviewMesh * tmpMesh = getPreviewMesh();
3320     tmpMesh->Copy( theElements, copyElements);
3321     if ( !theCopy && !theTargetMesh )
3322     {
3323       TIDSortedElemSet elemsAround, elemsAroundCopy;
3324       getElementsAround( theElements, getMeshDS(), elemsAround );
3325       tmpMesh->Copy( elemsAround, elemsAroundCopy);
3326     }
3327     workElements = & copyElements;
3328     theMakeGroups = false;
3329   }
3330
3331   ::SMESH_MeshEditor::PGroupIDs groupIds =
3332       getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
3333
3334   if ( theCopy && !myIsPreviewMode )
3335   {
3336     if ( theTargetMesh )
3337     {
3338       theTargetMesh->GetMeshDS()->Modified();
3339     }
3340     else
3341     {
3342       declareMeshModified( /*isReComputeSafe=*/false );
3343     }
3344   }
3345
3346   return theMakeGroups ? getGroups(groupIds.get()) : 0;
3347
3348   SMESH_CATCH( SMESH::throwCorbaException );
3349   return 0;
3350 }
3351
3352 //=======================================================================
3353 //function : Translate
3354 //purpose  :
3355 //=======================================================================
3356
3357 void SMESH_MeshEditor_i::Translate(const SMESH::long_array & theIDsOfElements,
3358                                    const SMESH::DirStruct &  theVector,
3359                                    CORBA::Boolean            theCopy)
3360   throw (SALOME::SALOME_Exception)
3361 {
3362   if (!myIsPreviewMode) {
3363     TPythonDump() << this << ".Translate( "
3364                   << theIDsOfElements << ", "
3365                   << theVector        << ", "
3366                   << theCopy          << " )";
3367   }
3368   if (theIDsOfElements.length()) {
3369     TIDSortedElemSet elements;
3370     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3371     translate(elements, theVector, theCopy, false);
3372   }
3373 }
3374
3375 //=======================================================================
3376 //function : TranslateObject
3377 //purpose  :
3378 //=======================================================================
3379
3380 void SMESH_MeshEditor_i::TranslateObject(SMESH::SMESH_IDSource_ptr theObject,
3381                                          const SMESH::DirStruct &  theVector,
3382                                          CORBA::Boolean            theCopy)
3383   throw (SALOME::SALOME_Exception)
3384 {
3385   if (!myIsPreviewMode) {
3386     TPythonDump() << this << ".TranslateObject( "
3387                   << theObject << ", "
3388                   << theVector << ", "
3389                   << theCopy   << " )";
3390   }
3391   TIDSortedElemSet elements;
3392
3393   bool emptyIfIsMesh = myIsPreviewMode ? false : true;
3394
3395   if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
3396     translate(elements, theVector, theCopy, false);
3397 }
3398
3399 //=======================================================================
3400 //function : TranslateMakeGroups
3401 //purpose  :
3402 //=======================================================================
3403
3404 SMESH::ListOfGroups*
3405 SMESH_MeshEditor_i::TranslateMakeGroups(const SMESH::long_array& theIDsOfElements,
3406                                         const SMESH::DirStruct&  theVector)
3407   throw (SALOME::SALOME_Exception)
3408 {
3409   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3410
3411   SMESH::ListOfGroups * aGroups = 0;
3412   if (theIDsOfElements.length()) {
3413     TIDSortedElemSet elements;
3414     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3415     aGroups = translate(elements,theVector,true,true);
3416   }
3417   if (!myIsPreviewMode) {
3418     dumpGroupsList(aPythonDump, aGroups);
3419     aPythonDump << this << ".TranslateMakeGroups( "
3420                 << theIDsOfElements << ", "
3421                 << theVector        << " )";
3422   }
3423   return aGroups;
3424 }
3425
3426 //=======================================================================
3427 //function : TranslateObjectMakeGroups
3428 //purpose  :
3429 //=======================================================================
3430
3431 SMESH::ListOfGroups*
3432 SMESH_MeshEditor_i::TranslateObjectMakeGroups(SMESH::SMESH_IDSource_ptr theObject,
3433                                               const SMESH::DirStruct&   theVector)
3434   throw (SALOME::SALOME_Exception)
3435 {
3436   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3437
3438   SMESH::ListOfGroups * aGroups = 0;
3439   TIDSortedElemSet elements;
3440   if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3441     aGroups = translate(elements, theVector, true, true);
3442
3443   if (!myIsPreviewMode) {
3444     dumpGroupsList(aPythonDump, aGroups);
3445     aPythonDump << this << ".TranslateObjectMakeGroups( "
3446                 << theObject << ", "
3447                 << theVector << " )";
3448   }
3449   return aGroups;
3450 }
3451
3452 //=======================================================================
3453 //function : TranslateMakeMesh
3454 //purpose  :
3455 //=======================================================================
3456
3457 SMESH::SMESH_Mesh_ptr
3458 SMESH_MeshEditor_i::TranslateMakeMesh(const SMESH::long_array& theIDsOfElements,
3459                                       const SMESH::DirStruct&  theVector,
3460                                       CORBA::Boolean           theCopyGroups,
3461                                       const char*              theMeshName)
3462   throw (SALOME::SALOME_Exception)
3463 {
3464   SMESH_Mesh_i* mesh_i;
3465   SMESH::SMESH_Mesh_var mesh;
3466
3467   { // open new scope to dump "MakeMesh" command
3468     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3469
3470     TPythonDump pydump; // to prevent dump at mesh creation
3471
3472     mesh = makeMesh( theMeshName );
3473     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3474
3475     if ( mesh_i && theIDsOfElements.length() )
3476     {
3477       TIDSortedElemSet elements;
3478       arrayToSet(theIDsOfElements, getMeshDS(), elements);
3479       translate(elements, theVector, false, theCopyGroups, & mesh_i->GetImpl());
3480       mesh_i->CreateGroupServants();
3481     }
3482
3483     if ( !myIsPreviewMode ) {
3484       pydump << mesh << " = " << this << ".TranslateMakeMesh( "
3485              << theIDsOfElements << ", "
3486              << theVector        << ", "
3487              << theCopyGroups    << ", '"
3488              << theMeshName      << "' )";
3489     }
3490   }
3491
3492   //dump "GetGroups"
3493   if (!myIsPreviewMode && mesh_i)
3494     mesh_i->GetGroups();
3495
3496   return mesh._retn();
3497 }
3498
3499 //=======================================================================
3500 //function : TranslateObjectMakeMesh
3501 //purpose  :
3502 //=======================================================================
3503
3504 SMESH::SMESH_Mesh_ptr
3505 SMESH_MeshEditor_i::TranslateObjectMakeMesh(SMESH::SMESH_IDSource_ptr theObject,
3506                                             const SMESH::DirStruct&   theVector,
3507                                             CORBA::Boolean            theCopyGroups,
3508                                             const char*               theMeshName)
3509   throw (SALOME::SALOME_Exception)
3510 {
3511   SMESH_TRY;
3512   SMESH_Mesh_i* mesh_i;
3513   SMESH::SMESH_Mesh_var mesh;
3514   { // open new scope to dump "MakeMesh" command
3515     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3516
3517     TPythonDump pydump; // to prevent dump at mesh creation
3518     mesh = makeMesh( theMeshName );
3519     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3520
3521     TIDSortedElemSet elements;
3522     if ( mesh_i &&
3523          idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3524     {
3525       translate(elements, theVector,false, theCopyGroups, & mesh_i->GetImpl());
3526       mesh_i->CreateGroupServants();
3527     }
3528     if ( !myIsPreviewMode ) {
3529       pydump << mesh << " = " << this << ".TranslateObjectMakeMesh( "
3530              << theObject     << ", "
3531              << theVector     << ", "
3532              << theCopyGroups << ", '"
3533              << theMeshName   << "' )";
3534     }
3535   }
3536
3537   // dump "GetGroups"
3538   if (!myIsPreviewMode && mesh_i)
3539     mesh_i->GetGroups();
3540
3541   return mesh._retn();
3542
3543   SMESH_CATCH( SMESH::throwCorbaException );
3544   return 0;
3545 }
3546
3547 //=======================================================================
3548 //function : rotate
3549 //purpose  :
3550 //=======================================================================
3551
3552 SMESH::ListOfGroups*
3553 SMESH_MeshEditor_i::rotate(TIDSortedElemSet &        theElements,
3554                            const SMESH::AxisStruct & theAxis,
3555                            CORBA::Double             theAngle,
3556                            CORBA::Boolean            theCopy,
3557                            bool                      theMakeGroups,
3558                            ::SMESH_Mesh*             theTargetMesh)
3559   throw (SALOME::SALOME_Exception)
3560 {
3561   SMESH_TRY;
3562   initData();
3563
3564   if ( theTargetMesh )
3565     theCopy = false;
3566
3567   gp_Pnt P ( theAxis.x, theAxis.y, theAxis.z );
3568   gp_Vec V ( theAxis.vx, theAxis.vy, theAxis.vz );
3569
3570   gp_Trsf aTrsf;
3571   aTrsf.SetRotation( gp_Ax1( P, V ), theAngle);
3572
3573   TIDSortedElemSet  copyElements;
3574   TIDSortedElemSet* workElements = &theElements;
3575   if ( myIsPreviewMode ) {
3576     TPreviewMesh * tmpMesh = getPreviewMesh();
3577     tmpMesh->Copy( theElements, copyElements );
3578     if ( !theCopy && !theTargetMesh )
3579     {
3580       TIDSortedElemSet elemsAround, elemsAroundCopy;
3581       getElementsAround( theElements, getMeshDS(), elemsAround );
3582       tmpMesh->Copy( elemsAround, elemsAroundCopy);
3583     }
3584     workElements = &copyElements;
3585     theMakeGroups = false;
3586   }
3587
3588   ::SMESH_MeshEditor::PGroupIDs groupIds =
3589       getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
3590
3591   if ( theCopy && !myIsPreviewMode)
3592   {
3593     if ( theTargetMesh ) theTargetMesh->GetMeshDS()->Modified();
3594     else                 declareMeshModified( /*isReComputeSafe=*/false );
3595   }
3596
3597   return theMakeGroups ? getGroups(groupIds.get()) : 0;
3598
3599   SMESH_CATCH( SMESH::throwCorbaException );
3600   return 0;
3601 }
3602
3603 //=======================================================================
3604 //function : Rotate
3605 //purpose  :
3606 //=======================================================================
3607
3608 void SMESH_MeshEditor_i::Rotate(const SMESH::long_array & theIDsOfElements,
3609                                 const SMESH::AxisStruct & theAxis,
3610                                 CORBA::Double             theAngle,
3611                                 CORBA::Boolean            theCopy)
3612   throw (SALOME::SALOME_Exception)
3613 {
3614   if (!myIsPreviewMode) {
3615     TPythonDump() << this << ".Rotate( "
3616                   << theIDsOfElements << ", "
3617                   << theAxis          << ", "
3618                   << TVar( theAngle ) << ", "
3619                   << theCopy          << " )";
3620   }
3621   if (theIDsOfElements.length() > 0)
3622   {
3623     TIDSortedElemSet elements;
3624     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3625     rotate(elements,theAxis,theAngle,theCopy,false);
3626   }
3627 }
3628
3629 //=======================================================================
3630 //function : RotateObject
3631 //purpose  :
3632 //=======================================================================
3633
3634 void SMESH_MeshEditor_i::RotateObject(SMESH::SMESH_IDSource_ptr theObject,
3635                                       const SMESH::AxisStruct & theAxis,
3636                                       CORBA::Double             theAngle,
3637                                       CORBA::Boolean            theCopy)
3638   throw (SALOME::SALOME_Exception)
3639 {
3640   if ( !myIsPreviewMode ) {
3641     TPythonDump() << this << ".RotateObject( "
3642                   << theObject        << ", "
3643                   << theAxis          << ", "
3644                   << TVar( theAngle ) << ", "
3645                   << theCopy          << " )";
3646   }
3647   TIDSortedElemSet elements;
3648   bool emptyIfIsMesh = myIsPreviewMode ? false : true;
3649   if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
3650     rotate(elements,theAxis,theAngle,theCopy,false);
3651 }
3652
3653 //=======================================================================
3654 //function : RotateMakeGroups
3655 //purpose  :
3656 //=======================================================================
3657
3658 SMESH::ListOfGroups*
3659 SMESH_MeshEditor_i::RotateMakeGroups(const SMESH::long_array& theIDsOfElements,
3660                                      const SMESH::AxisStruct& theAxis,
3661                                      CORBA::Double            theAngle)
3662   throw (SALOME::SALOME_Exception)
3663 {
3664   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3665
3666   SMESH::ListOfGroups * aGroups = 0;
3667   if (theIDsOfElements.length() > 0)
3668   {
3669     TIDSortedElemSet elements;
3670     arrayToSet(theIDsOfElements, getMeshDS(), elements);
3671     aGroups = rotate(elements,theAxis,theAngle,true,true);
3672   }
3673   if (!myIsPreviewMode) {
3674     dumpGroupsList(aPythonDump, aGroups);
3675     aPythonDump << this << ".RotateMakeGroups( "
3676                 << theIDsOfElements << ", "
3677                 << theAxis          << ", "
3678                 << TVar( theAngle ) << " )";
3679   }
3680   return aGroups;
3681 }
3682
3683 //=======================================================================
3684 //function : RotateObjectMakeGroups
3685 //purpose  :
3686 //=======================================================================
3687
3688 SMESH::ListOfGroups*
3689 SMESH_MeshEditor_i::RotateObjectMakeGroups(SMESH::SMESH_IDSource_ptr theObject,
3690                                            const SMESH::AxisStruct&  theAxis,
3691                                            CORBA::Double             theAngle)
3692   throw (SALOME::SALOME_Exception)
3693 {
3694   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3695
3696   SMESH::ListOfGroups * aGroups = 0;
3697   TIDSortedElemSet elements;
3698   if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3699     aGroups = rotate(elements, theAxis, theAngle, true, true);
3700
3701   if (!myIsPreviewMode) {
3702     dumpGroupsList(aPythonDump, aGroups);
3703     aPythonDump << this << ".RotateObjectMakeGroups( "
3704                 << theObject        << ", "
3705                 << theAxis          << ", "
3706                 << TVar( theAngle ) << " )";
3707   }
3708   return aGroups;
3709 }
3710
3711 //=======================================================================
3712 //function : RotateMakeMesh
3713 //purpose  :
3714 //=======================================================================
3715
3716 SMESH::SMESH_Mesh_ptr
3717 SMESH_MeshEditor_i::RotateMakeMesh(const SMESH::long_array& theIDsOfElements,
3718                                    const SMESH::AxisStruct& theAxis,
3719                                    CORBA::Double            theAngleInRadians,
3720                                    CORBA::Boolean           theCopyGroups,
3721                                    const char*              theMeshName)
3722   throw (SALOME::SALOME_Exception)
3723 {
3724   SMESH_TRY;
3725   SMESH::SMESH_Mesh_var mesh;
3726   SMESH_Mesh_i* mesh_i;
3727
3728   { // open new scope to dump "MakeMesh" command
3729     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3730
3731     TPythonDump pydump; // to prevent dump at mesh creation
3732
3733     mesh = makeMesh( theMeshName );
3734     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3735
3736     if ( mesh_i && theIDsOfElements.length() > 0 )
3737     {
3738       TIDSortedElemSet elements;
3739       arrayToSet(theIDsOfElements, getMeshDS(), elements);
3740       rotate(elements, theAxis, theAngleInRadians,
3741              false, theCopyGroups, & mesh_i->GetImpl());
3742       mesh_i->CreateGroupServants();
3743     }
3744     if ( !myIsPreviewMode ) {
3745       pydump << mesh << " = " << this << ".RotateMakeMesh( "
3746              << theIDsOfElements          << ", "
3747              << theAxis                   << ", "
3748              << TVar( theAngleInRadians ) << ", "
3749              << theCopyGroups             << ", '"
3750              << theMeshName               << "' )";
3751     }
3752   }
3753
3754   // dump "GetGroups"
3755   if (!myIsPreviewMode && mesh_i && theIDsOfElements.length() > 0 )
3756     mesh_i->GetGroups();
3757
3758   return mesh._retn();
3759
3760   SMESH_CATCH( SMESH::throwCorbaException );
3761   return 0;
3762 }
3763
3764 //=======================================================================
3765 //function : RotateObjectMakeMesh
3766 //purpose  :
3767 //=======================================================================
3768
3769 SMESH::SMESH_Mesh_ptr
3770 SMESH_MeshEditor_i::RotateObjectMakeMesh(SMESH::SMESH_IDSource_ptr theObject,
3771                                          const SMESH::AxisStruct&  theAxis,
3772                                          CORBA::Double             theAngleInRadians,
3773                                          CORBA::Boolean            theCopyGroups,
3774                                          const char*               theMeshName)
3775   throw (SALOME::SALOME_Exception)
3776 {
3777   SMESH_TRY;
3778   SMESH::SMESH_Mesh_var mesh;
3779   SMESH_Mesh_i* mesh_i;
3780
3781   {// open new scope to dump "MakeMesh" command
3782    // and then "GetGroups" using SMESH_Mesh::GetGroups()
3783
3784     TPythonDump pydump; // to prevent dump at mesh creation
3785     mesh = makeMesh( theMeshName );
3786     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3787
3788     TIDSortedElemSet elements;
3789     if (mesh_i &&
3790         idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
3791     {
3792       rotate(elements, theAxis, theAngleInRadians,
3793              false, theCopyGroups, & mesh_i->GetImpl());
3794       mesh_i->CreateGroupServants();
3795     }
3796     if ( !myIsPreviewMode ) {
3797       pydump << mesh << " = " << this << ".RotateObjectMakeMesh( "
3798              << theObject                 << ", "
3799              << theAxis                   << ", "
3800              << TVar( theAngleInRadians ) << ", "
3801              << theCopyGroups             << ", '"
3802              << theMeshName               << "' )";
3803     }
3804   }
3805
3806   // dump "GetGroups"
3807   if (!myIsPreviewMode && mesh_i)
3808     mesh_i->GetGroups();
3809
3810   return mesh._retn();
3811
3812   SMESH_CATCH( SMESH::throwCorbaException );
3813   return 0;
3814 }
3815
3816 //=======================================================================
3817 //function : scale
3818 //purpose  :
3819 //=======================================================================
3820
3821 SMESH::ListOfGroups*
3822 SMESH_MeshEditor_i::scale(SMESH::SMESH_IDSource_ptr  theObject,
3823                           const SMESH::PointStruct&  thePoint,
3824                           const SMESH::double_array& theScaleFact,
3825                           CORBA::Boolean             theCopy,
3826                           bool                       theMakeGroups,
3827                           ::SMESH_Mesh*              theTargetMesh)
3828   throw (SALOME::SALOME_Exception)
3829 {
3830   SMESH_TRY;
3831   initData();
3832   if ( theScaleFact.length() < 1 )
3833     THROW_SALOME_CORBA_EXCEPTION("Scale factor not given", SALOME::BAD_PARAM);
3834   if ( theScaleFact.length() == 2 )
3835     THROW_SALOME_CORBA_EXCEPTION("Invalid nb of scale factors : 2", SALOME::BAD_PARAM);
3836
3837   if ( theTargetMesh )
3838     theCopy = false;
3839
3840   TIDSortedElemSet elements;
3841   bool emptyIfIsMesh = myIsPreviewMode ? false : true;
3842   if ( !idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
3843     return 0;
3844
3845   double S[3] = {
3846     theScaleFact[0],
3847     (theScaleFact.length() == 1) ? theScaleFact[0] : theScaleFact[1],
3848     (theScaleFact.length() == 1) ? theScaleFact[0] : theScaleFact[2],
3849   };
3850   gp_Trsf aTrsf;
3851
3852 #if OCC_VERSION_LARGE > 0x06070100
3853   // fight against orthogonalization
3854   // aTrsf.SetValues( S[0], 0,    0,    thePoint.x * (1-S[0]),
3855   //                  0,    S[1], 0,    thePoint.y * (1-S[1]),
3856   //                  0,    0,    S[2], thePoint.z * (1-S[2]) );
3857   aTrsf.SetScale( gp::Origin(), 1.0 ); // set form which is used to make group names
3858   gp_XYZ & loc = ( gp_XYZ& ) aTrsf.TranslationPart();
3859   gp_Mat & M   = ( gp_Mat& ) aTrsf.HVectorialPart();
3860   loc.SetCoord( thePoint.x * (1-S[0]),
3861                 thePoint.y * (1-S[1]),
3862                 thePoint.z * (1-S[2]));
3863   M.SetDiagonal( S[0], S[1], S[2] );
3864
3865 #else
3866   double tol = std::numeric_limits<double>::max();
3867   aTrsf.SetValues( S[0], 0,    0,    thePoint.x * (1-S[0]),
3868                    0,    S[1], 0,    thePoint.y * (1-S[1]),
3869                    0,    0,    S[2], thePoint.z * (1-S[2]),   tol, tol);
3870 #endif
3871
3872   TIDSortedElemSet  copyElements;
3873   TIDSortedElemSet* workElements = &elements;
3874   if ( myIsPreviewMode )
3875   {
3876     TPreviewMesh * tmpMesh = getPreviewMesh();
3877     tmpMesh->Copy( elements, copyElements);
3878     if ( !theCopy && !theTargetMesh )
3879     {
3880       TIDSortedElemSet elemsAround, elemsAroundCopy;
3881       getElementsAround( elements, getMeshDS(), elemsAround );
3882       tmpMesh->Copy( elemsAround, elemsAroundCopy);
3883     }
3884     workElements = & copyElements;
3885     theMakeGroups = false;
3886   }
3887
3888   ::SMESH_MeshEditor::PGroupIDs groupIds =
3889       getEditor().Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
3890
3891   if ( theCopy && !myIsPreviewMode )
3892   {
3893     if ( theTargetMesh ) theTargetMesh->GetMeshDS()->Modified();
3894     else                 declareMeshModified( /*isReComputeSafe=*/false );
3895   }
3896   return theMakeGroups ? getGroups(groupIds.get()) : 0;
3897
3898   SMESH_CATCH( SMESH::throwCorbaException );
3899   return 0;
3900 }
3901
3902 //=======================================================================
3903 //function : Scale
3904 //purpose  :
3905 //=======================================================================
3906
3907 void SMESH_MeshEditor_i::Scale(SMESH::SMESH_IDSource_ptr  theObject,
3908                                const SMESH::PointStruct&  thePoint,
3909                                const SMESH::double_array& theScaleFact,
3910                                CORBA::Boolean             theCopy)
3911   throw (SALOME::SALOME_Exception)
3912 {
3913   if ( !myIsPreviewMode ) {
3914     TPythonDump() << this << ".Scale( "
3915                   << theObject            << ", "
3916                   << thePoint             << ", "
3917                   << TVar( theScaleFact ) << ", "
3918                   << theCopy              << " )";
3919   }
3920   scale(theObject, thePoint, theScaleFact, theCopy, false);
3921 }
3922
3923
3924 //=======================================================================
3925 //function : ScaleMakeGroups
3926 //purpose  :
3927 //=======================================================================
3928
3929 SMESH::ListOfGroups*
3930 SMESH_MeshEditor_i::ScaleMakeGroups(SMESH::SMESH_IDSource_ptr  theObject,
3931                                     const SMESH::PointStruct&  thePoint,
3932                                     const SMESH::double_array& theScaleFact)
3933   throw (SALOME::SALOME_Exception)
3934 {
3935   TPythonDump aPythonDump; // it is here to prevent dump of GetGroups()
3936
3937   SMESH::ListOfGroups * aGroups = scale(theObject, thePoint, theScaleFact, true, true);
3938   if (!myIsPreviewMode) {
3939     dumpGroupsList(aPythonDump, aGroups);
3940     aPythonDump << this << ".Scale("
3941                 << theObject            << ","
3942                 << thePoint             << ","
3943                 << TVar( theScaleFact ) << ",True,True)";
3944   }
3945   return aGroups;
3946 }
3947
3948
3949 //=======================================================================
3950 //function : ScaleMakeMesh
3951 //purpose  :
3952 //=======================================================================
3953
3954 SMESH::SMESH_Mesh_ptr
3955 SMESH_MeshEditor_i::ScaleMakeMesh(SMESH::SMESH_IDSource_ptr  theObject,
3956                                   const SMESH::PointStruct&  thePoint,
3957                                   const SMESH::double_array& theScaleFact,
3958                                   CORBA::Boolean             theCopyGroups,
3959                                   const char*                theMeshName)
3960   throw (SALOME::SALOME_Exception)
3961 {
3962   SMESH_Mesh_i* mesh_i;
3963   SMESH::SMESH_Mesh_var mesh;
3964   { // open new scope to dump "MakeMesh" command
3965     // and then "GetGroups" using SMESH_Mesh::GetGroups()
3966
3967     TPythonDump pydump; // to prevent dump at mesh creation
3968     mesh = makeMesh( theMeshName );
3969     mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
3970
3971     if ( mesh_i )
3972     {
3973       scale(theObject, thePoint, theScaleFact,false, theCopyGroups, & mesh_i->GetImpl());
3974       mesh_i->CreateGroupServants();
3975     }
3976     if ( !myIsPreviewMode )
3977       pydump << mesh << " = " << this << ".ScaleMakeMesh( "
3978              << theObject            << ", "
3979              << thePoint             << ", "
3980              << TVar( theScaleFact ) << ", "
3981              << theCopyGroups        << ", '"
3982              << theMeshName          << "' )";
3983   }
3984
3985   // dump "GetGroups"
3986   if (!myIsPreviewMode && mesh_i)
3987     mesh_i->GetGroups();
3988
3989   return mesh._retn();
3990 }
3991
3992
3993 //=======================================================================
3994 //function : findCoincidentNodes
3995 //purpose  :
3996 //=======================================================================
3997
3998 void SMESH_MeshEditor_i::
3999 findCoincidentNodes (TIDSortedNodeSet &             Nodes,
4000                      CORBA::Double                  Tolerance,
4001                      SMESH::array_of_long_array_out GroupsOfNodes,
4002                      CORBA::Boolean                 SeparateCornersAndMedium)
4003 {
4004   ::SMESH_MeshEditor::TListOfListOfNodes aListOfListOfNodes;
4005   getEditor().FindCoincidentNodes( Nodes, Tolerance, aListOfListOfNodes, SeparateCornersAndMedium );
4006
4007   GroupsOfNodes = new SMESH::array_of_long_array;
4008   GroupsOfNodes->length( aListOfListOfNodes.size() );
4009   ::SMESH_MeshEditor::TListOfListOfNodes::iterator llIt = aListOfListOfNodes.begin();
4010   for ( CORBA::Long i = 0; llIt != aListOfListOfNodes.end(); llIt++, i++ )
4011   {
4012     list< const SMDS_MeshNode* >& aListOfNodes = *llIt;
4013     list< const SMDS_MeshNode* >::iterator lIt = aListOfNodes.begin();;
4014     SMESH::long_array& aGroup = (*GroupsOfNodes)[ i ];
4015     aGroup.length( aListOfNodes.size() );
4016     for ( int j = 0; lIt != aListOfNodes.end(); lIt++, j++ )
4017       aGroup[ j ] = (*lIt)->GetID();
4018   }
4019 }
4020
4021 //=======================================================================
4022 //function : FindCoincidentNodes
4023 //purpose  :
4024 //=======================================================================
4025
4026 void SMESH_MeshEditor_i::
4027 FindCoincidentNodes (CORBA::Double                  Tolerance,
4028                      SMESH::array_of_long_array_out GroupsOfNodes,
4029                      CORBA::Boolean                 SeparateCornersAndMedium)
4030   throw (SALOME::SALOME_Exception)
4031 {
4032   SMESH_TRY;
4033   initData();
4034
4035   TIDSortedNodeSet nodes; // no input nodes
4036   findCoincidentNodes( nodes, Tolerance, GroupsOfNodes, SeparateCornersAndMedium );
4037
4038   TPythonDump() << "coincident_nodes = " << this << ".FindCoincidentNodes( "
4039                 << Tolerance << ", "
4040                 << SeparateCornersAndMedium << " )";
4041
4042   SMESH_CATCH( SMESH::throwCorbaException );
4043 }
4044
4045 //=======================================================================
4046 //function : FindCoincidentNodesOnPart
4047 //purpose  :
4048 //=======================================================================
4049
4050 void SMESH_MeshEditor_i::
4051 FindCoincidentNodesOnPart(SMESH::SMESH_IDSource_ptr      theObject,
4052                           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;
4061   idSourceToNodeSet( theObject, getMeshDS(), nodes );
4062
4063   findCoincidentNodes( nodes, Tolerance, GroupsOfNodes, SeparateCornersAndMedium );
4064
4065   TPythonDump() << "coincident_nodes_on_part = " << this << ".FindCoincidentNodesOnPart( "
4066                 << theObject <<", "
4067                 << Tolerance << ", "
4068                 << SeparateCornersAndMedium << " )";
4069
4070   SMESH_CATCH( SMESH::throwCorbaException );
4071 }
4072
4073 //================================================================================
4074 /*!
4075  * \brief Finds nodes coinsident with Tolerance within Object excluding nodes within
4076  *        ExceptSubMeshOrGroups
4077  */
4078 //================================================================================
4079
4080 void SMESH_MeshEditor_i::
4081 FindCoincidentNodesOnPartBut(SMESH::SMESH_IDSource_ptr      theObject,
4082                              CORBA::Double                  theTolerance,
4083                              SMESH::array_of_long_array_out theGroupsOfNodes,
4084                              const SMESH::ListOfIDSources&  theExceptSubMeshOrGroups,
4085                              CORBA::Boolean                 theSeparateCornersAndMedium)
4086   throw (SALOME::SALOME_Exception)
4087 {
4088   SMESH_TRY;
4089   initData();
4090
4091   TIDSortedNodeSet nodes;
4092   idSourceToNodeSet( theObject, getMeshDS(), nodes );
4093
4094   for ( int i = 0; i < theExceptSubMeshOrGroups.length(); ++i )
4095   {
4096     SMDS_ElemIteratorPtr nodeIt = myMesh_i->GetElements( theExceptSubMeshOrGroups[i],
4097                                                          SMESH::NODE );
4098     while ( nodeIt->more() )
4099       nodes.erase( cast2Node( nodeIt->next() ));
4100   }
4101   findCoincidentNodes( nodes, theTolerance, theGroupsOfNodes, theSeparateCornersAndMedium );
4102
4103   TPythonDump() << "coincident_nodes_on_part = " << this << ".FindCoincidentNodesOnPartBut( "
4104                 << theObject<<", "
4105                 << theTolerance << ", "
4106                 << theExceptSubMeshOrGroups << ", "
4107                 << theSeparateCornersAndMedium << " )";
4108
4109   SMESH_CATCH( SMESH::throwCorbaException );
4110 }
4111
4112 //=======================================================================
4113 //function : MergeNodes
4114 //purpose  :
4115 //=======================================================================
4116
4117 void SMESH_MeshEditor_i::MergeNodes (const SMESH::array_of_long_array& GroupsOfNodes,
4118                                      const SMESH::ListOfIDSources&     NodesToKeep)
4119   throw (SALOME::SALOME_Exception)
4120 {
4121   SMESH_TRY;
4122   initData();
4123
4124   SMESHDS_Mesh* aMesh = getMeshDS();
4125
4126   TPythonDump aTPythonDump;
4127   aTPythonDump << this << ".MergeNodes([";
4128
4129   TIDSortedNodeSet setOfNodesToKeep;
4130   for ( int i = 0; i < NodesToKeep.length(); ++i )
4131   {
4132     prepareIdSource( NodesToKeep[i] );
4133     SMDS_ElemIteratorPtr nodeIt = myMesh_i->GetElements( NodesToKeep[i], SMESH::NODE );
4134     while ( nodeIt->more() )
4135       setOfNodesToKeep.insert( setOfNodesToKeep.end(), cast2Node( nodeIt->next() ));
4136   }
4137
4138   ::SMESH_MeshEditor::TListOfListOfNodes aListOfListOfNodes;
4139   for (int i = 0; i < GroupsOfNodes.length(); i++)
4140   {
4141     const SMESH::long_array& aNodeGroup = GroupsOfNodes[ i ];
4142     aListOfListOfNodes.push_back( list< const SMDS_MeshNode* >() );
4143     list< const SMDS_MeshNode* >& aListOfNodes = aListOfListOfNodes.back();
4144     for ( int j = 0; j < aNodeGroup.length(); j++ )
4145     {
4146       CORBA::Long index = aNodeGroup[ j ];
4147       if ( const SMDS_MeshNode * node = aMesh->FindNode( index ))
4148       {
4149         if ( setOfNodesToKeep.count( node ))
4150           aListOfNodes.push_front( node );
4151         else
4152           aListOfNodes.push_back( node );
4153       }
4154     }
4155     if ( aListOfNodes.size() < 2 )
4156       aListOfListOfNodes.pop_back();
4157
4158     if ( i > 0 ) aTPythonDump << ", ";
4159     aTPythonDump << aNodeGroup;
4160   }
4161
4162   getEditor().MergeNodes( aListOfListOfNodes );
4163
4164   aTPythonDump << "], " << NodesToKeep << ")";
4165
4166   declareMeshModified( /*isReComputeSafe=*/false );
4167
4168   SMESH_CATCH( SMESH::throwCorbaException );
4169 }
4170
4171 //=======================================================================
4172 //function : FindEqualElements
4173 //purpose  :
4174 //=======================================================================
4175
4176 void SMESH_MeshEditor_i::FindEqualElements(SMESH::SMESH_IDSource_ptr      theObject,
4177                                            SMESH::array_of_long_array_out GroupsOfElementsID)
4178   throw (SALOME::SALOME_Exception)
4179 {
4180   SMESH_TRY;
4181   initData();
4182
4183   SMESH::SMESH_GroupBase_var group = SMESH::SMESH_GroupBase::_narrow(theObject);
4184   if ( !(!group->_is_nil() && group->GetType() == SMESH::NODE) )
4185   {
4186     TIDSortedElemSet elems;
4187     idSourceToSet( theObject, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true);
4188
4189     ::SMESH_MeshEditor::TListOfListOfElementsID aListOfListOfElementsID;
4190     getEditor().FindEqualElements( elems, aListOfListOfElementsID );
4191
4192     GroupsOfElementsID = new SMESH::array_of_long_array;
4193     GroupsOfElementsID->length( aListOfListOfElementsID.size() );
4194
4195     ::SMESH_MeshEditor::TListOfListOfElementsID::iterator arraysIt =
4196         aListOfListOfElementsID.begin();
4197     for (CORBA::Long j = 0; arraysIt != aListOfListOfElementsID.end(); ++arraysIt, ++j)
4198     {
4199       SMESH::long_array& aGroup = (*GroupsOfElementsID)[ j ];
4200       list<int>&      listOfIDs = *arraysIt;
4201       aGroup.length( listOfIDs.size() );
4202       list<int>::iterator idIt = listOfIDs.begin();
4203       for (int k = 0; idIt != listOfIDs.end(); ++idIt, ++k )
4204         aGroup[ k ] = *idIt;
4205     }
4206
4207     TPythonDump() << "equal_elements = " << this << ".FindEqualElements( "
4208                   <<theObject<<" )";
4209   }
4210
4211   SMESH_CATCH( SMESH::throwCorbaException );
4212 }
4213
4214 //=======================================================================
4215 //function : MergeElements
4216 //purpose  :
4217 //=======================================================================
4218
4219 void SMESH_MeshEditor_i::MergeElements(const SMESH::array_of_long_array& GroupsOfElementsID)
4220   throw (SALOME::SALOME_Exception)
4221 {
4222   SMESH_TRY;
4223   initData();
4224
4225   TPythonDump aTPythonDump;
4226   aTPythonDump << this << ".MergeElements( [";
4227
4228   ::SMESH_MeshEditor::TListOfListOfElementsID aListOfListOfElementsID;
4229
4230   for (int i = 0; i < GroupsOfElementsID.length(); i++) {
4231     const SMESH::long_array& anElemsIDGroup = GroupsOfElementsID[ i ];
4232     aListOfListOfElementsID.push_back( list< int >() );
4233     list< int >& aListOfElemsID = aListOfListOfElementsID.back();
4234     for ( int j = 0; j < anElemsIDGroup.length(); j++ ) {
4235       CORBA::Long id = anElemsIDGroup[ j ];
4236       aListOfElemsID.push_back( id );
4237     }
4238     if ( aListOfElemsID.size() < 2 )
4239       aListOfListOfElementsID.pop_back();
4240     if ( i > 0 ) aTPythonDump << ", ";
4241     aTPythonDump << anElemsIDGroup;
4242   }
4243
4244   getEditor().MergeElements(aListOfListOfElementsID);
4245
4246   declareMeshModified( /*isReComputeSafe=*/true );
4247
4248   aTPythonDump << "] )";
4249
4250   SMESH_CATCH( SMESH::throwCorbaException );
4251 }
4252
4253 //=======================================================================
4254 //function : MergeEqualElements
4255 //purpose  :
4256 //=======================================================================
4257
4258 void SMESH_MeshEditor_i::MergeEqualElements()
4259   throw (SALOME::SALOME_Exception)
4260 {
4261   SMESH_TRY;
4262   initData();
4263
4264   getEditor().MergeEqualElements();
4265
4266   declareMeshModified( /*isReComputeSafe=*/true );
4267
4268   TPythonDump() << this << ".MergeEqualElements()";
4269
4270   SMESH_CATCH( SMESH::throwCorbaException );
4271 }
4272
4273 //=============================================================================
4274 /*!
4275  * Move the node to a given point
4276  */
4277 //=============================================================================
4278
4279 CORBA::Boolean SMESH_MeshEditor_i::MoveNode(CORBA::Long   NodeID,
4280                                             CORBA::Double x,
4281                                             CORBA::Double y,
4282                                             CORBA::Double z)
4283   throw (SALOME::SALOME_Exception)
4284 {
4285   SMESH_TRY;
4286   initData(/*deleteSearchers=*/false);
4287
4288   const SMDS_MeshNode * node = getMeshDS()->FindNode( NodeID );
4289   if ( !node )
4290     return false;
4291
4292   if ( theNodeSearcher )
4293     theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
4294
4295   if ( myIsPreviewMode ) // make preview data
4296   {
4297     // in a preview mesh, make edges linked to a node
4298     TPreviewMesh& tmpMesh = *getPreviewMesh();
4299     TIDSortedElemSet linkedNodes;
4300     ::SMESH_MeshEditor::GetLinkedNodes( node, linkedNodes );
4301     TIDSortedElemSet::iterator nIt = linkedNodes.begin();
4302     SMDS_MeshNode *nodeCpy1 = tmpMesh.Copy(node);
4303     for ( ; nIt != linkedNodes.end(); ++nIt )
4304     {
4305       SMDS_MeshNode *nodeCpy2 = tmpMesh.Copy ( cast2Node( *nIt ));
4306       tmpMesh.GetMeshDS()->AddEdge(nodeCpy1, nodeCpy2);
4307     }
4308     // move copied node
4309     if ( nodeCpy1 )
4310       tmpMesh.GetMeshDS()->MoveNode(nodeCpy1, x, y, z);
4311     // fill preview data
4312   }
4313   else if ( theNodeSearcher ) // move node and update theNodeSearcher data accordingly
4314     theNodeSearcher->MoveNode(node, gp_Pnt( x,y,z ));
4315   else
4316     getMeshDS()->MoveNode(node, x, y, z);
4317
4318   if ( !myIsPreviewMode )
4319   {
4320     // Update Python script
4321     TPythonDump() << "isDone = " << this << ".MoveNode( "
4322                   << NodeID << ", " << TVar(x) << ", " << TVar(y) << ", " << TVar(z) << " )";
4323     declareMeshModified( /*isReComputeSafe=*/false );
4324   }
4325
4326   SMESH_CATCH( SMESH::throwCorbaException );
4327
4328   return true;
4329 }
4330
4331 //================================================================================
4332 /*!
4333  * \brief Return ID of node closest to a given point
4334  */
4335 //================================================================================
4336
4337 CORBA::Long SMESH_MeshEditor_i::FindNodeClosestTo(CORBA::Double x,
4338                                                   CORBA::Double y,
4339                                                   CORBA::Double z)
4340   throw (SALOME::SALOME_Exception)
4341 {
4342   SMESH_TRY;
4343   theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
4344
4345   if ( !theNodeSearcher ) {
4346     theNodeSearcher = SMESH_MeshAlgos::GetNodeSearcher( *getMeshDS() );
4347   }
4348   gp_Pnt p( x,y,z );
4349   if ( const SMDS_MeshNode* node = theNodeSearcher->FindClosestTo( p ))
4350     return node->GetID();
4351
4352   SMESH_CATCH( SMESH::throwCorbaException );
4353   return 0;
4354 }
4355
4356 //================================================================================
4357 /*!
4358  * \brief If the given ID is a valid node ID (nodeID > 0), just move this node, else
4359  * move the node closest to the point to point's location and return ID of the node
4360  */
4361 //================================================================================
4362
4363 CORBA::Long SMESH_MeshEditor_i::MoveClosestNodeToPoint(CORBA::Double x,
4364                                                        CORBA::Double y,
4365                                                        CORBA::Double z,
4366                                                        CORBA::Long   theNodeID)
4367   throw (SALOME::SALOME_Exception)
4368 {
4369   SMESH_TRY;
4370   // We keep theNodeSearcher until any mesh modification:
4371   // 1) initData() deletes theNodeSearcher at any edition,
4372   // 2) TSearchersDeleter - at any mesh compute event and mesh change
4373
4374   initData(/*deleteSearchers=*/false);
4375
4376   theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
4377
4378   int nodeID = theNodeID;
4379   const SMDS_MeshNode* node = getMeshDS()->FindNode( nodeID );
4380   if ( !node ) // preview moving node
4381   {
4382     if ( !theNodeSearcher ) {
4383       theNodeSearcher = SMESH_MeshAlgos::GetNodeSearcher( *getMeshDS() );
4384     }
4385     gp_Pnt p( x,y,z );
4386     node = theNodeSearcher->FindClosestTo( p );
4387   }
4388   if ( node ) {
4389     nodeID = node->GetID();
4390     if ( myIsPreviewMode ) // make preview data
4391     {
4392       // in a preview mesh, make edges linked to a node
4393       TPreviewMesh tmpMesh = *getPreviewMesh();
4394       TIDSortedElemSet linkedNodes;
4395       ::SMESH_MeshEditor::GetLinkedNodes( node, linkedNodes );
4396       TIDSortedElemSet::iterator nIt = linkedNodes.begin();
4397       for ( ; nIt != linkedNodes.end(); ++nIt )
4398       {
4399         SMDS_LinearEdge edge( node, cast2Node( *nIt ));
4400         tmpMesh.Copy( &edge );
4401       }
4402       // move copied node
4403       node = tmpMesh.GetMeshDS()->FindNode( nodeID );
4404       if ( node )
4405         tmpMesh.GetMeshDS()->MoveNode(node, x, y, z);
4406       // fill preview data
4407     }
4408     else if ( theNodeSearcher ) // move node and update theNodeSearcher data accordingly
4409     {
4410       theNodeSearcher->MoveNode(node, gp_Pnt( x,y,z ));
4411     }
4412     else
4413     {
4414       getMeshDS()->MoveNode(node, x, y, z);
4415     }
4416   }
4417
4418   if ( !myIsPreviewMode )
4419   {
4420     TPythonDump() << "nodeID = " << this
4421                   << ".MoveClosestNodeToPoint( "<< x << ", " << y << ", " << z
4422                   << ", " << nodeID << " )";
4423
4424     declareMeshModified( /*isReComputeSafe=*/false );
4425   }
4426
4427   return nodeID;
4428
4429   SMESH_CATCH( SMESH::throwCorbaException );
4430   return 0;
4431 }
4432
4433 //=======================================================================
4434 /*!
4435  * Return elements of given type where the given point is IN or ON.
4436  *
4437  * 'ALL' type means elements of any type excluding nodes
4438  */
4439 //=======================================================================
4440
4441 SMESH::long_array* SMESH_MeshEditor_i::FindElementsByPoint(CORBA::Double      x,
4442                                                            CORBA::Double      y,
4443                                                            CORBA::Double      z,
4444                                                            SMESH::ElementType type)
4445   throw (SALOME::SALOME_Exception)
4446 {
4447   SMESH_TRY;
4448   SMESH::long_array_var res = new SMESH::long_array;
4449   vector< const SMDS_MeshElement* > foundElems;
4450
4451   theSearchersDeleter.Set( myMesh );
4452   if ( !theElementSearcher ) {
4453     theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() );
4454   }
4455   theElementSearcher->FindElementsByPoint( gp_Pnt( x,y,z ),
4456                                            SMDSAbs_ElementType( type ),
4457                                            foundElems);
4458   res->length( foundElems.size() );
4459   for ( int i = 0; i < foundElems.size(); ++i )
4460     res[i] = foundElems[i]->GetID();
4461
4462   return res._retn();
4463
4464   SMESH_CATCH( SMESH::throwCorbaException );
4465   return 0;
4466 }
4467
4468 //=======================================================================
4469 //function : FindAmongElementsByPoint
4470 //purpose  : Searching among the given elements, return elements of given type 
4471 //           where the given point is IN or ON.
4472 //           'ALL' type means elements of any type excluding nodes
4473 //=======================================================================
4474
4475 SMESH::long_array*
4476 SMESH_MeshEditor_i::FindAmongElementsByPoint(SMESH::SMESH_IDSource_ptr elementIDs,
4477                                              CORBA::Double             x,
4478                                              CORBA::Double             y,
4479                                              CORBA::Double             z,
4480                                              SMESH::ElementType        type)
4481   throw (SALOME::SALOME_Exception)
4482 {
4483   SMESH_TRY;
4484   SMESH::long_array_var res = new SMESH::long_array;
4485   
4486   SMESH::array_of_ElementType_var types = elementIDs->GetTypes();
4487   if ( types->length() == 1 && // a part contains only nodes or 0D elements
4488        ( types[0] == SMESH::NODE || types[0] == SMESH::ELEM0D || types[0] == SMESH::BALL) &&
4489        type != types[0] ) // but search of elements of dim > 0
4490     return res._retn();
4491
4492   if ( SMESH::DownCast<SMESH_Mesh_i*>( elementIDs )) // elementIDs is the whole mesh 
4493     return FindElementsByPoint( x,y,z, type );
4494
4495   TIDSortedElemSet elements; // elems should live until FindElementsByPoint() finishes
4496
4497   theSearchersDeleter.Set( myMesh, getPartIOR( elementIDs, type ));
4498   if ( !theElementSearcher )
4499   {
4500     // create a searcher from elementIDs
4501     SMESH::SMESH_Mesh_var mesh = elementIDs->GetMesh();
4502     SMESHDS_Mesh* meshDS = SMESH::DownCast<SMESH_Mesh_i*>( mesh )->GetImpl().GetMeshDS();
4503
4504     if ( !idSourceToSet( elementIDs, meshDS, elements,
4505                          SMDSAbs_ElementType(type), /*emptyIfIsMesh=*/true))
4506       return res._retn();
4507
4508     typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator > TIter;
4509     SMDS_ElemIteratorPtr elemsIt( new TIter( elements.begin(), elements.end() ));
4510
4511     theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), elemsIt );
4512   }
4513
4514   vector< const SMDS_MeshElement* > foundElems;
4515
4516   theElementSearcher->FindElementsByPoint( gp_Pnt( x,y,z ),
4517                                            SMDSAbs_ElementType( type ),
4518                                            foundElems);
4519   res->length( foundElems.size() );
4520   for ( int i = 0; i < foundElems.size(); ++i )
4521     res[i] = foundElems[i]->GetID();
4522
4523   return res._retn();
4524
4525   SMESH_CATCH( SMESH::throwCorbaException );
4526   return 0;
4527 }
4528
4529 //=======================================================================
4530 //function : GetPointState
4531 //purpose  : Return point state in a closed 2D mesh in terms of TopAbs_State enumeration.
4532 //           TopAbs_UNKNOWN state means that either mesh is wrong or the analysis fails.
4533 //=======================================================================
4534
4535 CORBA::Short SMESH_MeshEditor_i::GetPointState(CORBA::Double x,
4536                                                CORBA::Double y,
4537                                                CORBA::Double z)
4538   throw (SALOME::SALOME_Exception)
4539 {
4540   SMESH_TRY;
4541   theSearchersDeleter.Set( myMesh );
4542   if ( !theElementSearcher ) {
4543     theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() );
4544   }
4545   return CORBA::Short( theElementSearcher->GetPointState( gp_Pnt( x,y,z )));
4546
4547   SMESH_CATCH( SMESH::throwCorbaException );
4548   return 0;
4549 }
4550
4551 //=======================================================================
4552 //function : convError
4553 //purpose  :
4554 //=======================================================================
4555
4556 #define RETCASE(enm) case ::SMESH_MeshEditor::enm: return SMESH::SMESH_MeshEditor::enm;
4557
4558 static SMESH::SMESH_MeshEditor::Sew_Error convError( const::SMESH_MeshEditor::Sew_Error e )
4559 {
4560   switch ( e ) {
4561     RETCASE( SEW_OK );
4562     RETCASE( SEW_BORDER1_NOT_FOUND );
4563     RETCASE( SEW_BORDER2_NOT_FOUND );
4564     RETCASE( SEW_BOTH_BORDERS_NOT_FOUND );
4565     RETCASE( SEW_BAD_SIDE_NODES );
4566     RETCASE( SEW_VOLUMES_TO_SPLIT );
4567     RETCASE( SEW_DIFF_NB_OF_ELEMENTS );
4568     RETCASE( SEW_TOPO_DIFF_SETS_OF_ELEMENTS );
4569     RETCASE( SEW_BAD_SIDE1_NODES );
4570     RETCASE( SEW_BAD_SIDE2_NODES );
4571   }
4572   return SMESH::SMESH_MeshEditor::SEW_OK;
4573 }
4574
4575 //=======================================================================
4576 /*!
4577  * Returns groups of FreeBorder's coincident within the given tolerance.
4578  * If the tolerance <= 0.0 then one tenth of an average size of elements adjacent
4579  * to free borders being compared is used.
4580  */
4581 //=======================================================================
4582
4583 SMESH::CoincidentFreeBorders*
4584 SMESH_MeshEditor_i::FindCoincidentFreeBorders(CORBA::Double tolerance)
4585 {
4586   SMESH::CoincidentFreeBorders_var aCFB = new SMESH::CoincidentFreeBorders;
4587
4588   SMESH_TRY;
4589
4590   SMESH_MeshAlgos::CoincidentFreeBorders cfb;
4591   SMESH_MeshAlgos::FindCoincidentFreeBorders( *getMeshDS(), tolerance, cfb );
4592
4593   // copy free borders
4594   aCFB->borders.length( cfb._borders.size() );
4595   for ( size_t i = 0; i < cfb._borders.size(); ++i )
4596   {
4597     SMESH_MeshAlgos::TFreeBorder& nodes = cfb._borders[i];
4598     SMESH::FreeBorder&             aBRD = aCFB->borders[i];
4599     aBRD.nodeIDs.length( nodes.size() );
4600     for ( size_t iN = 0; iN < nodes.size(); ++iN )
4601       aBRD.nodeIDs[ iN ] = nodes[ iN ]->GetID();
4602   }
4603
4604   // copy coincident parts
4605   aCFB->coincidentGroups.length( cfb._coincidentGroups.size() );
4606   for ( size_t i = 0; i < cfb._coincidentGroups.size(); ++i )
4607   {
4608     SMESH_MeshAlgos::TCoincidentGroup& grp = cfb._coincidentGroups[i];
4609     SMESH::FreeBordersGroup&          aGRP = aCFB->coincidentGroups[i];
4610     aGRP.length( grp.size() );
4611     for ( size_t iP = 0; iP < grp.size(); ++iP )
4612     {
4613       SMESH_MeshAlgos::TFreeBorderPart& part = grp[ iP ];
4614       SMESH::FreeBorderPart&           aPART = aGRP[ iP ];
4615       aPART.border   = part._border;
4616       aPART.node1    = part._node1;
4617       aPART.node2    = part._node2;
4618       aPART.nodeLast = part._nodeLast;
4619     }
4620   }
4621   SMESH_CATCH( SMESH::doNothing );
4622
4623   TPythonDump() << "CoincidentFreeBorders = "
4624                 << this << ".FindCoincidentFreeBorders( " << tolerance << " )";
4625
4626   return aCFB._retn();
4627 }
4628
4629 //=======================================================================
4630 /*!
4631  * Sew FreeBorder's of each group
4632  */
4633 //=======================================================================
4634
4635 CORBA::Short SMESH_MeshEditor_i::
4636 SewCoincidentFreeBorders(const SMESH::CoincidentFreeBorders& freeBorders,
4637                          CORBA::Boolean                      createPolygons,
4638                          CORBA::Boolean                      createPolyhedra)
4639   throw (SALOME::SALOME_Exception)
4640 {
4641   CORBA::Short nbSewed = 0;
4642
4643   SMESH_MeshAlgos::TFreeBorderVec groups;
4644   SMESH_MeshAlgos::TFreeBorder    borderNodes; // triples of nodes for every FreeBorderPart
4645
4646   // check the input and collect nodes
4647   for ( CORBA::ULong i = 0; i < freeBorders.coincidentGroups.length(); ++i )
4648   {
4649     borderNodes.clear();
4650     const SMESH::FreeBordersGroup& aGRP = freeBorders.coincidentGroups[ i ];
4651     for ( CORBA::ULong iP = 0; iP < aGRP.length(); ++iP )
4652     {
4653       const SMESH::FreeBorderPart& aPART = aGRP[ iP ];
4654       if ( aPART.border < 0 || aPART.border >= freeBorders.borders.length() )
4655         THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::border index", SALOME::BAD_PARAM);
4656
4657       const SMESH::FreeBorder& aBRD = freeBorders.borders[ aPART.border ];
4658
4659       if ( aPART.node1 < 0 || aPART.node1 > aBRD.nodeIDs.length() )
4660         THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::node1", SALOME::BAD_PARAM);
4661       if ( aPART.node2 < 0 || aPART.node2 > aBRD.nodeIDs.length() )
4662         THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::node2", SALOME::BAD_PARAM);
4663       if ( aPART.nodeLast < 0 || aPART.nodeLast > aBRD.nodeIDs.length() )
4664         THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::nodeLast", SALOME::BAD_PARAM);
4665
4666       // do not keep these nodes for further sewing as nodes can be removed by the sewing
4667       const SMDS_MeshNode* n1 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.node1    ]);
4668       const SMDS_MeshNode* n2 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.node2    ]);
4669       const SMDS_MeshNode* n3 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.nodeLast ]);
4670       if ( !n1)
4671         THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::node1", SALOME::BAD_PARAM);
4672       if ( !n2 )
4673         THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::node2", SALOME::BAD_PARAM);
4674       if ( !n3 )
4675         THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::nodeLast", SALOME::BAD_PARAM);
4676
4677       borderNodes.push_back( n1 );
4678       borderNodes.push_back( n2 );
4679       borderNodes.push_back( n3 );
4680     }
4681     groups.push_back( borderNodes );
4682   }
4683
4684   // SewFreeBorder() can merge nodes, thus nodes stored in 'groups' can become dead;
4685   // to get nodes that replace other nodes during merge we create 0D elements
4686   // on each node and MergeNodes() will replace underlying nodes of 0D elements by
4687   // new ones.
4688
4689   vector< const SMDS_MeshElement* > tmp0Delems;
4690   for ( size_t i = 0; i < groups.size(); ++i )
4691   {
4692     SMESH_MeshAlgos::TFreeBorder& nodes = groups[i];
4693     for ( size_t iN = 0; iN < nodes.size(); ++iN )
4694     {
4695       SMDS_ElemIteratorPtr it0D = nodes[iN]->GetInverseElementIterator(SMDSAbs_0DElement);
4696       if ( it0D->more() )
4697         tmp0Delems.push_back( it0D->next() );
4698       else
4699         tmp0Delems.push_back( getMeshDS()->Add0DElement( nodes[iN] ));
4700     }
4701   }
4702
4703   // cout << endl << "INIT" << endl;
4704   // for ( size_t i = 0; i < tmp0Delems.size(); ++i )
4705   // {
4706   //   cout << i << " ";
4707   //   if ( i % 3 == 0 ) cout << "^ ";
4708   //   tmp0Delems[i]->GetNode(0)->Print( cout );
4709   // }
4710
4711   SMESH_TRY;
4712
4713   ::SMESH_MeshEditor::Sew_Error res, ok = ::SMESH_MeshEditor::SEW_OK;
4714   int i0D = 0;
4715   for ( size_t i = 0; i < groups.size(); ++i )
4716   {
4717     bool isBordToBord = true;
4718     bool   groupSewed = false;
4719     SMESH_MeshAlgos::TFreeBorder& nodes = groups[i];
4720     for ( size_t iN = 3; iN+2 < nodes.size(); iN += 3 )
4721     {
4722       const SMDS_MeshNode* n0 = tmp0Delems[ i0D + 0 ]->GetNode( 0 );
4723       const SMDS_MeshNode* n1 = tmp0Delems[ i0D + 1 ]->GetNode( 0 );
4724       const SMDS_MeshNode* n2 = tmp0Delems[ i0D + 2 ]->GetNode( 0 );
4725
4726       const SMDS_MeshNode* n3 = tmp0Delems[ i0D + 0 + iN ]->GetNode( 0 );
4727       const SMDS_MeshNode* n4 = tmp0Delems[ i0D + 1 + iN ]->GetNode( 0 );
4728       const SMDS_MeshNode* n5 = tmp0Delems[ i0D + 2 + iN ]->GetNode( 0 );
4729
4730       if ( !n0 || !n1 || !n2 || !n3 || !n4 || !n5 )
4731         continue;
4732
4733       // TIDSortedElemSet emptySet, avoidSet;
4734       // if ( !SMESH_MeshAlgos::FindFaceInSet( n0, n1, emptySet, avoidSet))
4735       // {
4736       //   cout << "WRONG 2nd 1" << endl;
4737       //   n0->Print( cout );
4738       //   n1->Print( cout );
4739       // }
4740       // if ( !SMESH_MeshAlgos::FindFaceInSet( n3, n4, emptySet, avoidSet))
4741       // {
4742       //   cout << "WRONG 2nd 2" << endl;
4743       //   n3->Print( cout );
4744       //   n4->Print( cout );
4745       // }
4746
4747       if ( !isBordToBord )
4748       {
4749         n1 = n2; // at border-to-side sewing only last side node (n1) is needed
4750         n2 = 0;  //  and n2 is not used
4751       }
4752       // 1st border moves to 2nd
4753       res = getEditor().SewFreeBorder( n3, n4, n5 ,// 1st
4754                                        n0 ,n1 ,n2 ,// 2nd
4755                                        /*2ndIsFreeBorder=*/ isBordToBord,
4756                                        createPolygons, createPolyhedra);
4757       groupSewed = ( res == ok );
4758
4759       isBordToBord = false;
4760       // cout << endl << "SEWED GROUP " << i << " PART " << iN / 3 << endl;
4761       // for ( size_t t = 0; t < tmp0Delems.size(); ++t )
4762       // {
4763       //   cout << t << " ";
4764       //   if ( t % 3 == 0 ) cout << "^ ";
4765       //   tmp0Delems[t]->GetNode(0)->Print( cout );
4766       // }
4767     }
4768     i0D += nodes.size();
4769     nbSewed += groupSewed;
4770   }
4771
4772   TPythonDump() << "nbSewed = " << this << ".SewCoincidentFreeBorders( "
4773                 << freeBorders     << ", "
4774                 << createPolygons  << ", "
4775                 << createPolyhedra << " )";
4776
4777   SMESH_CATCH( SMESH::doNothing );
4778
4779   declareMeshModified( /*isReComputeSafe=*/false );
4780
4781   // remove tmp 0D elements
4782   SMESH_TRY;
4783   set< const SMDS_MeshElement* > removed0D;
4784   for ( size_t i = 0; i < tmp0Delems.size(); ++i )
4785   {
4786     if ( removed0D.insert( tmp0Delems[i] ).second )
4787       getMeshDS()->RemoveFreeElement( tmp0Delems[i], /*sm=*/0, /*fromGroups=*/false );
4788   }
4789   SMESH_CATCH( SMESH::throwCorbaException );
4790
4791   return nbSewed;
4792 }
4793
4794 //=======================================================================
4795 //function : SewFreeBorders
4796 //purpose  :
4797 //=======================================================================
4798
4799 SMESH::SMESH_MeshEditor::Sew_Error
4800 SMESH_MeshEditor_i::SewFreeBorders(CORBA::Long FirstNodeID1,
4801                                    CORBA::Long SecondNodeID1,
4802                                    CORBA::Long LastNodeID1,
4803                                    CORBA::Long FirstNodeID2,
4804                                    CORBA::Long SecondNodeID2,
4805                                    CORBA::Long LastNodeID2,
4806                                    CORBA::Boolean CreatePolygons,
4807                                    CORBA::Boolean CreatePolyedrs)
4808   throw (SALOME::SALOME_Exception)
4809 {
4810   SMESH_TRY;
4811   initData();
4812
4813   SMESHDS_Mesh* aMesh = getMeshDS();
4814
4815   const SMDS_MeshNode* aBorderFirstNode  = aMesh->FindNode( FirstNodeID1  );
4816   const SMDS_MeshNode* aBorderSecondNode = aMesh->FindNode( SecondNodeID1 );
4817   const SMDS_MeshNode* aBorderLastNode   = aMesh->FindNode( LastNodeID1   );
4818   const SMDS_MeshNode* aSide2FirstNode   = aMesh->FindNode( FirstNodeID2  );
4819   const SMDS_MeshNode* aSide2SecondNode  = aMesh->FindNode( SecondNodeID2 );
4820   const SMDS_MeshNode* aSide2ThirdNode   = aMesh->FindNode( LastNodeID2   );
4821
4822   if (!aBorderFirstNode ||
4823       !aBorderSecondNode||
4824       !aBorderLastNode)
4825     return SMESH::SMESH_MeshEditor::SEW_BORDER1_NOT_FOUND;
4826   if (!aSide2FirstNode  ||
4827       !aSide2SecondNode ||
4828       !aSide2ThirdNode)
4829     return SMESH::SMESH_MeshEditor::SEW_BORDER2_NOT_FOUND;
4830
4831   TPythonDump() << "error = " << this << ".SewFreeBorders( "
4832                 << FirstNodeID1  << ", "
4833                 << SecondNodeID1 << ", "
4834                 << LastNodeID1   << ", "
4835                 << FirstNodeID2  << ", "
4836                 << SecondNodeID2 << ", "
4837                 << LastNodeID2   << ", "
4838                 << CreatePolygons<< ", "
4839                 << CreatePolyedrs<< " )";
4840
4841   SMESH::SMESH_MeshEditor::Sew_Error error =
4842     convError( getEditor().SewFreeBorder (aBorderFirstNode,
4843                                           aBorderSecondNode,
4844                                           aBorderLastNode,
4845                                           aSide2FirstNode,
4846                                           aSide2SecondNode,
4847                                           aSide2ThirdNode,
4848                                           true,
4849                                           CreatePolygons,
4850                                           CreatePolyedrs) );
4851
4852
4853   declareMeshModified( /*isReComputeSafe=*/false );
4854   return error;
4855
4856   SMESH_CATCH( SMESH::throwCorbaException );
4857   return SMESH::SMESH_MeshEditor::Sew_Error(0);
4858 }
4859
4860
4861 //=======================================================================
4862 //function : SewConformFreeBorders
4863 //purpose  :
4864 //=======================================================================
4865
4866 SMESH::SMESH_MeshEditor::Sew_Error
4867 SMESH_MeshEditor_i::SewConformFreeBorders(CORBA::Long FirstNodeID1,
4868                                           CORBA::Long SecondNodeID1,
4869                                           CORBA::Long LastNodeID1,
4870                                           CORBA::Long FirstNodeID2,
4871                                           CORBA::Long SecondNodeID2)
4872   throw (SALOME::SALOME_Exception)
4873 {
4874   SMESH_TRY;
4875   initData();
4876
4877   SMESHDS_Mesh* aMesh = getMeshDS();
4878
4879   const SMDS_MeshNode* aBorderFirstNode  = aMesh->FindNode( FirstNodeID1  );
4880   const SMDS_MeshNode* aBorderSecondNode = aMesh->FindNode( SecondNodeID1 );
4881   const SMDS_MeshNode* aBorderLastNode   = aMesh->FindNode( LastNodeID1   );
4882   const SMDS_MeshNode* aSide2FirstNode   = aMesh->FindNode( FirstNodeID2  );
4883   const SMDS_MeshNode* aSide2SecondNode  = aMesh->FindNode( SecondNodeID2 );
4884   const SMDS_MeshNode* aSide2ThirdNode   = 0;
4885
4886   if (!aBorderFirstNode ||
4887       !aBorderSecondNode||
4888       !aBorderLastNode )
4889     return SMESH::SMESH_MeshEditor::SEW_BORDER1_NOT_FOUND;
4890   if (!aSide2FirstNode  ||
4891       !aSide2SecondNode)
4892     return SMESH::SMESH_MeshEditor::SEW_BORDER2_NOT_FOUND;
4893
4894   TPythonDump() << "error = " << this << ".SewConformFreeBorders( "
4895                 << FirstNodeID1  << ", "
4896                 << SecondNodeID1 << ", "
4897                 << LastNodeID1   << ", "
4898                 << FirstNodeID2  << ", "
4899                 << SecondNodeID2 << " )";
4900
4901   SMESH::SMESH_MeshEditor::Sew_Error error =
4902     convError( getEditor().SewFreeBorder (aBorderFirstNode,
4903                                           aBorderSecondNode,
4904                                           aBorderLastNode,
4905                                           aSide2FirstNode,
4906                                           aSide2SecondNode,
4907                                           aSide2ThirdNode,
4908                                           true,
4909                                           false, false) );
4910
4911   declareMeshModified( /*isReComputeSafe=*/false );
4912   return error;
4913
4914   SMESH_CATCH( SMESH::throwCorbaException );
4915   return SMESH::SMESH_MeshEditor::Sew_Error(0);
4916 }
4917
4918
4919 //=======================================================================
4920 //function : SewBorderToSide
4921 //purpose  :
4922 //=======================================================================
4923
4924 SMESH::SMESH_MeshEditor::Sew_Error
4925 SMESH_MeshEditor_i::SewBorderToSide(CORBA::Long FirstNodeIDOnFreeBorder,
4926                                     CORBA::Long SecondNodeIDOnFreeBorder,
4927                                     CORBA::Long LastNodeIDOnFreeBorder,
4928                                     CORBA::Long FirstNodeIDOnSide,
4929                                     CORBA::Long LastNodeIDOnSide,
4930                                     CORBA::Boolean CreatePolygons,
4931                                     CORBA::Boolean CreatePolyedrs)
4932   throw (SALOME::SALOME_Exception)
4933 {
4934   SMESH_TRY;
4935   initData();
4936
4937   SMESHDS_Mesh* aMesh = getMeshDS();
4938
4939   const SMDS_MeshNode* aBorderFirstNode  = aMesh->FindNode( FirstNodeIDOnFreeBorder  );
4940   const SMDS_MeshNode* aBorderSecondNode = aMesh->FindNode( SecondNodeIDOnFreeBorder );
4941   const SMDS_MeshNode* aBorderLastNode   = aMesh->FindNode( LastNodeIDOnFreeBorder   );
4942   const SMDS_MeshNode* aSide2FirstNode   = aMesh->FindNode( FirstNodeIDOnSide  );
4943   const SMDS_MeshNode* aSide2SecondNode  = aMesh->FindNode( LastNodeIDOnSide );
4944   const SMDS_MeshNode* aSide2ThirdNode   = 0;
4945
4946   if (!aBorderFirstNode ||
4947       !aBorderSecondNode||
4948       !aBorderLastNode  )
4949     return SMESH::SMESH_MeshEditor::SEW_BORDER1_NOT_FOUND;
4950   if (!aSide2FirstNode  ||
4951       !aSide2SecondNode)
4952     return SMESH::SMESH_MeshEditor::SEW_BAD_SIDE_NODES;
4953
4954   TPythonDump() << "error = " << this << ".SewBorderToSide( "
4955                 << FirstNodeIDOnFreeBorder  << ", "
4956                 << SecondNodeIDOnFreeBorder << ", "
4957                 << LastNodeIDOnFreeBorder   << ", "
4958                 << FirstNodeIDOnSide        << ", "
4959                 << LastNodeIDOnSide         << ", "
4960                 << CreatePolygons           << ", "
4961                 << CreatePolyedrs           << ") ";
4962
4963   SMESH::SMESH_MeshEditor::Sew_Error error =
4964     convError( getEditor().SewFreeBorder (aBorderFirstNode,
4965                                           aBorderSecondNode,
4966                                           aBorderLastNode,
4967                                           aSide2FirstNode,
4968                                           aSide2SecondNode,
4969                                           aSide2ThirdNode,
4970                                           false,
4971                                           CreatePolygons,
4972                                           CreatePolyedrs) );
4973
4974   declareMeshModified( /*isReComputeSafe=*/false );
4975   return error;
4976
4977   SMESH_CATCH( SMESH::throwCorbaException );
4978   return SMESH::SMESH_MeshEditor::Sew_Error(0);
4979 }
4980
4981
4982 //=======================================================================
4983 //function : SewSideElements
4984 //purpose  :
4985 //=======================================================================
4986
4987 SMESH::SMESH_MeshEditor::Sew_Error
4988 SMESH_MeshEditor_i::SewSideElements(const SMESH::long_array& IDsOfSide1Elements,
4989                                     const SMESH::long_array& IDsOfSide2Elements,
4990                                     CORBA::Long NodeID1OfSide1ToMerge,
4991                                     CORBA::Long NodeID1OfSide2ToMerge,
4992                                     CORBA::Long NodeID2OfSide1ToMerge,
4993                                     CORBA::Long NodeID2OfSide2ToMerge)
4994   throw (SALOME::SALOME_Exception)
4995 {
4996   SMESH_TRY;
4997   initData();
4998
4999   SMESHDS_Mesh* aMesh = getMeshDS();
5000
5001   const SMDS_MeshNode* aFirstNode1ToMerge  = aMesh->FindNode( NodeID1OfSide1ToMerge );
5002   const SMDS_MeshNode* aFirstNode2ToMerge  = aMesh->FindNode( NodeID1OfSide2ToMerge );
5003   const SMDS_MeshNode* aSecondNode1ToMerge = aMesh->FindNode( NodeID2OfSide1ToMerge );
5004   const SMDS_MeshNode* aSecondNode2ToMerge = aMesh->FindNode( NodeID2OfSide2ToMerge );
5005
5006   if (!aFirstNode1ToMerge ||
5007       !aFirstNode2ToMerge )
5008     return SMESH::SMESH_MeshEditor::SEW_BAD_SIDE1_NODES;
5009   if (!aSecondNode1ToMerge||
5010       !aSecondNode2ToMerge)
5011     return SMESH::SMESH_MeshEditor::SEW_BAD_SIDE2_NODES;
5012
5013   TIDSortedElemSet aSide1Elems, aSide2Elems;
5014   arrayToSet(IDsOfSide1Elements, aMesh, aSide1Elems);
5015   arrayToSet(IDsOfSide2Elements, aMesh, aSide2Elems);
5016
5017   TPythonDump() << "error = " << this << ".SewSideElements( "
5018                 << IDsOfSide1Elements << ", "
5019                 << IDsOfSide2Elements << ", "
5020                 << NodeID1OfSide1ToMerge << ", "
5021                 << NodeID1OfSide2ToMerge << ", "
5022                 << NodeID2OfSide1ToMerge << ", "
5023                 << NodeID2OfSide2ToMerge << ")";
5024
5025   SMESH::SMESH_MeshEditor::Sew_Error error =
5026     convError( getEditor().SewSideElements (aSide1Elems, aSide2Elems,
5027                                          aFirstNode1ToMerge,
5028                                          aFirstNode2ToMerge,
5029                                          aSecondNode1ToMerge,
5030                                          aSecondNode2ToMerge));
5031
5032   declareMeshModified( /*isReComputeSafe=*/false );
5033   return error;
5034
5035   SMESH_CATCH( SMESH::throwCorbaException );
5036   return SMESH::SMESH_MeshEditor::Sew_Error(0);
5037 }
5038
5039 //================================================================================
5040 /*!
5041  * \brief Set new nodes for given element
5042  * \param ide - element id
5043  * \param newIDs - new node ids
5044  * \retval CORBA::Boolean - true if result is OK
5045  */
5046 //================================================================================
5047
5048 CORBA::Boolean SMESH_MeshEditor_i::ChangeElemNodes(CORBA::Long ide,
5049                                                    const SMESH::long_array& newIDs)
5050   throw (SALOME::SALOME_Exception)
5051 {
5052   SMESH_TRY;
5053   initData();
5054
5055   const SMDS_MeshElement* elem = getMeshDS()->FindElement(ide);
5056   if(!elem) return false;
5057
5058   int nbn = newIDs.length();
5059   int i=0;
5060   vector<const SMDS_MeshNode*> aNodes(nbn);
5061   int nbn1=-1;
5062   for(; i<nbn; i++) {
5063     const SMDS_MeshNode* aNode = getMeshDS()->FindNode(newIDs[i]);
5064     if(aNode) {
5065       nbn1++;
5066       aNodes[nbn1] = aNode;
5067     }
5068   }
5069   TPythonDump() << "isDone = " << this << ".ChangeElemNodes( "
5070                 << ide << ", " << newIDs << " )";
5071
5072   MESSAGE("ChangeElementNodes");
5073   bool res = getMeshDS()->ChangeElementNodes( elem, & aNodes[0], nbn1+1 );
5074
5075   declareMeshModified( /*isReComputeSafe=*/ !res );
5076
5077   return res;
5078
5079   SMESH_CATCH( SMESH::throwCorbaException );
5080   return 0;
5081 }
5082
5083 //=======================================================================
5084 /*!
5085  * \brief Makes a part of the mesh quadratic or bi-quadratic
5086  */
5087 //=======================================================================
5088
5089 void SMESH_MeshEditor_i::convertToQuadratic(CORBA::Boolean            theForce3d,
5090                                             CORBA::Boolean            theToBiQuad,
5091                                             SMESH::SMESH_IDSource_ptr theObject)
5092   throw (SALOME::SALOME_Exception)
5093 {
5094   SMESH_TRY;
5095   initData();
5096
5097   TIDSortedElemSet elems;
5098   bool elemsOK;
5099   if ( !( elemsOK = CORBA::is_nil( theObject )))
5100   {
5101     elemsOK =  idSourceToSet( theObject, getMeshDS(), elems,
5102                               SMDSAbs_All, /*emptyIfIsMesh=*/true );
5103   }
5104   if ( elemsOK )
5105   {
5106     if ( !elems.empty() && (*elems.begin())->GetType() == SMDSAbs_Node )
5107       THROW_SALOME_CORBA_EXCEPTION("Group of nodes is not allowed", SALOME::BAD_PARAM);
5108
5109     if ( elems.empty() ) getEditor().ConvertToQuadratic(theForce3d, theToBiQuad);
5110     else                 getEditor().ConvertToQuadratic(theForce3d, elems, theToBiQuad);
5111
5112     declareMeshModified( /*isReComputeSafe=*/false );
5113   }
5114
5115   SMESH_CATCH( SMESH::throwCorbaException );
5116 }
5117
5118 //=======================================================================
5119 //function : ConvertFromQuadratic
5120 //purpose  :
5121 //=======================================================================
5122
5123 CORBA::Boolean SMESH_MeshEditor_i::ConvertFromQuadratic()
5124   throw (SALOME::SALOME_Exception)
5125 {
5126   SMESH_TRY;
5127   initData();
5128
5129   CORBA::Boolean isDone = getEditor().ConvertFromQuadratic();
5130   TPythonDump() << this << ".ConvertFromQuadratic()";
5131   declareMeshModified( /*isReComputeSafe=*/!isDone );
5132   return isDone;
5133
5134   SMESH_CATCH( SMESH::throwCorbaException );
5135   return false;
5136 }
5137
5138 //=======================================================================
5139 //function : ConvertToQuadratic
5140 //purpose  :
5141 //=======================================================================
5142
5143 void SMESH_MeshEditor_i::ConvertToQuadratic(CORBA::Boolean theForce3d)
5144   throw (SALOME::SALOME_Exception)
5145 {
5146   convertToQuadratic( theForce3d, false );
5147   TPythonDump() << this << ".ConvertToQuadratic("<<theForce3d<<")";
5148 }
5149
5150 //================================================================================
5151 /*!
5152  * \brief Makes a part of the mesh quadratic
5153  */
5154 //================================================================================
5155
5156 void SMESH_MeshEditor_i::ConvertToQuadraticObject(CORBA::Boolean            theForce3d,
5157                                                   SMESH::SMESH_IDSource_ptr theObject)
5158   throw (SALOME::SALOME_Exception)
5159 {
5160   convertToQuadratic( theForce3d, false, theObject );
5161   TPythonDump() << this << ".ConvertToQuadraticObject("<<theForce3d<<", "<<theObject<<")";
5162 }
5163
5164 //================================================================================
5165 /*!
5166  * \brief Makes a part of the mesh bi-quadratic
5167  */
5168 //================================================================================
5169
5170 void SMESH_MeshEditor_i::ConvertToBiQuadratic(CORBA::Boolean            theForce3d,
5171                                               SMESH::SMESH_IDSource_ptr theObject)
5172   throw (SALOME::SALOME_Exception)
5173 {
5174   convertToQuadratic( theForce3d, true, theObject );
5175   TPythonDump() << this << ".ConvertToBiQuadratic("<<theForce3d<<", "<<theObject<<")";
5176 }
5177
5178 //================================================================================
5179 /*!
5180  * \brief Makes a part of the mesh linear
5181  */
5182 //================================================================================
5183
5184 void SMESH_MeshEditor_i::ConvertFromQuadraticObject(SMESH::SMESH_IDSource_ptr theObject)
5185   throw (SALOME::SALOME_Exception)
5186 {
5187   SMESH_TRY;
5188   initData();
5189
5190   TPythonDump pyDump;
5191
5192   TIDSortedElemSet elems;
5193   if ( idSourceToSet( theObject, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true ))
5194   {
5195     if ( elems.empty() )
5196     {
5197       ConvertFromQuadratic();
5198     }
5199     else if ( (*elems.begin())->GetType() == SMDSAbs_Node )
5200     {
5201       THROW_SALOME_CORBA_EXCEPTION("Group of nodes is not allowed", SALOME::BAD_PARAM);
5202     }
5203     else
5204     {
5205       getEditor().ConvertFromQuadratic(elems);
5206     }
5207   }
5208   declareMeshModified( /*isReComputeSafe=*/false );
5209
5210   pyDump << this << ".ConvertFromQuadraticObject( "<<theObject<<" )";
5211
5212   SMESH_CATCH( SMESH::throwCorbaException );
5213 }
5214
5215 //=======================================================================
5216 //function : makeMesh
5217 //purpose  : create a named imported mesh
5218 //=======================================================================
5219
5220 SMESH::SMESH_Mesh_ptr SMESH_MeshEditor_i::makeMesh(const char* theMeshName)
5221 {
5222   SMESH_Gen_i*              gen = SMESH_Gen_i::GetSMESHGen();
5223   SMESH::SMESH_Mesh_var    mesh = gen->CreateEmptyMesh();
5224   SALOMEDS::Study_var     study = gen->GetCurrentStudy();
5225   SALOMEDS::SObject_wrap meshSO = gen->ObjectToSObject( study, mesh );
5226   gen->SetName( meshSO, theMeshName, "Mesh" );
5227   gen->SetPixMap( meshSO, "ICON_SMESH_TREE_MESH_IMPORTED");
5228
5229   return mesh._retn();
5230 }
5231
5232 //=======================================================================
5233 //function : dumpGroupsList
5234 //purpose  :
5235 //=======================================================================
5236
5237 void SMESH_MeshEditor_i::dumpGroupsList(TPythonDump &               theDumpPython,
5238                                         const SMESH::ListOfGroups * theGroupList)
5239 {
5240   bool isDumpGroupList = ( theGroupList && theGroupList->length() > 0 );
5241   if ( isDumpGroupList )
5242     theDumpPython << theGroupList << " = ";
5243 }
5244
5245 //================================================================================
5246 /*!
5247   \brief Generates the unique group name.
5248   \param thePrefix name prefix
5249   \return unique name
5250 */
5251 //================================================================================
5252
5253 string SMESH_MeshEditor_i::generateGroupName(const string& thePrefix)
5254 {
5255   SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
5256   set<string> groupNames;
5257
5258   // Get existing group names
5259   for (int i = 0, nbGroups = groups->length(); i < nbGroups; i++ ) {
5260     SMESH::SMESH_GroupBase_var aGroup = groups[i];
5261     if (CORBA::is_nil(aGroup))
5262       continue;
5263
5264     CORBA::String_var name = aGroup->GetName();
5265     groupNames.insert( name.in() );
5266   }
5267
5268   // Find new name
5269   string name = thePrefix;
5270   int index = 0;
5271
5272   while (!groupNames.insert(name).second)
5273     name = SMESH_Comment( thePrefix ) << "_" << index++;
5274
5275   return name;
5276 }
5277
5278 //================================================================================
5279 /*!
5280  * \brief Prepare SMESH_IDSource for work
5281  */
5282 //================================================================================
5283
5284 void SMESH_MeshEditor_i::prepareIdSource(SMESH::SMESH_IDSource_ptr theObject)
5285 {
5286   if ( SMESH::Filter_i* filter = SMESH::DownCast<SMESH::Filter_i*>( theObject ))
5287   {
5288     SMESH::SMESH_Mesh_var mesh = myMesh_i->_this();
5289     filter->SetMesh( mesh );
5290   }
5291 }
5292 //================================================================================
5293 /*!
5294  * \brief Retrieve elements of given type from SMESH_IDSource
5295  */
5296 //================================================================================
5297
5298 bool SMESH_MeshEditor_i::idSourceToSet(SMESH::SMESH_IDSource_ptr  theIDSource,
5299                                        const SMESHDS_Mesh*        theMeshDS,
5300                                        TIDSortedElemSet&          theElemSet,
5301                                        const SMDSAbs_ElementType  theType,
5302                                        const bool                 emptyIfIsMesh,
5303                                        IDSource_Error*            error)
5304
5305 {
5306   if ( error ) *error = IDSource_OK;
5307
5308   if ( CORBA::is_nil( theIDSource ) )
5309   {
5310     if ( error ) *error = IDSource_INVALID;
5311     return false;
5312   }
5313   if ( emptyIfIsMesh && SMESH::DownCast<SMESH_Mesh_i*>( theIDSource ))
5314   {
5315     if ( error && getMeshDS()->GetMeshInfo().NbElements( theType ) == 0 )
5316       *error = IDSource_EMPTY;
5317     return true;
5318   }
5319   prepareIdSource( theIDSource );
5320   SMESH::long_array_var anIDs = theIDSource->GetIDs();
5321   if ( anIDs->length() == 0 )
5322   {
5323     if ( error ) *error = IDSource_EMPTY;
5324     return false;
5325   }
5326   SMESH::array_of_ElementType_var types = theIDSource->GetTypes();
5327   if ( types->length() == 1 && types[0] == SMESH::NODE ) // group of nodes
5328   {
5329     if ( theType == SMDSAbs_All || theType == SMDSAbs_Node )
5330     {
5331       arrayToSet( anIDs, getMeshDS(), theElemSet, SMDSAbs_Node );
5332     }
5333     else
5334     {
5335       if ( error ) *error = IDSource_INVALID;
5336       return false;
5337     }
5338   }
5339   else
5340   {
5341     arrayToSet( anIDs, getMeshDS(), theElemSet, theType);
5342     if ( bool(anIDs->length()) != bool(theElemSet.size()))
5343     {
5344       if ( error ) *error = IDSource_INVALID;
5345       return false;
5346     }
5347   }
5348   return true;
5349 }
5350
5351 //================================================================================
5352 /*!
5353  * \brief Duplicates given elements, i.e. creates new elements based on the
5354  *        same nodes as the given ones.
5355  * \param theElements - container of elements to duplicate.
5356  * \param theGroupName - a name of group to contain the generated elements.
5357  *                    If a group with such a name already exists, the new elements
5358  *                    are added to the existng group, else a new group is created.
5359  *                    If \a theGroupName is empty, new elements are not added 
5360  *                    in any group.
5361  * \return a group where the new elements are added. NULL if theGroupName == "".
5362  * \sa DoubleNode()
5363  */
5364 //================================================================================
5365
5366 SMESH::SMESH_Group_ptr
5367 SMESH_MeshEditor_i::DoubleElements(SMESH::SMESH_IDSource_ptr theElements,
5368                                    const char*               theGroupName)
5369   throw (SALOME::SALOME_Exception)
5370 {
5371   SMESH::SMESH_Group_var newGroup;
5372
5373   SMESH_TRY;
5374   initData();
5375
5376   TPythonDump pyDump;
5377
5378   TIDSortedElemSet elems;
5379   if ( idSourceToSet( theElements, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true))
5380   {
5381     getEditor().DoubleElements( elems );
5382
5383     if ( strlen( theGroupName ) && !getEditor().GetLastCreatedElems().IsEmpty() )
5384     {
5385       // group type
5386       SMESH::ElementType type =
5387         SMESH::ElementType( getEditor().GetLastCreatedElems().Value(1)->GetType() );
5388       // find existing group
5389       SMESH::ListOfGroups_var groups = myMesh_i->GetGroups();
5390       for ( size_t i = 0; i < groups->length(); ++i )
5391         if ( groups[i]->GetType() == type )
5392         {
5393           CORBA::String_var name = groups[i]->GetName();
5394           if ( strcmp( name, theGroupName ) == 0 ) {
5395             newGroup = SMESH::SMESH_Group::_narrow( groups[i] );
5396             break;
5397           }
5398         }
5399       // create a new group
5400       if ( newGroup->_is_nil() )
5401         newGroup = myMesh_i->CreateGroup( type, theGroupName );
5402       // fill newGroup
5403       if ( SMESH_Group_i* group_i = SMESH::DownCast< SMESH_Group_i* >( newGroup ))
5404       {
5405         SMESHDS_Group* groupDS = static_cast< SMESHDS_Group* >( group_i->GetGroupDS() );
5406         const SMESH_SequenceOfElemPtr& aSeq = getEditor().GetLastCreatedElems();
5407         for ( int i = 1; i <= aSeq.Length(); i++ )
5408           groupDS->SMDSGroup().Add( aSeq(i) );
5409       }
5410     }
5411   }
5412   // python dump
5413   if ( !newGroup->_is_nil() )
5414     pyDump << newGroup << " = ";
5415   pyDump << this << ".DoubleElements( "
5416          << theElements << ", " << "'" << theGroupName <<"')";
5417
5418   SMESH_CATCH( SMESH::throwCorbaException );
5419
5420   return newGroup._retn();
5421 }
5422
5423 //================================================================================
5424 /*!
5425   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5426   \param theNodes - identifiers of nodes to be doubled
5427   \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
5428          nodes. If list of element identifiers is empty then nodes are doubled but
5429          they not assigned to elements
5430   \return TRUE if operation has been completed successfully, FALSE otherwise
5431   \sa DoubleNode(), DoubleNodeGroup(), DoubleNodeGroups()
5432 */
5433 //================================================================================
5434
5435 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodes( const SMESH::long_array& theNodes,
5436                                                 const SMESH::long_array& theModifiedElems )
5437   throw (SALOME::SALOME_Exception)
5438 {
5439   SMESH_TRY;
5440   initData();
5441
5442   list< int > aListOfNodes;
5443   int i, n;
5444   for ( i = 0, n = theNodes.length(); i < n; i++ )
5445     aListOfNodes.push_back( theNodes[ i ] );
5446
5447   list< int > aListOfElems;
5448   for ( i = 0, n = theModifiedElems.length(); i < n; i++ )
5449     aListOfElems.push_back( theModifiedElems[ i ] );
5450
5451   bool aResult = getEditor().DoubleNodes( aListOfNodes, aListOfElems );
5452
5453   declareMeshModified( /*isReComputeSafe=*/ !aResult );
5454
5455   // Update Python script
5456   TPythonDump() << this << ".DoubleNodes( " << theNodes << ", "<< theModifiedElems << " )";
5457
5458   return aResult;
5459
5460   SMESH_CATCH( SMESH::throwCorbaException );
5461   return 0;
5462 }
5463
5464 //================================================================================
5465 /*!
5466   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5467   This method provided for convenience works as DoubleNodes() described above.
5468   \param theNodeId - identifier of node to be doubled.
5469   \param theModifiedElems - identifiers of elements to be updated.
5470   \return TRUE if operation has been completed successfully, FALSE otherwise
5471   \sa DoubleNodes(), DoubleNodeGroup(), DoubleNodeGroups()
5472 */
5473 //================================================================================
5474
5475 CORBA::Boolean SMESH_MeshEditor_i::DoubleNode( CORBA::Long              theNodeId,
5476                                                const SMESH::long_array& theModifiedElems )
5477   throw (SALOME::SALOME_Exception)
5478 {
5479   SMESH_TRY;
5480   SMESH::long_array_var aNodes = new SMESH::long_array;
5481   aNodes->length( 1 );
5482   aNodes[ 0 ] = theNodeId;
5483
5484   TPythonDump pyDump; // suppress dump by the next line
5485
5486   CORBA::Boolean done = DoubleNodes( aNodes, theModifiedElems );
5487
5488   pyDump << this << ".DoubleNode( " << theNodeId << ", " << theModifiedElems << " )";
5489
5490   return done;
5491
5492   SMESH_CATCH( SMESH::throwCorbaException );
5493   return 0;
5494 }
5495
5496 //================================================================================
5497 /*!
5498   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5499   This method provided for convenience works as DoubleNodes() described above.
5500   \param theNodes - group of nodes to be doubled.
5501   \param theModifiedElems - group of elements to be updated.
5502   \return TRUE if operation has been completed successfully, FALSE otherwise
5503   \sa DoubleNode(), DoubleNodes(), DoubleNodeGroups()
5504 */
5505 //================================================================================
5506
5507 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroup(SMESH::SMESH_GroupBase_ptr theNodes,
5508                                                    SMESH::SMESH_GroupBase_ptr theModifiedElems )
5509   throw (SALOME::SALOME_Exception)
5510 {
5511   SMESH_TRY;
5512   if ( CORBA::is_nil( theNodes ) && theNodes->GetType() != SMESH::NODE )
5513     return false;
5514
5515   SMESH::long_array_var aNodes = theNodes->GetListOfID();
5516   SMESH::long_array_var aModifiedElems;
5517   if ( !CORBA::is_nil( theModifiedElems ) )
5518     aModifiedElems = theModifiedElems->GetListOfID();
5519   else
5520   {
5521     aModifiedElems = new SMESH::long_array;
5522     aModifiedElems->length( 0 );
5523   }
5524
5525   TPythonDump pyDump; // suppress dump by the next line
5526
5527   bool done = DoubleNodes( aNodes, aModifiedElems );
5528
5529   pyDump << this << ".DoubleNodeGroup( " << theNodes << ", " << theModifiedElems << " )";
5530
5531   return done;
5532
5533   SMESH_CATCH( SMESH::throwCorbaException );
5534   return 0;
5535 }
5536
5537 //================================================================================
5538 /*!
5539  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
5540  * Works as DoubleNodeGroup(), but returns a new group with newly created nodes.
5541  * \param theNodes - group of nodes to be doubled.
5542  * \param theModifiedElems - group of elements to be updated.
5543  * \return a new group with newly created nodes
5544  * \sa DoubleNodeGroup()
5545  */
5546 //================================================================================
5547
5548 SMESH::SMESH_Group_ptr
5549 SMESH_MeshEditor_i::DoubleNodeGroupNew( SMESH::SMESH_GroupBase_ptr theNodes,
5550                                         SMESH::SMESH_GroupBase_ptr theModifiedElems )
5551   throw (SALOME::SALOME_Exception)
5552 {
5553   SMESH_TRY;
5554   SMESH::SMESH_Group_var aNewGroup;
5555
5556   if ( CORBA::is_nil( theNodes ) && theNodes->GetType() != SMESH::NODE )
5557     return aNewGroup._retn();
5558
5559   // Duplicate nodes
5560   SMESH::long_array_var aNodes = theNodes->GetListOfID();
5561   SMESH::long_array_var aModifiedElems;
5562   if ( !CORBA::is_nil( theModifiedElems ) )
5563     aModifiedElems = theModifiedElems->GetListOfID();
5564   else {
5565     aModifiedElems = new SMESH::long_array;
5566     aModifiedElems->length( 0 );
5567   }
5568
5569   TPythonDump pyDump; // suppress dump by the next line
5570
5571   bool aResult = DoubleNodes( aNodes, aModifiedElems );
5572   if ( aResult )
5573   {
5574     // Create group with newly created nodes
5575     SMESH::long_array_var anIds = GetLastCreatedNodes();
5576     if (anIds->length() > 0) {
5577       string anUnindexedName (theNodes->GetName());
5578       string aNewName = generateGroupName(anUnindexedName + "_double");
5579       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
5580       aNewGroup->Add(anIds);
5581       pyDump << aNewGroup << " = ";
5582     }
5583   }
5584
5585   pyDump << this << ".DoubleNodeGroupNew( " << theNodes << ", "
5586          << theModifiedElems << " )";
5587
5588   return aNewGroup._retn();
5589
5590   SMESH_CATCH( SMESH::throwCorbaException );
5591   return 0;
5592 }
5593
5594 //================================================================================
5595 /*!
5596   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5597   This method provided for convenience works as DoubleNodes() described above.
5598   \param theNodes - list of groups of nodes to be doubled
5599   \param theModifiedElems - list of groups of elements to be updated.
5600   \return TRUE if operation has been completed successfully, FALSE otherwise
5601   \sa DoubleNode(), DoubleNodeGroup(), DoubleNodes()
5602 */
5603 //================================================================================
5604
5605 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroups(const SMESH::ListOfGroups& theNodes,
5606                                                     const SMESH::ListOfGroups& theModifiedElems )
5607   throw (SALOME::SALOME_Exception)
5608 {
5609   SMESH_TRY;
5610   initData();
5611
5612   std::list< int > aNodes;
5613   int i, n, j, m;
5614   for ( i = 0, n = theNodes.length(); i < n; i++ )
5615   {
5616     SMESH::SMESH_GroupBase_var aGrp = theNodes[ i ];
5617     if ( !CORBA::is_nil( aGrp ) && aGrp->GetType() == SMESH::NODE )
5618     {
5619       SMESH::long_array_var aCurr = aGrp->GetListOfID();
5620       for ( j = 0, m = aCurr->length(); j < m; j++ )
5621         aNodes.push_back( aCurr[ j ] );
5622     }
5623   }
5624
5625   std::list< int > anElems;
5626   for ( i = 0, n = theModifiedElems.length(); i < n; i++ )
5627   {
5628     SMESH::SMESH_GroupBase_var aGrp = theModifiedElems[ i ];
5629     if ( !CORBA::is_nil( aGrp ) && aGrp->GetType() != SMESH::NODE )
5630     {
5631       SMESH::long_array_var aCurr = aGrp->GetListOfID();
5632       for ( j = 0, m = aCurr->length(); j < m; j++ )
5633         anElems.push_back( aCurr[ j ] );
5634     }
5635   }
5636
5637   bool aResult = getEditor().DoubleNodes( aNodes, anElems );
5638
5639   declareMeshModified( /*isReComputeSafe=*/false );
5640
5641   TPythonDump() << this << ".DoubleNodeGroups( " << theNodes << ", " << theModifiedElems << " )";
5642
5643   return aResult;
5644
5645   SMESH_CATCH( SMESH::throwCorbaException );
5646   return 0;
5647 }
5648
5649 //================================================================================
5650 /*!
5651  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
5652  * Works as DoubleNodeGroups(), but returns a new group with newly created nodes.
5653  * \param theNodes - group of nodes to be doubled.
5654  * \param theModifiedElems - group of elements to be updated.
5655  * \return a new group with newly created nodes
5656  * \sa DoubleNodeGroups()
5657  */
5658 //================================================================================
5659
5660 SMESH::SMESH_Group_ptr
5661 SMESH_MeshEditor_i::DoubleNodeGroupsNew( const SMESH::ListOfGroups& theNodes,
5662                                          const SMESH::ListOfGroups& theModifiedElems )
5663   throw (SALOME::SALOME_Exception)
5664 {
5665   SMESH::SMESH_Group_var aNewGroup;
5666
5667   TPythonDump pyDump; // suppress dump by the next line
5668
5669   bool aResult = DoubleNodeGroups( theNodes, theModifiedElems );
5670
5671   if ( aResult )
5672   {
5673     // Create group with newly created nodes
5674     SMESH::long_array_var anIds = GetLastCreatedNodes();
5675     if (anIds->length() > 0) {
5676       string anUnindexedName (theNodes[0]->GetName());
5677       string aNewName = generateGroupName(anUnindexedName + "_double");
5678       aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
5679       aNewGroup->Add(anIds);
5680       pyDump << aNewGroup << " = ";
5681     }
5682   }
5683
5684   pyDump << this << ".DoubleNodeGroupsNew( " << theNodes << ", "
5685          << theModifiedElems << " )";
5686
5687   return aNewGroup._retn();
5688 }
5689
5690
5691 //================================================================================
5692 /*!
5693   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5694   \param theElems - the list of elements (edges or faces) to be replicated
5695   The nodes for duplication could be found from these elements
5696   \param theNodesNot - list of nodes to NOT replicate
5697   \param theAffectedElems - the list of elements (cells and edges) to which the
5698   replicated nodes should be associated to.
5699   \return TRUE if operation has been completed successfully, FALSE otherwise
5700   \sa DoubleNodeGroup(), DoubleNodeGroups()
5701 */
5702 //================================================================================
5703
5704 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElem( const SMESH::long_array& theElems,
5705                                                    const SMESH::long_array& theNodesNot,
5706                                                    const SMESH::long_array& theAffectedElems )
5707   throw (SALOME::SALOME_Exception)
5708 {
5709   SMESH_TRY;
5710   initData();
5711
5712   SMESHDS_Mesh* aMeshDS = getMeshDS();
5713   TIDSortedElemSet anElems, aNodes, anAffected;
5714   arrayToSet(theElems, aMeshDS, anElems, SMDSAbs_All);
5715   arrayToSet(theNodesNot, aMeshDS, aNodes, SMDSAbs_Node);
5716   arrayToSet(theAffectedElems, aMeshDS, anAffected, SMDSAbs_All);
5717
5718   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5719
5720   // Update Python script
5721   TPythonDump() << this << ".DoubleNodeElem( " << theElems << ", "
5722                 << theNodesNot << ", " << theAffectedElems << " )";
5723
5724   declareMeshModified( /*isReComputeSafe=*/false );
5725   return aResult;
5726
5727   SMESH_CATCH( SMESH::throwCorbaException );
5728   return 0;
5729 }
5730
5731 //================================================================================
5732 /*!
5733   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5734   \param theElems - the list of elements (edges or faces) to be replicated
5735   The nodes for duplication could be found from these elements
5736   \param theNodesNot - list of nodes to NOT replicate
5737   \param theShape - shape to detect affected elements (element which geometric center
5738   located on or inside shape).
5739   The replicated nodes should be associated to affected elements.
5740   \return TRUE if operation has been completed successfully, FALSE otherwise
5741   \sa DoubleNodeGroupInRegion(), DoubleNodeGroupsInRegion()
5742 */
5743 //================================================================================
5744
5745 CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemInRegion ( const SMESH::long_array& theElems,
5746                                                             const SMESH::long_array& theNodesNot,
5747                                                             GEOM::GEOM_Object_ptr    theShape )
5748   throw (SALOME::SALOME_Exception)
5749 {
5750   SMESH_TRY;
5751   initData();
5752
5753
5754   SMESHDS_Mesh* aMeshDS = getMeshDS();
5755   TIDSortedElemSet anElems, aNodes;
5756   arrayToSet(theElems, aMeshDS, anElems, SMDSAbs_All);
5757   arrayToSet(theNodesNot, aMeshDS, aNodes, SMDSAbs_Node);
5758
5759   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
5760   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
5761
5762   // Update Python script
5763   TPythonDump() << "isDone = " << this << ".DoubleNodeElemInRegion( " << theElems << ", "
5764                 << theNodesNot << ", " << theShape << " )";
5765
5766   declareMeshModified( /*isReComputeSafe=*/false );
5767   return aResult;
5768
5769   SMESH_CATCH( SMESH::throwCorbaException );
5770   return 0;
5771 }
5772
5773 //================================================================================
5774 /*!
5775   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5776   \param theElems - group of of elements (edges or faces) to be replicated
5777   \param theNodesNot - group of nodes not to replicated
5778   \param theAffectedElems - group of elements to which the replicated nodes
5779   should be associated to.
5780   \return TRUE if operation has been completed successfully, FALSE otherwise
5781   \sa DoubleNodes(), DoubleNodeGroups()
5782 */
5783 //================================================================================
5784
5785 CORBA::Boolean
5786 SMESH_MeshEditor_i::DoubleNodeElemGroup(SMESH::SMESH_GroupBase_ptr theElems,
5787                                         SMESH::SMESH_GroupBase_ptr theNodesNot,
5788                                         SMESH::SMESH_GroupBase_ptr theAffectedElems)
5789   throw (SALOME::SALOME_Exception)
5790 {
5791   SMESH_TRY;
5792   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
5793     return false;
5794
5795   initData();
5796
5797
5798   SMESHDS_Mesh* aMeshDS = getMeshDS();
5799   TIDSortedElemSet anElems, aNodes, anAffected;
5800   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
5801   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
5802   idSourceToSet( theAffectedElems, aMeshDS, anAffected, SMDSAbs_All );
5803
5804   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5805
5806   // Update Python script
5807   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroup( " << theElems << ", "
5808                 << theNodesNot << ", " << theAffectedElems << " )";
5809
5810   declareMeshModified( /*isReComputeSafe=*/false );
5811   return aResult;
5812
5813   SMESH_CATCH( SMESH::throwCorbaException );
5814   return 0;
5815 }
5816
5817 //================================================================================
5818 /*!
5819  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5820  * Works as DoubleNodeElemGroup(), but returns a new group with newly created elements.
5821  * \param theElems - group of of elements (edges or faces) to be replicated
5822  * \param theNodesNot - group of nodes not to replicated
5823  * \param theAffectedElems - group of elements to which the replicated nodes
5824  *        should be associated to.
5825  * \return a new group with newly created elements
5826  * \sa DoubleNodeElemGroup()
5827  */
5828 //================================================================================
5829
5830 SMESH::SMESH_Group_ptr
5831 SMESH_MeshEditor_i::DoubleNodeElemGroupNew(SMESH::SMESH_GroupBase_ptr theElems,
5832                                            SMESH::SMESH_GroupBase_ptr theNodesNot,
5833                                            SMESH::SMESH_GroupBase_ptr theAffectedElems)
5834   throw (SALOME::SALOME_Exception)
5835 {
5836   TPythonDump pyDump;
5837   SMESH::ListOfGroups_var twoGroups = DoubleNodeElemGroup2New( theElems,
5838                                                                theNodesNot,
5839                                                                theAffectedElems,
5840                                                                true, false );
5841   SMESH::SMESH_GroupBase_var baseGroup = twoGroups[0].in();
5842   SMESH::SMESH_Group_var     elemGroup = SMESH::SMESH_Group::_narrow( baseGroup );
5843
5844   pyDump << elemGroup << " = " << this << ".DoubleNodeElemGroupNew( "
5845          << theElems         << ", "
5846          << theNodesNot      << ", "
5847          << theAffectedElems << " )";
5848
5849   return elemGroup._retn();
5850 }
5851
5852 //================================================================================
5853 /*!
5854  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5855  * Works as DoubleNodeElemGroup(), but returns a new group with newly created elements.
5856  * \param theElems - group of of elements (edges or faces) to be replicated
5857  * \param theNodesNot - group of nodes not to replicated
5858  * \param theAffectedElems - group of elements to which the replicated nodes
5859  *        should be associated to.
5860  * \return a new group with newly created elements
5861  * \sa DoubleNodeElemGroup()
5862  */
5863 //================================================================================
5864
5865 SMESH::ListOfGroups*
5866 SMESH_MeshEditor_i::DoubleNodeElemGroup2New(SMESH::SMESH_GroupBase_ptr theElems,
5867                                             SMESH::SMESH_GroupBase_ptr theNodesNot,
5868                                             SMESH::SMESH_GroupBase_ptr theAffectedElems,
5869                                             CORBA::Boolean             theElemGroupNeeded,
5870                                             CORBA::Boolean             theNodeGroupNeeded)
5871   throw (SALOME::SALOME_Exception)
5872 {
5873   SMESH_TRY;
5874   SMESH::SMESH_Group_var aNewElemGroup, aNewNodeGroup;
5875   SMESH::ListOfGroups_var aTwoGroups = new SMESH::ListOfGroups();
5876   aTwoGroups->length( 2 );
5877
5878   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
5879     return aTwoGroups._retn();
5880
5881   initData();
5882
5883
5884   SMESHDS_Mesh* aMeshDS = getMeshDS();
5885   TIDSortedElemSet anElems, aNodes, anAffected;
5886   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
5887   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
5888   idSourceToSet( theAffectedElems, aMeshDS, anAffected, SMDSAbs_All );
5889
5890
5891   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
5892
5893   declareMeshModified( /*isReComputeSafe=*/ !aResult );
5894
5895   TPythonDump pyDump;
5896
5897   if ( aResult )
5898   {
5899     // Create group with newly created elements
5900     CORBA::String_var elemGroupName = theElems->GetName();
5901     string aNewName = generateGroupName( string(elemGroupName.in()) + "_double");
5902     if ( !getEditor().GetLastCreatedElems().IsEmpty() && theElemGroupNeeded )
5903     {
5904       SMESH::long_array_var anIds = GetLastCreatedElems();
5905       SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true);
5906       aNewElemGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str());
5907       aNewElemGroup->Add(anIds);
5908     }
5909     if ( !getEditor().GetLastCreatedNodes().IsEmpty() && theNodeGroupNeeded )
5910     {
5911       SMESH::long_array_var anIds = GetLastCreatedNodes();
5912       aNewNodeGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
5913       aNewNodeGroup->Add(anIds);
5914     }
5915   }
5916
5917   // Update Python script
5918
5919   pyDump << "[ ";
5920   if ( aNewElemGroup->_is_nil() ) pyDump << "nothing, ";
5921   else                            pyDump << aNewElemGroup << ", ";
5922   if ( aNewNodeGroup->_is_nil() ) pyDump << "nothing ] = ";
5923   else                            pyDump << aNewNodeGroup << " ] = ";
5924
5925   pyDump << this << ".DoubleNodeElemGroup2New( " << theElems << ", "
5926          << theNodesNot        << ", "
5927          << theAffectedElems   << ", "
5928          << theElemGroupNeeded << ", "
5929          << theNodeGroupNeeded <<" )";
5930
5931   aTwoGroups[0] = aNewElemGroup._retn();
5932   aTwoGroups[1] = aNewNodeGroup._retn();
5933   return aTwoGroups._retn();
5934
5935   SMESH_CATCH( SMESH::throwCorbaException );
5936   return 0;
5937 }
5938
5939 //================================================================================
5940 /*!
5941   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
5942   \param theElems - group of of elements (edges or faces) to be replicated
5943   \param theNodesNot - group of nodes not to replicated
5944   \param theShape - shape to detect affected elements (element which geometric center
5945   located on or inside shape).
5946   The replicated nodes should be associated to affected elements.
5947   \return TRUE if operation has been completed successfully, FALSE otherwise
5948   \sa DoubleNodesInRegion(), DoubleNodeGroupsInRegion()
5949 */
5950 //================================================================================
5951
5952 CORBA::Boolean
5953 SMESH_MeshEditor_i::DoubleNodeElemGroupInRegion(SMESH::SMESH_GroupBase_ptr theElems,
5954                                                 SMESH::SMESH_GroupBase_ptr theNodesNot,
5955                                                 GEOM::GEOM_Object_ptr      theShape )
5956   throw (SALOME::SALOME_Exception)
5957 {
5958   SMESH_TRY;
5959   if ( CORBA::is_nil( theElems ) && theElems->GetType() == SMESH::NODE )
5960     return false;
5961
5962   initData();
5963
5964
5965   SMESHDS_Mesh* aMeshDS = getMeshDS();
5966   TIDSortedElemSet anElems, aNodes, anAffected;
5967   idSourceToSet( theElems, aMeshDS, anElems, SMDSAbs_All );
5968   idSourceToSet( theNodesNot, aMeshDS, aNodes, SMDSAbs_Node );
5969
5970   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
5971   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
5972
5973
5974   declareMeshModified( /*isReComputeSafe=*/ !aResult );
5975
5976   // Update Python script
5977   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroupInRegion( " << theElems << ", "
5978                 << theNodesNot << ", " << theShape << " )";
5979   return aResult;
5980
5981   SMESH_CATCH( SMESH::throwCorbaException );
5982   return 0;
5983 }
5984
5985 //================================================================================
5986 /*!
5987  * \brief Re-load elements from a list of groups into a TIDSortedElemSet
5988  *  \param [in] theGrpList - groups
5989  *  \param [in] theMeshDS -  mesh
5990  *  \param [out] theElemSet - set of elements
5991  *  \param [in] theIsNodeGrp - is \a theGrpList includes goups of nodes
5992  */
5993 //================================================================================
5994
5995 static void listOfGroupToSet(const SMESH::ListOfGroups& theGrpList,
5996                              SMESHDS_Mesh*              theMeshDS,
5997                              TIDSortedElemSet&          theElemSet,
5998                              const bool                 theIsNodeGrp)
5999 {
6000   for ( int i = 0, n = theGrpList.length(); i < n; i++ )
6001   {
6002     SMESH::SMESH_GroupBase_var aGrp = theGrpList[ i ];
6003     if ( !CORBA::is_nil( aGrp ) && (theIsNodeGrp ? aGrp->GetType() == SMESH::NODE
6004                                     : aGrp->GetType() != SMESH::NODE ) )
6005     {
6006       SMESH::long_array_var anIDs = aGrp->GetIDs();
6007       arrayToSet( anIDs, theMeshDS, theElemSet, theIsNodeGrp ? SMDSAbs_Node : SMDSAbs_All );
6008     }
6009   }
6010 }
6011
6012 //================================================================================
6013 /*!
6014   \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
6015   This method provided for convenience works as DoubleNodes() described above.
6016   \param theElems - list of groups of elements (edges or faces) to be replicated
6017   \param theNodesNot - list of groups of nodes not to replicated
6018   \param theAffectedElems - group of elements to which the replicated nodes
6019   should be associated to.
6020   \return TRUE if operation has been completed successfully, FALSE otherwise
6021   \sa DoubleNodeGroup(), DoubleNodes(), DoubleNodeElemGroupsNew()
6022 */
6023 //================================================================================
6024
6025 CORBA::Boolean
6026 SMESH_MeshEditor_i::DoubleNodeElemGroups(const SMESH::ListOfGroups& theElems,
6027                                          const SMESH::ListOfGroups& theNodesNot,
6028                                          const SMESH::ListOfGroups& theAffectedElems)
6029   throw (SALOME::SALOME_Exception)
6030 {
6031   SMESH_TRY;
6032   initData();
6033
6034
6035   SMESHDS_Mesh* aMeshDS = getMeshDS();
6036   TIDSortedElemSet anElems, aNodes, anAffected;
6037   listOfGroupToSet(theElems, aMeshDS, anElems, false );
6038   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
6039   listOfGroupToSet(theAffectedElems, aMeshDS, anAffected, false );
6040
6041   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
6042
6043   // Update Python script
6044   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroups( " << &theElems << ", "
6045                 << &theNodesNot << ", " << &theAffectedElems << " )";
6046
6047   declareMeshModified( /*isReComputeSafe=*/false );
6048   return aResult;
6049
6050   SMESH_CATCH( SMESH::throwCorbaException );
6051   return 0;
6052 }
6053
6054 //================================================================================
6055 /*!
6056  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6057  * Works as DoubleNodeElemGroups(), but returns a new group with newly created elements.
6058   \param theElems - list of groups of elements (edges or faces) to be replicated
6059   \param theNodesNot - list of groups of nodes not to replicated
6060   \param theAffectedElems - group of elements to which the replicated nodes
6061   should be associated to.
6062  * \return a new group with newly created elements
6063  * \sa DoubleNodeElemGroups()
6064  */
6065 //================================================================================
6066
6067 SMESH::SMESH_Group_ptr
6068 SMESH_MeshEditor_i::DoubleNodeElemGroupsNew(const SMESH::ListOfGroups& theElems,
6069                                             const SMESH::ListOfGroups& theNodesNot,
6070                                             const SMESH::ListOfGroups& theAffectedElems)
6071   throw (SALOME::SALOME_Exception)
6072 {
6073   TPythonDump pyDump;
6074   SMESH::ListOfGroups_var twoGroups = DoubleNodeElemGroups2New( theElems,
6075                                                                 theNodesNot,
6076                                                                 theAffectedElems,
6077                                                                 true, false );
6078   SMESH::SMESH_GroupBase_var baseGroup = twoGroups[0].in();
6079   SMESH::SMESH_Group_var     elemGroup = SMESH::SMESH_Group::_narrow( baseGroup );
6080
6081   pyDump << elemGroup << " = " << this << ".DoubleNodeElemGroupsNew( "
6082          << theElems         << ", "
6083          << theNodesNot      << ", "
6084          << theAffectedElems << " )";
6085
6086   return elemGroup._retn();
6087 }
6088
6089 //================================================================================
6090 /*!
6091  * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6092  * Works as DoubleNodeElemGroups(), but returns a new group with newly created elements.
6093   \param theElems - list of groups of elements (edges or faces) to be replicated
6094   \param theNodesNot - list of groups of nodes not to replicated
6095   \param theAffectedElems - group of elements to which the replicated nodes
6096   should be associated to.
6097  * \return a new group with newly created elements
6098  * \sa DoubleNodeElemGroups()
6099  */
6100 //================================================================================
6101
6102 SMESH::ListOfGroups*
6103 SMESH_MeshEditor_i::DoubleNodeElemGroups2New(const SMESH::ListOfGroups& theElems,
6104                                              const SMESH::ListOfGroups& theNodesNot,
6105                                              const SMESH::ListOfGroups& theAffectedElems,
6106                                              CORBA::Boolean             theElemGroupNeeded,
6107                                              CORBA::Boolean             theNodeGroupNeeded)
6108   throw (SALOME::SALOME_Exception)
6109 {
6110   SMESH_TRY;
6111   SMESH::SMESH_Group_var aNewElemGroup, aNewNodeGroup;
6112   SMESH::ListOfGroups_var aTwoGroups = new SMESH::ListOfGroups();
6113   aTwoGroups->length( 2 );
6114   
6115   initData();
6116
6117
6118   SMESHDS_Mesh* aMeshDS = getMeshDS();
6119   TIDSortedElemSet anElems, aNodes, anAffected;
6120   listOfGroupToSet(theElems, aMeshDS, anElems, false );
6121   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
6122   listOfGroupToSet(theAffectedElems, aMeshDS, anAffected, false );
6123
6124   bool aResult = getEditor().DoubleNodes( anElems, aNodes, anAffected );
6125
6126   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6127
6128   TPythonDump pyDump;
6129   if ( aResult )
6130   {
6131     // Create group with newly created elements
6132     CORBA::String_var elemGroupName = theElems[0]->GetName();
6133     string aNewName = generateGroupName( string(elemGroupName.in()) + "_double");
6134     if ( !getEditor().GetLastCreatedElems().IsEmpty() && theElemGroupNeeded )
6135     {
6136       SMESH::long_array_var anIds = GetLastCreatedElems();
6137       SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true);
6138       aNewElemGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str());
6139       aNewElemGroup->Add(anIds);
6140     }
6141     if ( !getEditor().GetLastCreatedNodes().IsEmpty() && theNodeGroupNeeded )
6142     {
6143       SMESH::long_array_var anIds = GetLastCreatedNodes();
6144       aNewNodeGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
6145       aNewNodeGroup->Add(anIds);
6146     }
6147   }
6148
6149   // Update Python script
6150
6151   pyDump << "[ ";
6152   if ( aNewElemGroup->_is_nil() ) pyDump << "nothing, ";
6153   else                            pyDump << aNewElemGroup << ", ";
6154   if ( aNewNodeGroup->_is_nil() ) pyDump << "nothing ] = ";
6155   else                            pyDump << aNewNodeGroup << " ] = ";
6156
6157   pyDump << this << ".DoubleNodeElemGroups2New( " << &theElems << ", "
6158          << &theNodesNot       << ", "
6159          << &theAffectedElems  << ", "
6160          << theElemGroupNeeded << ", "
6161          << theNodeGroupNeeded << " )";
6162
6163   aTwoGroups[0] = aNewElemGroup._retn();
6164   aTwoGroups[1] = aNewNodeGroup._retn();
6165   return aTwoGroups._retn();
6166
6167   SMESH_CATCH( SMESH::throwCorbaException );
6168   return 0;
6169 }
6170
6171 //================================================================================
6172 /*!
6173   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
6174   This method provided for convenience works as DoubleNodes() described above.
6175   \param theElems - list of groups of elements (edges or faces) to be replicated
6176   \param theNodesNot - list of groups of nodes not to replicated
6177   \param theShape - shape to detect affected elements (element which geometric center
6178   located on or inside shape).
6179   The replicated nodes should be associated to affected elements.
6180   \return TRUE if operation has been completed successfully, FALSE otherwise
6181   \sa DoubleNodeGroupInRegion(), DoubleNodesInRegion()
6182 */
6183 //================================================================================
6184
6185 CORBA::Boolean
6186 SMESH_MeshEditor_i::DoubleNodeElemGroupsInRegion(const SMESH::ListOfGroups& theElems,
6187                                                  const SMESH::ListOfGroups& theNodesNot,
6188                                                  GEOM::GEOM_Object_ptr      theShape )
6189   throw (SALOME::SALOME_Exception)
6190 {
6191   SMESH_TRY;
6192   initData();
6193
6194
6195   SMESHDS_Mesh* aMeshDS = getMeshDS();
6196   TIDSortedElemSet anElems, aNodes;
6197   listOfGroupToSet(theElems, aMeshDS, anElems,false );
6198   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
6199
6200   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
6201   bool aResult = getEditor().DoubleNodesInRegion( anElems, aNodes, aShape );
6202
6203   // Update Python script
6204   TPythonDump() << "isDone = " << this << ".DoubleNodeElemGroupsInRegion( " << &theElems << ", "
6205                 << &theNodesNot << ", " << theShape << " )";
6206
6207   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6208   return aResult;
6209
6210   SMESH_CATCH( SMESH::throwCorbaException );
6211   return 0;
6212 }
6213
6214 //================================================================================
6215 /*!
6216   \brief Identify the elements that will be affected by node duplication (actual
6217          duplication is not performed.
6218   This method is the first step of DoubleNodeElemGroupsInRegion.
6219   \param theElems - list of groups of elements (edges or faces) to be replicated
6220   \param theNodesNot - list of groups of nodes not to replicated
6221   \param theShape - shape to detect affected elements (element which geometric center
6222          located on or inside shape).
6223          The replicated nodes should be associated to affected elements.
6224   \return groups of affected elements
6225   \sa DoubleNodeElemGroupsInRegion()
6226 */
6227 //================================================================================
6228 SMESH::ListOfGroups*
6229 SMESH_MeshEditor_i::AffectedElemGroupsInRegion( const SMESH::ListOfGroups& theElems,
6230                                                 const SMESH::ListOfGroups& theNodesNot,
6231                                                 GEOM::GEOM_Object_ptr      theShape )
6232   throw (SALOME::SALOME_Exception)
6233 {
6234   SMESH_TRY;
6235   MESSAGE("AffectedElemGroupsInRegion");
6236   SMESH::ListOfGroups_var aListOfGroups = new SMESH::ListOfGroups();
6237   bool isEdgeGroup = false;
6238   bool isFaceGroup = false;
6239   bool isVolumeGroup = false;
6240   SMESH::SMESH_Group_var aNewEdgeGroup = myMesh_i->CreateGroup(SMESH::EDGE, "affectedEdges");
6241   SMESH::SMESH_Group_var aNewFaceGroup = myMesh_i->CreateGroup(SMESH::FACE, "affectedFaces");
6242   SMESH::SMESH_Group_var aNewVolumeGroup = myMesh_i->CreateGroup(SMESH::VOLUME, "affectedVolumes");
6243
6244   initData();
6245
6246   ::SMESH_MeshEditor aMeshEditor(myMesh);
6247
6248   SMESHDS_Mesh* aMeshDS = getMeshDS();
6249   TIDSortedElemSet anElems, aNodes;
6250   listOfGroupToSet(theElems, aMeshDS, anElems, false);
6251   listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true);
6252
6253   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape(theShape);
6254   TIDSortedElemSet anAffected;
6255   bool aResult = aMeshEditor.AffectedElemGroupsInRegion(anElems, aNodes, aShape, anAffected);
6256
6257
6258   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6259
6260   TPythonDump pyDump;
6261   if (aResult)
6262   {
6263     int lg = anAffected.size();
6264     MESSAGE("lg="<< lg);
6265     SMESH::long_array_var volumeIds = new SMESH::long_array;
6266     volumeIds->length(lg);
6267     SMESH::long_array_var faceIds = new SMESH::long_array;
6268     faceIds->length(lg);
6269     SMESH::long_array_var edgeIds = new SMESH::long_array;
6270     edgeIds->length(lg);
6271     int ivol = 0;
6272     int iface = 0;
6273     int iedge = 0;
6274
6275     TIDSortedElemSet::const_iterator eIt = anAffected.begin();
6276     for (; eIt != anAffected.end(); ++eIt)
6277     {
6278       const SMDS_MeshElement* anElem = *eIt;
6279       if (!anElem)
6280         continue;
6281       int elemId = anElem->GetID();
6282       if (myMesh->GetElementType(elemId, true) == SMDSAbs_Volume)
6283         volumeIds[ivol++] = elemId;
6284       else if (myMesh->GetElementType(elemId, true) == SMDSAbs_Face)
6285         faceIds[iface++] = elemId;
6286       else if (myMesh->GetElementType(elemId, true) == SMDSAbs_Edge)
6287         edgeIds[iedge++] = elemId;
6288     }
6289     volumeIds->length(ivol);
6290     faceIds->length(iface);
6291     edgeIds->length(iedge);
6292
6293     aNewVolumeGroup->Add(volumeIds);
6294     aNewFaceGroup->Add(faceIds);
6295     aNewEdgeGroup->Add(edgeIds);
6296     isVolumeGroup = (aNewVolumeGroup->Size() > 0);
6297     isFaceGroup = (aNewFaceGroup->Size() > 0);
6298     isEdgeGroup = (aNewEdgeGroup->Size() > 0);
6299   }
6300
6301   int nbGroups = 0;
6302   if (isEdgeGroup)   nbGroups++;
6303   if (isFaceGroup)   nbGroups++;
6304   if (isVolumeGroup) nbGroups++;
6305   aListOfGroups->length(nbGroups);
6306
6307   int i = 0;
6308   if (isEdgeGroup)   aListOfGroups[i++] = aNewEdgeGroup._retn();
6309   if (isFaceGroup)   aListOfGroups[i++] = aNewFaceGroup._retn();
6310   if (isVolumeGroup) aListOfGroups[i++] = aNewVolumeGroup._retn();
6311
6312   // Update Python script
6313
6314   pyDump << "[ ";
6315   if (isEdgeGroup)   pyDump << aNewEdgeGroup << ", ";
6316   if (isFaceGroup)   pyDump << aNewFaceGroup << ", ";
6317   if (isVolumeGroup) pyDump << aNewVolumeGroup << ", ";
6318   pyDump << "] = ";
6319   pyDump << this << ".AffectedElemGroupsInRegion( "
6320          << &theElems << ", " << &theNodesNot << ", " << theShape << " )";
6321
6322   return aListOfGroups._retn();
6323
6324   SMESH_CATCH( SMESH::throwCorbaException );
6325   return 0;
6326 }
6327
6328 //================================================================================
6329 /*!
6330   \brief Generated skin mesh (containing 2D cells) from 3D mesh
6331    The created 2D mesh elements based on nodes of free faces of boundary volumes
6332   \return TRUE if operation has been completed successfully, FALSE otherwise
6333 */
6334 //================================================================================
6335
6336 CORBA::Boolean SMESH_MeshEditor_i::Make2DMeshFrom3D()
6337   throw (SALOME::SALOME_Exception)
6338 {
6339   SMESH_TRY;
6340   initData();
6341
6342   bool aResult = getEditor().Make2DMeshFrom3D();
6343
6344   TPythonDump() << "isDone = " << this << ".Make2DMeshFrom3D()";
6345
6346   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6347   return aResult;
6348
6349   SMESH_CATCH( SMESH::throwCorbaException );
6350   return false;
6351 }
6352
6353 //================================================================================
6354 /*!
6355  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
6356  * The list of groups must contain at least two groups. The groups have to be disjoint:
6357  * no common element into two different groups.
6358  * The nodes of the internal faces at the boundaries of the groups are doubled.
6359  * Optionally, the internal faces are replaced by flat elements.
6360  * Triangles are transformed into prisms, and quadrangles into hexahedrons.
6361  * The flat elements are stored in groups of volumes.
6362  * These groups are named according to the position of the group in the list:
6363  * 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.
6364  * 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.
6365  * All the flat elements are gathered into the group named "joints3D" (or "joints2D" in 2D situation).
6366  * The flat element of the multiple junctions between the simple junction are stored in a group named "jointsMultiples".
6367  * \param theDomains - list of groups of volumes
6368  * \param createJointElems - if TRUE, create the elements
6369  * \param onAllBoundaries - if TRUE, the nodes and elements are also created on
6370  *        the boundary between \a theDomains and the rest mesh
6371  * \return TRUE if operation has been completed successfully, FALSE otherwise
6372  */
6373 //================================================================================
6374
6375 CORBA::Boolean
6376 SMESH_MeshEditor_i::DoubleNodesOnGroupBoundaries( const SMESH::ListOfGroups& theDomains,
6377                                                   CORBA::Boolean             createJointElems,
6378                                                   CORBA::Boolean             onAllBoundaries )
6379   throw (SALOME::SALOME_Exception)
6380 {
6381   bool isOK = false;
6382
6383   SMESH_TRY;
6384   initData();
6385
6386   SMESHDS_Mesh* aMeshDS = getMeshDS();
6387
6388   // MESSAGE("theDomains.length = "<<theDomains.length());
6389   if ( theDomains.length() <= 1 && !onAllBoundaries )
6390     THROW_SALOME_CORBA_EXCEPTION("At least 2 groups are required.", SALOME::BAD_PARAM);
6391
6392   vector<TIDSortedElemSet> domains;
6393   domains.resize( theDomains.length() );
6394
6395   for ( int i = 0, n = theDomains.length(); i < n; i++ )
6396   {
6397     SMESH::SMESH_GroupBase_var aGrp = theDomains[ i ];
6398     if ( !CORBA::is_nil( aGrp ) /*&& ( aGrp->GetType() != SMESH::NODE )*/ )
6399     {
6400 //      if ( aGrp->GetType() != SMESH::VOLUME )
6401 //        THROW_SALOME_CORBA_EXCEPTION("Not a volume group", SALOME::BAD_PARAM);
6402       SMESH::long_array_var anIDs = aGrp->GetIDs();
6403       arrayToSet( anIDs, aMeshDS, domains[ i ], SMDSAbs_All );
6404     }
6405   }
6406
6407   isOK = getEditor().DoubleNodesOnGroupBoundaries( domains, createJointElems, onAllBoundaries );
6408   // TODO publish the groups of flat elements in study
6409
6410   declareMeshModified( /*isReComputeSafe=*/ !isOK );
6411
6412   // Update Python script
6413   TPythonDump() << "isDone = " << this << ".DoubleNodesOnGroupBoundaries( " << &theDomains
6414                 << ", " << createJointElems << ", " << onAllBoundaries << " )";
6415
6416   SMESH_CATCH( SMESH::throwCorbaException );
6417
6418   myMesh_i->CreateGroupServants(); // publish created groups if any
6419
6420   return isOK;
6421 }
6422
6423 //================================================================================
6424 /*!
6425  * \brief Double nodes on some external faces and create flat elements.
6426  * Flat elements are mainly used by some types of mechanic calculations.
6427  *
6428  * Each group of the list must be constituted of faces.
6429  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
6430  * @param theGroupsOfFaces - list of groups of faces
6431  * @return TRUE if operation has been completed successfully, FALSE otherwise
6432  */
6433 //================================================================================
6434
6435 CORBA::Boolean
6436 SMESH_MeshEditor_i::CreateFlatElementsOnFacesGroups( const SMESH::ListOfGroups& theGroupsOfFaces )
6437   throw (SALOME::SALOME_Exception)
6438 {
6439   SMESH_TRY;
6440   initData();
6441
6442   SMESHDS_Mesh* aMeshDS = getMeshDS();
6443
6444   vector<TIDSortedElemSet> faceGroups;
6445   faceGroups.clear();
6446
6447   for ( int i = 0, n = theGroupsOfFaces.length(); i < n; i++ )
6448   {
6449     SMESH::SMESH_GroupBase_var aGrp = theGroupsOfFaces[ i ];
6450     if ( !CORBA::is_nil( aGrp ) && ( aGrp->GetType() != SMESH::NODE ) )
6451     {
6452       TIDSortedElemSet faceGroup;
6453       faceGroup.clear();
6454       faceGroups.push_back(faceGroup);
6455       SMESH::long_array_var anIDs = aGrp->GetIDs();
6456       arrayToSet( anIDs, aMeshDS, faceGroups[ i ], SMDSAbs_All );
6457     }
6458   }
6459
6460   bool aResult = getEditor().CreateFlatElementsOnFacesGroups( faceGroups );
6461   // TODO publish the groups of flat elements in study
6462
6463   declareMeshModified( /*isReComputeSafe=*/ !aResult );
6464
6465   // Update Python script
6466   TPythonDump() << this << ".CreateFlatElementsOnFacesGroups( " << &theGroupsOfFaces << " )";
6467   return aResult;
6468
6469   SMESH_CATCH( SMESH::throwCorbaException );
6470   return false;
6471 }
6472
6473 //================================================================================
6474 /*!
6475  *  \brief Identify all the elements around a geom shape, get the faces delimiting
6476  *         the hole.
6477  *
6478  *  Build groups of volume to remove, groups of faces to replace on the skin of the
6479  *  object, groups of faces to remove inside the object, (idem edges).
6480  *  Build ordered list of nodes at the border of each group of faces to replace
6481  *  (to be used to build a geom subshape).
6482  */
6483 //================================================================================
6484
6485 void SMESH_MeshEditor_i::CreateHoleSkin(CORBA::Double                  radius,
6486                                         GEOM::GEOM_Object_ptr          theShape,
6487                                         const char*                    groupName,
6488                                         const SMESH::double_array&     theNodesCoords,
6489                                         SMESH::array_of_long_array_out GroupsOfNodes)
6490   throw (SALOME::SALOME_Exception)
6491 {
6492   SMESH_TRY;
6493
6494   initData();
6495   std::vector<std::vector<int> > aListOfListOfNodes;
6496   ::SMESH_MeshEditor aMeshEditor( myMesh );
6497
6498   theSearchersDeleter.Set( myMesh ); // remove theNodeSearcher if mesh is other
6499   if ( !theNodeSearcher )
6500     theNodeSearcher = SMESH_MeshAlgos::GetNodeSearcher( *getMeshDS() );
6501
6502   vector<double> nodesCoords;
6503   for (int i = 0; i < theNodesCoords.length(); i++)
6504   {
6505     nodesCoords.push_back( theNodesCoords[i] );
6506   }
6507
6508   TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape );
6509   aMeshEditor.CreateHoleSkin(radius, aShape, theNodeSearcher, groupName,
6510                              nodesCoords, aListOfListOfNodes);
6511
6512   GroupsOfNodes = new SMESH::array_of_long_array;
6513   GroupsOfNodes->length( aListOfListOfNodes.size() );
6514   std::vector<std::vector<int> >::iterator llIt = aListOfListOfNodes.begin();
6515   for ( CORBA::Long i = 0; llIt != aListOfListOfNodes.end(); llIt++, i++ )
6516   {
6517     vector<int>& aListOfNodes = *llIt;
6518     vector<int>::iterator lIt = aListOfNodes.begin();;
6519     SMESH::long_array& aGroup = (*GroupsOfNodes)[ i ];
6520     aGroup.length( aListOfNodes.size() );
6521     for ( int j = 0; lIt != aListOfNodes.end(); lIt++, j++ )
6522       aGroup[ j ] = (*lIt);
6523   }
6524   TPythonDump() << "lists_nodes = " << this << ".CreateHoleSkin( "
6525                 << radius << ", "
6526                 << theShape
6527                 << ", '" << groupName << "', "
6528                 << theNodesCoords << " )";
6529
6530   SMESH_CATCH( SMESH::throwCorbaException );
6531 }
6532
6533 // issue 20749 ===================================================================
6534 /*!
6535  * \brief Creates missing boundary elements
6536  *  \param elements - elements whose boundary is to be checked
6537  *  \param dimension - defines type of boundary elements to create
6538  *  \param groupName - a name of group to store created boundary elements in,
6539  *                     "" means not to create the group
6540  *  \param meshName - a name of new mesh to store created boundary elements in,
6541  *                     "" means not to create the new mesh
6542  *  \param toCopyElements - if true, the checked elements will be copied into the new mesh
6543  *  \param toCopyExistingBondary - if true, not only new but also pre-existing
6544  *                                boundary elements will be copied into the new mesh
6545  *  \param group - returns the create group, if any
6546  *  \retval SMESH::SMESH_Mesh - the mesh where elements were added to
6547  */
6548 // ================================================================================
6549
6550 SMESH::SMESH_Mesh_ptr
6551 SMESH_MeshEditor_i::MakeBoundaryMesh(SMESH::SMESH_IDSource_ptr idSource,
6552                                      SMESH::Bnd_Dimension      dim,
6553                                      const char*               groupName,
6554                                      const char*               meshName,
6555                                      CORBA::Boolean            toCopyElements,
6556                                      CORBA::Boolean            toCopyExistingBondary,
6557                                      SMESH::SMESH_Group_out    group)
6558   throw (SALOME::SALOME_Exception)
6559 {
6560   SMESH_TRY;
6561   initData();
6562
6563   if ( dim > SMESH::BND_1DFROM2D )
6564     THROW_SALOME_CORBA_EXCEPTION("Invalid boundary dimension", SALOME::BAD_PARAM);
6565
6566   SMESHDS_Mesh* aMeshDS = getMeshDS();
6567
6568   SMESH::SMESH_Mesh_var mesh_var;
6569   SMESH::SMESH_Group_var group_var;
6570
6571   TPythonDump pyDump;
6572
6573   TIDSortedElemSet elements;
6574   SMDSAbs_ElementType elemType = (dim == SMESH::BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
6575   if ( idSourceToSet( idSource, aMeshDS, elements, elemType,/*emptyIfIsMesh=*/true ))
6576   {
6577     // mesh to fill in
6578     mesh_var =
6579       strlen(meshName) ? makeMesh(meshName) : SMESH::SMESH_Mesh::_duplicate(myMesh_i->_this());
6580     SMESH_Mesh_i* mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh_var );
6581     // other mesh
6582     SMESH_Mesh* smesh_mesh = (mesh_i==myMesh_i) ? (SMESH_Mesh*)0 : &mesh_i->GetImpl();
6583
6584     // group of new boundary elements
6585     SMESH_Group* smesh_group = 0;
6586     if ( strlen(groupName) )
6587     {
6588       group_var = mesh_i->CreateGroup( SMESH::ElementType(int(elemType)-1),groupName);
6589       if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( group_var ))
6590         smesh_group = group_i->GetSmeshGroup();
6591     }
6592
6593     // do it
6594     getEditor().MakeBoundaryMesh( elements,
6595                                   ::SMESH_MeshEditor::Bnd_Dimension(dim),
6596                                   smesh_group,
6597                                   smesh_mesh,
6598                                   toCopyElements,
6599                                   toCopyExistingBondary);
6600
6601     if ( smesh_mesh )
6602       smesh_mesh->GetMeshDS()->Modified();
6603   }
6604
6605   const char* dimName[] = { "BND_2DFROM3D", "BND_1DFROM3D", "BND_1DFROM2D" };
6606
6607   // result of MakeBoundaryMesh() is a tuple (mesh, group)
6608   if ( mesh_var->_is_nil() )
6609     pyDump << myMesh_i->_this() << ", ";
6610   else
6611     pyDump << mesh_var << ", ";
6612   if ( group_var->_is_nil() )
6613     pyDump << "_NoneGroup = "; // assignment to None is forbiden
6614   else
6615     pyDump << group_var << " = ";
6616   pyDump << this << ".MakeBoundaryMesh( "
6617          << idSource << ", "
6618          << "SMESH." << dimName[int(dim)] << ", "
6619          << "'" << groupName << "', "
6620          << "'" << meshName<< "', "
6621          << toCopyElements << ", "
6622          << toCopyExistingBondary << ")";
6623
6624   group = group_var._retn();
6625   return mesh_var._retn();
6626
6627   SMESH_CATCH( SMESH::throwCorbaException );
6628   return SMESH::SMESH_Mesh::_nil();
6629 }
6630
6631 //================================================================================
6632 /*!
6633  * \brief Creates missing boundary elements
6634  *  \param dimension - defines type of boundary elements to create
6635  *  \param groupName - a name of group to store all boundary elements in,
6636  *    "" means not to create the group
6637  *  \param meshName - a name of a new mesh, which is a copy of the initial 
6638  *    mesh + created boundary elements; "" means not to create the new mesh
6639  *  \param toCopyAll - if true, the whole initial mesh will be copied into
6640  *    the new mesh else only boundary elements will be copied into the new mesh
6641  *  \param groups - optional groups of elements to make boundary around
6642  *  \param mesh - returns the mesh where elements were added to
6643  *  \param group - returns the created group, if any
6644  *  \retval long - number of added boundary elements
6645  */
6646 //================================================================================
6647
6648 CORBA::Long SMESH_MeshEditor_i::MakeBoundaryElements(SMESH::Bnd_Dimension dim,
6649                                                      const char* groupName,
6650                                                      const char* meshName,
6651                                                      CORBA::Boolean toCopyAll,
6652                                                      const SMESH::ListOfIDSources& groups,
6653                                                      SMESH::SMESH_Mesh_out mesh,
6654                                                      SMESH::SMESH_Group_out group)
6655   throw (SALOME::SALOME_Exception)
6656 {
6657   SMESH_TRY;
6658   initData();
6659
6660   if ( dim > SMESH::BND_1DFROM2D )
6661     THROW_SALOME_CORBA_EXCEPTION("Invalid boundary dimension", SALOME::BAD_PARAM);
6662
6663   // separate groups belonging to this and other mesh
6664   SMESH::ListOfIDSources_var groupsOfThisMesh  = new SMESH::ListOfIDSources;
6665   SMESH::ListOfIDSources_var groupsOfOtherMesh = new SMESH::ListOfIDSources;
6666   groupsOfThisMesh ->length( groups.length() );
6667   groupsOfOtherMesh->length( groups.length() );
6668   int nbGroups = 0, nbGroupsOfOtherMesh = 0;
6669   for ( int i = 0; i < groups.length(); ++i )
6670   {
6671     SMESH::SMESH_Mesh_var m = groups[i]->GetMesh();
6672     if ( myMesh_i != SMESH::DownCast<SMESH_Mesh_i*>( m ))
6673       groupsOfOtherMesh[ nbGroupsOfOtherMesh++ ] = groups[i];
6674     else
6675       groupsOfThisMesh[ nbGroups++ ] = groups[i];
6676     if ( SMESH::DownCast<SMESH_Mesh_i*>( groups[i] ))
6677       THROW_SALOME_CORBA_EXCEPTION("expect a group but recieve a mesh", SALOME::BAD_PARAM);
6678   }
6679   groupsOfThisMesh->length( nbGroups );
6680   groupsOfOtherMesh->length( nbGroupsOfOtherMesh );
6681
6682   int nbAdded = 0;
6683   TPythonDump pyDump;
6684
6685   if ( nbGroupsOfOtherMesh > 0 )
6686   {
6687     // process groups belonging to another mesh
6688     SMESH::SMESH_Mesh_var    otherMesh = groupsOfOtherMesh[0]->GetMesh();
6689     SMESH::SMESH_MeshEditor_var editor = otherMesh->GetMeshEditor();
6690     nbAdded += editor->MakeBoundaryElements( dim, groupName, meshName, toCopyAll,
6691                                              groupsOfOtherMesh, mesh, group );
6692   }
6693
6694   SMESH::SMESH_Mesh_var mesh_var;
6695   SMESH::SMESH_Group_var group_var;
6696
6697   // get mesh to fill
6698   mesh_var = SMESH::SMESH_Mesh::_duplicate( myMesh_i->_this() );
6699   const bool toCopyMesh = ( strlen( meshName ) > 0 );
6700   if ( toCopyMesh )
6701   {
6702     if ( toCopyAll )
6703       mesh_var = SMESH_Gen_i::GetSMESHGen()->CopyMesh(mesh_var,
6704                                                       meshName,
6705                                                       /*toCopyGroups=*/false,
6706                                                       /*toKeepIDs=*/true);
6707     else
6708       mesh_var = makeMesh(meshName);
6709   }
6710   SMESH_Mesh_i* mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh_var );
6711   SMESH_Mesh*  tgtMesh = &mesh_i->GetImpl();
6712
6713   // source mesh
6714   SMESH_Mesh*     srcMesh = ( toCopyMesh && !toCopyAll ) ? myMesh : tgtMesh;
6715   SMESHDS_Mesh* srcMeshDS = srcMesh->GetMeshDS();
6716
6717   // group of boundary elements
6718   SMESH_Group* smesh_group = 0;
6719   SMDSAbs_ElementType elemType = (dim == SMESH::BND_2DFROM3D) ? SMDSAbs_Volume : SMDSAbs_Face;
6720   if ( strlen(groupName) )
6721   {
6722     SMESH::ElementType groupType = SMESH::ElementType( int(elemType)-1 );
6723     group_var = mesh_i->CreateGroup( groupType, groupName );
6724     if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( group_var ))
6725       smesh_group = group_i->GetSmeshGroup();
6726   }
6727
6728   TIDSortedElemSet elements;
6729
6730   if ( groups.length() > 0 )
6731   {
6732     for ( int i = 0; i < nbGroups; ++i )
6733     {
6734       elements.clear();
6735       if ( idSourceToSet( groupsOfThisMesh[i], srcMeshDS, elements, elemType,/*emptyIfIsMesh=*/0 ))
6736       {
6737         SMESH::Bnd_Dimension bdim = 
6738           ( elemType == SMDSAbs_Volume ) ? SMESH::BND_2DFROM3D : SMESH::BND_1DFROM2D;
6739         nbAdded += getEditor().MakeBoundaryMesh( elements,
6740                                                  ::SMESH_MeshEditor::Bnd_Dimension(bdim),
6741                                                  smesh_group,
6742                                                  tgtMesh,
6743                                                  /*toCopyElements=*/false,
6744                                                  /*toCopyExistingBondary=*/srcMesh != tgtMesh,
6745                                                  /*toAddExistingBondary=*/true,
6746                                                  /*aroundElements=*/true);
6747       }
6748     }
6749   }
6750   else
6751   {
6752     nbAdded += getEditor().MakeBoundaryMesh( elements,
6753                                              ::SMESH_MeshEditor::Bnd_Dimension(dim),
6754                                              smesh_group,
6755                                              tgtMesh,
6756                                              /*toCopyElements=*/false,
6757                                              /*toCopyExistingBondary=*/srcMesh != tgtMesh,
6758                                              /*toAddExistingBondary=*/true);
6759   }
6760   tgtMesh->GetMeshDS()->Modified();
6761
6762   const char* dimName[] = { "BND_2DFROM3D", "BND_1DFROM3D", "BND_1DFROM2D" };
6763
6764   // result of MakeBoundaryElements() is a tuple (nb, mesh, group)
6765   pyDump << "nbAdded, ";
6766   if ( mesh_var->_is_nil() )
6767     pyDump << myMesh_i->_this() << ", ";
6768   else
6769     pyDump << mesh_var << ", ";
6770   if ( group_var->_is_nil() )
6771     pyDump << "_NoneGroup = "; // assignment to None is forbiden
6772   else
6773     pyDump << group_var << " = ";
6774   pyDump << this << ".MakeBoundaryElements( "
6775          << "SMESH." << dimName[int(dim)] << ", "
6776          << "'" << groupName << "', "
6777          << "'" << meshName<< "', "
6778          << toCopyAll << ", "
6779          << groups << ")";
6780
6781   mesh  = mesh_var._retn();
6782   group = group_var._retn();
6783   return nbAdded;
6784
6785   SMESH_CATCH( SMESH::throwCorbaException );
6786   return 0;
6787 }