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