]> SALOME platform Git repositories - modules/smesh.git/blob - src/SMESHGUI/SMESHGUI_ReorientFacesDlg.cxx
Salome HOME
bos #29143 [CEA] Compute takes too much time in polyhedron per solid use case
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_ReorientFacesDlg.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
23 // File   : SMESHGUI_ReorientFacesDlg.cxx
24 // Author : Edward AGAPOV, Open CASCADE S.A.S.
25 // SMESH includes
26 //
27 #include "SMESHGUI_ReorientFacesDlg.h"
28
29 #include "SMESHGUI.h"
30 #include "SMESHGUI_IdValidator.h"
31 #include "SMESHGUI_MeshUtils.h"
32 #include "SMESHGUI_VTKUtils.h"
33 #include "SMESHGUI_SpinBox.h"
34 #include "SMESHGUI_MeshEditPreview.h"
35
36 #include <SMDS_Mesh.hxx>
37 #include <SMESH_Actor.h>
38 #include <SMESH_ActorUtils.h>
39 #include <SMESH_NumberFilter.hxx>
40 #include <SMESH_LogicalFilter.hxx>
41 #include <SMESH_TypeFilter.hxx>
42
43 // SALOME GEOM includes
44 #include <GEOMBase.h>
45
46 // SALOME GUI includes
47 #include <LightApp_SelectionMgr.h>
48 #include <SALOME_ListIO.hxx>
49 #include <SUIT_Desktop.h>
50 #include <SUIT_MessageBox.h>
51 #include <SUIT_OverrideCursor.h>
52 #include <SUIT_ResourceMgr.h>
53 #include <SVTK_ViewModel.h>
54 #include <SVTK_ViewWindow.h>
55 #include <SalomeApp_Tools.h>
56 #include <SalomeApp_TypeFilter.h>
57
58 // SALOME KERNEL includes
59 #include <SALOMEDS_SObject.hxx>
60
61 // OCCT includes
62 #include <BRep_Tool.hxx>
63 #include <TColStd_MapOfInteger.hxx>
64 #include <TColgp_SequenceOfXYZ.hxx>
65 #include <TopoDS_Vertex.hxx>
66 #include <gp_Pnt.hxx>
67
68 // Qt includes
69 #include <QGroupBox>
70 #include <QGridLayout>
71 #include <QHBoxLayout>
72 #include <QVBoxLayout>
73 #include <QLineEdit>
74 #include <QPushButton>
75 #include <QLabel>
76 #include <QRadioButton>
77 #include <QCheckBox>
78 #include <QButtonGroup>
79
80 // VTK includes
81 #include <vtkProperty.h>
82
83 // IDL includes
84 #include CORBA_SERVER_HEADER(SMESH_MeshEditor)
85
86 // std
87 #include <limits>
88
89 #define SPACING 6
90 #define MARGIN  11
91
92 enum { CONSTRUCTOR_POINT=0, CONSTRUCTOR_FACE, CONSTRUCTOR_FACE_GROUPS, CONSTRUCTOR_VOLUME,
93        EObject, EPoint, EFace, EDirection, ERefGroups };
94
95 //=======================================================================
96 /*!
97  * \brief Dialog to reorient faces according to vector
98  */
99 //=======================================================================
100
101 SMESHGUI_ReorientFacesDlg::SMESHGUI_ReorientFacesDlg()
102   : SMESHGUI_Dialog( 0, false, true )
103 {
104   setWindowTitle(tr("CAPTION"));
105
106   QVBoxLayout* aDlgLay = new QVBoxLayout (mainFrame());
107   aDlgLay->setMargin(0);
108   aDlgLay->setSpacing(SPACING);
109
110   QWidget* aMainFrame = createMainFrame  (mainFrame());
111
112   aDlgLay->addWidget(aMainFrame);
113
114   aDlgLay->setStretchFactor(aMainFrame, 1);
115 }
116
117 //================================================================================
118 /*!
119  * \brief Create frame containing dialog's input fields
120  */
121 //================================================================================
122
123 QWidget* SMESHGUI_ReorientFacesDlg::createMainFrame (QWidget* theParent)
124 {
125   QWidget* aFrame = new QWidget(theParent);
126
127   // constructors
128
129   QPixmap iconReoriPoint (resMgr()->loadPixmap("SMESH", tr("ICON_DLG_REORIENT2D_POINT")));
130   QPixmap iconReoriFace  (resMgr()->loadPixmap("SMESH", tr("ICON_DLG_REORIENT2D_FACE")));
131   QPixmap iconReoriGroups(resMgr()->loadPixmap("SMESH", tr("ICON_DLG_REORIENT2D_GROUPS")));
132   QPixmap iconReoriVolum (resMgr()->loadPixmap("SMESH", tr("ICON_DLG_REORIENT2D_VOLUME")));
133
134   QGroupBox* aConstructorBox = new QGroupBox(tr("REORIENT_FACES"), aFrame);
135   myConstructorGrp = new QButtonGroup(aConstructorBox);
136   QHBoxLayout* aConstructorGrpLayout = new QHBoxLayout(aConstructorBox);
137   aConstructorGrpLayout->setMargin(MARGIN);
138   aConstructorGrpLayout->setSpacing(SPACING);
139
140   QRadioButton* aPntBut = new QRadioButton(aConstructorBox);
141   aPntBut->setIcon(iconReoriPoint);
142   aPntBut->setChecked(true);
143   aConstructorGrpLayout->addWidget(aPntBut);
144   myConstructorGrp->addButton(aPntBut, CONSTRUCTOR_POINT);
145
146   QRadioButton* aFaceBut= new QRadioButton(aConstructorBox);
147   aFaceBut->setIcon(iconReoriFace);
148   aConstructorGrpLayout->addWidget(aFaceBut);
149   myConstructorGrp->addButton(aFaceBut, CONSTRUCTOR_FACE);
150
151   QRadioButton* aGroupBut= new QRadioButton(aConstructorBox);
152   aGroupBut->setIcon(iconReoriGroups);
153   aConstructorGrpLayout->addWidget(aGroupBut);
154   myConstructorGrp->addButton(aGroupBut, CONSTRUCTOR_FACE_GROUPS);
155
156   QRadioButton* aVolBut= new QRadioButton(aConstructorBox);
157   aVolBut->setIcon(iconReoriVolum);
158   aConstructorGrpLayout->addWidget(aVolBut);
159   myConstructorGrp->addButton(aVolBut, CONSTRUCTOR_VOLUME);
160
161   // Create other controls
162
163   setObjectPixmap( "SMESH", tr( "ICON_SELECT" ) );
164
165   createObject( tr("OBJECT")   , aFrame, EObject );
166   createObject( tr("POINT")    , aFrame, EPoint );
167   createObject( tr("FACE")     , aFrame, EFace );
168   createObject( tr("DIRECTION"), aFrame, EDirection );
169   createObject( tr("VOLUMES"),   aFrame, ERefGroups );
170   setNameIndication( EObject, ListOfNames );
171   setNameIndication( EFace, OneName );
172   setNameIndication( ERefGroups, ListOfNames );
173   setReadOnly( EFace, false );
174   if ( QLineEdit* le = qobject_cast<QLineEdit*>( objectWg( EFace, Control ) ))
175     le->setValidator( new SMESHGUI_IdValidator( this,1 ));
176
177   int width = aFaceBut->fontMetrics().width( tr("DIRECTION"));
178   objectWg( EDirection, Label )->setFixedWidth( width );
179   objectWg( EObject   , Label )->setFixedWidth( width );
180   objectWg( EPoint    , Label )->setFixedWidth( width );
181   objectWg( EFace     , Label )->setFixedWidth( width );
182
183   myOutsideChk = new QCheckBox( tr("OUTSIDE_VOLUME_NORMAL"), aFrame);
184   myOutsideChk->setChecked( true );
185
186   QLabel* aXLabel = new QLabel(tr("SMESH_X"), aFrame);
187   myX = new SMESHGUI_SpinBox(aFrame);
188   QLabel* aYLabel = new QLabel(tr("SMESH_Y"), aFrame);
189   myY = new SMESHGUI_SpinBox(aFrame);
190   QLabel* aZLabel = new QLabel(tr("SMESH_Z"), aFrame);
191   myZ = new SMESHGUI_SpinBox(aFrame);
192
193   myX->RangeStepAndValidator(COORD_MIN, COORD_MAX, 10.0, "length_precision");
194   myY->RangeStepAndValidator(COORD_MIN, COORD_MAX, 10.0, "length_precision");
195   myZ->RangeStepAndValidator(COORD_MIN, COORD_MAX, 10.0, "length_precision");
196   myX->SetValue(0);
197   myY->SetValue(0);
198   myZ->SetValue(0);
199
200   QLabel* aDXLabel = new QLabel(tr("SMESH_DX"), aFrame);
201   myDX = new SMESHGUI_SpinBox(aFrame);
202   QLabel* aDYLabel = new QLabel(tr("SMESH_DY"), aFrame);
203   myDY = new SMESHGUI_SpinBox(aFrame);
204   QLabel* aDZLabel = new QLabel(tr("SMESH_DZ"), aFrame);
205   myDZ = new SMESHGUI_SpinBox(aFrame);
206   myDX->SetValue(1);
207   myDY->SetValue(0);
208   myDZ->SetValue(0);
209
210   myDX->RangeStepAndValidator(COORD_MIN, COORD_MAX, 1.0, "length_precision");
211   myDY->RangeStepAndValidator(COORD_MIN, COORD_MAX, 1.0, "length_precision");
212   myDZ->RangeStepAndValidator(COORD_MIN, COORD_MAX, 1.0, "length_precision");
213
214   width = Max( aFaceBut->fontMetrics().width( tr("SMESH_X")),
215                aFaceBut->fontMetrics().width( tr("SMESH_DX")));
216   aXLabel->setFixedWidth( width );
217   aYLabel->setFixedWidth( width );
218   aZLabel->setFixedWidth( width );
219   aDXLabel->setFixedWidth( width );
220   aDYLabel->setFixedWidth( width );
221   aDZLabel->setFixedWidth( width );
222
223   // Layouting
224
225   QGroupBox* anObjectGrp = new QGroupBox(tr("FACES"), aFrame);
226   QHBoxLayout* anObjectGrpLayout = new QHBoxLayout(anObjectGrp);
227   anObjectGrpLayout->setMargin(MARGIN);
228   anObjectGrpLayout->setSpacing(SPACING);
229   anObjectGrpLayout->addWidget( objectWg( EObject, Label ));
230   anObjectGrpLayout->addWidget( objectWg( EObject, Btn ));
231   anObjectGrpLayout->addWidget( objectWg( EObject, Control ));
232
233   myPointFrm = new QFrame(aFrame);
234   QHBoxLayout* aPointGrpLayout = new QHBoxLayout(myPointFrm);
235   aPointGrpLayout->setMargin(0);
236   objectWg( EPoint, Control )->hide();
237   aPointGrpLayout->addWidget( objectWg( EPoint, Label ) );
238   aPointGrpLayout->addWidget( objectWg( EPoint, Btn ) );
239   aPointGrpLayout->addWidget( aXLabel, 0 );
240   aPointGrpLayout->addWidget( myX,     1 );
241   aPointGrpLayout->addWidget( aYLabel, 0 );
242   aPointGrpLayout->addWidget( myY,     1 );
243   aPointGrpLayout->addWidget( aZLabel, 0 );
244   aPointGrpLayout->addWidget( myZ,     1 );
245
246   myFaceFrm = new QFrame(aFrame);
247   QHBoxLayout* aFaceGrpLayout = new QHBoxLayout(myFaceFrm);
248   aFaceGrpLayout->setMargin(0);
249   aFaceGrpLayout->addWidget( objectWg( EFace, Label ) );
250   aFaceGrpLayout->addWidget( objectWg( EFace, Btn ) );
251   aFaceGrpLayout->addWidget( objectWg( EFace, Control ) );
252
253   myRefGroupFrm = new QFrame(aFrame);
254   QGridLayout* aRefGrpLayout = new QGridLayout(myRefGroupFrm);
255   aRefGrpLayout->setMargin(0);
256   aRefGrpLayout->setSpacing(SPACING);
257   aRefGrpLayout->addWidget( objectWg( ERefGroups, Label ),   0, 0 );
258   aRefGrpLayout->addWidget( objectWg( ERefGroups, Btn ),     0, 1 );
259   aRefGrpLayout->addWidget( objectWg( ERefGroups, Control ), 0, 2 );
260   aRefGrpLayout->addWidget( myOutsideChk,                    1, 0, 1, 3 );
261
262   myDirFrm = new QFrame(aFrame);
263   QHBoxLayout* aDirectGrpLayout = new QHBoxLayout(myDirFrm);
264   aDirectGrpLayout->setMargin(0);
265   objectWg( EDirection, Control )->hide();
266   aDirectGrpLayout->addWidget( objectWg( EDirection, Label ) );
267   aDirectGrpLayout->addWidget( objectWg( EDirection, Btn ) );
268   aDirectGrpLayout->addWidget( aDXLabel, 0 );
269   aDirectGrpLayout->addWidget( myDX,     1 );
270   aDirectGrpLayout->addWidget( aDYLabel, 0 );
271   aDirectGrpLayout->addWidget( myDY,     1 );
272   aDirectGrpLayout->addWidget( aDZLabel, 0 );
273   aDirectGrpLayout->addWidget( myDZ,     1 );
274   
275
276   QGroupBox* anOrientGrp = new QGroupBox(tr("ORIENTATION"), aFrame);
277   QVBoxLayout* anOrientGrpLayout = new QVBoxLayout ( anOrientGrp );
278   anOrientGrpLayout->addWidget(myPointFrm);
279   anOrientGrpLayout->addWidget(myFaceFrm);
280   anOrientGrpLayout->addWidget(myRefGroupFrm);
281   anOrientGrpLayout->addWidget(myDirFrm);
282   
283
284   QVBoxLayout* aLay = new QVBoxLayout(aFrame);
285   aLay->addWidget(aConstructorBox);
286   aLay->addWidget(anObjectGrp);
287   aLay->addWidget(anOrientGrp);
288
289   connect( myConstructorGrp, SIGNAL(buttonClicked (int)), this, SLOT(constructorChange(int)));
290
291   return aFrame;
292 }
293
294 //================================================================================
295 /*!
296  * \brief Show point or face
297  */
298 //================================================================================
299
300 void SMESHGUI_ReorientFacesDlg::constructorChange(int id)
301 {
302   if ( id == CONSTRUCTOR_FACE )
303   {
304     myPointFrm->hide();
305     myRefGroupFrm->hide();
306     myFaceFrm->show();
307     myDirFrm->show();
308     activateObject( EFace );
309   }
310   else if ( id == CONSTRUCTOR_POINT )
311   {
312     myFaceFrm->hide();
313     myRefGroupFrm->hide();
314     myPointFrm->show();
315     myDirFrm->show();
316     activateObject( EPoint );
317   }
318   else // CONSTRUCTOR_VOLUME || CONSTRUCTOR_FACE_GROUPS
319   {
320     myFaceFrm->hide();
321     myPointFrm->hide();
322     myDirFrm->hide();
323     myOutsideChk->setVisible( id == CONSTRUCTOR_VOLUME );
324     myRefGroupFrm->show();
325     QAbstractButton* refButton = qobject_cast<QAbstractButton*>( objectWg( ERefGroups, Btn ));
326     refButton->setChecked( false ); // force ERefGroups activation
327     activateObject( ERefGroups );
328     setLabel( ERefGroups, id == CONSTRUCTOR_VOLUME ? "VOLUMES" : "REF_GROUPS" );
329   }
330
331   // minimize width of labels
332   QFontMetrics font = objectWg( EDirection, Label )->fontMetrics();
333   int width = 0;
334   for ( int obj = EObject; obj <= ERefGroups; ++obj )
335   {
336     QLabel* label = qobject_cast< QLabel* >( objectWg( obj, Label ));
337     if ( label->isVisible() )
338       width = std::max( width, font.width( label->text() ));
339   }
340
341   for ( int obj = EObject; obj <= ERefGroups; ++obj )
342   {
343     QWidget* label = objectWg( obj, Label );
344     if ( label->isVisible() )
345       label->setFixedWidth( width );
346   }
347 }
348
349 //================================================================================
350 /*!
351  * \brief Set object label
352  */
353 //================================================================================
354
355 void SMESHGUI_ReorientFacesDlg::setLabel( int object, const char* text )
356 {
357   qobject_cast< QLabel* >( objectWg( object, Label ))->setText( tr( text ));
358 }
359
360 //================================================================================
361 /*!
362  * \brief Constructor
363  */
364 //================================================================================
365
366 SMESHGUI_ReorientFacesOp::SMESHGUI_ReorientFacesOp()
367   :SMESHGUI_SelectionOp( ActorSelection )
368 {
369   //myVectorPreview = 0;
370   myHelpFileName = "reorient_faces.html";
371
372   myDlg = new SMESHGUI_ReorientFacesDlg;
373   myDlg->constructorChange( CONSTRUCTOR_POINT );
374
375   myRefGroupFilter   = new SMESH_TypeFilter( SMESH::GROUP_VOLUME );
376   myRefSubMeshFilter = new SMESH_TypeFilter( SMESH::SUBMESH_SOLID );
377   myRefMeshFilter    = new SMESH_TypeFilter( SMESH::MESH );
378
379   myObjects   = new SMESH::ListOfIDSources();
380   myRefGroups = new SMESH::ListOfIDSources();
381
382   // connect signals and slots
383   connect( myDlg->objectWg( EFace, LightApp_Dialog::Control ), SIGNAL(textChanged(const QString&)),
384            this, SLOT(onTextChange(const QString&)));
385 }
386
387 //=======================================================================
388 // function : startOperation()
389 // purpose  : Init dialog fields, connect signals and slots, show dialog
390 //=======================================================================
391
392 void SMESHGUI_ReorientFacesOp::startOperation()
393 {
394   myObjectActor = 0;
395
396   SMESHGUI_SelectionOp::startOperation();
397
398   myDlg->show();
399
400   mySelectionMode = EObject;
401   myDlg->activateObject( EObject );
402
403   selectionDone();
404 }
405
406 //================================================================================
407 /*!
408  * \brief Stops operation
409  */
410 //================================================================================
411
412 void SMESHGUI_ReorientFacesOp::stopOperation()
413 {
414   if ( myObjectActor )
415   {
416     myObjectActor->SetPointRepresentation(false);
417     SMESH::RepaintCurrentView();
418     myObjectActor = 0;
419   }
420   SMESHGUI_SelectionOp::stopOperation();
421   myDlg->deactivateAll();
422 }
423
424 //================================================================================
425 /*!
426  * \brief Set selection mode corresponding to a pressed selection button
427  */
428 //================================================================================
429
430 void SMESHGUI_ReorientFacesOp::onActivateObject( int what )
431 {
432   if ( what == mySelectionMode )
433   {
434     if ( what == ERefGroups )
435       setRefFiltersByConstructor();
436   }
437   else
438   {
439     mySelectionMode = what;
440     switch ( mySelectionMode )
441     {
442     case EPoint:
443     case EDirection:
444       SMESH::SetPointRepresentation(true);
445       setSelectionMode( NodeSelection );
446       SMESH::SetPickable();
447       break;
448     case EObject:
449       SMESH::SetPointRepresentation(false);
450       setSelectionMode( ActorSelection );
451       break;
452     case ERefGroups:
453       SMESH::SetPointRepresentation(false);
454       setSelectionMode( ActorSelection );
455       setRefFiltersByConstructor();
456       break;
457     case EFace:
458       SMESH::SetPointRepresentation(false);
459       setSelectionMode( FaceSelection );
460       if ( myObjectActor )
461         SMESH::SetPickable( myObjectActor );
462       else
463         SMESH::SetPickable();
464       break;
465     }
466   }
467   SMESHGUI_SelectionOp::onActivateObject( what );
468
469   myDlg->setLabel( EObject, onlyOneObjAllowed() ? "OBJECT" : "OBJECTS" );
470 }
471
472 //================================================================================
473 /*!
474  * \brief Creates a filter corresponding to a pressed selection button
475  */
476 //================================================================================
477
478 SUIT_SelectionFilter* SMESHGUI_ReorientFacesOp::createFilter( const int what ) const
479 {
480   switch ( what )
481   {
482   case EObject:
483     {
484       QList<SUIT_SelectionFilter*> filters;
485       filters.append( new SMESH_TypeFilter( SMESH::MESH ));
486       filters.append( new SMESH_TypeFilter( SMESH::SUBMESH_FACE ));
487       filters.append( new SMESH_TypeFilter( SMESH::GROUP_FACE ));
488       return new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR );
489     }
490   case ERefGroups:
491     {
492       QList<SUIT_SelectionFilter*> filters;
493       filters <<  myRefGroupFilter << myRefSubMeshFilter << myRefMeshFilter;
494       return new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR );
495     }
496   case EPoint:
497     {
498       QList<SUIT_SelectionFilter*> filters;
499       filters.append( new SMESH_TypeFilter( SMESH::IDSOURCE ));
500       filters.append( new SMESH_NumberFilter( "GEOM",TopAbs_VERTEX, 1, TopAbs_VERTEX ));
501       return new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR );
502     }
503   case EFace:
504   case EDirection:
505     {
506       return new SMESH_TypeFilter( SMESH::IDSOURCE );
507     }
508   }
509   return NULL;
510 }
511
512 //================================================================================
513 /*!
514  * \brief Switch between selection of faces and volumes according to the constructor
515  */
516 //================================================================================
517
518 void SMESHGUI_ReorientFacesOp::setRefFiltersByConstructor()
519 {
520   if ( constructorID() == CONSTRUCTOR_VOLUME )
521   {
522     myRefMeshFilter   ->setType( SMESH::MESH );// SMESH::NB_SMESH_TYPES
523     myRefGroupFilter  ->setType( SMESH::GROUP_VOLUME );
524     myRefSubMeshFilter->setType( SMESH::SUBMESH_SOLID );
525   }
526   else
527   {
528     myRefMeshFilter   ->setType( SMESH::NB_SMESH_TYPES ); // mesh not allowed
529     myRefGroupFilter  ->setType( SMESH::GROUP_FACE );
530     myRefSubMeshFilter->setType( SMESH::SUBMESH_FACE );
531   }
532 }
533
534 //================================================================================
535 /*!
536  * \brief get data from selection
537  */
538 //================================================================================
539
540 void SMESHGUI_ReorientFacesOp::selectionDone()
541 {
542   if ( !myDlg->isVisible() || !myDlg->isEnabled() )
543     return;
544
545   myDlg->clearSelection( mySelectionMode );
546
547   SALOME_ListIO aList;
548   selectionMgr()->selectedObjects(aList);
549   const int nbSelected = aList.Extent();
550   if ( nbSelected == 0 )
551     return;
552
553   if ( onlyOneObjAllowed() && nbSelected != 1 )
554     return;
555
556   if ( mySelectionMode == ERefGroups )
557   {
558     SMESHGUI_SelectionOp::selectionDone();
559     return;
560   }
561
562   Handle(SALOME_InteractiveObject) anIO = aList.First();
563
564   try
565   {
566     switch ( mySelectionMode )
567     {
568     case EObject: { // get an actor of object
569
570       SMESHGUI_SelectionOp::selectionDone();
571       myObjectActor = SMESH::FindActorByEntry( anIO->getEntry() );
572       break;
573     }
574     case EFace: {  // get a face ID
575
576       SVTK_TIndexedMapOfVtkId faceIndices;
577       selector()->GetIndex( anIO, faceIndices );
578       if ( faceIndices.Extent() == 1 )
579       {
580         SMESH_Actor* savedActor = myObjectActor;
581         myObjectActor = 0; // to prevent work of onTextChange()
582         myDlg->setObjectText( EFace, QString("%1").arg( faceIndices(1) ));
583         myObjectActor = savedActor;
584
585         if ( !myObjectActor )
586         {
587           myDlg->selectObject( EObject, anIO->getName(), 0, anIO->getEntry(), true );
588           // typeById( aList.First()->getEntry(),
589           //           SMESHGUI_SelectionOp::Object ),
590           myObjectActor = SMESH::FindActorByEntry( anIO->getEntry() );
591         }
592       }
593       break;
594     }
595     case EPoint:
596     case EDirection: {  // set XYZ by selected nodes or vertices
597
598       TColgp_SequenceOfXYZ points;
599       for( SALOME_ListIteratorOfListIO anIt( aList ); anIt.More(); anIt.Next() )
600       {
601         anIO = anIt.Value();
602         GEOM::GEOM_Object_var geom = SMESH::IObjectToInterface<GEOM::GEOM_Object>(anIO);
603         if ( !geom->_is_nil() ) {
604           TopoDS_Vertex aShape;
605           if ( GEOMBase::GetShape(geom, aShape) && aShape.ShapeType() == TopAbs_VERTEX ) {
606             gp_Pnt P = BRep_Tool::Pnt(aShape);
607             points.Append( P.XYZ() );
608           }
609         }
610         else
611         {
612           SVTK_TIndexedMapOfVtkId nodeIndices;
613           selector()->GetIndex( anIO, nodeIndices );
614           if ( nodeIndices.Extent() > 0 && nodeIndices.Extent() <=2 )
615           {
616             if ( SMESH_Actor* aMeshActor = SMESH::FindActorByEntry(anIO->getEntry()))
617               if (SMDS_Mesh* aMesh = aMeshActor->GetObject()->GetMesh())
618               {
619                 if (const SMDS_MeshNode* aNode = aMesh->FindNode( nodeIndices(1)))
620                   points.Append( gp_XYZ( aNode->X(), aNode->Y(), aNode->Z()));
621                 if ( nodeIndices.Extent() == 2 )
622                   if (const SMDS_MeshNode* aNode = aMesh->FindNode( nodeIndices(2)))
623                     points.Append( gp_XYZ( aNode->X(), aNode->Y(), aNode->Z()));
624               }
625           }
626         }
627       }
628       gp_XYZ xyz;
629       if ( points.Length() == 1 )
630         xyz = points(1);
631       else if ( points.Length() == 2 )
632         xyz = points(2) - points(1);
633       else
634         return;
635       if ( points.Length() == 1 && mySelectionMode == EPoint )
636       {
637         myDlg->myX->SetValue( xyz.X() );
638         myDlg->myY->SetValue( xyz.Y() );
639         myDlg->myZ->SetValue( xyz.Z() );
640         redisplayPreview();
641       }
642       if ( mySelectionMode == EDirection )
643       {
644         myDlg->myDX->SetValue( xyz.X() );
645         myDlg->myDY->SetValue( xyz.Y() );
646         myDlg->myDZ->SetValue( xyz.Z() );
647         redisplayPreview();
648       }
649       break;
650     } // case EPoint || EDirection
651     } // switch
652   }
653   catch (...)
654   {
655   }
656 }
657
658 //================================================================================
659 /*!
660  * \brief SLOT called when the face id is changed
661  */
662 //================================================================================
663
664 void SMESHGUI_ReorientFacesOp::onTextChange( const QString& theText )
665 {
666   if( myObjectActor )
667   {
668     sender()->blockSignals( true );
669     if ( mySelectionMode != EFace )
670     {
671       myDlg->activateObject( EFace );
672       myDlg->setObjectText( EFace, theText );
673     }
674     SVTK_TVtkIDsMap ids;
675     if ( !theText.isEmpty() && theText.toInt() > 0 )
676       ids.Add( theText.toInt() );
677
678     SMESHGUI_SelectionOp::addOrRemoveIndex( myObjectActor->getIO(), ids, false );
679     SMESHGUI_SelectionOp::highlight( myObjectActor->getIO(), true, true );
680     sender()->blockSignals( false );
681   }
682 }
683
684 //================================================================================
685 /*!
686  * \brief perform it's intention action: reorient faces of myObject
687  */
688 //================================================================================
689
690 bool SMESHGUI_ReorientFacesOp::onApply()
691 {
692   if( SMESHGUI::isStudyLocked() )
693     return false;
694
695   QString msg;
696   if ( !isValid( msg ) ) { // node id is invalid
697     if( !msg.isEmpty() )
698       SUIT_MessageBox::warning( dlg(), tr( "SMESH_WRN_WARNING" ), msg );
699     dlg()->show();
700     return false;
701   }
702
703   QStringList aParameters;
704   aParameters << myDlg->myDX->text();
705   aParameters << myDlg->myDY->text();
706   aParameters << myDlg->myDZ->text();
707   aParameters << myDlg->myX->text();
708   aParameters << myDlg->myY->text();
709   aParameters << myDlg->myZ->text();
710
711   try {
712     SUIT_OverrideCursor wc;
713
714     SMESH::SMESH_Mesh_var aMesh = myObjects[0]->GetMesh();
715     if ( aMesh->_is_nil() ) return false;
716
717     SMESH::SMESH_MeshEditor_var aMeshEditor = aMesh->GetMeshEditor();
718     if (aMeshEditor->_is_nil()) return false;
719
720     int aResult = 0;
721     switch ( constructorID() )
722     {
723     case CONSTRUCTOR_VOLUME:
724     {
725       bool outsideNormal = myDlg->myOutsideChk->isChecked();
726
727       aResult = aMeshEditor->Reorient2DBy3D( myObjects, myRefGroups[0], outsideNormal );
728
729       break;
730     }
731     case CONSTRUCTOR_FACE_GROUPS:
732     {
733       aResult = aMeshEditor->Reorient2DByNeighbours( myObjects, myRefGroups );
734
735       break;
736     }
737     default:
738     {
739       SMESH::DirStruct direction;
740       direction.PS.x = myDlg->myDX->GetValue();
741       direction.PS.y = myDlg->myDY->GetValue();
742       direction.PS.z = myDlg->myDZ->GetValue();
743
744       long face = myDlg->objectText( EFace ).toInt();
745       if ( constructorID() == CONSTRUCTOR_POINT )
746         face = -1;
747
748       SMESH::PointStruct point;
749       point.x = myDlg->myX->GetValue();
750       point.y = myDlg->myY->GetValue();
751       point.z = myDlg->myZ->GetValue();
752
753       aMesh->SetParameters( aParameters.join(":").toUtf8().constData() );
754
755       aResult = aMeshEditor->Reorient2D( myObjects[0], direction, face, point );
756     }
757     }
758
759     if (aResult)
760     {
761       SALOME_ListIO aList;
762       selectionMgr()->setSelectedObjects(aList,false);
763       SMESH::UpdateView();
764       SMESHGUI::Modified();
765     }
766     wc.suspend();
767     SUIT_MessageBox::information(SMESHGUI::desktop(), tr("SMESH_INFORMATION"),
768                                  tr("NB_REORIENTED").arg(aResult));
769   }
770   catch (const SALOME::SALOME_Exception& S_ex) {
771     SalomeApp_Tools::QtCatchCorbaException(S_ex);
772   }
773   catch (...) {
774   }
775
776   return true;
777 }
778
779 //================================================================================
780 /*!
781  * \brief Check data validity
782  */
783 //================================================================================
784
785 bool SMESHGUI_ReorientFacesOp::isValid( QString& msg )
786 {
787   // Check objects
788
789   QStringList objectEntries;
790   myDlg->selectedObject( EObject, objectEntries );
791   if ( objectEntries.size() == 0 )
792   {
793     msg = tr("NO_OBJECT_SELECTED");
794     return false;
795   }
796   myObjects->length( objectEntries.size() );
797   int nbObj = 0;
798   for ( QString & entry : objectEntries )
799   {
800     SMESH::SMESH_IDSource_var obj = SMESH::EntryToInterface< SMESH::SMESH_IDSource >( entry );
801     if ( !obj->_is_nil() )
802     {
803       bool hasFaces = false;
804       SMESH::array_of_ElementType_var types = obj->GetTypes();
805       for ( size_t i = 0; i < types->length() && !hasFaces; ++i )
806         hasFaces = ( types[i] == SMESH::FACE );
807       if ( hasFaces )
808         myObjects[ nbObj++ ] = SMESH::SMESH_IDSource::_duplicate( obj );
809     }
810   }
811   if ( nbObj == 0 )
812   {
813     msg = tr("NO_FACES");
814     return false;
815   }
816   myObjects->length( nbObj );
817
818   // Check volume object or ref faces
819
820   int constructorType = constructorID();
821   if ( constructorType >= CONSTRUCTOR_FACE_GROUPS )
822   {
823     objectEntries.clear();
824     myDlg->selectedObject( ERefGroups, objectEntries );
825     myRefGroups->length( objectEntries.size() );
826     nbObj = 0;
827     for ( QString & entry : objectEntries )
828     {
829       SMESH::SMESH_IDSource_var obj = SMESH::EntryToInterface< SMESH::SMESH_IDSource >( entry );
830       if ( !obj->_is_nil() )
831       {
832         bool hasElems = false;
833         SMESH::ElementType elemType =
834           ( constructorType == CONSTRUCTOR_VOLUME ? SMESH::VOLUME : SMESH::FACE );
835         SMESH::array_of_ElementType_var types = obj->GetTypes();
836         for ( size_t i = 0; i < types->length() && !hasElems; ++i )
837           hasElems = ( types[i] == elemType );
838         if ( hasElems )
839           myRefGroups[ nbObj++ ] = SMESH::SMESH_IDSource::_duplicate( obj );
840       }
841     }
842     if ( nbObj == 0 && constructorType == CONSTRUCTOR_VOLUME )
843     {
844       msg = tr("NO_VOLUMES");
845       return false;
846     }
847     myRefGroups->length( nbObj );
848   }
849
850   // Check vector
851
852   gp_Vec vec( myDlg->myDX->GetValue(),
853               myDlg->myDY->GetValue(),
854               myDlg->myDZ->GetValue() );
855   if ( vec.Magnitude() < std::numeric_limits<double>::min() )
856   {
857     msg = tr("ZERO_SIZE_VECTOR");
858     return false;
859   }
860
861   // Check face ID
862
863   if ( constructorID() == CONSTRUCTOR_FACE )
864   {
865     int faceID = myDlg->objectText( EFace ).toInt();
866     bool faceOK = ( faceID > 0 );
867     if ( faceOK )
868     {
869       if ( myObjectActor )
870       {
871         faceOK = ( myObjectActor->GetObject()->GetElemDimension( faceID ) == 2 );
872       }
873       else
874       {
875         SMESH::SMESH_Mesh_var aMesh = myObjects[0]->GetMesh();
876         if ( !aMesh->_is_nil() )
877           faceOK = ( aMesh->GetElementType( faceID, true ) == SMESH::FACE );
878       }
879     }
880     if ( !faceOK )
881     {
882       msg = tr("INVALID_FACE");
883       return false;
884     }
885   }
886
887   return true;
888 }
889
890 //================================================================================
891 /*!
892  * \brief Destructor
893  */
894 //================================================================================
895
896 SMESHGUI_ReorientFacesOp::~SMESHGUI_ReorientFacesOp()
897 {
898   if ( myDlg )        delete myDlg;
899   //if ( myVectorPreview ) delete myVectorPreview;
900 }
901
902 //================================================================================
903 /*!
904  * \brief Gets dialog of this operation
905  * \retval LightApp_Dialog* - pointer to dialog of this operation
906  */
907 //================================================================================
908
909 LightApp_Dialog* SMESHGUI_ReorientFacesOp::dlg() const
910 {
911   return myDlg;
912 }
913
914 //================================================================================
915 /*!
916  * \brief ID of a current constructor: CONSTRUCTOR_FACE, CONSTRUCTOR_POINT etc.
917  */
918 //================================================================================
919
920 int SMESHGUI_ReorientFacesOp::constructorID()
921 {
922   return myDlg->myConstructorGrp->checkedId();
923 }
924
925 //================================================================================
926 /*!
927  * \brief Check if selection of multiple objects allowed
928  */
929 //================================================================================
930
931 bool SMESHGUI_ReorientFacesOp::onlyOneObjAllowed()
932 {
933   return (( constructorID() <= CONSTRUCTOR_FACE ) ||
934           ( constructorID() == CONSTRUCTOR_VOLUME && mySelectionMode == ERefGroups ));
935 }
936
937 //================================================================================
938 /*!
939  * \brief update preview
940  */
941 //================================================================================
942
943 void SMESHGUI_ReorientFacesOp::redisplayPreview()
944 {
945 }