1 // Copyright (C) 2007-2013 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
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.
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.
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
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 // File : SMESHGUI_Measurements.cxx
23 // Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
25 #include "SMESHGUI_Measurements.h"
27 #include "SMESH_Actor.h"
29 #include "SMESHGUI_IdValidator.h"
30 #include "SMESHGUI_Utils.h"
31 #include "SMESHGUI_VTKUtils.h"
32 #include <SMESH_TypeFilter.hxx>
33 #include <SMESH_LogicalFilter.hxx>
35 #include <LightApp_SelectionMgr.h>
36 #include <SUIT_OverrideCursor.h>
37 #include <SUIT_ResourceMgr.h>
38 #include <SVTK_ViewWindow.h>
39 #include <SALOME_ListIteratorOfListIO.hxx>
41 #include <QButtonGroup>
42 #include <QGridLayout>
44 #include <QHBoxLayout>
48 #include <QPushButton>
49 #include <QRadioButton>
51 #include <QVBoxLayout>
53 #include <vtkPoints.h>
54 #include <vtkUnstructuredGrid.h>
55 #include <vtkIdList.h>
56 #include <vtkCellArray.h>
57 #include <vtkUnsignedCharArray.h>
58 #include <vtkDataSetMapper.h>
59 #include <VTKViewer_CellLocationsArray.h>
60 #include <vtkProperty.h>
62 #include <SALOMEconfig.h>
63 #include CORBA_SERVER_HEADER(SMESH_MeshEditor)
64 #include CORBA_SERVER_HEADER(SMESH_Measurements)
66 const int SPACING = 6; // layout spacing
67 const int MARGIN = 9; // layout margin
68 const int MAX_NB_FOR_EDITOR = 40; // max nb of items in the ID list editor field
70 // Uncomment as soon as elements are supported by Min Distance operation
71 //#define MINDIST_ENABLE_ELEMENT
73 // Uncomment as soon as objects are supported by Min Distance operation
74 //#define MINDIST_ENABLE_OBJECT
77 \class SMESHGUI_MinDistance
78 \brief Minimum distance measurement widget.
80 Widget to calculate minimum distance between two objects.
85 \param parent parent widget
87 SMESHGUI_MinDistance::SMESHGUI_MinDistance( QWidget* parent )
88 : QWidget( parent ), myCurrentTgt( FirstTgt ), myFirstActor( 0 ), mySecondActor( 0 ), myPreview( 0 )
90 QGroupBox* aFirstTgtGrp = new QGroupBox( tr( "FIRST_TARGET" ), this );
91 QRadioButton* aFNode = new QRadioButton( tr( "NODE" ), aFirstTgtGrp );
92 QRadioButton* aFElem = new QRadioButton( tr( "ELEMENT" ), aFirstTgtGrp );
93 QRadioButton* aFObject = new QRadioButton( tr( "OBJECT" ), aFirstTgtGrp );
94 myFirstTgt = new QLineEdit( aFirstTgtGrp );
96 QGridLayout* fl = new QGridLayout( aFirstTgtGrp );
97 fl->setMargin( MARGIN );
98 fl->setSpacing( SPACING );
99 fl->addWidget( aFNode, 0, 0 );
100 fl->addWidget( aFElem, 0, 1 );
101 fl->addWidget( aFObject, 0, 2 );
102 fl->addWidget( myFirstTgt, 1, 0, 1, 3 );
104 myFirst = new QButtonGroup( this );
105 myFirst->addButton( aFNode, NodeTgt );
106 myFirst->addButton( aFElem, ElementTgt );
107 myFirst->addButton( aFObject, ObjectTgt );
109 QGroupBox* aSecondTgtGrp = new QGroupBox( tr( "SECOND_TARGET" ), this );
110 QRadioButton* aSOrigin = new QRadioButton( tr( "ORIGIN" ), aSecondTgtGrp );
111 QRadioButton* aSNode = new QRadioButton( tr( "NODE" ), aSecondTgtGrp );
112 QRadioButton* aSElem = new QRadioButton( tr( "ELEMENT" ), aSecondTgtGrp );
113 QRadioButton* aSObject = new QRadioButton( tr( "OBJECT" ), aSecondTgtGrp );
114 mySecondTgt = new QLineEdit( aSecondTgtGrp );
116 QGridLayout* sl = new QGridLayout( aSecondTgtGrp );
117 sl->setMargin( MARGIN );
118 sl->setSpacing( SPACING );
119 sl->addWidget( aSOrigin, 0, 0 );
120 sl->addWidget( aSNode, 0, 1 );
121 sl->addWidget( aSElem, 0, 2 );
122 sl->addWidget( aSObject, 0, 3 );
123 sl->addWidget( mySecondTgt, 1, 0, 1, 4 );
125 mySecond = new QButtonGroup( this );
126 mySecond->addButton( aSOrigin, OriginTgt );
127 mySecond->addButton( aSNode, NodeTgt );
128 mySecond->addButton( aSElem, ElementTgt );
129 mySecond->addButton( aSObject, ObjectTgt );
131 QPushButton* aCompute = new QPushButton( tr( "COMPUTE" ), this );
133 QGroupBox* aResults = new QGroupBox( tr( "RESULT" ), this );
134 QLabel* aDxLab = new QLabel( "dX", aResults );
135 myDX = new QLineEdit( aResults );
136 QLabel* aDyLab = new QLabel( "dY", aResults );
137 myDY = new QLineEdit( aResults );
138 QLabel* aDzLab = new QLabel( "dZ", aResults );
139 myDZ = new QLineEdit( aResults );
140 QLabel* aDistLab = new QLabel( tr( "DISTANCE" ), aResults );
141 myDistance = new QLineEdit( aResults );
143 QGridLayout* rl = new QGridLayout( aResults );
144 rl->setMargin( MARGIN );
145 rl->setSpacing( SPACING );
146 rl->addWidget( aDxLab, 0, 0 );
147 rl->addWidget( myDX, 0, 1 );
148 rl->addWidget( aDyLab, 1, 0 );
149 rl->addWidget( myDY, 1, 1 );
150 rl->addWidget( aDzLab, 2, 0 );
151 rl->addWidget( myDZ, 2, 1 );
152 rl->addWidget( aDistLab, 0, 2 );
153 rl->addWidget( myDistance, 0, 3 );
155 QGridLayout* l = new QGridLayout( this );
156 l->setMargin( MARGIN );
157 l->setSpacing( SPACING );
159 l->addWidget( aFirstTgtGrp, 0, 0, 1, 2 );
160 l->addWidget( aSecondTgtGrp, 1, 0, 1, 2 );
161 l->addWidget( aCompute, 2, 0 );
162 l->addWidget( aResults, 3, 0, 1, 2 );
163 l->setColumnStretch( 1, 5 );
164 l->setRowStretch( 4, 5 );
166 aFNode->setChecked( true );
167 aSOrigin->setChecked( true );
168 #ifndef MINDIST_ENABLE_ELEMENT
169 aFElem->setEnabled( false ); // NOT AVAILABLE YET
170 aSElem->setEnabled( false ); // NOT AVAILABLE YET
172 #ifndef MINDIST_ENABLE_OBJECT
173 aFObject->setEnabled( false ); // NOT AVAILABLE YET
174 aSObject->setEnabled( false ); // NOT AVAILABLE YET
176 myDX->setReadOnly( true );
177 myDY->setReadOnly( true );
178 myDZ->setReadOnly( true );
179 myDistance->setReadOnly( true );
181 myValidator = new SMESHGUI_IdValidator( this, 1 );
183 myFirstTgt->installEventFilter( this );
184 mySecondTgt->installEventFilter( this );
186 connect( myFirst, SIGNAL( buttonClicked( int ) ), this, SLOT( firstChanged() ) );
187 connect( mySecond, SIGNAL( buttonClicked( int ) ), this, SLOT( secondChanged() ) );
188 connect( aCompute, SIGNAL( clicked() ), this, SLOT( compute() ) );
189 connect( myFirstTgt, SIGNAL( textEdited( QString ) ), this, SLOT( firstEdited() ) );
190 connect( mySecondTgt, SIGNAL( textEdited( QString ) ), this, SLOT( secondEdited() ) );
192 QList<SUIT_SelectionFilter*> filters;
193 filters.append( new SMESH_TypeFilter( SMESH::MESHorSUBMESH ) );
194 filters.append( new SMESH_TypeFilter( SMESH::GROUP ) );
195 myFilter = new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR );
197 mySecondTgt->setEnabled( mySecond->checkedId() != OriginTgt );
200 //setTarget( FirstTgt );
206 SMESHGUI_MinDistance::~SMESHGUI_MinDistance()
217 \return \c true if event is filtered or \c false otherwise
219 bool SMESHGUI_MinDistance::eventFilter( QObject* o, QEvent* e )
221 if ( e->type() == QEvent::FocusIn ) {
222 if ( o == myFirstTgt )
223 setTarget( FirstTgt );
224 else if ( o == mySecondTgt )
225 setTarget( SecondTgt );
227 return QWidget::eventFilter( o, e );
231 \brief Setup selection mode depending on the current widget state
233 void SMESHGUI_MinDistance::updateSelection()
235 LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
237 disconnect( selMgr, 0, this, 0 );
238 selMgr->clearFilters();
240 bool nodeMode = ( myCurrentTgt == FirstTgt && myFirst->checkedId() == NodeTgt ) ||
241 ( myCurrentTgt == SecondTgt && mySecond->checkedId() == NodeTgt );
242 bool elemMode = ( myCurrentTgt == FirstTgt && myFirst->checkedId() == ElementTgt ) ||
243 ( myCurrentTgt == SecondTgt && mySecond->checkedId() == ElementTgt );
244 bool objMode = ( myCurrentTgt == FirstTgt && myFirst->checkedId() == ObjectTgt ) ||
245 ( myCurrentTgt == SecondTgt && mySecond->checkedId() == ObjectTgt ) ||
246 ( myCurrentTgt == NoTgt );
249 SMESH::SetPointRepresentation( true );
250 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
251 aViewWindow->SetSelectionMode( NodeSelection );
253 else if ( elemMode ) {
254 SMESH::SetPointRepresentation( false );
255 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
256 aViewWindow->SetSelectionMode( CellSelection );
258 else if ( objMode ) {
259 SMESH::SetPointRepresentation( false );
260 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
261 aViewWindow->SetSelectionMode( ActorSelection );
262 selMgr->installFilter( myFilter );
265 connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( selectionChanged() ) );
267 if ( myCurrentTgt == FirstTgt )
269 else if ( myCurrentTgt == SecondTgt )
272 //selectionChanged();
276 \brief Deactivate widget
278 void SMESHGUI_MinDistance::deactivate()
280 disconnect( SMESHGUI::selectionMgr(), 0, this, 0 );
284 \brief Set current target for selection
285 \param target new target ID
287 void SMESHGUI_MinDistance::setTarget( int target )
289 if ( myCurrentTgt != target ) {
290 myCurrentTgt = target;
296 \brief Erase preview actor
298 void SMESHGUI_MinDistance::erasePreview()
300 SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow();
301 if ( aViewWindow && myPreview ) {
302 aViewWindow->RemoveActor( myPreview );
303 aViewWindow->Repaint();
308 \brief Display preview actor
310 void SMESHGUI_MinDistance::displayPreview()
312 SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow();
313 if ( aViewWindow && myPreview ) {
314 aViewWindow->AddActor( myPreview );
315 aViewWindow->Repaint();
320 \brief Create preview actor
321 \param x1 X coordinate of first point
322 \param y1 X coordinate of first point
323 \param z1 Y coordinate of first point
324 \param x2 Y coordinate of second point
325 \param y2 Z coordinate of second point
326 \param z2 Z coordinate of second point
328 void SMESHGUI_MinDistance::createPreview( double x1, double y1, double z1, double x2, double y2, double z2 )
333 vtkUnstructuredGrid* aGrid = vtkUnstructuredGrid::New();
335 vtkPoints* aPoints = vtkPoints::New();
336 aPoints->SetNumberOfPoints( 2 );
337 aPoints->SetPoint( 0, x1, y1, z1 );
338 aPoints->SetPoint( 1, x2, y2, z2 );
339 aGrid->SetPoints( aPoints );
342 vtkIdList* anIdList = vtkIdList::New();
343 anIdList->SetNumberOfIds( 2 );
344 vtkCellArray* aCells = vtkCellArray::New();
345 aCells->Allocate( 2, 0);
346 vtkUnsignedCharArray* aCellTypesArray = vtkUnsignedCharArray::New();
347 aCellTypesArray->SetNumberOfComponents( 1 );
348 aCellTypesArray->Allocate( 1 );
349 anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 1 );
350 aCells->InsertNextCell( anIdList );
351 aCellTypesArray->InsertNextValue( VTK_LINE );
353 VTKViewer_CellLocationsArray* aCellLocationsArray = VTKViewer_CellLocationsArray::New();
354 aCellLocationsArray->SetNumberOfComponents( 1 );
355 aCellLocationsArray->SetNumberOfTuples( 1 );
356 aCells->InitTraversal();
357 for( vtkIdType idType = 0, *pts, npts; aCells->GetNextCell( npts, pts ); idType++ )
358 aCellLocationsArray->SetValue( idType, aCells->GetTraversalLocation( npts ) );
359 aGrid->SetCells( aCellTypesArray, aCellLocationsArray, aCells );
360 aCellLocationsArray->Delete();
361 aCellTypesArray->Delete();
364 vtkDataSetMapper* aMapper = vtkDataSetMapper::New();
365 aMapper->SetInput( aGrid );
367 myPreview = SALOME_Actor::New();
368 myPreview->PickableOff();
369 myPreview->SetMapper( aMapper );
371 vtkProperty* aProp = vtkProperty::New();
372 aProp->SetRepresentationToWireframe();
373 aProp->SetColor( 250, 0, 250 );
374 aProp->SetPointSize( 5 );
375 aProp->SetLineWidth( 3 );
376 myPreview->SetProperty( aProp );
381 \brief Called when selection is changed
383 void SMESHGUI_MinDistance::selectionChanged()
385 SUIT_OverrideCursor wc;
387 SALOME_ListIO selected;
388 SMESHGUI::selectionMgr()->selectedObjects( selected );
390 if ( selected.Extent() == 1 ) {
391 Handle(SALOME_InteractiveObject) IO = selected.First();
392 SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
393 if ( !CORBA::is_nil( obj ) ) {
394 if ( myCurrentTgt == FirstTgt ) {
396 myFirstActor = SMESH::FindActorByEntry( IO->getEntry() );
397 if ( myFirst->checkedId() == ObjectTgt ) {
399 SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
400 myFirstTgt->setText( aName );
403 SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
406 if ( myFirstActor && selector ) {
407 nb = myFirst->checkedId() == NodeTgt ?
408 SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
409 SMESH::GetNameOfSelectedNodes( selector, IO, ID );
412 myFirstTgt->setText( ID.trimmed() );
417 else if ( myCurrentTgt == SecondTgt ) {
419 mySecondActor = SMESH::FindActorByEntry( IO->getEntry() );
420 if ( mySecond->checkedId() == ObjectTgt ) {
422 SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
423 mySecondTgt->setText( aName );
426 SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
429 if ( mySecondActor && selector ) {
430 nb = mySecond->checkedId() == NodeTgt ?
431 SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
432 SMESH::GetNameOfSelectedNodes( selector, IO, ID );
435 mySecondTgt->setText( ID.trimmed() );
437 mySecondTgt->clear();
446 \brief Called when first target mode is changed by the user
448 void SMESHGUI_MinDistance::firstChanged()
450 myFirstSrc = SMESH::SMESH_IDSource::_nil();
452 myFirstTgt->setReadOnly( myFirst->checkedId() == ObjectTgt );
453 myFirstTgt->setValidator( myFirst->checkedId() == ObjectTgt ? 0 : myValidator );
454 setTarget( FirstTgt );
460 \brief Called when second target mode is changed by the user
462 void SMESHGUI_MinDistance::secondChanged()
464 mySecondSrc = SMESH::SMESH_IDSource::_nil();
465 mySecondTgt->setEnabled( mySecond->checkedId() != OriginTgt );
466 mySecondTgt->setReadOnly( mySecond->checkedId() == ObjectTgt );
467 mySecondTgt->setValidator( mySecond->checkedId() == ObjectTgt ? 0 : myValidator );
468 mySecondTgt->clear();
469 setTarget( mySecond->checkedId() != OriginTgt ? SecondTgt : NoTgt );
475 \brief Called when first target is edited by the user
477 void SMESHGUI_MinDistance::firstEdited()
479 setTarget( FirstTgt );
480 if ( sender() == myFirstTgt )
482 SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
483 if ( myFirstActor && selector ) {
484 Handle(SALOME_InteractiveObject) IO = myFirstActor->getIO();
485 if ( myFirst->checkedId() == NodeTgt || myFirst->checkedId() == ElementTgt ) {
486 TColStd_MapOfInteger ID;
487 ID.Add( myFirstTgt->text().toLong() );
488 selector->AddOrRemoveIndex( IO, ID, false );
490 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
491 aViewWindow->highlight( IO, true, true );
496 \brief Called when second target is edited by the user
498 void SMESHGUI_MinDistance::secondEdited()
500 setTarget( SecondTgt );
501 if ( sender() == mySecondTgt )
503 SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
504 if ( mySecondActor && selector ) {
505 Handle(SALOME_InteractiveObject) IO = mySecondActor->getIO();
506 if ( mySecond->checkedId() == NodeTgt || mySecond->checkedId() == ElementTgt ) {
507 TColStd_MapOfInteger ID;
508 ID.Add( mySecondTgt->text().toLong() );
509 selector->AddOrRemoveIndex( IO, ID, false );
511 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
512 aViewWindow->highlight( IO, true, true );
517 \brief Compute the minimum distance between targets
519 void SMESHGUI_MinDistance::compute()
521 SUIT_OverrideCursor wc;
522 SMESH::SMESH_IDSource_var s1;
523 SMESH::SMESH_IDSource_var s2;
524 bool isOrigin = mySecond->checkedId() == OriginTgt;
526 // process first target
527 if ( !CORBA::is_nil( myFirstSrc ) ) {
528 if ( myFirst->checkedId() == NodeTgt || myFirst->checkedId() == ElementTgt ) {
529 SMESH::SMESH_Mesh_var m = myFirstSrc->GetMesh();
530 long id = myFirstTgt->text().toLong();
531 if ( !CORBA::is_nil( m ) && id ) {
532 SMESH::long_array_var ids = new SMESH::long_array();
535 SMESH::SMESH_MeshEditor_var me = m->GetMeshEditor();
536 s1 = me->MakeIDSource( ids.in(), myFirst->checkedId() == NodeTgt ? SMESH::NODE : SMESH::FACE );
544 // process second target
545 if ( !CORBA::is_nil( mySecondSrc ) ) {
546 if ( mySecond->checkedId() == NodeTgt || mySecond->checkedId() == ElementTgt ) {
547 SMESH::SMESH_Mesh_var m = mySecondSrc->GetMesh();
548 long id = mySecondTgt->text().toLong();
549 if ( !CORBA::is_nil( m ) && id ) {
550 SMESH::long_array_var ids = new SMESH::long_array();
553 SMESH::SMESH_MeshEditor_var me = m->GetMeshEditor();
554 s2 = me->MakeIDSource( ids.in(), mySecond->checkedId() == NodeTgt ? SMESH::NODE : SMESH::FACE );
562 if ( !CORBA::is_nil( s1 ) && ( !CORBA::is_nil( s2 ) || isOrigin ) ) {
563 // compute min distance
564 int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
565 SMESH::Measurements_var measure = SMESHGUI::GetSMESHGen()->CreateMeasurements();
566 SMESH::Measure result = measure->MinDistance( s1.in(), s2.in() );
567 measure->UnRegister();
568 myDX->setText( QString::number( result.minX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
569 myDY->setText( QString::number( result.minY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
570 myDZ->setText( QString::number( result.minZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
571 myDistance->setText( QString::number( result.value, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
572 // update preview actor
574 double x1, y1, z1, x2, y2, z2;
575 SMESH::double_array_var coord = s1->GetMesh()->GetNodeXYZ( result.node1 );
576 x1 = coord[0]; y1 = coord[1]; z1 = coord[2];
581 coord = s2->GetMesh()->GetNodeXYZ( result.node2 );
582 x2 = coord[0]; y2 = coord[1]; z2 = coord[2];
584 createPreview( x1, y1, z1, x2, y2, z2 );
593 \brief Reset the widget to the initial state (nullify result fields)
595 void SMESHGUI_MinDistance::clear()
605 \class SMESHGUI_BoundingBox
606 \brief Bounding box measurement widget.
608 Widget to calculate bounding box of the selected object(s).
613 \param parent parent widget
615 SMESHGUI_BoundingBox::SMESHGUI_BoundingBox( QWidget* parent )
616 : QWidget( parent ), myActor( 0 ), myPreview( 0 )
618 QGroupBox* aSourceGrp = new QGroupBox( tr( "SOURCE" ), this );
619 QRadioButton* aObjects = new QRadioButton( tr( "OBJECTS" ), aSourceGrp );
620 QRadioButton* aNodes = new QRadioButton( tr( "NODES" ), aSourceGrp );
621 QRadioButton* aElements = new QRadioButton( tr( "ELEMENTS" ), aSourceGrp );
622 mySource = new QLineEdit( aSourceGrp );
624 QGridLayout* fl = new QGridLayout( aSourceGrp );
625 fl->setMargin( MARGIN );
626 fl->setSpacing( SPACING );
627 fl->addWidget( aObjects, 0, 0 );
628 fl->addWidget( aNodes, 0, 1 );
629 fl->addWidget( aElements, 0, 2 );
630 fl->addWidget( mySource, 1, 0, 1, 3 );
632 mySourceMode = new QButtonGroup( this );
633 mySourceMode->addButton( aObjects, ObjectsSrc );
634 mySourceMode->addButton( aNodes, NodesSrc );
635 mySourceMode->addButton( aElements, ElementsSrc );
637 QPushButton* aCompute = new QPushButton( tr( "COMPUTE" ), this );
639 QGroupBox* aResults = new QGroupBox( tr( "RESULT" ), this );
640 QLabel* aXminLab = new QLabel( "Xmin", aResults );
641 myXmin = new QLineEdit( aResults );
642 QLabel* aXmaxLab = new QLabel( "Xmax", aResults );
643 myXmax = new QLineEdit( aResults );
644 QLabel* aDxLab = new QLabel( "dX", aResults );
645 myDX = new QLineEdit( aResults );
646 QLabel* aYminLab = new QLabel( "Ymin", aResults );
647 myYmin = new QLineEdit( aResults );
648 QLabel* aYmaxLab = new QLabel( "Ymax", aResults );
649 myYmax = new QLineEdit( aResults );
650 QLabel* aDyLab = new QLabel( "dY", aResults );
651 myDY = new QLineEdit( aResults );
652 QLabel* aZminLab = new QLabel( "Zmin", aResults );
653 myZmin = new QLineEdit( aResults );
654 QLabel* aZmaxLab = new QLabel( "Zmax", aResults );
655 myZmax = new QLineEdit( aResults );
656 QLabel* aDzLab = new QLabel( "dZ", aResults );
657 myDZ = new QLineEdit( aResults );
659 QGridLayout* rl = new QGridLayout( aResults );
660 rl->setMargin( MARGIN );
661 rl->setSpacing( SPACING );
662 rl->addWidget( aXminLab, 0, 0 );
663 rl->addWidget( myXmin, 0, 1 );
664 rl->addWidget( aXmaxLab, 0, 2 );
665 rl->addWidget( myXmax, 0, 3 );
666 rl->addWidget( aDxLab, 0, 4 );
667 rl->addWidget( myDX, 0, 5 );
668 rl->addWidget( aYminLab, 1, 0 );
669 rl->addWidget( myYmin, 1, 1 );
670 rl->addWidget( aYmaxLab, 1, 2 );
671 rl->addWidget( myYmax, 1, 3 );
672 rl->addWidget( aDyLab, 1, 4 );
673 rl->addWidget( myDY, 1, 5 );
674 rl->addWidget( aZminLab, 2, 0 );
675 rl->addWidget( myZmin, 2, 1 );
676 rl->addWidget( aZmaxLab, 2, 2 );
677 rl->addWidget( myZmax, 2, 3 );
678 rl->addWidget( aDzLab, 2, 4 );
679 rl->addWidget( myDZ, 2, 5 );
681 QGridLayout* l = new QGridLayout( this );
682 l->setMargin( MARGIN );
683 l->setSpacing( SPACING );
685 l->addWidget( aSourceGrp, 0, 0, 1, 2 );
686 l->addWidget( aCompute, 1, 0 );
687 l->addWidget( aResults, 2, 0, 1, 2 );
688 l->setColumnStretch( 1, 5 );
689 l->setRowStretch( 3, 5 );
691 aObjects->setChecked( true );
692 myXmin->setReadOnly( true );
693 myXmax->setReadOnly( true );
694 myDX->setReadOnly( true );
695 myYmin->setReadOnly( true );
696 myYmax->setReadOnly( true );
697 myDY->setReadOnly( true );
698 myZmin->setReadOnly( true );
699 myZmax->setReadOnly( true );
700 myDZ->setReadOnly( true );
702 myValidator = new SMESHGUI_IdValidator( this );
704 connect( mySourceMode, SIGNAL( buttonClicked( int ) ), this, SLOT( sourceChanged() ) );
705 connect( aCompute, SIGNAL( clicked() ), this, SLOT( compute() ) );
706 connect( mySource, SIGNAL( textEdited( QString ) ), this, SLOT( sourceEdited() ) );
708 QList<SUIT_SelectionFilter*> filters;
709 filters.append( new SMESH_TypeFilter( SMESH::MESHorSUBMESH ) );
710 filters.append( new SMESH_TypeFilter( SMESH::GROUP ) );
711 myFilter = new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR );
719 SMESHGUI_BoundingBox::~SMESHGUI_BoundingBox()
727 \brief Setup selection mode depending on the current widget state
729 void SMESHGUI_BoundingBox::updateSelection()
731 LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
733 disconnect( selMgr, 0, this, 0 );
734 selMgr->clearFilters();
736 bool nodeMode = mySourceMode->checkedId() == NodesSrc;
737 bool elemMode = mySourceMode->checkedId() == ElementsSrc;
738 bool objMode = mySourceMode->checkedId() == ObjectsSrc;
741 SMESH::SetPointRepresentation( true );
742 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
743 aViewWindow->SetSelectionMode( NodeSelection );
745 else if ( elemMode ) {
746 SMESH::SetPointRepresentation( false );
747 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
748 aViewWindow->SetSelectionMode( CellSelection );
750 else if ( objMode ) {
751 SMESH::SetPointRepresentation( false );
752 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
753 aViewWindow->SetSelectionMode( ActorSelection );
754 selMgr->installFilter( myFilter );
757 connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( selectionChanged() ) );
761 //selectionChanged();
765 \brief Deactivate widget
767 void SMESHGUI_BoundingBox::deactivate()
769 disconnect( SMESHGUI::selectionMgr(), 0, this, 0 );
773 \brief Erase preview actor
775 void SMESHGUI_BoundingBox::erasePreview()
777 SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow();
778 if ( aViewWindow && myPreview ) {
779 aViewWindow->RemoveActor( myPreview );
780 aViewWindow->Repaint();
785 \brief Display preview actor
787 void SMESHGUI_BoundingBox::displayPreview()
789 SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow();
790 if ( aViewWindow && myPreview ) {
791 aViewWindow->AddActor( myPreview );
792 aViewWindow->Repaint();
797 \brief Create preview actor
798 \param minX min X coordinate of bounding box
799 \param maxX max X coordinate of bounding box
800 \param minY min Y coordinate of bounding box
801 \param maxY max Y coordinate of bounding box
802 \param minZ min Z coordinate of bounding box
803 \param maxZ max Z coordinate of bounding box
805 void SMESHGUI_BoundingBox::createPreview( double minX, double maxX, double minY, double maxY, double minZ, double maxZ )
810 vtkUnstructuredGrid* aGrid = vtkUnstructuredGrid::New();
812 vtkPoints* aPoints = vtkPoints::New();
813 aPoints->SetNumberOfPoints( 8 );
814 aPoints->SetPoint( 0, minX, minY, minZ );
815 aPoints->SetPoint( 1, maxX, minY, minZ );
816 aPoints->SetPoint( 2, minX, maxY, minZ );
817 aPoints->SetPoint( 3, maxX, maxY, minZ );
818 aPoints->SetPoint( 4, minX, minY, maxZ );
819 aPoints->SetPoint( 5, maxX, minY, maxZ );
820 aPoints->SetPoint( 6, minX, maxY, maxZ );
821 aPoints->SetPoint( 7, maxX, maxY, maxZ );
822 aGrid->SetPoints( aPoints );
825 // connectivity: 0-1 0-4 0-2 1-5 1-3 2-6 2-3 3-7 4-6 4-5 5-7 6-7
826 vtkIdList* anIdList = vtkIdList::New();
827 anIdList->SetNumberOfIds( 2 );
828 vtkCellArray* aCells = vtkCellArray::New();
829 aCells->Allocate( 2*12, 0);
830 vtkUnsignedCharArray* aCellTypesArray = vtkUnsignedCharArray::New();
831 aCellTypesArray->SetNumberOfComponents( 1 );
832 aCellTypesArray->Allocate( 12 );
833 anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 1 );
834 aCells->InsertNextCell( anIdList );
835 aCellTypesArray->InsertNextValue( VTK_LINE );
836 anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 4 );
837 aCells->InsertNextCell( anIdList );
838 aCellTypesArray->InsertNextValue( VTK_LINE );
839 anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 2 );
840 aCells->InsertNextCell( anIdList );
841 aCellTypesArray->InsertNextValue( VTK_LINE );
842 anIdList->SetId( 0, 1 ); anIdList->SetId( 1, 5 );
843 aCells->InsertNextCell( anIdList );
844 aCellTypesArray->InsertNextValue( VTK_LINE );
845 anIdList->SetId( 0, 1 ); anIdList->SetId( 1, 3 );
846 aCells->InsertNextCell( anIdList );
847 aCellTypesArray->InsertNextValue( VTK_LINE );
848 anIdList->SetId( 0, 2 ); anIdList->SetId( 1, 6 );
849 aCells->InsertNextCell( anIdList );
850 aCellTypesArray->InsertNextValue( VTK_LINE );
851 anIdList->SetId( 0, 2 ); anIdList->SetId( 1, 3 );
852 aCells->InsertNextCell( anIdList );
853 aCellTypesArray->InsertNextValue( VTK_LINE );
854 anIdList->SetId( 0, 3 ); anIdList->SetId( 1, 7 );
855 aCells->InsertNextCell( anIdList );
856 aCellTypesArray->InsertNextValue( VTK_LINE );
857 anIdList->SetId( 0, 4 ); anIdList->SetId( 1, 6 );
858 aCells->InsertNextCell( anIdList );
859 aCellTypesArray->InsertNextValue( VTK_LINE );
860 anIdList->SetId( 0, 4 ); anIdList->SetId( 1, 5 );
861 aCells->InsertNextCell( anIdList );
862 aCellTypesArray->InsertNextValue( VTK_LINE );
863 anIdList->SetId( 0, 5 ); anIdList->SetId( 1, 7 );
864 aCells->InsertNextCell( anIdList );
865 aCellTypesArray->InsertNextValue( VTK_LINE );
866 anIdList->SetId( 0, 6 ); anIdList->SetId( 1, 7 );
867 aCells->InsertNextCell( anIdList );
868 aCellTypesArray->InsertNextValue( VTK_LINE );
870 VTKViewer_CellLocationsArray* aCellLocationsArray = VTKViewer_CellLocationsArray::New();
871 aCellLocationsArray->SetNumberOfComponents( 1 );
872 aCellLocationsArray->SetNumberOfTuples( 12 );
873 aCells->InitTraversal();
874 for( vtkIdType idType = 0, *pts, npts; aCells->GetNextCell( npts, pts ); idType++ )
875 aCellLocationsArray->SetValue( idType, aCells->GetTraversalLocation( npts ) );
876 aGrid->SetCells( aCellTypesArray, aCellLocationsArray, aCells );
877 aCellLocationsArray->Delete();
878 aCellTypesArray->Delete();
881 vtkDataSetMapper* aMapper = vtkDataSetMapper::New();
882 aMapper->SetInput( aGrid );
884 myPreview = SALOME_Actor::New();
885 myPreview->PickableOff();
886 myPreview->SetMapper( aMapper );
888 vtkProperty* aProp = vtkProperty::New();
889 aProp->SetRepresentationToWireframe();
890 aProp->SetColor( 250, 0, 250 );
891 aProp->SetPointSize( 5 );
892 aProp->SetLineWidth( 3 );
893 myPreview->SetProperty( aProp );
898 \brief Called when selection is changed
900 void SMESHGUI_BoundingBox::selectionChanged()
902 SUIT_OverrideCursor wc;
904 SALOME_ListIO selected;
905 SMESHGUI::selectionMgr()->selectedObjects( selected );
907 if ( selected.Extent() == 1 ) {
908 Handle(SALOME_InteractiveObject) IO = selected.First();
909 SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
910 if ( !CORBA::is_nil( obj ) ) {
913 myActor = SMESH::FindActorByEntry( IO->getEntry() );
914 if ( mySourceMode->checkedId() == ObjectsSrc ) {
916 SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
917 mySource->setText( aName );
920 SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
923 if ( myActor && selector ) {
924 nb = mySourceMode->checkedId() == NodesSrc ?
925 SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
926 SMESH::GetNameOfSelectedNodes( selector, IO, ID );
929 myIDs = ID.trimmed();
930 if ( nb < MAX_NB_FOR_EDITOR ) {
931 mySource->setReadOnly( false );
932 if ( mySource->validator() != myValidator )
933 mySource->setValidator( myValidator );
934 mySource->setText( ID.trimmed() );
937 mySource->setReadOnly( true );
938 mySource->setValidator( 0 );
939 mySource->setText( tr( "SELECTED_NB_OBJ" ).arg( nb )
940 .arg( mySourceMode->checkedId() == NodesSrc ? tr( "NB_NODES" ) : tr( "NB_ELEMENTS") ) );
946 mySource->setReadOnly( false );
947 mySource->setValidator( myValidator );
952 else if ( selected.Extent() > 1 ) {
954 SALOME_ListIteratorOfListIO It( selected );
957 if ( mySourceMode->checkedId() == ObjectsSrc ) {
958 for( ; It.More(); It.Next()){
959 Handle(SALOME_InteractiveObject) IO = It.Value();
960 SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
961 if ( !CORBA::is_nil( obj ) ) {
966 SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
967 mySource->setText( aName );
977 \brief Called when source mode is changed by the user
979 void SMESHGUI_BoundingBox::sourceChanged()
983 mySource->setReadOnly( mySourceMode->checkedId() == ObjectsSrc );
984 mySource->setValidator( mySourceMode->checkedId() == ObjectsSrc ? 0 : myValidator );
990 \brief Called when source mode is edited by the user
992 void SMESHGUI_BoundingBox::sourceEdited()
994 if ( sender() == mySource )
996 SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
997 if ( myActor && selector ) {
998 Handle(SALOME_InteractiveObject) IO = myActor->getIO();
999 if ( mySourceMode->checkedId() == NodesSrc || mySourceMode->checkedId() == ElementsSrc ) {
1000 TColStd_MapOfInteger ID;
1001 if ( !mySource->isReadOnly() )
1002 myIDs = mySource->text();
1003 QStringList ids = myIDs.split( " ", QString::SkipEmptyParts );
1004 foreach ( QString id, ids )
1005 ID.Add( id.trimmed().toLong() );
1006 selector->AddOrRemoveIndex( IO, ID, false );
1008 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1009 aViewWindow->highlight( IO, true, true );
1014 \brief Calculate bounding box of the selected object(s)
1016 void SMESHGUI_BoundingBox::compute()
1018 SUIT_OverrideCursor wc;
1019 SMESH::ListOfIDSources_var srcList = new SMESH::ListOfIDSources();
1020 if ( mySourceMode->checkedId() == NodesSrc || mySourceMode->checkedId() == ElementsSrc ) {
1021 if ( mySrc.count() > 0 && !CORBA::is_nil( mySrc[0] ) ) {
1022 SMESH::SMESH_Mesh_var m = mySrc[0]->GetMesh();
1023 QStringList ids = myIDs.split( " ", QString::SkipEmptyParts );
1024 if ( !CORBA::is_nil( m ) && ids.count() > 0 ) {
1025 SMESH::long_array_var ids_in = new SMESH::long_array();
1026 ids_in->length( ids.count() );
1027 for( int i = 0; i < ids.count(); i++ )
1028 ids_in[i] = ids[i].trimmed().toLong();
1029 SMESH::SMESH_MeshEditor_var me = m->GetMeshEditor();
1030 SMESH::SMESH_IDSource_var s = me->MakeIDSource( ids_in.in(), mySourceMode->checkedId() == NodesSrc ? SMESH::NODE : SMESH::FACE );
1031 srcList->length( 1 );
1037 srcList->length( mySrc.count() );
1038 for( int i = 0; i < mySrc.count(); i++ )
1039 srcList[i] = mySrc[i];
1041 if ( srcList->length() > 0 ) {
1042 // compute bounding box
1043 int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
1044 SMESH::Measurements_var measure = SMESHGUI::GetSMESHGen()->CreateMeasurements();
1045 SMESH::Measure result = measure->BoundingBox( srcList.in() );
1046 measure->UnRegister();
1047 myXmin->setText( QString::number( result.minX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1048 myXmax->setText( QString::number( result.maxX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1049 myDX->setText( QString::number( result.maxX-result.minX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1050 myYmin->setText( QString::number( result.minY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1051 myYmax->setText( QString::number( result.maxY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1052 myDY->setText( QString::number( result.maxY-result.minY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1053 myZmin->setText( QString::number( result.minZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1054 myZmax->setText( QString::number( result.maxZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1055 myDZ->setText( QString::number( result.maxZ-result.minZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1056 // update preview actor
1058 createPreview( result.minX, result.maxX, result.minY, result.maxY, result.minZ, result.maxZ );
1067 \brief Reset the widget to the initial state (nullify result fields)
1069 void SMESHGUI_BoundingBox::clear()
1084 \class SMESHGUI_MeshInfoDlg
1085 \brief Centralized dialog box for the measurements
1090 \param parent parent widget
1091 \param page specifies the dialog page to be shown at the start-up
1093 SMESHGUI_MeasureDlg::SMESHGUI_MeasureDlg( QWidget* parent, int page )
1097 setAttribute( Qt::WA_DeleteOnClose, true );
1098 setWindowTitle( tr( "MEASUREMENTS" ) );
1099 setSizeGripEnabled( true );
1101 SUIT_ResourceMgr* resMgr = SMESHGUI::resourceMgr();
1103 myTabWidget = new QTabWidget( this );
1107 myMinDist = new SMESHGUI_MinDistance( myTabWidget );
1108 myTabWidget->addTab( myMinDist, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_MIN_DIST" ) ), tr( "MIN_DIST" ) );
1112 myBndBox = new SMESHGUI_BoundingBox( myTabWidget );
1113 myTabWidget->addTab( myBndBox, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_BND_BOX" ) ), tr( "BND_BOX" ) );
1116 QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this );
1117 okBtn->setAutoDefault( true );
1118 okBtn->setDefault( true );
1120 QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this );
1121 helpBtn->setAutoDefault( true );
1123 QHBoxLayout* btnLayout = new QHBoxLayout;
1124 btnLayout->setSpacing( SPACING );
1125 btnLayout->setMargin( 0 );
1126 btnLayout->addWidget( okBtn );
1127 btnLayout->addStretch( 10 );
1128 btnLayout->addWidget( helpBtn );
1130 QVBoxLayout* l = new QVBoxLayout ( this );
1131 l->setMargin( MARGIN );
1132 l->setSpacing( SPACING );
1133 l->addWidget( myTabWidget );
1135 l->addLayout( btnLayout );
1137 myTabWidget->setCurrentIndex( qMax( (int)MinDistance, qMin( (int)BoundingBox, page ) ) );
1139 connect( okBtn, SIGNAL( clicked() ), this, SLOT( reject() ) );
1140 connect( helpBtn, SIGNAL( clicked() ), this, SLOT( help() ) );
1141 connect( myTabWidget, SIGNAL( currentChanged( int ) ), this, SLOT( updateSelection() ) );
1142 connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) );
1143 connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalCloseAllDialogs() ), this, SLOT( reject() ) );
1151 SMESHGUI_MeasureDlg::~SMESHGUI_MeasureDlg()
1156 \brief Perform clean-up actions on the dialog box closing.
1158 void SMESHGUI_MeasureDlg::reject()
1160 LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
1161 selMgr->clearFilters();
1162 SMESH::SetPointRepresentation( false );
1163 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1164 aViewWindow->SetSelectionMode( ActorSelection );
1169 \brief Process keyboard event
1170 \param e key press event
1172 void SMESHGUI_MeasureDlg::keyPressEvent( QKeyEvent* e )
1174 QDialog::keyPressEvent( e );
1175 if ( !e->isAccepted() && e->key() == Qt::Key_F1 ) {
1182 \brief Reactivate dialog box, when mouse pointer goes into it.
1184 void SMESHGUI_MeasureDlg::enterEvent( QEvent* )
1190 \brief Setup selection mode depending on the current dialog box state.
1192 void SMESHGUI_MeasureDlg::updateSelection()
1194 if ( myTabWidget->currentIndex() == MinDistance )
1195 myMinDist->updateSelection();
1196 else if ( myTabWidget->currentIndex() == BoundingBox )
1197 myBndBox->updateSelection();
1202 \brief Show help page
1204 void SMESHGUI_MeasureDlg::help()
1206 SMESH::ShowHelpFile( myTabWidget->currentIndex() == MinDistance ?
1207 "measurements_page.html#min_distance_anchor" :
1208 "measurements_page.html#bounding_box_anchor" );
1212 \brief Activate dialog box
1214 void SMESHGUI_MeasureDlg::activate()
1216 SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog();
1217 SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this );
1218 myTabWidget->setEnabled( true );
1223 \brief Deactivate dialog box
1225 void SMESHGUI_MeasureDlg::deactivate()
1227 myMinDist->deactivate();
1228 myBndBox->deactivate();
1229 myTabWidget->setEnabled( false );
1230 disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );