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