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