1 // Copyright (C) 2007-2020 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, or (at your option) any later version.
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_MeshEditPreview.h"
32 #include "SMESHGUI_VTKUtils.h"
33 #include <SMESH_TypeFilter.hxx>
34 #include <SMESH_MeshAlgos.hxx>
35 #include <SMESH_LogicalFilter.hxx>
36 #include <SMDS_Mesh.hxx>
37 #include <SMDS_MeshNode.hxx>
39 #include <LightApp_SelectionMgr.h>
40 #include <SUIT_OverrideCursor.h>
41 #include <SUIT_ResourceMgr.h>
42 #include <SVTK_ViewWindow.h>
43 #include <SALOME_ListIO.hxx>
45 #include <QButtonGroup>
46 #include <QGridLayout>
48 #include <QHBoxLayout>
52 #include <QPushButton>
53 #include <QRadioButton>
55 #include <QVBoxLayout>
57 #include <vtkPoints.h>
58 #include <vtkUnstructuredGrid.h>
59 #include <vtkIdList.h>
60 #include <vtkCellArray.h>
61 #include <vtkUnsignedCharArray.h>
62 #include <vtkDataSetMapper.h>
63 #include <VTKViewer_CellLocationsArray.h>
64 #include <vtkProperty.h>
68 #include <SALOMEconfig.h>
69 #include CORBA_SERVER_HEADER(SMESH_MeshEditor)
70 #include CORBA_SERVER_HEADER(SMESH_Measurements)
72 const int SPACING = 6; // layout spacing
73 const int MARGIN = 9; // layout margin
74 const int MAX_NB_FOR_EDITOR = 40; // max nb of items in the ID list editor field
76 // Uncomment as soon as elements are supported by Min Distance operation
77 //#define MINDIST_ENABLE_ELEMENT
79 // Uncomment as soon as objects are supported by Min Distance operation
80 //#define MINDIST_ENABLE_OBJECT
83 \class SMESHGUI_MinDistance
84 \brief Minimum distance measurement widget.
86 Widget to calculate minimum distance between two objects.
91 \param parent parent widget
93 SMESHGUI_MinDistance::SMESHGUI_MinDistance( QWidget* parent )
94 : QWidget( parent ), myCurrentTgt( FirstTgt ), myFirstActor( 0 ), mySecondActor( 0 ), myPreview( 0 )
96 QGroupBox* aFirstTgtGrp = new QGroupBox( tr( "FIRST_TARGET" ), this );
97 QRadioButton* aFNode = new QRadioButton( tr( "NODE" ), aFirstTgtGrp );
98 QRadioButton* aFElem = new QRadioButton( tr( "ELEMENT" ), aFirstTgtGrp );
99 QRadioButton* aFObject = new QRadioButton( tr( "OBJECT" ), aFirstTgtGrp );
100 myFirstTgt = new QLineEdit( aFirstTgtGrp );
102 QGridLayout* fl = new QGridLayout( aFirstTgtGrp );
103 fl->setMargin( MARGIN );
104 fl->setSpacing( SPACING );
105 fl->addWidget( aFNode, 0, 0 );
106 fl->addWidget( aFElem, 0, 1 );
107 fl->addWidget( aFObject, 0, 2 );
108 fl->addWidget( myFirstTgt, 1, 0, 1, 3 );
110 myFirst = new QButtonGroup( this );
111 myFirst->addButton( aFNode, NodeTgt );
112 myFirst->addButton( aFElem, ElementTgt );
113 myFirst->addButton( aFObject, ObjectTgt );
115 QGroupBox* aSecondTgtGrp = new QGroupBox( tr( "SECOND_TARGET" ), this );
116 QRadioButton* aSOrigin = new QRadioButton( tr( "ORIGIN" ), aSecondTgtGrp );
117 QRadioButton* aSNode = new QRadioButton( tr( "NODE" ), aSecondTgtGrp );
118 QRadioButton* aSElem = new QRadioButton( tr( "ELEMENT" ), aSecondTgtGrp );
119 QRadioButton* aSObject = new QRadioButton( tr( "OBJECT" ), aSecondTgtGrp );
120 mySecondTgt = new QLineEdit( aSecondTgtGrp );
122 QGridLayout* sl = new QGridLayout( aSecondTgtGrp );
123 sl->setMargin( MARGIN );
124 sl->setSpacing( SPACING );
125 sl->addWidget( aSOrigin, 0, 0 );
126 sl->addWidget( aSNode, 0, 1 );
127 sl->addWidget( aSElem, 0, 2 );
128 sl->addWidget( aSObject, 0, 3 );
129 sl->addWidget( mySecondTgt, 1, 0, 1, 4 );
131 mySecond = new QButtonGroup( this );
132 mySecond->addButton( aSOrigin, OriginTgt );
133 mySecond->addButton( aSNode, NodeTgt );
134 mySecond->addButton( aSElem, ElementTgt );
135 mySecond->addButton( aSObject, ObjectTgt );
137 QPushButton* aCompute = new QPushButton( tr( "COMPUTE" ), this );
139 QGroupBox* aResults = new QGroupBox( tr( "RESULT" ), this );
140 QLabel* aDxLab = new QLabel( "dX", aResults );
141 myDX = new QLineEdit( aResults );
142 QLabel* aDyLab = new QLabel( "dY", aResults );
143 myDY = new QLineEdit( aResults );
144 QLabel* aDzLab = new QLabel( "dZ", aResults );
145 myDZ = new QLineEdit( aResults );
146 QLabel* aDistLab = new QLabel( tr( "DISTANCE" ), aResults );
147 myDistance = new QLineEdit( aResults );
149 QGridLayout* rl = new QGridLayout( aResults );
150 rl->setMargin( MARGIN );
151 rl->setSpacing( SPACING );
152 rl->addWidget( aDxLab, 0, 0 );
153 rl->addWidget( myDX, 0, 1 );
154 rl->addWidget( aDyLab, 1, 0 );
155 rl->addWidget( myDY, 1, 1 );
156 rl->addWidget( aDzLab, 2, 0 );
157 rl->addWidget( myDZ, 2, 1 );
158 rl->addWidget( aDistLab, 0, 2 );
159 rl->addWidget( myDistance, 0, 3 );
161 QGridLayout* l = new QGridLayout( this );
162 l->setMargin( MARGIN );
163 l->setSpacing( SPACING );
165 l->addWidget( aFirstTgtGrp, 0, 0, 1, 2 );
166 l->addWidget( aSecondTgtGrp, 1, 0, 1, 2 );
167 l->addWidget( aCompute, 2, 0 );
168 l->addWidget( aResults, 3, 0, 1, 2 );
169 l->setColumnStretch( 1, 5 );
170 l->setRowStretch( 4, 5 );
172 aFNode->setChecked( true );
173 aSOrigin->setChecked( true );
174 #ifndef MINDIST_ENABLE_ELEMENT
175 aFElem->setEnabled( false ); // NOT AVAILABLE YET
176 //aSElem->setEnabled( false ); // NOT AVAILABLE YET
178 #ifndef MINDIST_ENABLE_OBJECT
179 aFObject->setEnabled( false ); // NOT AVAILABLE YET
180 //aSObject->setEnabled( false ); // NOT AVAILABLE YET
182 myDX->setReadOnly( true );
183 myDY->setReadOnly( true );
184 myDZ->setReadOnly( true );
185 myDistance->setReadOnly( true );
187 myValidator = new SMESHGUI_IdValidator( this, 1 );
189 myFirstTgt->installEventFilter( this );
190 mySecondTgt->installEventFilter( this );
192 connect( myFirst, SIGNAL( buttonClicked( int ) ), this, SLOT( firstChanged() ) );
193 connect( mySecond, SIGNAL( buttonClicked( int ) ), this, SLOT( secondChanged() ) );
194 connect( aCompute, SIGNAL( clicked() ), this, SLOT( compute() ) );
195 connect( myFirstTgt, SIGNAL( textEdited( QString ) ), this, SLOT( firstEdited() ) );
196 connect( mySecondTgt, SIGNAL( textEdited( QString ) ), this, SLOT( secondEdited() ) );
198 QList<SUIT_SelectionFilter*> filters;
199 filters.append( new SMESH_TypeFilter( SMESH::MESHorSUBMESH ) );
200 filters.append( new SMESH_TypeFilter( SMESH::GROUP ) );
201 myFilter = new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR );
203 mySecondTgt->setEnabled( mySecond->checkedId() != OriginTgt );
206 //setTarget( FirstTgt );
213 SMESHGUI_MinDistance::~SMESHGUI_MinDistance()
224 \return \c true if event is filtered or \c false otherwise
226 bool SMESHGUI_MinDistance::eventFilter( QObject* o, QEvent* e )
228 if ( e->type() == QEvent::FocusIn ) {
229 if ( o == myFirstTgt )
230 setTarget( FirstTgt );
231 else if ( o == mySecondTgt )
232 setTarget( SecondTgt );
234 return QWidget::eventFilter( o, e );
238 \brief Setup selection mode depending on the current widget state
240 void SMESHGUI_MinDistance::updateSelection()
242 LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
244 disconnect( selMgr, 0, this, 0 );
245 selMgr->clearFilters();
247 bool nodeMode = ( myCurrentTgt == FirstTgt && myFirst->checkedId() == NodeTgt ) ||
248 ( myCurrentTgt == SecondTgt && mySecond->checkedId() == NodeTgt );
249 bool elemMode = ( myCurrentTgt == FirstTgt && myFirst->checkedId() == ElementTgt ) ||
250 ( myCurrentTgt == SecondTgt && mySecond->checkedId() == ElementTgt );
251 bool objMode = ( myCurrentTgt == FirstTgt && myFirst->checkedId() == ObjectTgt ) ||
252 ( myCurrentTgt == SecondTgt && mySecond->checkedId() == ObjectTgt ) ||
253 ( myCurrentTgt == NoTgt );
256 SMESH::SetPointRepresentation( true );
257 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
258 aViewWindow->SetSelectionMode( NodeSelection );
260 else if ( elemMode ) {
261 SMESH::SetPointRepresentation( false );
262 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
263 aViewWindow->SetSelectionMode( CellSelection );
265 else if ( objMode ) {
266 SMESH::SetPointRepresentation( false );
267 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
268 aViewWindow->SetSelectionMode( ActorSelection );
269 selMgr->installFilter( myFilter );
272 connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( selectionChanged() ) );
274 if ( myCurrentTgt == FirstTgt )
276 else if ( myCurrentTgt == SecondTgt )
279 //selectionChanged();
283 \brief Deactivate widget
285 void SMESHGUI_MinDistance::deactivate()
287 disconnect( SMESHGUI::selectionMgr(), 0, this, 0 );
291 \brief Set current target for selection
292 \param target new target ID
294 void SMESHGUI_MinDistance::setTarget( int target )
296 if ( myCurrentTgt != target ) {
297 myCurrentTgt = target;
303 \brief Erase preview actor
305 void SMESHGUI_MinDistance::erasePreview()
307 SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow();
308 if ( aViewWindow && myPreview ) {
309 aViewWindow->RemoveActor( myPreview );
310 aViewWindow->Repaint();
315 \brief Display preview actor
317 void SMESHGUI_MinDistance::displayPreview()
319 SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow();
320 if ( aViewWindow && myPreview ) {
321 aViewWindow->AddActor( myPreview );
322 aViewWindow->Repaint();
327 \brief Create preview actor
328 \param x1 X coordinate of first point
329 \param y1 X coordinate of first point
330 \param z1 Y coordinate of first point
331 \param x2 Y coordinate of second point
332 \param y2 Z coordinate of second point
333 \param z2 Z coordinate of second point
335 void SMESHGUI_MinDistance::createPreview( double x1, double y1, double z1, double x2, double y2, double z2 )
340 vtkUnstructuredGrid* aGrid = vtkUnstructuredGrid::New();
342 vtkPoints* aPoints = vtkPoints::New();
343 aPoints->SetNumberOfPoints( 2 );
344 aPoints->SetPoint( 0, x1, y1, z1 );
345 aPoints->SetPoint( 1, x2, y2, z2 );
346 aGrid->SetPoints( aPoints );
349 vtkIdList* anIdList = vtkIdList::New();
350 anIdList->SetNumberOfIds( 2 );
351 vtkCellArray* aCells = vtkCellArray::New();
352 aCells->Allocate( 2, 0);
353 vtkUnsignedCharArray* aCellTypesArray = vtkUnsignedCharArray::New();
354 aCellTypesArray->SetNumberOfComponents( 1 );
355 aCellTypesArray->Allocate( 1 );
356 anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 1 );
357 aCells->InsertNextCell( anIdList );
358 aCellTypesArray->InsertNextValue( VTK_LINE );
360 VTKViewer_CellLocationsArray* aCellLocationsArray = VTKViewer_CellLocationsArray::New();
361 aCellLocationsArray->SetNumberOfComponents( 1 );
362 aCellLocationsArray->SetNumberOfTuples( 1 );
363 aCells->InitTraversal();
364 vtkIdType const *pts(nullptr);
365 for( vtkIdType idType = 0, npts; aCells->GetNextCell( npts, pts ); idType++ )
366 aCellLocationsArray->SetValue( idType, aCells->GetTraversalLocation( npts ) );
367 aGrid->SetCells( aCellTypesArray, aCellLocationsArray, aCells );
368 aCellLocationsArray->Delete();
369 aCellTypesArray->Delete();
372 vtkDataSetMapper* aMapper = vtkDataSetMapper::New();
373 aMapper->SetInputData( aGrid );
375 myPreview = SALOME_Actor::New();
376 myPreview->PickableOff();
377 myPreview->SetMapper( aMapper );
378 myPreview->SetResolveCoincidentTopology(true);
380 vtkProperty* aProp = vtkProperty::New();
381 aProp->SetRepresentationToWireframe();
382 aProp->SetColor( 250, 0, 250 );
383 aProp->SetPointSize( 5 );
384 aProp->SetLineWidth( 3 );
385 myPreview->SetProperty( aProp );
390 \brief Called when selection is changed
392 void SMESHGUI_MinDistance::selectionChanged()
394 SUIT_OverrideCursor wc;
396 SALOME_ListIO selected;
397 SMESHGUI::selectionMgr()->selectedObjects( selected );
399 if ( selected.Extent() == 1 ) {
400 Handle(SALOME_InteractiveObject) IO = selected.First();
401 SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
402 if ( !CORBA::is_nil( obj ) ) {
403 if ( myCurrentTgt == FirstTgt ) {
405 myFirstActor = SMESH::FindActorByEntry( IO->getEntry() );
406 if ( myFirst->checkedId() == ObjectTgt ) {
408 SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
409 myFirstTgt->setText( aName );
412 SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
415 if ( myFirstActor && selector ) {
416 nb = myFirst->checkedId() == NodeTgt ?
417 SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
418 SMESH::GetNameOfSelectedNodes( selector, IO, ID );
421 myFirstTgt->setText( ID.trimmed() );
426 else if ( myCurrentTgt == SecondTgt ) {
428 mySecondActor = SMESH::FindActorByEntry( IO->getEntry() );
429 if ( mySecond->checkedId() == ObjectTgt ) {
431 SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
432 mySecondTgt->setText( aName );
435 SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
438 if ( mySecondActor && selector ) {
439 nb = mySecond->checkedId() == NodeTgt ?
440 SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
441 SMESH::GetNameOfSelectedNodes( selector, IO, ID );
444 mySecondTgt->setText( ID.trimmed() );
446 mySecondTgt->clear();
455 \brief Called when first target mode is changed by the user
457 void SMESHGUI_MinDistance::firstChanged()
459 myFirstSrc = SMESH::SMESH_IDSource::_nil();
461 myFirstTgt->setReadOnly( myFirst->checkedId() == ObjectTgt );
462 myFirstTgt->setValidator( myFirst->checkedId() == ObjectTgt ? 0 : myValidator );
463 setTarget( FirstTgt );
469 \brief Called when second target mode is changed by the user
471 void SMESHGUI_MinDistance::secondChanged()
473 mySecondSrc = SMESH::SMESH_IDSource::_nil();
474 mySecondTgt->setEnabled( mySecond->checkedId() != OriginTgt );
475 mySecondTgt->setReadOnly( mySecond->checkedId() == ObjectTgt );
476 mySecondTgt->setValidator( mySecond->checkedId() == ObjectTgt ? 0 : myValidator );
477 mySecondTgt->clear();
478 setTarget( mySecond->checkedId() != OriginTgt ? SecondTgt : NoTgt );
484 \brief Called when first target is edited by the user
486 void SMESHGUI_MinDistance::firstEdited()
488 setTarget( FirstTgt );
489 if ( sender() == myFirstTgt )
491 SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
492 if ( myFirstActor && selector ) {
493 Handle(SALOME_InteractiveObject) IO = myFirstActor->getIO();
494 if ( myFirst->checkedId() == NodeTgt || myFirst->checkedId() == ElementTgt ) {
495 TColStd_MapOfInteger ID;
496 ID.Add( myFirstTgt->text().toLong() );
497 selector->AddOrRemoveIndex( IO, ID, false );
499 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
500 aViewWindow->highlight( IO, true, true );
505 \brief Called when second target is edited by the user
507 void SMESHGUI_MinDistance::secondEdited()
509 setTarget( SecondTgt );
510 if ( sender() == mySecondTgt )
512 QString text = mySecondTgt->text();
513 if ( !mySecondActor )
516 mySecondTgt->setText( text );
518 SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
519 if ( mySecondActor && selector ) {
520 Handle(SALOME_InteractiveObject) IO = mySecondActor->getIO();
521 if ( mySecond->checkedId() == NodeTgt || mySecond->checkedId() == ElementTgt ) {
522 if ( !text.isEmpty() ) {
523 TColStd_MapOfInteger ID;
524 ID.Add( text.toLong() );
525 selector->AddOrRemoveIndex( IO, ID, false );
528 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
529 aViewWindow->highlight( IO, true, true );
534 \brief Compute the minimum distance between targets
536 void SMESHGUI_MinDistance::compute()
538 SUIT_OverrideCursor wc;
539 SMESH::IDSource_wrap s1;
540 SMESH::IDSource_wrap s2;
541 bool isOrigin = mySecond->checkedId() == OriginTgt;
543 // process first target
544 if ( !CORBA::is_nil( myFirstSrc ) ) {
545 if ( myFirst->checkedId() == NodeTgt || myFirst->checkedId() == ElementTgt ) {
546 SMESH::SMESH_Mesh_var m = myFirstSrc->GetMesh();
547 long id = myFirstTgt->text().toLong();
548 if ( !CORBA::is_nil( m ) && id ) {
549 SMESH::smIdType_array_var ids = new SMESH::smIdType_array();
552 SMESH::SMESH_MeshEditor_var me = m->GetMeshEditor();
553 s1 = me->MakeIDSource( ids.in(), myFirst->checkedId() == NodeTgt ? SMESH::NODE : SMESH::FACE );
562 // process second target
563 if ( !CORBA::is_nil( mySecondSrc ) ) {
564 if ( mySecond->checkedId() == NodeTgt || mySecond->checkedId() == ElementTgt ) {
565 SMESH::SMESH_Mesh_var m = mySecondSrc->GetMesh();
566 long id = mySecondTgt->text().toLong();
567 if ( !CORBA::is_nil( m ) && id ) {
568 SMESH::smIdType_array_var ids = new SMESH::smIdType_array();
571 SMESH::SMESH_MeshEditor_var me = m->GetMeshEditor();
572 s2 = me->MakeIDSource( ids.in(), mySecond->checkedId() == NodeTgt ? SMESH::NODE : SMESH::FACE );
581 if ( !CORBA::is_nil( s1 ) && ( !CORBA::is_nil( s2 ) || isOrigin ) ) {
582 // compute min distance
583 int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
584 SMESH::Measurements_var measure = SMESHGUI::GetSMESHGen()->CreateMeasurements();
585 SMESH::Measure result = measure->MinDistance( s1.in(), s2.in() );
586 measure->UnRegister();
587 myDX->setText( QString::number( result.minX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
588 myDY->setText( QString::number( result.minY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
589 myDZ->setText( QString::number( result.minZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
590 myDistance->setText( QString::number( result.value, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
591 // update preview actor
593 double x1, y1, z1, x2, y2, z2;
594 SMESH::double_array_var coord = s1->GetMesh()->GetNodeXYZ( result.node1 );
595 x1 = coord[0]; y1 = coord[1]; z1 = coord[2];
599 else if ( mySecond->checkedId() == NodeTgt ) {
600 coord = s2->GetMesh()->GetNodeXYZ( result.node2 );
601 x2 = coord[0]; y2 = coord[1]; z2 = coord[2];
605 x2 = result.maxX; y2 = result.maxY; z2 = result.maxZ;
607 createPreview( x1, y1, z1, x2, y2, z2 );
616 \brief Reset the widget to the initial state (nullify result fields)
618 void SMESHGUI_MinDistance::clear()
628 \class SMESHGUI_BoundingBox
629 \brief Bounding box measurement widget.
631 Widget to calculate bounding box of the selected object(s).
636 \param parent parent widget
638 SMESHGUI_BoundingBox::SMESHGUI_BoundingBox( QWidget* parent )
639 : QWidget( parent ), myActor( 0 ), myPreview( 0 )
641 QGroupBox* aSourceGrp = new QGroupBox( tr( "SOURCE" ), this );
642 QRadioButton* aObjects = new QRadioButton( tr( "OBJECTS" ), aSourceGrp );
643 QRadioButton* aNodes = new QRadioButton( tr( "NODES" ), aSourceGrp );
644 QRadioButton* aElements = new QRadioButton( tr( "ELEMENTS" ), aSourceGrp );
645 mySource = new QLineEdit( aSourceGrp );
647 QGridLayout* fl = new QGridLayout( aSourceGrp );
648 fl->setMargin( MARGIN );
649 fl->setSpacing( SPACING );
650 fl->addWidget( aObjects, 0, 0 );
651 fl->addWidget( aNodes, 0, 1 );
652 fl->addWidget( aElements, 0, 2 );
653 fl->addWidget( mySource, 1, 0, 1, 3 );
655 mySourceMode = new QButtonGroup( this );
656 mySourceMode->addButton( aObjects, ObjectsSrc );
657 mySourceMode->addButton( aNodes, NodesSrc );
658 mySourceMode->addButton( aElements, ElementsSrc );
660 QPushButton* aCompute = new QPushButton( tr( "COMPUTE" ), this );
662 QGroupBox* aResults = new QGroupBox( tr( "RESULT" ), this );
663 QLabel* aXminLab = new QLabel( "Xmin", aResults );
664 myXmin = new QLineEdit( aResults );
665 QLabel* aXmaxLab = new QLabel( "Xmax", aResults );
666 myXmax = new QLineEdit( aResults );
667 QLabel* aDxLab = new QLabel( "dX", aResults );
668 myDX = new QLineEdit( aResults );
669 QLabel* aYminLab = new QLabel( "Ymin", aResults );
670 myYmin = new QLineEdit( aResults );
671 QLabel* aYmaxLab = new QLabel( "Ymax", aResults );
672 myYmax = new QLineEdit( aResults );
673 QLabel* aDyLab = new QLabel( "dY", aResults );
674 myDY = new QLineEdit( aResults );
675 QLabel* aZminLab = new QLabel( "Zmin", aResults );
676 myZmin = new QLineEdit( aResults );
677 QLabel* aZmaxLab = new QLabel( "Zmax", aResults );
678 myZmax = new QLineEdit( aResults );
679 QLabel* aDzLab = new QLabel( "dZ", aResults );
680 myDZ = new QLineEdit( aResults );
682 QGridLayout* rl = new QGridLayout( aResults );
683 rl->setMargin( MARGIN );
684 rl->setSpacing( SPACING );
685 rl->addWidget( aXminLab, 0, 0 );
686 rl->addWidget( myXmin, 0, 1 );
687 rl->addWidget( aXmaxLab, 0, 2 );
688 rl->addWidget( myXmax, 0, 3 );
689 rl->addWidget( aDxLab, 0, 4 );
690 rl->addWidget( myDX, 0, 5 );
691 rl->addWidget( aYminLab, 1, 0 );
692 rl->addWidget( myYmin, 1, 1 );
693 rl->addWidget( aYmaxLab, 1, 2 );
694 rl->addWidget( myYmax, 1, 3 );
695 rl->addWidget( aDyLab, 1, 4 );
696 rl->addWidget( myDY, 1, 5 );
697 rl->addWidget( aZminLab, 2, 0 );
698 rl->addWidget( myZmin, 2, 1 );
699 rl->addWidget( aZmaxLab, 2, 2 );
700 rl->addWidget( myZmax, 2, 3 );
701 rl->addWidget( aDzLab, 2, 4 );
702 rl->addWidget( myDZ, 2, 5 );
704 QGridLayout* l = new QGridLayout( this );
705 l->setMargin( MARGIN );
706 l->setSpacing( SPACING );
708 l->addWidget( aSourceGrp, 0, 0, 1, 2 );
709 l->addWidget( aCompute, 1, 0 );
710 l->addWidget( aResults, 2, 0, 1, 2 );
711 l->setColumnStretch( 1, 5 );
712 l->setRowStretch( 3, 5 );
714 aObjects->setChecked( true );
715 myXmin->setReadOnly( true );
716 myXmax->setReadOnly( true );
717 myDX->setReadOnly( true );
718 myYmin->setReadOnly( true );
719 myYmax->setReadOnly( true );
720 myDY->setReadOnly( true );
721 myZmin->setReadOnly( true );
722 myZmax->setReadOnly( true );
723 myDZ->setReadOnly( true );
725 myValidator = new SMESHGUI_IdValidator( this );
727 connect( mySourceMode, SIGNAL( buttonClicked( int ) ), this, SLOT( sourceChanged() ) );
728 connect( aCompute, SIGNAL( clicked() ), this, SLOT( compute() ) );
729 connect( mySource, SIGNAL( textEdited( QString ) ), this, SLOT( sourceEdited() ) );
731 QList<SUIT_SelectionFilter*> filters;
732 filters.append( new SMESH_TypeFilter( SMESH::MESHorSUBMESH ) );
733 filters.append( new SMESH_TypeFilter( SMESH::GROUP ) );
734 myFilter = new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR );
742 SMESHGUI_BoundingBox::~SMESHGUI_BoundingBox()
750 \brief Setup selection mode depending on the current widget state
752 void SMESHGUI_BoundingBox::updateSelection()
754 LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
756 disconnect( selMgr, 0, this, 0 );
757 selMgr->clearFilters();
759 bool nodeMode = mySourceMode->checkedId() == NodesSrc;
760 bool elemMode = mySourceMode->checkedId() == ElementsSrc;
761 bool objMode = mySourceMode->checkedId() == ObjectsSrc;
764 SMESH::SetPointRepresentation( true );
765 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
766 aViewWindow->SetSelectionMode( NodeSelection );
768 else if ( elemMode ) {
769 SMESH::SetPointRepresentation( false );
770 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
771 aViewWindow->SetSelectionMode( CellSelection );
773 else if ( objMode ) {
774 SMESH::SetPointRepresentation( false );
775 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
776 aViewWindow->SetSelectionMode( ActorSelection );
777 selMgr->installFilter( myFilter );
780 connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( selectionChanged() ) );
784 if ( mySource->text().isEmpty() )
789 \brief Deactivate widget
791 void SMESHGUI_BoundingBox::deactivate()
793 disconnect( SMESHGUI::selectionMgr(), 0, this, 0 );
797 \brief Erase preview actor
799 void SMESHGUI_BoundingBox::erasePreview()
801 SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow();
802 if ( aViewWindow && myPreview ) {
803 aViewWindow->RemoveActor( myPreview );
804 aViewWindow->Repaint();
809 \brief Display preview actor
811 void SMESHGUI_BoundingBox::displayPreview()
813 SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow();
814 if ( aViewWindow && myPreview ) {
815 aViewWindow->AddActor( myPreview );
816 aViewWindow->Repaint();
821 \brief Create preview actor
822 \param minX min X coordinate of bounding box
823 \param maxX max X coordinate of bounding box
824 \param minY min Y coordinate of bounding box
825 \param maxY max Y coordinate of bounding box
826 \param minZ min Z coordinate of bounding box
827 \param maxZ max Z coordinate of bounding box
829 void SMESHGUI_BoundingBox::createPreview( double minX, double maxX, double minY, double maxY, double minZ, double maxZ )
834 vtkUnstructuredGrid* aGrid = vtkUnstructuredGrid::New();
836 vtkPoints* aPoints = vtkPoints::New();
837 aPoints->SetNumberOfPoints( 8 );
838 aPoints->SetPoint( 0, minX, minY, minZ );
839 aPoints->SetPoint( 1, maxX, minY, minZ );
840 aPoints->SetPoint( 2, minX, maxY, minZ );
841 aPoints->SetPoint( 3, maxX, maxY, minZ );
842 aPoints->SetPoint( 4, minX, minY, maxZ );
843 aPoints->SetPoint( 5, maxX, minY, maxZ );
844 aPoints->SetPoint( 6, minX, maxY, maxZ );
845 aPoints->SetPoint( 7, maxX, maxY, maxZ );
846 aGrid->SetPoints( aPoints );
849 // 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
850 vtkIdList* anIdList = vtkIdList::New();
851 anIdList->SetNumberOfIds( 2 );
852 vtkCellArray* aCells = vtkCellArray::New();
853 aCells->Allocate( 2*12, 0);
854 vtkUnsignedCharArray* aCellTypesArray = vtkUnsignedCharArray::New();
855 aCellTypesArray->SetNumberOfComponents( 1 );
856 aCellTypesArray->Allocate( 12 );
857 anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 1 );
858 aCells->InsertNextCell( anIdList );
859 aCellTypesArray->InsertNextValue( VTK_LINE );
860 anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 4 );
861 aCells->InsertNextCell( anIdList );
862 aCellTypesArray->InsertNextValue( VTK_LINE );
863 anIdList->SetId( 0, 0 ); anIdList->SetId( 1, 2 );
864 aCells->InsertNextCell( anIdList );
865 aCellTypesArray->InsertNextValue( VTK_LINE );
866 anIdList->SetId( 0, 1 ); anIdList->SetId( 1, 5 );
867 aCells->InsertNextCell( anIdList );
868 aCellTypesArray->InsertNextValue( VTK_LINE );
869 anIdList->SetId( 0, 1 ); anIdList->SetId( 1, 3 );
870 aCells->InsertNextCell( anIdList );
871 aCellTypesArray->InsertNextValue( VTK_LINE );
872 anIdList->SetId( 0, 2 ); anIdList->SetId( 1, 6 );
873 aCells->InsertNextCell( anIdList );
874 aCellTypesArray->InsertNextValue( VTK_LINE );
875 anIdList->SetId( 0, 2 ); anIdList->SetId( 1, 3 );
876 aCells->InsertNextCell( anIdList );
877 aCellTypesArray->InsertNextValue( VTK_LINE );
878 anIdList->SetId( 0, 3 ); anIdList->SetId( 1, 7 );
879 aCells->InsertNextCell( anIdList );
880 aCellTypesArray->InsertNextValue( VTK_LINE );
881 anIdList->SetId( 0, 4 ); anIdList->SetId( 1, 6 );
882 aCells->InsertNextCell( anIdList );
883 aCellTypesArray->InsertNextValue( VTK_LINE );
884 anIdList->SetId( 0, 4 ); anIdList->SetId( 1, 5 );
885 aCells->InsertNextCell( anIdList );
886 aCellTypesArray->InsertNextValue( VTK_LINE );
887 anIdList->SetId( 0, 5 ); anIdList->SetId( 1, 7 );
888 aCells->InsertNextCell( anIdList );
889 aCellTypesArray->InsertNextValue( VTK_LINE );
890 anIdList->SetId( 0, 6 ); anIdList->SetId( 1, 7 );
891 aCells->InsertNextCell( anIdList );
892 aCellTypesArray->InsertNextValue( VTK_LINE );
894 VTKViewer_CellLocationsArray* aCellLocationsArray = VTKViewer_CellLocationsArray::New();
895 aCellLocationsArray->SetNumberOfComponents( 1 );
896 aCellLocationsArray->SetNumberOfTuples( 12 );
897 aCells->InitTraversal();
898 vtkIdType const *pts(nullptr);
899 for( vtkIdType idType = 0, npts; aCells->GetNextCell( npts, pts ); idType++ )
900 aCellLocationsArray->SetValue( idType, aCells->GetTraversalLocation( npts ) );
901 aGrid->SetCells( aCellTypesArray, aCellLocationsArray, aCells );
902 aCellLocationsArray->Delete();
903 aCellTypesArray->Delete();
906 vtkDataSetMapper* aMapper = vtkDataSetMapper::New();
907 aMapper->SetInputData( aGrid );
909 myPreview = SALOME_Actor::New();
910 myPreview->PickableOff();
911 myPreview->SetMapper( aMapper );
913 vtkProperty* aProp = vtkProperty::New();
914 aProp->SetRepresentationToWireframe();
915 aProp->SetColor( 250, 0, 250 );
916 aProp->SetPointSize( 5 );
917 aProp->SetLineWidth( 3 );
918 myPreview->SetProperty( aProp );
923 \brief Called when selection is changed
925 void SMESHGUI_BoundingBox::selectionChanged()
927 SUIT_OverrideCursor wc;
929 SALOME_ListIO selected;
930 SMESHGUI::selectionMgr()->selectedObjects( selected );
932 if ( selected.Extent() == 1 ) {
933 Handle(SALOME_InteractiveObject) IO = selected.First();
934 SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
935 if ( !CORBA::is_nil( obj ) ) {
938 myActor = SMESH::FindActorByEntry( IO->getEntry() );
939 if ( mySourceMode->checkedId() == ObjectsSrc ) {
941 SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
942 mySource->setText( aName );
945 SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
948 if ( myActor && selector ) {
949 nb = mySourceMode->checkedId() == NodesSrc ?
950 SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
951 SMESH::GetNameOfSelectedNodes( selector, IO, ID );
954 myIDs = ID.trimmed();
955 if ( nb < MAX_NB_FOR_EDITOR ) {
956 mySource->setReadOnly( false );
957 if ( mySource->validator() != myValidator )
958 mySource->setValidator( myValidator );
959 mySource->setText( ID.trimmed() );
962 mySource->setReadOnly( true );
963 mySource->setValidator( 0 );
964 mySource->setText( tr( "SELECTED_NB_OBJ" ).arg( nb )
965 .arg( mySourceMode->checkedId() == NodesSrc ? tr( "NB_NODES" ) : tr( "NB_ELEMENTS") ) );
971 mySource->setReadOnly( false );
972 mySource->setValidator( myValidator );
977 else if ( selected.Extent() > 1 ) {
979 SALOME_ListIteratorOfListIO It( selected );
982 if ( mySourceMode->checkedId() == ObjectsSrc ) {
983 for( ; It.More(); It.Next()){
984 Handle(SALOME_InteractiveObject) IO = It.Value();
985 SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
986 if ( !CORBA::is_nil( obj ) ) {
991 SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
992 mySource->setText( aName );
1002 \brief Called when source mode is changed by the user
1004 void SMESHGUI_BoundingBox::sourceChanged()
1008 mySource->setReadOnly( mySourceMode->checkedId() == ObjectsSrc );
1009 mySource->setValidator( mySourceMode->checkedId() == ObjectsSrc ? 0 : myValidator );
1015 \brief Called when source mode is edited by the user
1017 void SMESHGUI_BoundingBox::sourceEdited()
1019 if ( sender() == mySource )
1021 SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
1022 if ( myActor && selector ) {
1023 Handle(SALOME_InteractiveObject) IO = myActor->getIO();
1024 if ( mySourceMode->checkedId() == NodesSrc || mySourceMode->checkedId() == ElementsSrc ) {
1025 TColStd_MapOfInteger ID;
1026 if ( !mySource->isReadOnly() )
1027 myIDs = mySource->text();
1028 QStringList ids = myIDs.split( " ", QString::SkipEmptyParts );
1029 foreach ( QString id, ids )
1030 ID.Add( id.trimmed().toLong() );
1031 selector->AddOrRemoveIndex( IO, ID, false );
1033 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1034 aViewWindow->highlight( IO, true, true );
1039 \brief Calculate bounding box of the selected object(s)
1041 void SMESHGUI_BoundingBox::compute()
1043 SUIT_OverrideCursor wc;
1044 SMESH::ListOfIDSources_var srcList = new SMESH::ListOfIDSources();
1045 if ( mySourceMode->checkedId() == NodesSrc || mySourceMode->checkedId() == ElementsSrc ) {
1046 if ( mySrc.count() > 0 && !CORBA::is_nil( mySrc[0] ) ) {
1047 SMESH::SMESH_Mesh_var m = mySrc[0]->GetMesh();
1048 QStringList ids = myIDs.split( " ", QString::SkipEmptyParts );
1049 if ( !CORBA::is_nil( m ) && ids.count() > 0 ) {
1050 SMESH::smIdType_array_var ids_in = new SMESH::smIdType_array();
1051 ids_in->length( ids.count() );
1052 for( int i = 0; i < ids.count(); i++ )
1053 ids_in[i] = ids[i].trimmed().toLong();
1054 SMESH::SMESH_MeshEditor_var me = m->GetMeshEditor();
1055 SMESH::SMESH_IDSource_var s = me->MakeIDSource( ids_in.in(), mySourceMode->checkedId() == NodesSrc ? SMESH::NODE : SMESH::FACE );
1056 srcList->length( 1 );
1062 srcList->length( mySrc.count() );
1063 for( int i = 0; i < mySrc.count(); i++ ) {
1064 srcList[i] = mySrc[i];
1065 mySrc[i]->Register();
1068 if ( srcList->length() > 0 ) {
1069 // compute bounding box
1070 int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
1071 SMESH::Measurements_var measure = SMESHGUI::GetSMESHGen()->CreateMeasurements();
1072 SMESH::Measure result = measure->BoundingBox( srcList.in() );
1073 SALOME::UnRegister( srcList );
1074 measure->UnRegister();
1075 myXmin->setText( QString::number( result.minX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1076 myXmax->setText( QString::number( result.maxX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1077 myDX->setText( QString::number( result.maxX-result.minX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1078 myYmin->setText( QString::number( result.minY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1079 myYmax->setText( QString::number( result.maxY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1080 myDY->setText( QString::number( result.maxY-result.minY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1081 myZmin->setText( QString::number( result.minZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1082 myZmax->setText( QString::number( result.maxZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1083 myDZ->setText( QString::number( result.maxZ-result.minZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1084 // update preview actor
1086 createPreview( result.minX, result.maxX, result.minY, result.maxY, result.minZ, result.maxZ );
1095 \brief Reset the widget to the initial state (nullify result fields)
1097 void SMESHGUI_BoundingBox::clear()
1112 \class SMESHGUI_BasicProperties
1113 \brief basic properties measurement widget.
1115 Widget to calculate length, area or volume for the selected object(s).
1120 \param parent parent widget
1122 SMESHGUI_BasicProperties::SMESHGUI_BasicProperties( QWidget* parent )
1125 // Property (length, area or volume)
1126 QGroupBox* aPropertyGrp = new QGroupBox( tr( "PROPERTY" ), this );
1128 QRadioButton* aLength = new QRadioButton( tr( "LENGTH" ), aPropertyGrp );
1129 QRadioButton* anArea = new QRadioButton( tr( "AREA" ), aPropertyGrp );
1130 QRadioButton* aVolume = new QRadioButton( tr( "VOLUME" ), aPropertyGrp );
1132 myMode = new QButtonGroup( this );
1133 myMode->addButton( aLength, Length );
1134 myMode->addButton( anArea, Area );
1135 myMode->addButton( aVolume, Volume );
1137 QHBoxLayout* aPropertyLayout = new QHBoxLayout;
1138 aPropertyLayout->addWidget( aLength );
1139 aPropertyLayout->addWidget( anArea );
1140 aPropertyLayout->addWidget( aVolume );
1142 aPropertyGrp->setLayout( aPropertyLayout );
1145 QGroupBox* aSourceGrp = new QGroupBox( tr( "SOURCE_MESH_SUBMESH_GROUP" ), this );
1147 mySource = new QLineEdit( aSourceGrp );
1148 mySource->setReadOnly( true );
1150 QHBoxLayout* aSourceLayout = new QHBoxLayout;
1151 aSourceLayout->addWidget( mySource );
1153 aSourceGrp->setLayout( aSourceLayout );
1156 QPushButton* aCompute = new QPushButton( tr( "COMPUTE" ), this );
1158 // Result of computation (length, area or volume)
1159 myResultGrp = new QGroupBox( this );
1161 myResult = new QLineEdit;
1162 myResult->setReadOnly( true );
1164 QHBoxLayout* aResultLayout = new QHBoxLayout;
1165 aResultLayout->addWidget( myResult );
1167 myResultGrp->setLayout( aResultLayout );
1170 QGridLayout* aMainLayout = new QGridLayout( this );
1171 aMainLayout->setMargin( MARGIN );
1172 aMainLayout->setSpacing( SPACING );
1174 aMainLayout->addWidget( aPropertyGrp, 0, 0, 1, 2 );
1175 aMainLayout->addWidget( aSourceGrp, 1, 0, 1, 2 );
1176 aMainLayout->addWidget( aCompute, 2, 0 );
1177 aMainLayout->addWidget( myResultGrp, 3, 0, 1, 2 );
1178 aMainLayout->setColumnStretch( 1, 5 );
1179 aMainLayout->setRowStretch( 4, 5 );
1185 connect( myMode, SIGNAL( buttonClicked( int ) ), this, SLOT( modeChanged( int ) ) );
1186 connect( aCompute, SIGNAL( clicked() ), this, SLOT( compute() ) );
1189 QList<SUIT_SelectionFilter*> filters;
1190 filters.append( new SMESH_TypeFilter( SMESH::MESHorSUBMESH ) );
1191 filters.append( new SMESH_TypeFilter( SMESH::GROUP ) );
1192 myFilter = new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR );
1198 SMESHGUI_BasicProperties::~SMESHGUI_BasicProperties()
1203 \brief Sets the measurement mode.
1204 \param theMode the mode to set (length, area or volume meausurement)
1206 void SMESHGUI_BasicProperties::setMode( const Mode theMode )
1208 QRadioButton* aButton = qobject_cast<QRadioButton*>( myMode->button( theMode ) );
1210 aButton->setChecked( true );
1211 modeChanged( theMode );
1216 \brief Setup the selection mode.
1218 void SMESHGUI_BasicProperties::updateSelection()
1220 LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
1222 disconnect( selMgr, 0, this, 0 );
1223 selMgr->clearFilters();
1225 SMESH::SetPointRepresentation( false );
1226 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) {
1227 aViewWindow->SetSelectionMode( ActorSelection );
1229 selMgr->installFilter( myFilter );
1231 connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( selectionChanged() ) );
1233 if ( mySource->text().isEmpty() )
1238 \brief Deactivate widget
1240 void SMESHGUI_BasicProperties::deactivate()
1242 disconnect( SMESHGUI::selectionMgr(), 0, this, 0 );
1246 \brief Called when selection is changed
1248 void SMESHGUI_BasicProperties::selectionChanged()
1250 SUIT_OverrideCursor wc;
1252 SALOME_ListIO selected;
1253 SMESHGUI::selectionMgr()->selectedObjects( selected );
1255 if ( selected.Extent() == 1 ) {
1256 Handle(SALOME_InteractiveObject) IO = selected.First();
1257 SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
1258 if ( !CORBA::is_nil( obj ) ) {
1262 SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
1263 mySource->setText( aName );
1271 \brief Called when the measurement mode selection is changed.
1272 \param theMode the selected mode
1274 void SMESHGUI_BasicProperties::modeChanged( int theMode )
1278 if ( theMode == Length ) {
1279 myResultGrp->setTitle( tr("LENGTH") );
1280 } else if ( theMode == Area ) {
1281 myResultGrp->setTitle( tr("AREA") );
1282 } else if ( theMode == Volume ) {
1283 myResultGrp->setTitle( tr("VOLUME") );
1288 \brief Calculate length, area or volume for the selected object(s)
1290 void SMESHGUI_BasicProperties::compute()
1292 SUIT_OverrideCursor wc;
1294 SMESH::SMESH_IDSource_var source;
1296 if ( !CORBA::is_nil( mySrc ) ) {
1298 int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
1299 SMESH::Measurements_var measure = SMESHGUI::GetSMESHGen()->CreateMeasurements();
1303 if ( myMode->checkedId() == Length ) {
1304 result = measure->Length( mySrc.in() );
1305 } else if ( myMode->checkedId() == Area ) {
1306 result = measure->Area( mySrc.in() );
1307 } else if ( myMode->checkedId() == Volume ) {
1308 result = measure->Volume( mySrc.in() );
1311 measure->UnRegister();
1313 myResult->setText( QString::number( result, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1320 \brief Reset the widget to the initial state (nullify the result field)
1322 void SMESHGUI_BasicProperties::clear()
1328 \class SMESHGUI_Angle
1329 \brief Angle measurement widget.
1331 Widget to calculate angle between 3 nodes.
1336 \param parent parent widget
1338 SMESHGUI_Angle::SMESHGUI_Angle( QWidget* parent )
1343 QGroupBox* aNodesGrp = new QGroupBox( tr( "NODES_GROUP" ), this );
1344 myNodes = new QLineEdit( aNodesGrp );
1345 myNodes->setValidator( new SMESHGUI_IdValidator( this, 3 ));
1346 QHBoxLayout* aNodesLayout = new QHBoxLayout( aNodesGrp );
1347 aNodesLayout->addWidget( myNodes );
1350 QPushButton* aCompute = new QPushButton( tr( "COMPUTE" ), this );
1354 QGroupBox* aResultGrp = new QGroupBox( tr( "RESULT" ), this );
1356 myResult = new QLineEdit;
1357 myResult->setReadOnly( true );
1359 QHBoxLayout* aResultLayout = new QHBoxLayout( aResultGrp );
1360 aResultLayout->addWidget( myResult );
1364 QGridLayout* aMainLayout = new QGridLayout( this );
1365 aMainLayout->setMargin( MARGIN );
1366 aMainLayout->setSpacing( SPACING );
1368 aMainLayout->addWidget( aNodesGrp, 0, 0, 1, 2 );
1369 aMainLayout->addWidget( aCompute, 1, 0 );
1370 aMainLayout->addWidget( aResultGrp, 2, 0, 1, 2 );
1371 aMainLayout->setColumnStretch( 1, 5 );
1372 aMainLayout->setRowStretch( 3, 5 );
1375 connect( aCompute, SIGNAL( clicked() ), this, SLOT( compute() ));
1379 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1381 myPreview = new SMESHGUI_MeshEditPreview( aViewWindow );
1382 if ( myPreview && myPreview->GetActor() )
1383 myPreview->GetActor()->GetProperty()->SetLineWidth( 5 );
1388 SMESHGUI_Angle::~SMESHGUI_Angle()
1395 \brief Setup selection mode
1397 void SMESHGUI_Angle::updateSelection()
1399 LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
1401 disconnect( selMgr, 0, this, 0 );
1402 selMgr->clearFilters();
1404 SMESH::SetPointRepresentation( true );
1405 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1406 aViewWindow->SetSelectionMode( NodeSelection );
1408 connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( selectionChanged() ));
1409 connect( myNodes, SIGNAL( textEdited( QString ) ), this, SLOT( nodesEdited() ));
1411 if ( myPoints.empty() )
1416 \brief Called when selection is changed
1418 void SMESHGUI_Angle::selectionChanged()
1421 QString nodesString;
1423 TColStd_IndexedMapOfInteger idsMap;
1424 SALOME_ListIO selected;
1425 SMESHGUI::selectionMgr()->selectedObjects( selected );
1426 selected.Reverse(); // to keep order of selection
1428 SALOME_ListIteratorOfListIO ioIterator( selected );
1429 for ( ; ioIterator.More(); ioIterator.Next() )
1431 Handle(SALOME_InteractiveObject) IO = ioIterator.Value();
1434 if ( SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector() )
1435 selector->GetIndex( IO, idsMap );
1437 if ( SMESH_Actor* actor = SMESH::FindActorByEntry( IO->getEntry() ))
1440 for ( int i = 1; i <= idsMap.Extent() && myPoints.size() < 3; ++i )
1441 if ( addPointByActor( idsMap(i) ))
1442 nodesString += QString(" %1").arg( idsMap(i) );
1445 SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
1446 if ( !CORBA::is_nil( obj ) )
1449 for ( int i = 1; i <= idsMap.Extent() && myPoints.size() < 3; ++i )
1450 if ( addPointByIDSource( idsMap(i) ))
1451 nodesString += QString(" %1").arg( idsMap(i) );
1455 myNodes->setText( nodesString );
1458 //=======================================================================
1460 //purpose : Erase preview and result
1461 //=======================================================================
1463 void SMESHGUI_Angle::clear()
1467 if ( myPreview && myPreview->GetActor())
1469 myPreview->GetActor()->SetVisibility( false );
1470 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1471 aViewWindow->Repaint();
1475 //=======================================================================
1476 //function : addPointByActor
1477 //purpose : append to myPoints XYZ got from myActor
1478 //=======================================================================
1480 bool SMESHGUI_Angle::addPointByActor( int id )
1482 size_t nbP = myPoints.size();
1486 TVisualObjPtr obj = myActor->GetObject();
1487 if ( SMDS_Mesh* mesh = obj->GetMesh() )
1488 if ( const SMDS_MeshNode* node = mesh->FindNode( id ))
1490 SMESH::PointStruct p = { node->X(), node->Y(), node->Z() };
1491 myPoints.push_back( p );
1494 return nbP < myPoints.size();
1497 //=======================================================================
1498 //function : addPointByIDSource
1499 //purpose : append to myPoints XYZ got from myIDSrc
1500 //=======================================================================
1502 bool SMESHGUI_Angle::addPointByIDSource( int id )
1504 size_t nbP = myPoints.size();
1506 if ( !myIDSrc->_is_nil() )
1508 SMESH::SMESH_Mesh_var mesh = myIDSrc->GetMesh();
1509 if ( !mesh->_is_nil() )
1511 SMESH::double_array_var xyz = mesh->GetNodeXYZ( id );
1512 if ( xyz->length() == 3 )
1514 SMESH::PointStruct p = { xyz[0], xyz[1], xyz[2] };
1515 myPoints.push_back( p );
1519 return nbP < myPoints.size();
1522 //=======================================================================
1523 //function : nodesEdited
1524 //purpose : SLOT called when the user types node IDs
1525 //=======================================================================
1527 void SMESHGUI_Angle::nodesEdited()
1531 TColStd_MapOfInteger ID;
1532 QStringList ids = myNodes->text().split( " ", QString::SkipEmptyParts );
1533 foreach ( QString idStr, ids )
1535 int id = idStr.trimmed().toLong();
1536 if (( !ID.Contains( id )) &&
1537 ( addPointByActor( id ) || addPointByIDSource( id )))
1541 SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
1542 if ( myActor && selector )
1544 Handle(SALOME_InteractiveObject) IO = myActor->getIO();
1545 selector->AddOrRemoveIndex( IO, ID, false );
1546 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1547 aViewWindow->highlight( IO, true, true );
1551 //=======================================================================
1552 //function : compute
1553 //purpose : SLOT. Compute angle and show preview
1554 //=======================================================================
1556 void SMESHGUI_Angle::compute()
1558 if ( myPoints.size() != 3 )
1565 SMESH::Measurements_var measure = SMESHGUI::GetSMESHGen()->CreateMeasurements();
1566 double radians = measure->Angle( myPoints[0], myPoints[1], myPoints[2] );
1567 measure->UnRegister();
1571 int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
1572 myResult->setText( QString::number( radians * 180 / M_PI,
1573 precision > 0 ? 'f' : 'g', qAbs( precision )));
1579 if ( !myPreview || !myPreview->GetActor() )
1582 SMESH::MeshPreviewStruct preveiwData;
1584 const double anglePerSeg = 5 * M_PI/180; // angle per an arc segment
1585 const double arcRadiusFactor = 0.5; // arc position, from p1
1587 gp_Pnt p0 ( myPoints[0].x, myPoints[0].y, myPoints[0].z );
1588 gp_Pnt p1 ( myPoints[1].x, myPoints[1].y, myPoints[1].z );
1589 gp_Pnt p2 ( myPoints[2].x, myPoints[2].y, myPoints[2].z );
1590 gp_Vec vec10( p1, p0 ), vec12( p1, p2 ), norm( vec10 ^ vec12 );
1592 if ( norm.Magnitude() <= gp::Resolution() ) // 180 degrees
1593 norm = getNormal( vec10 );
1595 double len10 = vec10.Magnitude();
1596 double len12 = vec12.Magnitude();
1597 double lenMax = Max( len10, len12 );
1598 double arcRadius = arcRadiusFactor * lenMax;
1600 p0 = p1.Translated( lenMax * vec10.Normalized() );
1601 p2 = p1.Translated( lenMax * vec12.Normalized() );
1603 gp_Circ arc( gp_Ax2( p1, norm, vec10 ), arcRadius );
1605 int nbRadialSegmensts = ceil( radians / anglePerSeg ) + 1;
1606 int nbNodes = 3 + ( nbRadialSegmensts + 1 );
1609 preveiwData.nodesXYZ.length( nbNodes );
1611 for ( ; iP < nbRadialSegmensts + 1; ++iP )
1613 double u = double( iP ) / nbRadialSegmensts * radians;
1614 gp_Pnt p = ElCLib::Value( u, arc );
1615 preveiwData.nodesXYZ[ iP ].x = p.X();
1616 preveiwData.nodesXYZ[ iP ].y = p.Y();
1617 preveiwData.nodesXYZ[ iP ].z = p.Z();
1620 preveiwData.nodesXYZ[ iP ].x = p0.X();
1621 preveiwData.nodesXYZ[ iP ].y = p0.Y();
1622 preveiwData.nodesXYZ[ iP ].z = p0.Z();
1624 preveiwData.nodesXYZ[ iP ].x = p1.X();
1625 preveiwData.nodesXYZ[ iP ].y = p1.Y();
1626 preveiwData.nodesXYZ[ iP ].z = p1.Z();
1628 preveiwData.nodesXYZ[ iP ].x = p2.X();
1629 preveiwData.nodesXYZ[ iP ].y = p2.Y();
1630 preveiwData.nodesXYZ[ iP ].z = p2.Z();
1633 preveiwData.elementConnectivities.length( 2 * ( 2 + nbRadialSegmensts ));
1634 for ( int iSeg = 0; iSeg < nbRadialSegmensts; ++iSeg )
1636 preveiwData.elementConnectivities[ iSeg * 2 + 0 ] = iSeg;
1637 preveiwData.elementConnectivities[ iSeg * 2 + 1 ] = iSeg + 1;
1639 int iSeg = nbRadialSegmensts;
1640 preveiwData.elementConnectivities[ iSeg * 2 + 0 ] = iP0;
1641 preveiwData.elementConnectivities[ iSeg * 2 + 1 ] = iP1;
1643 preveiwData.elementConnectivities[ iSeg * 2 + 0 ] = iP1;
1644 preveiwData.elementConnectivities[ iSeg * 2 + 1 ] = iP2;
1647 preveiwData.elementTypes.length( 2 + nbRadialSegmensts );
1648 SMESH::ElementSubType type = { SMESH::EDGE, /*isPoly=*/false, /*nbNodesInElement=*/2 };
1649 for ( CORBA::ULong i = 0; i < preveiwData.elementTypes.length(); ++i )
1650 preveiwData.elementTypes[ i ] = type;
1652 myPreview->SetData( preveiwData );
1655 //================================================================================
1657 * \brief Return normal to a plane of drawing in the case of 180 degrees angle
1659 //================================================================================
1661 gp_Vec SMESHGUI_Angle::getNormal(const gp_Vec& vec10 )
1665 // try to get normal by a face at the 2nd node
1666 if ( myActor && myActor->GetObject()->GetMesh() )
1668 QStringList ids = myNodes->text().split( " ", QString::SkipEmptyParts );
1669 SMDS_Mesh* mesh = myActor->GetObject()->GetMesh();
1670 if ( const SMDS_MeshNode* n = mesh->FindNode( ids[1].trimmed().toLong() ))
1672 SMDS_ElemIteratorPtr faceIt = n->GetInverseElementIterator( SMDSAbs_Face );
1673 while ( faceIt->more() )
1674 if ( SMESH_MeshAlgos::FaceNormal( faceIt->next(), norm ))
1679 if ( vec10.Coord( iMinCoord ) > vec10.Y() ) iMinCoord = 2;
1680 if ( vec10.Coord( iMinCoord ) > vec10.Z() ) iMinCoord = 3;
1683 vec.SetCoord( iMinCoord, vec10.Coord( iMinCoord ) + 1. );
1689 \class SMESHGUI_MeshInfoDlg
1690 \brief Centralized dialog box for the measurements
1695 \param parent parent widget
1696 \param page specifies the dialog page to be shown at the start-up
1698 SMESHGUI_MeasureDlg::SMESHGUI_MeasureDlg( QWidget* parent, int page )
1702 setAttribute( Qt::WA_DeleteOnClose, true );
1703 setWindowTitle( tr( "MEASUREMENTS" ) );
1704 setSizeGripEnabled( true );
1706 SUIT_ResourceMgr* resMgr = SMESHGUI::resourceMgr();
1708 myTabWidget = new QTabWidget( this );
1712 myMinDist = new SMESHGUI_MinDistance( myTabWidget );
1713 int aMinDistInd = myTabWidget->addTab( myMinDist, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_MIN_DIST" ) ), tr( "MIN_DIST" ) );
1717 myBndBox = new SMESHGUI_BoundingBox( myTabWidget );
1718 int aBndBoxInd = myTabWidget->addTab( myBndBox, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_BND_BOX" ) ), tr( "BND_BOX" ) );
1722 myBasicProps = new SMESHGUI_BasicProperties( myTabWidget );
1723 int aBasicPropInd = myTabWidget->addTab( myBasicProps, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_BASIC_PROPS" ) ), tr( "BASIC_PROPERTIES" ) );
1725 myAngle = new SMESHGUI_Angle( myTabWidget );
1726 int aAngleInd = myTabWidget->addTab( myAngle, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_ANGLE" ) ), tr( "ANGLE" ) );
1729 QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this );
1730 okBtn->setAutoDefault( true );
1731 okBtn->setDefault( true );
1733 QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this );
1734 helpBtn->setAutoDefault( true );
1736 QHBoxLayout* btnLayout = new QHBoxLayout;
1737 btnLayout->setSpacing( SPACING );
1738 btnLayout->setMargin( 0 );
1739 btnLayout->addWidget( okBtn );
1740 btnLayout->addStretch( 10 );
1741 btnLayout->addWidget( helpBtn );
1743 QVBoxLayout* l = new QVBoxLayout ( this );
1744 l->setMargin( MARGIN );
1745 l->setSpacing( SPACING );
1746 l->addWidget( myTabWidget );
1748 l->addLayout( btnLayout );
1751 if ( page == MinDistance ) {
1752 anInd = aMinDistInd;
1753 } else if ( page == BoundingBox ) {
1755 } else if ( page == Angle ) {
1757 } else if ( page == Length || page == Area || page == Volume ) {
1758 myBasicProps->setMode( (SMESHGUI_BasicProperties::Mode)(page - Length) );
1759 anInd = aBasicPropInd;
1763 myTabWidget->setCurrentIndex( anInd );
1766 connect( okBtn, SIGNAL( clicked() ), this, SLOT( reject() ) );
1767 connect( helpBtn, SIGNAL( clicked() ), this, SLOT( help() ) );
1768 connect( myTabWidget, SIGNAL( currentChanged( int ) ), this, SLOT( updateSelection() ) );
1769 connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) );
1770 connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalCloseAllDialogs() ), this, SLOT( reject() ) );
1778 SMESHGUI_MeasureDlg::~SMESHGUI_MeasureDlg()
1783 \brief Perform clean-up actions on the dialog box closing.
1785 void SMESHGUI_MeasureDlg::reject()
1787 LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
1788 selMgr->clearFilters();
1789 SMESH::SetPointRepresentation( false );
1790 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1791 aViewWindow->SetSelectionMode( ActorSelection );
1796 \brief Process keyboard event
1797 \param e key press event
1799 void SMESHGUI_MeasureDlg::keyPressEvent( QKeyEvent* e )
1801 QDialog::keyPressEvent( e );
1802 if ( !e->isAccepted() && e->key() == Qt::Key_F1 ) {
1809 \brief Reactivate dialog box, when mouse pointer goes into it.
1811 void SMESHGUI_MeasureDlg::enterEvent( QEvent* )
1817 \brief Setup selection mode depending on the current dialog box state.
1819 void SMESHGUI_MeasureDlg::updateSelection()
1821 if ( myTabWidget->currentIndex() == MinDistance )
1822 myMinDist->updateSelection();
1823 else if ( myTabWidget->currentIndex() == BoundingBox )
1824 myBndBox->updateSelection();
1825 else if ( myTabWidget->currentWidget() == myAngle )
1826 myAngle->updateSelection();
1828 myBndBox->erasePreview();
1829 myBasicProps->updateSelection();
1834 \brief Show help page
1836 void SMESHGUI_MeasureDlg::help()
1839 if ( myTabWidget->currentIndex() == MinDistance ) {
1840 aHelpFile = "measurements.html#min-distance-anchor";
1841 } else if ( myTabWidget->currentIndex() == BoundingBox ) {
1842 aHelpFile = "measurements.html#bounding-box-anchor";
1843 } else if ( myTabWidget->currentWidget() == myAngle ) {
1844 aHelpFile = "measurements.html#angle-anchor";
1846 aHelpFile = "measurements.html#basic-properties-anchor";
1849 SMESH::ShowHelpFile( aHelpFile );
1853 \brief Activate dialog box
1855 void SMESHGUI_MeasureDlg::activate()
1857 SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog();
1858 SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this );
1859 myTabWidget->setEnabled( true );
1864 \brief Deactivate dialog box
1866 void SMESHGUI_MeasureDlg::deactivate()
1868 myBasicProps->deactivate();
1869 myMinDist->deactivate();
1870 myBndBox->deactivate();
1871 myTabWidget->setEnabled( false );
1872 disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );