Salome HOME
PAL20885 EDF 607 SMESH: Measure tools
authorvsr <vsr@opencascade.com>
Tue, 2 Nov 2010 21:43:34 +0000 (21:43 +0000)
committervsr <vsr@opencascade.com>
Tue, 2 Nov 2010 21:43:34 +0000 (21:43 +0000)
GUI part 1: Min Distance

src/SMESHGUI/Makefile.am
src/SMESHGUI/SMESHGUI.cxx
src/SMESHGUI/SMESHGUI_Measurements.cxx [new file with mode: 0644]
src/SMESHGUI/SMESHGUI_Measurements.h [new file with mode: 0644]
src/SMESHGUI/SMESH_msg_en.ts
src/SMESH_I/SMESH_Measurements_i.cxx

index 43ed76c57312a24e9f0dab97ef2080969c621175..7e7448f59556982a622799adcf6fcd36c6458315 100644 (file)
@@ -48,6 +48,7 @@ salomeinclude_HEADERS = \
        SMESHGUI_RemoveNodesDlg.h \
        SMESHGUI_RemoveElementsDlg.h \
        SMESHGUI_MeshInfo.h \
+       SMESHGUI_Measurements.h \
        SMESHGUI_Preferences_ColorDlg.h \
        SMESHGUI_Preferences_ScalarBarDlg.h \
        SMESHGUI_AddMeshElementDlg.h \
@@ -110,6 +111,7 @@ dist_libSMESH_la_SOURCES = \
        SMESHGUI_RemoveNodesDlg.cxx \
        SMESHGUI_RemoveElementsDlg.cxx \
        SMESHGUI_MeshInfo.cxx \
+       SMESHGUI_Measurements.cxx \
        SMESHGUI_Preferences_ColorDlg.cxx \
        SMESHGUI_Preferences_ScalarBarDlg.cxx \
        SMESHGUI_AddMeshElementDlg.cxx \
@@ -180,6 +182,7 @@ MOC_FILES = \
        SMESHGUI_RemoveNodesDlg_moc.cxx \
        SMESHGUI_RemoveElementsDlg_moc.cxx \
        SMESHGUI_MeshInfo_moc.cxx \
+       SMESHGUI_Measurements_moc.cxx \
        SMESHGUI_Preferences_ColorDlg_moc.cxx \
        SMESHGUI_Preferences_ScalarBarDlg_moc.cxx \
        SMESHGUI_AddMeshElementDlg_moc.cxx \
index bcc33b7480ef402c62bb92b1605b8fef713c9bd9..9a83e9be2043b99d0a852f8b11c74c189c09b07a 100644 (file)
@@ -49,6 +49,7 @@
 #include "SMESHGUI_Make2DFrom3DOp.h"
 #include "SMESHGUI_MakeNodeAtPointDlg.h"
 //#include "SMESHGUI_MeshInfosDlg.h"
+#include "SMESHGUI_Measurements.h"
 #include "SMESHGUI_MeshInfo.h"
 #include "SMESHGUI_MeshOp.h"
 #include "SMESHGUI_MeshOrderOp.h"
@@ -2985,6 +2986,15 @@ bool SMESHGUI::OnGUIEvent( int theCommandID )
       }
       break;
     }
+  case 501:
+  case 502:
+    {
+      int page = theCommandID == 501 ? SMESHGUI_MeasureDlg::MinDistance : SMESHGUI_MeasureDlg::BoundingBox;
+      EmitSignalDeactivateDialog();
+      SMESHGUI_MeasureDlg* dlg = new SMESHGUI_MeasureDlg( SMESHGUI::desktop(), page );
+      dlg->show();
+      break;
+    }
   }
 
   anApp->updateActions(); //SRN: To update a Save button in the toolbar
@@ -3238,6 +3248,9 @@ void SMESHGUI::initialize( CAM_Application* app )
   createSMESHAction( 1137, "DISABLE_AUTO_COLOR" );
   createSMESHAction( 2000, "CTRL" );
 
+  createSMESHAction( 501, "MEASURE_MIN_DIST" );
+  createSMESHAction( 502, "MEASURE_BND_BOX" );
+
   createSMESHAction( 300, "ERASE" );
   createSMESHAction( 301, "DISPLAY" );
   createSMESHAction( 302, "DISPLAY_ONLY" );
@@ -3251,13 +3264,14 @@ void SMESHGUI::initialize( CAM_Application* app )
   createSMESHAction( 4040, "QUADRATIC_HEXAHEDRON", "ICON_DLG_QUADRATIC_HEXAHEDRON" );
 
   // ----- create menu --------------
-  int fileId   = createMenu( tr( "MEN_FILE" ),   -1,  1 ),
-      editId   = createMenu( tr( "MEN_EDIT" ),   -1,  3 ),
-      toolsId  = createMenu( tr( "MEN_TOOLS" ),  -1,  5, 50 ),
-      meshId   = createMenu( tr( "MEN_MESH" ),   -1, 70, 10 ),
-      ctrlId   = createMenu( tr( "MEN_CTRL" ),   -1, 60, 10 ),
-      modifyId = createMenu( tr( "MEN_MODIFY" ), -1, 40, 10 ),
-      viewId   = createMenu( tr( "MEN_VIEW" ),   -1,  2 );
+  int fileId    = createMenu( tr( "MEN_FILE" ),    -1,  1 ),
+      editId    = createMenu( tr( "MEN_EDIT" ),    -1,  3 ),
+      toolsId   = createMenu( tr( "MEN_TOOLS" ),   -1,  5, 50 ),
+      meshId    = createMenu( tr( "MEN_MESH" ),    -1, 70, 10 ),
+      ctrlId    = createMenu( tr( "MEN_CTRL" ),    -1, 60, 10 ),
+      modifyId  = createMenu( tr( "MEN_MODIFY" ),  -1, 40, 10 ),
+      measureId = createMenu( tr( "MEN_MEASURE" ), -1, 50, 10 ),
+      viewId    = createMenu( tr( "MEN_VIEW" ),    -1,  2 );
 
   createMenu( separator(), fileId );
 
@@ -3387,6 +3401,8 @@ void SMESHGUI::initialize( CAM_Application* app )
   createMenu( 417, modifyId, -1 );
   createMenu( 418, modifyId, -1 );
 
+  createMenu( 501, measureId, -1 );
+  createMenu( 502, measureId, -1 );
   createMenu( 214, viewId, -1 );
 
   // ----- create toolbars --------------
diff --git a/src/SMESHGUI/SMESHGUI_Measurements.cxx b/src/SMESHGUI/SMESHGUI_Measurements.cxx
new file mode 100644 (file)
index 0000000..5aef4bf
--- /dev/null
@@ -0,0 +1,938 @@
+//  Copyright (C) 2007-2010  CEA/DEN, EDF R&D, OPEN CASCADE
+//
+//  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+//  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2.1 of the License.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+//  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+//  File   : SMESHGUI_Measurements.cxx
+//  Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
+
+#include "SMESHGUI_Measurements.h"
+
+#include "SMESH_Actor.h"
+#include "SMESHGUI.h"
+#include "SMESHGUI_IdValidator.h"
+#include "SMESHGUI_Utils.h"
+#include "SMESHGUI_VTKUtils.h"
+#include <SMESH_TypeFilter.hxx>
+#include <SMESH_LogicalFilter.hxx>
+
+#include <LightApp_SelectionMgr.h>
+#include <SUIT_OverrideCursor.h>
+#include <SUIT_ResourceMgr.h>
+#include <SVTK_ViewWindow.h>
+#include <SALOME_ListIteratorOfListIO.hxx>
+
+#include <QButtonGroup>
+#include <QGridLayout>
+#include <QGroupBox>
+#include <QHBoxLayout>
+#include <QKeyEvent>
+#include <QLabel>
+#include <QLineEdit>
+#include <QPushButton>
+#include <QRadioButton>
+#include <QTabWidget>
+#include <QVBoxLayout>
+
+#include <SALOMEconfig.h>
+#include CORBA_SERVER_HEADER(SMESH_MeshEditor)
+#include CORBA_SERVER_HEADER(SMESH_Measurements)
+
+const int SPACING = 6;            // layout spacing
+const int MARGIN  = 9;            // layout margin
+const int MAX_NB_FOR_EDITOR = 40; // max nb of items in the ID list editor field
+
+// Uncomment as soon as elements are supported by Min Distance operation
+//#define MINDIST_ENABLE_ELEMENT
+
+// Uncomment as soon as objects are supported by Min Distance operation
+//#define MINDIST_ENABLE_OBJECT
+
+/*!
+  \class SMESHGUI_MinDistance
+  \brief Minimum distance measurement widget.
+  
+  Widget to calculate minimum distance between two objects.
+*/
+
+/*!
+  \brief Constructor.
+  \param parent parent widget
+*/
+SMESHGUI_MinDistance::SMESHGUI_MinDistance( QWidget* parent )
+: QWidget( parent ), myCurrentTgt( FirstTgt ), myFirstActor( 0 ), mySecondActor( 0 )
+{
+  QGroupBox*    aFirstTgtGrp = new QGroupBox( tr( "FIRST_TARGET" ), this );
+  QRadioButton* aFNode       = new QRadioButton( tr( "NODE" ),    aFirstTgtGrp );
+  QRadioButton* aFElem       = new QRadioButton( tr( "ELEMENT" ), aFirstTgtGrp );
+  QRadioButton* aFObject     = new QRadioButton( tr( "OBJECT" ),  aFirstTgtGrp );
+  myFirstTgt                 = new QLineEdit( aFirstTgtGrp );
+
+  QGridLayout* fl = new QGridLayout( aFirstTgtGrp );
+  fl->setMargin( MARGIN );
+  fl->setSpacing( SPACING );
+  fl->addWidget( aFNode,     0, 0 );
+  fl->addWidget( aFElem,     0, 1 );
+  fl->addWidget( aFObject,   0, 2 );
+  fl->addWidget( myFirstTgt, 1, 0, 1, 3 );
+
+  myFirst = new QButtonGroup( this );
+  myFirst->addButton( aFNode,   NodeTgt );
+  myFirst->addButton( aFElem,   ElementTgt );
+  myFirst->addButton( aFObject, ObjectTgt );
+
+  QGroupBox*    aSecondTgtGrp = new QGroupBox( tr( "SECOND_TARGET" ), this );
+  QRadioButton* aSOrigin      = new QRadioButton( tr( "ORIGIN" ),  aSecondTgtGrp );
+  QRadioButton* aSNode        = new QRadioButton( tr( "NODE" ),    aSecondTgtGrp );
+  QRadioButton* aSElem        = new QRadioButton( tr( "ELEMENT" ), aSecondTgtGrp );
+  QRadioButton* aSObject      = new QRadioButton( tr( "OBJECT" ),  aSecondTgtGrp );
+  mySecondTgt                 = new QLineEdit( aSecondTgtGrp );
+
+  QGridLayout* sl = new QGridLayout( aSecondTgtGrp );
+  sl->setMargin( MARGIN );
+  sl->setSpacing( SPACING );
+  sl->addWidget( aSOrigin,   0, 0 );
+  sl->addWidget( aSNode,     0, 1 );
+  sl->addWidget( aSElem,     0, 2 );
+  sl->addWidget( aSObject,   0, 3 );
+  sl->addWidget( mySecondTgt, 1, 0, 1, 4 );
+
+  mySecond = new QButtonGroup( this );
+  mySecond->addButton( aSOrigin, OriginTgt );
+  mySecond->addButton( aSNode,   NodeTgt );
+  mySecond->addButton( aSElem,   ElementTgt );
+  mySecond->addButton( aSObject, ObjectTgt );
+
+  QPushButton* aCompute = new QPushButton( tr( "COMPUTE" ), this );
+  
+  QGroupBox* aResults = new QGroupBox( tr( "RESULT" ), this );
+  QLabel* aDxLab   = new QLabel( "dX", aResults );
+  myDX             = new QLineEdit( aResults );
+  QLabel* aDyLab   = new QLabel( "dY", aResults );
+  myDY             = new QLineEdit( aResults );
+  QLabel* aDzLab   = new QLabel( "dZ", aResults );
+  myDZ             = new QLineEdit( aResults );
+  QLabel* aDistLab = new QLabel( tr( "DISTANCE" ), aResults );
+  myDistance       = new QLineEdit( aResults );
+
+  QGridLayout* rl = new QGridLayout( aResults );
+  rl->setMargin( MARGIN );
+  rl->setSpacing( SPACING );
+  rl->addWidget( aDxLab,     0, 0 );
+  rl->addWidget( myDX,       0, 1 );
+  rl->addWidget( aDyLab,     1, 0 );
+  rl->addWidget( myDY,       1, 1 );
+  rl->addWidget( aDzLab,     2, 0 );
+  rl->addWidget( myDZ,       2, 1 );
+  rl->addWidget( aDistLab,   0, 2 );
+  rl->addWidget( myDistance, 0, 3 );
+
+  QGridLayout* l = new QGridLayout( this );
+  l->setMargin( MARGIN );
+  l->setSpacing( SPACING );
+
+  l->addWidget( aFirstTgtGrp,  0, 0, 1, 2 );
+  l->addWidget( aSecondTgtGrp, 1, 0, 1, 2 );
+  l->addWidget( aCompute,      2, 0 );
+  l->addWidget( aResults,      3, 0, 1, 2 );
+  l->setColumnStretch( 1, 5 );
+  l->setRowStretch( 4, 5 );
+
+  aFNode->setChecked( true );
+  aSOrigin->setChecked( true );
+#ifndef MINDIST_ENABLE_ELEMENT
+  aFElem->setEnabled( false );   // NOT AVAILABLE YET
+  aSElem->setEnabled( false );   // NOT AVAILABLE YET
+#endif
+#ifndef MINDIST_ENABLE_OBJECT
+  aFObject->setEnabled( false ); // NOT AVAILABLE YET
+  aSObject->setEnabled( false ); // NOT AVAILABLE YET
+#endif
+  myDX->setReadOnly( true );
+  myDY->setReadOnly( true );
+  myDZ->setReadOnly( true );
+  myDistance->setReadOnly( true );
+
+  myValidator = new SMESHGUI_IdValidator( this, 1 );
+
+  myFirstTgt->installEventFilter( this );
+  mySecondTgt->installEventFilter( this );
+
+  connect( myFirst,     SIGNAL( buttonClicked( int ) ),  this, SLOT( firstChanged() ) );
+  connect( mySecond,    SIGNAL( buttonClicked( int ) ),  this, SLOT( secondChanged() ) );
+  connect( aCompute,    SIGNAL( clicked() ),             this, SLOT( compute() ) );
+  connect( myFirstTgt,  SIGNAL( textEdited( QString ) ), this, SLOT( firstEdited() ) );
+  connect( mySecondTgt, SIGNAL( textEdited( QString ) ), this, SLOT( secondEdited() ) );
+
+  QList<SUIT_SelectionFilter*> filters;
+  filters.append( new SMESH_TypeFilter( MESHorSUBMESH ) );
+  filters.append( new SMESH_TypeFilter( GROUP ) );
+  myFilter = new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR );
+
+  clear();
+
+  //setTarget( FirstTgt );
+}
+
+/*!
+  \brief Destructor
+*/
+SMESHGUI_MinDistance::~SMESHGUI_MinDistance()
+{
+}
+
+/*!
+  \brief Event filter
+  \param o object
+  \param o event
+  \return \c true if event is filtered or \c false otherwise
+*/
+bool SMESHGUI_MinDistance::eventFilter( QObject* o, QEvent* e )
+{
+  if ( e->type() == QEvent::FocusIn ) {
+    if ( o == myFirstTgt )
+      setTarget( FirstTgt );
+    else if ( o == mySecondTgt )
+      setTarget( SecondTgt );
+  }
+  return QWidget::eventFilter( o, e );
+}
+
+/*!
+  \brief Setup selection mode depending on the current widget state
+*/
+void SMESHGUI_MinDistance::updateSelection()
+{
+  LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
+
+  disconnect( selMgr, 0, this, 0 );
+  selMgr->clearFilters();
+  
+  bool nodeMode = ( myCurrentTgt == FirstTgt  && myFirst->checkedId() == NodeTgt ) ||
+                  ( myCurrentTgt == SecondTgt && mySecond->checkedId() == NodeTgt );
+  bool elemMode = ( myCurrentTgt == FirstTgt  && myFirst->checkedId() == ElementTgt ) ||
+                  ( myCurrentTgt == SecondTgt && mySecond->checkedId() == ElementTgt );
+  bool objMode  = ( myCurrentTgt == FirstTgt  && myFirst->checkedId() == ObjectTgt ) ||
+                  ( myCurrentTgt == SecondTgt && mySecond->checkedId() == ObjectTgt ) ||
+                  ( myCurrentTgt == NoTgt );
+
+  if ( nodeMode ) {
+    SMESH::SetPointRepresentation( true );
+    if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
+      aViewWindow->SetSelectionMode( NodeSelection );
+  }
+  else if ( elemMode ) {
+    SMESH::SetPointRepresentation( false );
+    if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
+      aViewWindow->SetSelectionMode( CellSelection );
+  }
+  else if ( objMode ) {
+    SMESH::SetPointRepresentation( false );
+    if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
+      aViewWindow->SetSelectionMode( ActorSelection );
+    selMgr->installFilter( myFilter );
+  }
+
+  connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( selectionChanged() ) );
+
+  if ( myCurrentTgt == FirstTgt )
+    firstEdited();
+  else if ( myCurrentTgt == SecondTgt )
+    secondEdited();
+
+  //selectionChanged();
+}
+
+/*!
+  \brief Deactivate widget
+*/
+void SMESHGUI_MinDistance::deactivate()
+{
+  disconnect( SMESHGUI::selectionMgr(), 0, this, 0 );
+}
+
+/*!
+  \brief Set current target for selection
+  \param target new target ID
+*/
+void SMESHGUI_MinDistance::setTarget( int target )
+{
+  if ( myCurrentTgt != target ) {
+    myCurrentTgt = target;
+    updateSelection();
+  }
+}
+
+/*!
+  \brief Called when selection is changed
+*/
+void SMESHGUI_MinDistance::selectionChanged()
+{
+  SUIT_OverrideCursor wc;
+
+  SALOME_ListIO selected;
+  SMESHGUI::selectionMgr()->selectedObjects( selected );
+
+  if ( selected.Extent() == 1 ) {
+    Handle(SALOME_InteractiveObject) IO = selected.First();
+    SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
+    if ( !CORBA::is_nil( obj ) ) {
+      if ( myCurrentTgt == FirstTgt ) {
+       myFirstSrc = obj;
+       myFirstActor = SMESH::FindActorByEntry( IO->getEntry() );
+       if ( myFirst->checkedId() == ObjectTgt ) {
+         QString aName;
+         SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
+         myFirstTgt->setText( aName );
+       }
+       else {
+         SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
+         QString ID;
+         int nb = 0;
+         if ( myFirstActor && selector ) {
+           nb = myFirst->checkedId() == NodeTgt ? 
+             SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
+             SMESH::GetNameOfSelectedNodes( selector, IO, ID );
+         }
+         if ( nb == 1 )
+           myFirstTgt->setText( ID.trimmed() );
+         else
+           myFirstTgt->clear();
+       }
+      }
+      else if ( myCurrentTgt == SecondTgt ) {
+       mySecondSrc = obj;
+       mySecondActor = SMESH::FindActorByEntry( IO->getEntry() );
+       if ( mySecond->checkedId() == ObjectTgt ) {
+         QString aName;
+         SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
+         mySecondTgt->setText( aName );
+       }
+       else {
+         SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
+         QString ID;
+         int nb = 0;
+         if ( mySecondActor && selector ) {
+           nb = mySecond->checkedId() == NodeTgt ? 
+             SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
+             SMESH::GetNameOfSelectedNodes( selector, IO, ID );
+         }
+         if ( nb == 1 )
+           mySecondTgt->setText( ID.trimmed() );
+         else
+           mySecondTgt->clear();
+       }
+      }
+    }
+  }
+}
+
+/*!
+  \brief Called when first target mode is changed by the user
+*/
+void SMESHGUI_MinDistance::firstChanged()
+{
+  myFirstTgt->clear();
+  myFirstTgt->setReadOnly( myFirst->checkedId() == ObjectTgt );
+  myFirstTgt->setValidator( myFirst->checkedId() == ObjectTgt ? 0 : myValidator );
+  setTarget( FirstTgt );
+  updateSelection();
+  clear();
+}
+
+/*!
+  \brief Called when second target mode is changed by the user
+*/
+void SMESHGUI_MinDistance::secondChanged()
+{
+  mySecondTgt->setEnabled( mySecond->checkedId() != OriginTgt );
+  mySecondTgt->setReadOnly( mySecond->checkedId() == ObjectTgt );
+  mySecondTgt->setValidator( mySecond->checkedId() == ObjectTgt ? 0 : myValidator );
+  mySecondTgt->clear();
+  setTarget( mySecond->checkedId() != OriginTgt ? SecondTgt : NoTgt );
+  updateSelection();
+  clear();
+}
+
+/*!
+  \brief Called when first target is edited by the user
+*/
+void SMESHGUI_MinDistance::firstEdited()
+{
+  setTarget( FirstTgt );
+  clear();
+  SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
+  if ( myFirstActor && selector ) {
+    Handle(SALOME_InteractiveObject) IO = myFirstActor->getIO();
+    if ( myFirst->checkedId() == NodeTgt || myFirst->checkedId() == ElementTgt ) {
+      TColStd_MapOfInteger ID;
+      ID.Add( myFirstTgt->text().toLong() );
+      selector->AddOrRemoveIndex( IO, ID, false );
+    }
+    if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
+      aViewWindow->highlight( IO, true, true );
+  }
+}
+
+/*!
+  \brief Called when second target is edited by the user
+*/
+void SMESHGUI_MinDistance::secondEdited()
+{
+  setTarget( SecondTgt );
+  clear();
+  SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
+  if ( mySecondActor && selector ) {
+    Handle(SALOME_InteractiveObject) IO = mySecondActor->getIO();
+    if ( mySecond->checkedId() == NodeTgt || mySecond->checkedId() == ElementTgt ) {
+      TColStd_MapOfInteger ID;
+      ID.Add( mySecondTgt->text().toLong() );
+      selector->AddOrRemoveIndex( IO, ID, false );
+    }
+    if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
+      aViewWindow->highlight( IO, true, true );
+  }
+}
+
+/*!
+  \brief Compute the minimum distance between targets
+*/
+void SMESHGUI_MinDistance::compute()
+{
+  SUIT_OverrideCursor wc;
+  SMESH::SMESH_IDSource_var s1;
+  SMESH::SMESH_IDSource_var s2;
+  bool isOrigin = mySecond->checkedId() == OriginTgt;
+
+  // process first target
+  if ( !CORBA::is_nil( myFirstSrc ) ) {
+    if ( myFirst->checkedId() == NodeTgt || myFirst->checkedId() == ElementTgt ) {
+      SMESH::SMESH_Mesh_var m = myFirstSrc->GetMesh();
+      long id = myFirstTgt->text().toLong();
+      if ( !CORBA::is_nil( m ) && id ) {
+       SMESH::long_array_var ids = new SMESH::long_array();
+       ids->length( 1 );
+       ids[0] = id;
+       SMESH::SMESH_MeshEditor_var me = m->GetMeshEditor();
+       s1 = me->MakeIDSource( ids.in(), myFirst->checkedId() == NodeTgt ? SMESH::NODE : SMESH::FACE );
+      }
+    }
+    else {
+      s1 = myFirstSrc;
+    }
+  }
+
+  // process second target
+  if ( !CORBA::is_nil( mySecondSrc ) ) {
+    if ( mySecond->checkedId() == NodeTgt || mySecond->checkedId() == ElementTgt ) {
+      SMESH::SMESH_Mesh_var m = mySecondSrc->GetMesh();
+      long id = mySecondTgt->text().toLong();
+      if ( !CORBA::is_nil( m ) && id ) {
+       SMESH::long_array_var ids = new SMESH::long_array();
+       ids->length( 1 );
+       ids[0] = id;
+       SMESH::SMESH_MeshEditor_var me = m->GetMeshEditor();
+       s2 = me->MakeIDSource( ids.in(), mySecond->checkedId() == NodeTgt ? SMESH::NODE : SMESH::FACE );
+      }
+    }
+    else {
+      s2 = mySecondSrc;
+    }
+  }
+
+  if ( !CORBA::is_nil( s1 ) && ( !CORBA::is_nil( s2 ) || isOrigin ) ) {
+    int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
+    SMESH::Measurements_var measure = SMESHGUI::GetSMESHGen()->CreateMeasurements();
+    SMESH::Measure result = measure->MinDistance( s1.in(), s2.in() );
+    measure->Destroy();
+    myDX->setText( QString::number( result.minX, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
+    myDY->setText( QString::number( result.minY, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
+    myDZ->setText( QString::number( result.minZ, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
+    myDistance->setText( QString::number( result.value, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
+  }
+  else {
+    clear();
+  }
+}
+
+/*!
+  \brief Reset the widget to the initial state (nullify result fields)
+*/
+void SMESHGUI_MinDistance::clear()
+{
+  myDX->clear();
+  myDY->clear();
+  myDZ->clear();
+  myDistance->clear();
+}
+
+/*!
+  \class SMESHGUI_BoundingBox
+  \brief Bounding box measurement widget.
+  
+  Widget to calculate bounding box of the selected object(s).
+*/
+
+/*!
+  \brief Constructor.
+  \param parent parent widget
+*/
+SMESHGUI_BoundingBox::SMESHGUI_BoundingBox( QWidget* parent )
+: QWidget( parent ), myActor( 0 )
+{
+  QGroupBox* aSourceGrp = new QGroupBox( tr( "SOURCE" ), this );
+  QRadioButton* aObjects  = new QRadioButton( tr( "OBJECTS" ),  aSourceGrp );
+  QRadioButton* aNodes    = new QRadioButton( tr( "NODES" ),    aSourceGrp );
+  QRadioButton* aElements = new QRadioButton( tr( "ELEMENTS" ), aSourceGrp );
+  mySource = new QLineEdit( aSourceGrp );
+  
+  QGridLayout* fl = new QGridLayout( aSourceGrp );
+  fl->setMargin( MARGIN );
+  fl->setSpacing( SPACING );
+  fl->addWidget( aObjects,   0, 0 );
+  fl->addWidget( aNodes,     0, 1 );
+  fl->addWidget( aElements,  0, 2 );
+  fl->addWidget( mySource,   1, 0, 1, 3 );
+  
+  mySourceMode = new QButtonGroup( this );
+  mySourceMode->addButton( aObjects,  ObjectsSrc );
+  mySourceMode->addButton( aNodes,    NodesSrc );
+  mySourceMode->addButton( aElements, ElementsSrc );
+
+  QPushButton* aCompute = new QPushButton( tr( "COMPUTE" ), this );
+
+  QGroupBox* aResults = new QGroupBox( tr( "RESULT" ), this );
+  QLabel* aXminLab = new QLabel( "Xmin", aResults );
+  myXmin           = new QLineEdit( aResults );
+  QLabel* aXmaxLab = new QLabel( "Xmax", aResults );
+  myXmax           = new QLineEdit( aResults );
+  QLabel* aDxLab   = new QLabel( "dX", aResults );
+  myDX             = new QLineEdit( aResults );
+  QLabel* aYminLab = new QLabel( "Ymin", aResults );
+  myYmin           = new QLineEdit( aResults );
+  QLabel* aYmaxLab = new QLabel( "Ymax", aResults );
+  myYmax           = new QLineEdit( aResults );
+  QLabel* aDyLab   = new QLabel( "dY", aResults );
+  myDY             = new QLineEdit( aResults );
+  QLabel* aZminLab = new QLabel( "Zmin", aResults );
+  myZmin           = new QLineEdit( aResults );
+  QLabel* aZmaxLab = new QLabel( "Zmax", aResults );
+  myZmax           = new QLineEdit( aResults );
+  QLabel* aDzLab   = new QLabel( "dZ", aResults );
+  myDZ             = new QLineEdit( aResults );
+
+  QGridLayout* rl  = new QGridLayout( aResults );
+  rl->setMargin( MARGIN );
+  rl->setSpacing( SPACING );
+  rl->addWidget( aXminLab,   0, 0 );
+  rl->addWidget( myXmin,     0, 1 );
+  rl->addWidget( aXmaxLab,   0, 2 );
+  rl->addWidget( myXmax,     0, 3 );
+  rl->addWidget( aDxLab,     0, 4 );
+  rl->addWidget( myDX,       0, 5 );
+  rl->addWidget( aYminLab,   1, 0 );
+  rl->addWidget( myYmin,     1, 1 );
+  rl->addWidget( aYmaxLab,   1, 2 );
+  rl->addWidget( myYmax,     1, 3 );
+  rl->addWidget( aDyLab,     1, 4 );
+  rl->addWidget( myDY,       1, 5 );
+  rl->addWidget( aZminLab,   2, 0 );
+  rl->addWidget( myZmin,     2, 1 );
+  rl->addWidget( aZmaxLab,   2, 2 );
+  rl->addWidget( myZmax,     2, 3 );
+  rl->addWidget( aDzLab,     2, 4 );
+  rl->addWidget( myDZ,       2, 5 );
+
+  QGridLayout* l = new QGridLayout( this );
+  l->setMargin( MARGIN );
+  l->setSpacing( SPACING );
+
+  l->addWidget( aSourceGrp, 0, 0, 1, 2 );
+  l->addWidget( aCompute,   1, 0 );
+  l->addWidget( aResults,   2, 0, 1, 2 );
+  l->setColumnStretch( 1, 5 );
+  l->setRowStretch( 3, 5 );
+
+  aObjects->setChecked( true );
+  myXmin->setReadOnly( true );
+  myXmax->setReadOnly( true );
+  myDX->setReadOnly( true );
+  myYmin->setReadOnly( true );
+  myYmax->setReadOnly( true );
+  myDY->setReadOnly( true );
+  myZmin->setReadOnly( true );
+  myZmax->setReadOnly( true );
+  myDZ->setReadOnly( true );
+
+  myValidator = new SMESHGUI_IdValidator( this );
+
+  connect( mySourceMode, SIGNAL( buttonClicked( int ) ),  this, SLOT( sourceChanged() ) );
+  connect( aCompute,     SIGNAL( clicked() ),             this, SLOT( compute() ) );
+  connect( mySource,     SIGNAL( textEdited( QString ) ), this, SLOT( sourceEdited() ) );
+
+  QList<SUIT_SelectionFilter*> filters;
+  filters.append( new SMESH_TypeFilter( MESHorSUBMESH ) );
+  filters.append( new SMESH_TypeFilter( GROUP ) );
+  myFilter = new SMESH_LogicalFilter( filters, SMESH_LogicalFilter::LO_OR );
+
+  clear();
+}
+
+/*!
+  \brief Destructor
+*/
+SMESHGUI_BoundingBox::~SMESHGUI_BoundingBox()
+{
+}
+
+/*!
+  \brief Setup selection mode depending on the current widget state
+*/
+void SMESHGUI_BoundingBox::updateSelection()
+{
+  LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
+
+  disconnect( selMgr, 0, this, 0 );
+  selMgr->clearFilters();
+  
+  bool nodeMode = mySourceMode->checkedId() == NodesSrc;
+  bool elemMode = mySourceMode->checkedId() == ElementsSrc;
+  bool objMode  = mySourceMode->checkedId() == ObjectsSrc;
+
+  if ( nodeMode ) {
+    SMESH::SetPointRepresentation( true );
+    if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
+      aViewWindow->SetSelectionMode( NodeSelection );
+  }
+  else if ( elemMode ) {
+    SMESH::SetPointRepresentation( false );
+    if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
+      aViewWindow->SetSelectionMode( CellSelection );
+  }
+  else if ( objMode ) {
+    SMESH::SetPointRepresentation( false );
+    if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
+      aViewWindow->SetSelectionMode( ActorSelection );
+    selMgr->installFilter( myFilter );
+  }
+
+  connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( selectionChanged() ) );
+
+  sourceEdited();
+
+  //selectionChanged();
+}
+
+/*!
+  \brief Deactivate widget
+*/
+void SMESHGUI_BoundingBox::deactivate()
+{
+  disconnect( SMESHGUI::selectionMgr(), 0, this, 0 );
+}
+
+/*!
+  \brief Called when selection is changed
+*/
+void SMESHGUI_BoundingBox::selectionChanged()
+{
+  SUIT_OverrideCursor wc;
+
+  SALOME_ListIO selected;
+  SMESHGUI::selectionMgr()->selectedObjects( selected );
+
+  if ( selected.Extent() == 1 ) {
+    Handle(SALOME_InteractiveObject) IO = selected.First();
+    SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
+    if ( !CORBA::is_nil( obj ) ) {
+      mySrc.clear();
+      mySrc.append( obj );
+      myActor = SMESH::FindActorByEntry( IO->getEntry() );
+      if ( mySourceMode->checkedId() == ObjectsSrc ) {
+       QString aName;
+       SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
+       mySource->setText( aName );
+      }
+      else {
+       SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
+       QString ID;
+       int nb = 0;
+       if ( myActor && selector ) {
+         nb = mySourceMode->checkedId() == NodesSrc ? 
+           SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
+           SMESH::GetNameOfSelectedNodes( selector, IO, ID );
+       }
+       if ( nb > 0 ) {
+         myIDs = ID.trimmed();
+         if ( nb < MAX_NB_FOR_EDITOR ) {
+           mySource->setReadOnly( false );
+           if ( mySource->validator() != myValidator )
+             mySource->setValidator( myValidator );
+           mySource->setText( ID.trimmed() );
+         }
+         else {
+           mySource->setReadOnly( true );
+           mySource->setValidator( 0 );
+           mySource->setText( tr( "SELECTED_NB_OBJ" ).arg( nb )
+                              .arg( mySourceMode->checkedId() == NodesSrc ? tr( "NB_NODES" ) : tr( "NB_ELEMENTS") ) );
+         }
+       }
+       else {
+         myIDs = "";
+         mySource->clear();
+         mySource->setReadOnly( false );
+         mySource->setValidator( myValidator );
+       }
+      }
+    }
+  }
+  else if ( selected.Extent() > 1 ) {
+    myIDs = "";
+    SALOME_ListIteratorOfListIO It( selected );
+    mySrc.clear();
+    myActor = 0;
+    if ( mySourceMode->checkedId() == ObjectsSrc ) {
+      for( ; It.More(); It.Next()){
+       Handle(SALOME_InteractiveObject) IO = It.Value();
+       SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
+       if ( !CORBA::is_nil( obj ) ) {
+         mySrc.append( obj );
+       }
+      }
+      QString aName;
+      SMESH::GetNameOfSelectedIObjects( SMESHGUI::selectionMgr(), aName );
+      mySource->setText( aName );
+    }
+    else {
+      mySource->clear();
+    }
+  }
+}
+
+/*!
+  \brief Called when source mode is changed by the user
+*/
+void SMESHGUI_BoundingBox::sourceChanged()
+{
+  myIDs = "";
+  mySource->clear();
+  mySource->setReadOnly( mySourceMode->checkedId() == ObjectsSrc );
+  mySource->setValidator( mySourceMode->checkedId() == ObjectsSrc ? 0 : myValidator );
+  updateSelection();
+  clear();
+}
+
+/*!
+  \brief Called when source mode is edited by the user
+*/
+void SMESHGUI_BoundingBox::sourceEdited()
+{
+  clear();
+  SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
+  if ( myActor && selector ) {
+    Handle(SALOME_InteractiveObject) IO = myActor->getIO();
+    if ( mySourceMode->checkedId() == NodesSrc || mySourceMode->checkedId() == ElementsSrc ) {
+      TColStd_MapOfInteger ID;
+      if ( !mySource->isReadOnly() )
+       myIDs = mySource->text();
+      QStringList ids = mySource->text().split( " ", QString::SkipEmptyParts );
+      foreach ( QString id, ids )
+       ID.Add( id.trimmed().toLong() );
+      selector->AddOrRemoveIndex( IO, ID, false );
+    }
+    if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
+      aViewWindow->highlight( IO, true, true );
+  }
+}
+
+/*!
+  \brief Calculate bounding box of the selected object(s)
+*/
+void SMESHGUI_BoundingBox::compute()
+{
+  SUIT_OverrideCursor wc;
+  if ( mySourceMode->checkedId() == NodesSrc ) {
+  }
+  else {
+  }
+}
+
+/*!
+  \brief Reset the widget to the initial state (nullify result fields)
+*/
+void SMESHGUI_BoundingBox::clear()
+{
+  myXmin->clear();
+  myXmax->clear();
+  myDX->clear();
+  myYmin->clear();
+  myYmax->clear();
+  myDY->clear();
+  myZmin->clear();
+  myZmax->clear();
+  myDZ->clear();
+}
+
+/*!
+  \class SMESHGUI_MeshInfoDlg
+  \brief Centralized dialog box for the measurements
+*/
+
+/*!
+  \brief Constructor
+  \param parent parent widget
+  \param page specifies the dialog page to be shown at the start-up
+*/
+SMESHGUI_MeasureDlg::SMESHGUI_MeasureDlg( QWidget* parent, int page )
+: QDialog( parent )
+{
+  setModal( false );
+  setAttribute( Qt::WA_DeleteOnClose, true );
+  setWindowTitle( tr( "MEASUREMENTS" ) );
+  setSizeGripEnabled( true );
+
+  myTabWidget = new QTabWidget( this );
+
+  // min distance
+
+  myMinDist = new SMESHGUI_MinDistance( myTabWidget );
+  myTabWidget->addTab( myMinDist, tr( "MIN_DIST" ) );
+
+  // bounding box
+  
+  myBndBox = new SMESHGUI_BoundingBox( myTabWidget );
+  myTabWidget->addTab( myBndBox, tr( "BND_BOX" ) );
+
+  // buttons
+  QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this );
+  okBtn->setAutoDefault( true );
+  okBtn->setDefault( true );
+  okBtn->setFocus();
+  QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this );
+  helpBtn->setAutoDefault( true );
+
+  QHBoxLayout* btnLayout = new QHBoxLayout;
+  btnLayout->setSpacing( SPACING );
+  btnLayout->setMargin( 0 );
+  btnLayout->addWidget( okBtn );
+  btnLayout->addStretch( 10 );
+  btnLayout->addWidget( helpBtn );
+
+  QVBoxLayout* l = new QVBoxLayout ( this );
+  l->setMargin( MARGIN );
+  l->setSpacing( SPACING );
+  l->addWidget( myTabWidget );
+  l->addStretch();
+  l->addLayout( btnLayout );
+
+  myTabWidget->setCurrentIndex( qMax( (int)MinDistance, qMin( (int)BoundingBox, page ) ) );
+
+  connect( okBtn,       SIGNAL( clicked() ),              this, SLOT( reject() ) );
+  connect( helpBtn,     SIGNAL( clicked() ),              this, SLOT( help() ) );
+  connect( myTabWidget, SIGNAL( currentChanged( int  ) ), this, SLOT( updateSelection() ) );
+  connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) );
+  connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalCloseAllDialogs() ),        this, SLOT( reject() ) );
+
+  updateSelection();
+}
+
+/*!
+  \brief Destructor
+*/
+SMESHGUI_MeasureDlg::~SMESHGUI_MeasureDlg()
+{
+}
+
+/*!
+  \brief Perform clean-up actions on the dialog box closing.
+*/
+void SMESHGUI_MeasureDlg::reject()
+{
+  LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
+  selMgr->clearFilters();
+  SMESH::SetPointRepresentation( false );
+  if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
+    aViewWindow->SetSelectionMode( ActorSelection );
+  QDialog::reject();
+}
+
+/*!
+  \brief Process keyboard event
+  \param e key press event
+*/
+void SMESHGUI_MeasureDlg::keyPressEvent( QKeyEvent* e )
+{
+  QDialog::keyPressEvent( e );
+  if ( !e->isAccepted() && e->key() == Qt::Key_F1 ) {
+    e->accept();
+    help();
+  }
+}
+
+/*!
+  \brief Reactivate dialog box, when mouse pointer goes into it.
+*/
+void SMESHGUI_MeasureDlg::enterEvent( QEvent* )
+{
+  activate();
+}
+
+/*!
+  \brief Setup selection mode depending on the current dialog box state.
+*/
+void SMESHGUI_MeasureDlg::updateSelection()
+{
+  if ( myTabWidget->currentIndex() == MinDistance )
+    myMinDist->updateSelection();
+  else if ( myTabWidget->currentIndex() == BoundingBox )
+    myBndBox->updateSelection();
+    
+}
+
+/*!
+  \brief Show help page
+*/
+void SMESHGUI_MeasureDlg::help()
+{
+  SMESH::ShowHelpFile( myTabWidget->currentIndex() == MinDistance ?
+                      "measurements_page.html#min_distance_anchor" : 
+                      "measurements_page.html#bounding_box_anchor" );
+}
+
+/*!
+  \brief Activate dialog box
+*/
+void SMESHGUI_MeasureDlg::activate()
+{
+  SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog();
+  SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this );
+  myTabWidget->setEnabled( true );
+  updateSelection();
+}
+
+/*!
+  \brief Deactivate dialog box
+*/
+void SMESHGUI_MeasureDlg::deactivate()
+{
+  myMinDist->deactivate();
+  myBndBox->deactivate();
+  myTabWidget->setEnabled( false );
+  disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
+}
diff --git a/src/SMESHGUI/SMESHGUI_Measurements.h b/src/SMESHGUI/SMESHGUI_Measurements.h
new file mode 100644 (file)
index 0000000..ae3d312
--- /dev/null
@@ -0,0 +1,161 @@
+//  Copyright (C) 2007-2010  CEA/DEN, EDF R&D, OPEN CASCADE
+//
+//  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+//  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2.1 of the License.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+//  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+//  File   : SMESHGUI_Measurements.h
+//  Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
+
+#ifndef SMESHGUI_MEASUREMENTS_H
+#define SMESHGUI_MEASUREMENTS_H
+
+#include "SMESH_SMESHGUI.hxx"
+
+#include <QDialog>
+
+class QButtonGroup;
+class QLineEdit;
+class QTabWidget;
+class SUIT_SelectionFilter;
+class SMESH_Actor;
+class SMESHGUI_IdValidator;
+
+#include <SALOMEconfig.h>
+#include CORBA_SERVER_HEADER(SMESH_Mesh)
+
+class SMESHGUI_EXPORT SMESHGUI_MinDistance : public QWidget
+{
+  Q_OBJECT;
+
+  enum { NoTgt, FirstTgt, SecondTgt };
+  enum { OriginTgt, NodeTgt, ElementTgt, ObjectTgt };
+
+public:
+  SMESHGUI_MinDistance( QWidget* = 0 );
+  ~SMESHGUI_MinDistance();
+
+  bool eventFilter( QObject*, QEvent* );
+  void updateSelection();
+  void deactivate();
+
+private: 
+  void setTarget( int );
+
+private slots:
+  void selectionChanged();
+  void firstChanged();
+  void secondChanged();
+  void firstEdited();
+  void secondEdited();
+  void compute();
+  void clear();
+
+private:
+  QButtonGroup*             myFirst;
+  QButtonGroup*             mySecond;
+  QLineEdit*                myFirstTgt;
+  QLineEdit*                mySecondTgt;
+  QLineEdit*                myDX;
+  QLineEdit*                myDY;
+  QLineEdit*                myDZ;
+  QLineEdit*                myDistance;
+  int                       myCurrentTgt;
+  SMESH::SMESH_IDSource_var myFirstSrc;
+  SMESH::SMESH_IDSource_var mySecondSrc;
+  SMESH_Actor*              myFirstActor;
+  SMESH_Actor*              mySecondActor;
+  SMESHGUI_IdValidator*     myValidator;
+  SUIT_SelectionFilter*     myFilter;
+};
+
+class SMESHGUI_EXPORT SMESHGUI_BoundingBox : public QWidget
+{
+  Q_OBJECT;
+
+  enum { ObjectsSrc, NodesSrc, ElementsSrc };
+  
+public:
+  SMESHGUI_BoundingBox( QWidget* = 0 );
+  ~SMESHGUI_BoundingBox();
+
+  void updateSelection();
+  void deactivate();
+
+private slots:
+  void selectionChanged();
+  void sourceChanged();
+  void sourceEdited();
+  void compute();
+  void clear();
+
+private:
+  typedef QList<SMESH::SMESH_IDSource_var> SourceList;
+  QButtonGroup*             mySourceMode;
+  QLineEdit*                mySource;
+  QLineEdit*                myXmin;
+  QLineEdit*                myXmax;
+  QLineEdit*                myDX;
+  QLineEdit*                myYmin;
+  QLineEdit*                myYmax;
+  QLineEdit*                myDY;
+  QLineEdit*                myZmin;
+  QLineEdit*                myZmax;
+  QLineEdit*                myDZ;
+  SourceList                mySrc;
+  SMESH_Actor*              myActor;
+  SMESHGUI_IdValidator*     myValidator;
+  QString                   myIDs;
+  SUIT_SelectionFilter*     myFilter;
+};
+
+class SMESHGUI_EXPORT SMESHGUI_MeasureDlg : public QDialog
+{ 
+  Q_OBJECT;
+
+  enum { NodeMode, ElemMode };
+
+public:
+  //! Measurement type
+  enum { 
+    MinDistance,   //!< minimum distance
+    BoundingBox    //!< bounding box
+  };
+
+  SMESHGUI_MeasureDlg( QWidget* = 0, int = MinDistance );
+  ~SMESHGUI_MeasureDlg();
+
+  void reject();
+
+protected:
+  void keyPressEvent( QKeyEvent* );
+  void enterEvent( QEvent* );
+
+private slots:
+  void help();
+  void updateSelection();
+  void activate();
+  void deactivate();
+
+private:
+  QTabWidget*           myTabWidget;
+  SMESHGUI_MinDistance* myMinDist;   
+  SMESHGUI_BoundingBox* myBndBox;
+};
+
+#endif // SMESHGUI_MEASUREMENTS_H
index 6f5139439c6b399cd0d6e2e2759acf1f45bc019e..c5183a84e0803df04753b47926e8f881d64a1708 100644 (file)
         <source>MEN_MODIFY</source>
         <translation>Modification</translation>
     </message>
+    <message>
+        <source>MEN_MEASURE</source>
+        <translation>Measurements</translation>
+    </message>
+    <message>
+        <source>MEN_MEASURE_MIN_DIST</source>
+        <translation>Minimum Distance</translation>
+    </message>
+    <message>
+        <source>STB_MEASURE_MIN_DIST</source>
+        <translation>Calculate minimum distance between two objects</translation>
+    </message>
+    <message>
+        <source>TOP_MEASURE_MIN_DIST</source>
+        <translation>Minimum distance</translation>
+    </message>
+    <message>
+        <source>MEN_MEASURE_BND_BOX</source>
+        <translation>Bounding Box</translation>
+    </message>
+    <message>
+        <source>STB_MEASURE_BND_BOX</source>
+        <translation>Calculate bounding box for the selected object(s)</translation>
+    </message>
+    <message>
+        <source>TOP_MEASURE_BND_BOX</source>
+        <translation>Bounding box</translation>
+    </message>
     <message>
         <source>MEN_MOVE</source>
         <translation>Move Node</translation>
@@ -5645,4 +5673,97 @@ It is impossible to read point coordinates from file</translation>
         <translation>Value</translation>
     </message>
 </context>
+<context>
+    <name>SMESHGUI_MinDistance</name>
+    <message>
+        <source>FIRST_TARGET</source>
+        <translation>First target</translation>
+    </message>
+    <message>
+        <source>SECOND_TARGET</source>
+        <translation>Second target</translation>
+    </message>
+    <message>
+        <source>NODE</source>
+        <translation>Node</translation>
+    </message>
+    <message>
+        <source>ELEMENT</source>
+        <translation>Element</translation>
+    </message>
+    <message>
+        <source>OBJECT</source>
+        <translation>Object</translation>
+    </message>
+    <message>
+        <source>ORIGIN</source>
+        <translation>Origin</translation>
+    </message>
+    <message>
+        <source>COMPUTE</source>
+        <translation>Compute</translation>
+    </message>
+    <message>
+        <source>RESULT</source>
+        <translation>Distance between targets</translation>
+    </message>
+    <message>
+        <source>DISTANCE</source>
+        <translation>Distance</translation>
+    </message>
+</context>
+<context>
+    <name>SMESHGUI_MeasureDlg</name>
+    <message>
+        <source>MEASUREMENTS</source>
+        <translation>Measurements</translation>
+    </message>
+    <message>
+        <source>MIN_DIST</source>
+        <translation>Minimum Distance</translation>
+    </message>
+    <message>
+        <source>BND_BOX</source>
+        <translation>Bounding Box</translation>
+    </message>
+</context>
+<context>
+    <name>SMESHGUI_BoundingBox</name>
+    <message>
+        <source>SOURCE</source>
+        <translation>Source</translation>
+    </message>
+    <message>
+        <source>OBJECTS</source>
+        <translation>Objects</translation>
+    </message>
+    <message>
+        <source>NODES</source>
+        <translation>Nodes</translation>
+    </message>
+    <message>
+        <source>ELEMENTS</source>
+        <translation>Elements</translation>
+    </message>
+    <message>
+        <source>COMPUTE</source>
+        <translation>Compute</translation>
+    </message>
+    <message>
+        <source>RESULT</source>
+        <translation>Bounding Box</translation>
+    </message>
+    <message>
+        <source>SELECTED_NB_OBJ</source>
+        <translation>%1 %2 selected</translation>
+    </message>
+    <message>
+        <source>NB_NODES</source>
+        <translation>nodes</translation>
+    </message>
+    <message>
+        <source>NB_ELEMENTS</source>
+        <translation>elements</translation>
+    </message>
+</context>
 </TS>
index fa52f66e6308e5ae9f56fb41281fc456467eec7d..87946a1da6ebe531e43fd1948243caddbae67f21 100644 (file)
@@ -95,18 +95,27 @@ Measurements_i::~Measurements_i()
   //TPythonDump()<<this<<".Destroy()";
 }
 
-static double getNodeNodeDistance (const SMDS_MeshNode* theNode1,
-                                   const SMDS_MeshNode* theNode2)
+static bool getNodeNodeDistance (SMESH::Measure& theMeasure,
+                                const SMDS_MeshNode* theNode1,
+                                const SMDS_MeshNode* theNode2 = 0)
 {
   double dist = 0., dd = 0.;
-  if (!theNode1 || !theNode2)
-    return dist;
-  dd = theNode1->X(); dd -= theNode2->X(); dd *= dd; dist += dd;
-  dd = theNode1->Y(); dd -= theNode2->Y(); dd *= dd; dist += dd;
-  dd = theNode1->Z(); dd -= theNode2->Z(); dd *= dd; dist += dd;
+
+  if (!theNode1)
+    return false;
+
+  dd = theNode1->X(); if (theNode2) dd -= theNode2->X(); theMeasure.minX = dd; dd *= dd; dist += dd;
+  dd = theNode1->Y(); if (theNode2) dd -= theNode2->Y(); theMeasure.minY = dd; dd *= dd; dist += dd;
+  dd = theNode1->Z(); if (theNode2) dd -= theNode2->Z(); theMeasure.minZ = dd; dd *= dd; dist += dd;
+
   if (dist < 0)
-    return 0;
-  return sqrt(dist);
+    return false;
+  
+  theMeasure.value = sqrt(dist);
+  theMeasure.node1 = theNode1->GetID();
+  theMeasure.node2 = theNode2 ? theNode2->GetID() : 0;
+
+  return true;
 }
 
 static SMESHDS_Mesh* getMesh(SMESH::SMESH_IDSource_ptr theSource)
@@ -136,38 +145,39 @@ SMESH::Measure Measurements_i::MinDistance
   SMESH::Measure aMeasure;
   initMeasure(aMeasure);
 
-  if (CORBA::is_nil( theSource1 ) || CORBA::is_nil( theSource2 ))
+  if (CORBA::is_nil( theSource1 ))
     return aMeasure;
+  
+  // if second source is null, min distance from theSource1 to the origin is calculated
+  bool isOrigin =  CORBA::is_nil( theSource2 );
 
   // calculate minimal distance between two mesh entities
   SMESH::array_of_ElementType_var types1 = theSource1->GetTypes();
-  SMESH::array_of_ElementType_var types2 = theSource2->GetTypes();
+  SMESH::array_of_ElementType_var types2;
+  if ( !isOrigin ) types2 = theSource2->GetTypes();
+
   // here we assume that type of all IDs defined by first type in array
-  const bool isNode1 = isNodeType(types1);
-  const bool isNode2 = isNodeType(types2);
+  bool isNode1 = isNodeType(types1);
+  bool isNode2 = isOrigin || isNodeType(types2);
 
   SMESH::long_array_var aElementsId1 = theSource1->GetIDs();
-  SMESH::long_array_var aElementsId2 = theSource2->GetIDs();
+  SMESH::long_array_var aElementsId2;
+  if ( !isOrigin ) aElementsId2 = theSource2->GetIDs();
 
   // compute distance between two entities
-  /** NOTE: currently only node-node case implemented
-   * all other cases could be implemented later
-   * this IF should be replaced by comples swtich
+  /* NOTE: currently only node-to-node case is implemented
+   * all other cases will be implemented later
+   * below IF should be replaced by complete switch
    * on mesh entities types
    */
   if (isNode1 && isNode2)
   {
     // node - node
     const SMESHDS_Mesh* aMesh1 = getMesh( theSource1 );
-    const SMESHDS_Mesh* aMesh2 = getMesh( theSource2 );
+    const SMESHDS_Mesh* aMesh2 = isOrigin ? 0 : getMesh( theSource2 );
     const SMDS_MeshNode* theNode1 = aMesh1 ? aMesh1->FindNode( aElementsId1[0] ) : 0;
     const SMDS_MeshNode* theNode2 = aMesh2 ? aMesh2->FindNode( aElementsId2[0] ) : 0;
-    aMeasure.value = getNodeNodeDistance( theNode1, theNode2 );
-    if (theNode1 && theNode2)
-    {
-      aMeasure.node1 = theNode1->GetID();
-      aMeasure.node2 = theNode2->GetID();
-    }
+    getNodeNodeDistance( aMeasure, theNode1, theNode2 );
   }
   else
   {
@@ -216,7 +226,7 @@ static void enlargeBoundingBox(const SMESH::SMESH_IDSource_ptr theObject,
       enlargeBoundingBox( aMesh->FindNode( aElementsId[i] ), theMeasure);
     else
     {
-      const SMDS_MeshElement * elem = aMesh->FindElement( aElementsId[i] );
+      const SMDS_MeshElement* elem = aMesh->FindElement( aElementsId[i] );
       if (!elem)
         continue;
       SMDS_ElemIteratorPtr aNodeIter = elem->nodesIterator();