Salome HOME
correct previous integration (Porting to Python 2.6)
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_ShapeByMeshDlg.cxx
1 //  Copyright (C) 2007-2008  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.
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   : SMESHGUI_ShapeByMeshDlg.cxx
23 // Author : Edward AGAPOV, Open CASCADE S.A.S.
24 // SMESH includes
25 //
26 #include "SMESHGUI_ShapeByMeshDlg.h"
27
28 #include "SMESHGUI.h"
29 #include "SMESHGUI_GEOMGenUtils.h"
30 #include "SMESHGUI_IdValidator.h"
31 #include "SMESHGUI_MeshUtils.h"
32 #include "SMESHGUI_Utils.h"
33 #include "SMESHGUI_VTKUtils.h"
34
35 #include <SMDS_Mesh.hxx>
36 #include <SMDS_MeshNode.hxx>
37 #include <SMESH_Actor.h>
38
39 // SALOME GEOM includes
40 #include <GEOMBase.h>
41 #include <GeometryGUI.h>
42
43 // SALOME GUI includes
44 #include <LightApp_DataOwner.h>
45 #include <LightApp_SelectionMgr.h>
46 #include <SALOME_ListIO.hxx>
47 #include <SUIT_Desktop.h>
48 #include <SVTK_Selector.h>
49 #include <SVTK_ViewWindow.h>
50 #include <SVTK_ViewModel.h>
51 #include <SalomeApp_Tools.h>
52
53 // SALOME KERNEL includes
54 #include <SALOMEDSClient_SObject.hxx>
55
56 // OCCT includes
57 #include <TColStd_MapOfInteger.hxx>
58 #include <TopoDS_Shape.hxx>
59 #include <TopExp_Explorer.hxx>
60
61 // Qt includes
62 #include <QFrame>
63 #include <QVBoxLayout>
64 #include <QHBoxLayout>
65 #include <QGridLayout>
66 #include <QLineEdit>
67 #include <QLabel>
68 #include <QRadioButton>
69 #include <QButtonGroup>
70 #include <QGroupBox>
71 #include <QStringList>
72
73 #define SPACING 6
74 #define MARGIN  11
75
76 enum { EDGE = 0, FACE, VOLUME };
77
78 /*!
79  * \brief Dialog to publish a sub-shape of the mesh main shape
80  *        by selecting mesh elements
81  */
82 SMESHGUI_ShapeByMeshDlg::SMESHGUI_ShapeByMeshDlg()
83   : SMESHGUI_Dialog( 0, false, true, OK | Close )
84 {
85   setWindowTitle(tr("CAPTION"));
86
87   QVBoxLayout* aDlgLay = new QVBoxLayout (mainFrame());
88   aDlgLay->setMargin(MARGIN);
89   aDlgLay->setSpacing(SPACING);
90
91   QFrame* aMainFrame = createMainFrame  (mainFrame());
92
93   aDlgLay->addWidget(aMainFrame);
94
95   aDlgLay->setStretchFactor(aMainFrame, 1);
96 }
97
98 //=======================================================================
99 // function : createMainFrame()
100 // purpose  : Create frame containing dialog's input fields
101 //=======================================================================
102 QFrame* SMESHGUI_ShapeByMeshDlg::createMainFrame (QWidget* theParent)
103 {
104   QFrame* aMainGrp = new QFrame(theParent);
105   QGridLayout* aLayout = new QGridLayout(aMainGrp);
106   aLayout->setMargin(0);
107   aLayout->setSpacing(SPACING);
108
109   // elem type
110   myElemTypeBox = new QGroupBox(tr("SMESH_ELEMENT_TYPE"), aMainGrp);
111   myElemTypeGroup = new QButtonGroup(aMainGrp);
112   QHBoxLayout* myElemTypeBoxLayout = new QHBoxLayout(myElemTypeBox);
113   myElemTypeBoxLayout->setMargin(MARGIN);
114   myElemTypeBoxLayout->setSpacing(SPACING);
115
116   QRadioButton* aEdgeRb   = new QRadioButton( tr("SMESH_EDGE"),   myElemTypeBox);
117   QRadioButton* aFaceRb   = new QRadioButton( tr("SMESH_FACE"),   myElemTypeBox);
118   QRadioButton* aVolumeRb = new QRadioButton( tr("SMESH_VOLUME"), myElemTypeBox);
119   
120   myElemTypeBoxLayout->addWidget(aEdgeRb);
121   myElemTypeBoxLayout->addWidget(aFaceRb);
122   myElemTypeBoxLayout->addWidget(aVolumeRb);
123   myElemTypeGroup->addButton(aEdgeRb, 0);
124   myElemTypeGroup->addButton(aFaceRb, 1);
125   myElemTypeGroup->addButton(aVolumeRb, 2);
126   aEdgeRb->setChecked(true);
127   
128   // element id
129   QLabel* anIdLabel = new QLabel( tr("ELEMENT_ID"), aMainGrp );
130   myElementId = new QLineEdit( aMainGrp );
131   myElementId->setValidator( new SMESHGUI_IdValidator( theParent, 
132                                                        !myIsMultipleAllowed ? 1 : 0 ) ); // 0 for any number of entities
133
134   // shape name
135   QLabel* aNameLabel = new QLabel( tr("GEOMETRY_NAME"), aMainGrp );
136   myGeomName = new QLineEdit( aMainGrp );
137
138   aLayout->addWidget(myElemTypeBox, 0, 0, 1, 2);
139   aLayout->addWidget(anIdLabel,   1, 0);
140   aLayout->addWidget(myElementId, 1, 1);
141   aLayout->addWidget(aNameLabel,  2, 0);
142   aLayout->addWidget(myGeomName,  2, 1);
143
144   return aMainGrp;
145 }
146
147 //=======================================================================
148 // function : ~SMESHGUI_ShapeByMeshDlg()
149 // purpose  : Destructor
150 //=======================================================================
151 SMESHGUI_ShapeByMeshDlg::~SMESHGUI_ShapeByMeshDlg()
152 {
153 }
154
155 void SMESHGUI_ShapeByMeshDlg:: setMultipleAllowed( bool isAllowed )
156 {
157   myIsMultipleAllowed = isAllowed;
158 }
159
160 //================================================================================
161 /*!
162  * \brief Constructor
163  */
164 //================================================================================
165 SMESHGUI_ShapeByMeshOp::SMESHGUI_ShapeByMeshOp(bool isMultipleAllowed):
166   myIsMultipleAllowed(isMultipleAllowed)
167 {
168   if ( GeometryGUI::GetGeomGen()->_is_nil() )// check that GEOM_Gen exists
169     GeometryGUI::InitGeomGen();
170
171   myDlg = new SMESHGUI_ShapeByMeshDlg;
172   myDlg->setMultipleAllowed(myIsMultipleAllowed);
173
174   connect(myDlg->myElemTypeGroup, SIGNAL(buttonClicked(int)), SLOT(onTypeChanged(int)));
175   connect(myDlg->myElementId, SIGNAL(textChanged(const QString&)), SLOT(onElemIdChanged(const QString&)));
176 }
177
178
179 //=======================================================================
180 // function : startOperation()
181 // purpose  : Init dialog fields, connect signals and slots, show dialog
182 //=======================================================================
183 void SMESHGUI_ShapeByMeshOp::startOperation()
184 {
185   //SetMesh( SMESH::SMESH_Mesh::_nil() );
186   myIsManualIdEnter = false;
187
188   SMESHGUI_SelectionOp::startOperation();
189
190   //activateSelection(); // set filters
191   onSelectionDone(); // desable/enable [ OK ]
192
193   myDlg->show();
194 }
195
196 //================================================================================
197 /*!
198  * \brief Destructor
199  */
200 //================================================================================
201 SMESHGUI_ShapeByMeshOp::~SMESHGUI_ShapeByMeshOp()
202 {
203   if ( myDlg )
204     delete myDlg;
205 }
206
207 //================================================================================
208 /*!
209  * \brief Gets dialog of this operation
210  * \retval LightApp_Dialog* - pointer to dialog of this operation
211  */
212 //================================================================================
213 LightApp_Dialog* SMESHGUI_ShapeByMeshOp::dlg() const
214 {
215   return myDlg;
216 }
217
218 SMESH::SMESH_Mesh_ptr SMESHGUI_ShapeByMeshOp::GetMesh()
219 {
220   return myMesh;
221 }
222
223 //=======================================================================
224 // function : GetShape()
225 // purpose  : Get published sub-shape
226 //=======================================================================
227 GEOM::GEOM_Object_ptr SMESHGUI_ShapeByMeshOp::GetShape()
228 {
229   return myGeomObj.in();
230 }
231
232 //=======================================================================
233 // function : SetMesh()
234 // purpose  : Set mesh to dialog
235 //=======================================================================
236
237 void SMESHGUI_ShapeByMeshOp::SetMesh (SMESH::SMESH_Mesh_ptr thePtr)
238 {
239   myMesh    = SMESH::SMESH_Mesh::_duplicate(thePtr);
240   myGeomObj = GEOM::GEOM_Object::_nil();
241   myHasSolids = false;
242
243   std::vector< bool > hasElement (myDlg->myElemTypeGroup->buttons().count(), false);
244   if (!myMesh->_is_nil() )
245     {
246       //     _PTR(SObject) aSobj = SMESH::FindSObject(myMesh.in());
247       //     SUIT_DataOwnerPtr anIObj (new LightApp_DataOwner(aSobj->GetID().c_str()));
248
249       std::vector< int > nbShapes( TopAbs_SHAPE, 0 );
250       int shapeDim = 0; // max dim with several shapes
251       //if ( /*mySelectionMgr*/ selectionMgr()->isOk(anIObj) ) // check that the mesh has a valid shape
252       {
253         _PTR(SObject) aSO = SMESH::FindSObject(myMesh.in());
254         GEOM::GEOM_Object_var mainShape = SMESH::GetGeom(aSO);
255         if ( !mainShape->_is_nil() ) 
256           {
257             TopoDS_Shape aShape;
258             if ( GEOMBase::GetShape(mainShape, aShape))
259               {
260                 TopAbs_ShapeEnum types[4] = { TopAbs_EDGE, TopAbs_FACE, TopAbs_SHELL, TopAbs_SOLID };
261                 for ( int dim = 4; dim > 0; --dim ) {
262                   TopAbs_ShapeEnum type = types[ dim - 1 ];
263                   TopAbs_ShapeEnum avoid = ( type == TopAbs_SHELL ) ? TopAbs_SOLID : TopAbs_SHAPE;
264                   TopExp_Explorer exp( aShape, type, avoid );
265                   for ( ; nbShapes[ type ] < 2 && exp.More(); exp.Next() )
266                     ++nbShapes[ type ];
267                   if ( nbShapes[ type ] > 1 ) {
268                     shapeDim = dim;
269                     break;
270                   }
271                 }
272               }
273           }
274       }
275       if (shapeDim > 0)
276         {
277           if ( nbShapes[ TopAbs_SHELL ] + nbShapes[ TopAbs_SOLID ] > 1 )
278             shapeDim = 3;
279           hasElement[ EDGE ]   = shapeDim > 0 && myMesh->NbEdges();
280           hasElement[ FACE ]   = shapeDim > 1 && myMesh->NbFaces();
281           hasElement[ VOLUME ] = shapeDim > 2 && myMesh->NbVolumes();
282         }
283       myHasSolids = nbShapes[ TopAbs_SOLID ];
284     }
285
286   // disable inexistant elem types
287   for ( int i = 0; i < myDlg->myElemTypeGroup->buttons().count(); ++i ) {
288     if ( QAbstractButton* button = myDlg->myElemTypeGroup->button( i ) )
289       button->setEnabled( hasElement[ i ] );
290   }
291   myDlg->myElementId->setEnabled( hasElement[ EDGE ] );
292   myDlg->myGeomName-> setEnabled( hasElement[ EDGE ] );
293
294   setElementID("");
295 }
296
297 //=======================================================================
298 // function : commitOperation()
299 // purpose  : called when "Ok" button pressed.
300 //=======================================================================
301
302 void SMESHGUI_ShapeByMeshOp::commitOperation()
303 {
304   SMESHGUI_SelectionOp::commitOperation();
305   try {
306     QStringList aListId = myDlg->myElementId->text().split( " ", QString::SkipEmptyParts);
307     if (aListId.count() == 1)
308       {
309         int elemID = (aListId.first()).toInt();
310         myGeomObj = GEOM::GEOM_Object::_duplicate(
311             SMESHGUI::GetSMESHGen()->GetGeometryByMeshElement
312           ( myMesh.in(), elemID, myDlg->myGeomName->text().toLatin1().constData()) );
313       }
314     else
315       {
316         GEOM::GEOM_Gen_var geomGen = SMESH::GetGEOMGen();
317         _PTR(Study) aStudy = SMESH::GetActiveStudyDocument();
318         
319         if (geomGen->_is_nil() || !aStudy)
320           return;
321         
322         GEOM::GEOM_IShapesOperations_var aShapesOp =
323           geomGen->GetIShapesOperations(aStudy->StudyId());
324         if (aShapesOp->_is_nil() )
325           return;
326         
327         TopAbs_ShapeEnum aGroupType = TopAbs_SHAPE;
328         
329         std::map<double, GEOM::GEOM_Object_var> aGeomObjectsMap;
330         GEOM::GEOM_Object_var aGeomObject;
331
332         GEOM::GEOM_Object_var aMeshShape = myMesh->GetShapeToMesh();
333         
334         for ( int i = 0; i < aListId.count(); i++ )
335           {
336             aGeomObject =
337               SMESHGUI::GetSMESHGen()->FindGeometryByMeshElement(myMesh.in(), aListId[i].toInt());
338
339             if (aGeomObject->_is_nil()) continue;
340             
341             double anId = aShapesOp->GetSubShapeIndex(aMeshShape, aGeomObject);
342             if (aShapesOp->IsDone() && aGeomObjectsMap.find(anId) == aGeomObjectsMap.end())
343               {
344                 aGeomObjectsMap[anId] = aGeomObject;
345
346                 TopAbs_ShapeEnum aSubShapeType = (TopAbs_ShapeEnum)aGeomObject->GetShapeType();
347                 if (i == 0)
348                   aGroupType = aSubShapeType;
349                 else if (aSubShapeType != aGroupType)
350                   aGroupType = TopAbs_SHAPE;
351               }
352           }
353         
354         int aNumberOfGO = aGeomObjectsMap.size();
355         if (aNumberOfGO == 1)
356           myGeomObj = (*aGeomObjectsMap.begin()).second;
357         else if (aNumberOfGO > 1)
358           {
359             GEOM::GEOM_IGroupOperations_var aGroupOp =
360               geomGen->GetIGroupOperations(aStudy->StudyId());
361             if(aGroupOp->_is_nil())
362               return;
363             
364             GEOM::ListOfGO_var aGeomObjects = new GEOM::ListOfGO();
365             aGeomObjects->length( aNumberOfGO );
366
367             int i = 0;
368             std::map<double, GEOM::GEOM_Object_var>::iterator anIter;
369             for (anIter = aGeomObjectsMap.begin(); anIter!=aGeomObjectsMap.end(); anIter++)
370               aGeomObjects[i++] = (*anIter).second;
371           
372             //create geometry group
373             myGeomObj = aGroupOp->CreateGroup(aMeshShape, aGroupType);
374             aGroupOp->UnionList(myGeomObj, aGeomObjects);
375
376             if (!aGroupOp->IsDone())
377               return;
378           }
379         
380         // publish the GEOM object in study
381         QString aNewGeomGroupName ( myDlg->myGeomName->text() );
382           
383         SALOMEDS::SObject_var aNewGroupSO =
384           geomGen->AddInStudy(SMESHGUI::GetSMESHGen()->GetCurrentStudy(), myGeomObj, 
385                               aNewGeomGroupName.toLatin1().data(), aMeshShape);
386       }
387   }
388   catch (const SALOME::SALOME_Exception& S_ex) {
389     SalomeApp_Tools::QtCatchCorbaException(S_ex);
390   }
391   catch (...) {
392   }
393
394 }
395
396 bool SMESHGUI_ShapeByMeshOp::onApply()
397 {
398   return true;
399 }
400
401 //=======================================================================
402 // function : onSelectionDone()
403 // purpose  : SLOT called when selection changed. Enable/desable [ OK ]
404 //=======================================================================
405 void SMESHGUI_ShapeByMeshOp::onSelectionDone()
406 {
407   myDlg->setButtonEnabled( false, QtxDialog::OK );
408   setElementID("");
409
410   try {
411     SALOME_ListIO aList;
412     selectionMgr()->selectedObjects(aList, SVTK_Viewer::Type());
413     if (!myIsMultipleAllowed && aList.Extent() != 1)
414       return;
415
416     SMESH::SMESH_Mesh_var aMesh = SMESH::GetMeshByIO(aList.First());
417     if (aMesh->_is_nil() || myMesh->_is_nil() || aMesh->GetId() != myMesh->GetId() )
418       return;
419
420     QString aString;
421     int nbElems = SMESH::GetNameOfSelectedElements(selector(),//myViewWindow->GetSelector(),
422                                                    aList.First(), aString);
423     if (nbElems > 0) {
424       if (!myIsMultipleAllowed && nbElems != 1 )
425         return;
426       setElementID( aString );
427       myDlg->setButtonEnabled( true, QtxDialog::OK );
428     }
429   } catch (...) {
430   }
431 }
432
433 //=======================================================================
434 // function : activateSelection()
435 // purpose  : Activate selection in accordance with current pattern type
436 //=======================================================================
437 void SMESHGUI_ShapeByMeshOp::activateSelection()
438 {
439   selectionMgr()->clearFilters();
440   //SMESH::SetPointRepresentation(false);
441
442   myDlg->myGeomName->setText("");
443
444   QString geomName;
445   Selection_Mode mode = EdgeSelection;
446   switch ( myDlg->myElemTypeGroup->checkedId() ) {
447   case EDGE  :
448     mode = EdgeSelection;   geomName = tr("GEOM_EDGE"); break;
449   case FACE  :
450     mode = FaceSelection;   geomName = tr("GEOM_FACE"); break;
451   case VOLUME:
452     mode = VolumeSelection; geomName = tr(myHasSolids ? "GEOM_SOLID" : "GEOM_SHELL"); break;
453   default: return;
454   }
455   if ( selectionMode() != mode )
456     setSelectionMode( mode );
457
458   myDlg->myGeomName->setText( GEOMBase::GetDefaultName( geomName ));
459 }
460
461 //=======================================================================
462 //function : onTypeChanged
463 //purpose  : SLOT. Called when element type changed.
464 //=======================================================================
465
466 void SMESHGUI_ShapeByMeshOp::onTypeChanged (int theType)
467 {
468   setElementID("");
469   activateSelection();
470 }
471
472 //=======================================================================
473 //function : onTypeChanged
474 //purpose  : SLOT. Called when element id is entered
475 //           Highlight the element whose Ids the user entered manually
476 //=======================================================================
477
478 void SMESHGUI_ShapeByMeshOp::onElemIdChanged(const QString& theNewText)
479 {
480   myDlg->setButtonEnabled( false, QtxDialog::OK );
481
482   if ( myIsManualIdEnter && !myMesh->_is_nil() )
483   {
484     if ( SMESH_Actor* actor = SMESH::FindActorByObject(myMesh) )
485     {
486       if ( SMDS_Mesh* aMesh = actor->GetObject()->GetMesh() )
487       {
488         SMDSAbs_ElementType type = SMDSAbs_Edge;
489         switch ( myDlg->myElemTypeGroup->checkedId() ) {
490         case EDGE  : type = SMDSAbs_Edge;   break;
491         case FACE  : type = SMDSAbs_Face;   break;
492         case VOLUME: type = SMDSAbs_Volume; break;
493         default: return;
494         }
495         TColStd_MapOfInteger newIndices;
496         QStringList aListId = theNewText.split( " ", QString::SkipEmptyParts);
497         for ( int i = 0; i < aListId.count(); i++ ) {
498           if ( const SMDS_MeshElement * e = aMesh->FindElement( aListId[ i ].toInt() ))
499             if ( e->GetType() == type )
500               newIndices.Add( e->GetID() );
501         }
502         
503         if ( !newIndices.IsEmpty() )
504         {
505           if (!myIsMultipleAllowed && newIndices.Extent() != 1)
506             return;
507           if ( SVTK_Selector* s = selector() ) {
508             s->AddOrRemoveIndex( actor->getIO(), newIndices, false );
509             viewWindow()->highlight( actor->getIO(), true, true );
510             myDlg->setButtonEnabled( true, QtxDialog::OK );
511           }
512         }
513       }
514     }
515   }
516 }
517
518 //=======================================================================
519 //function : setElementID
520 //purpose  : programmatically set element id
521 //=======================================================================
522
523 void SMESHGUI_ShapeByMeshOp::setElementID(const QString& theText)
524 {
525   myIsManualIdEnter = false;
526   myDlg->myElementId->setText(theText);
527   myIsManualIdEnter = true;
528 }