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