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