X-Git-Url: http://git.salome-platform.org/gitweb/?p=modules%2Fsmesh.git;a=blobdiff_plain;f=src%2FSMESHGUI%2FSMESHGUI_Measurements.cxx;h=c20c5404a02b30a7ea70cff200cd8e3fce034cda;hp=4b30659ebe8f87193bf6d16a5a2933b4528793ca;hb=b09372829929f8f561495d6c16527134971a1909;hpb=7a65c9fad427b1ccba6b9ccae612296e5092a324 diff --git a/src/SMESHGUI/SMESHGUI_Measurements.cxx b/src/SMESHGUI/SMESHGUI_Measurements.cxx index 4b30659eb..c20c5404a 100644 --- a/src/SMESHGUI/SMESHGUI_Measurements.cxx +++ b/src/SMESHGUI/SMESHGUI_Measurements.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2021 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 @@ -28,9 +28,13 @@ #include "SMESHGUI.h" #include "SMESHGUI_IdValidator.h" #include "SMESHGUI_Utils.h" +#include "SMESHGUI_MeshEditPreview.h" #include "SMESHGUI_VTKUtils.h" #include +#include #include +#include +#include #include #include @@ -56,9 +60,11 @@ #include #include #include -#include +//#include #include +#include + #include #include CORBA_SERVER_HEADER(SMESH_MeshEditor) #include CORBA_SERVER_HEADER(SMESH_Measurements) @@ -167,11 +173,11 @@ SMESHGUI_MinDistance::SMESHGUI_MinDistance( QWidget* parent ) aSOrigin->setChecked( true ); #ifndef MINDIST_ENABLE_ELEMENT aFElem->setEnabled( false ); // NOT AVAILABLE YET - aSElem->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 + //aSObject->setEnabled( false ); // NOT AVAILABLE YET #endif myDX->setReadOnly( true ); myDY->setReadOnly( true ); @@ -351,11 +357,12 @@ void SMESHGUI_MinDistance::createPreview( double x1, double y1, double z1, doubl aCells->InsertNextCell( anIdList ); aCellTypesArray->InsertNextValue( VTK_LINE ); anIdList->Delete(); - VTKViewer_CellLocationsArray* aCellLocationsArray = VTKViewer_CellLocationsArray::New(); + vtkIdTypeArray* aCellLocationsArray = vtkIdTypeArray::New(); aCellLocationsArray->SetNumberOfComponents( 1 ); aCellLocationsArray->SetNumberOfTuples( 1 ); aCells->InitTraversal(); - for( vtkIdType idType = 0, *pts, npts; aCells->GetNextCell( npts, pts ); idType++ ) + vtkIdType const *pts(nullptr); + for( vtkIdType idType = 0, npts; aCells->GetNextCell( npts, pts ); idType++ ) aCellLocationsArray->SetValue( idType, aCells->GetTraversalLocation( npts ) ); aGrid->SetCells( aCellTypesArray, aCellLocationsArray, aCells ); aCellLocationsArray->Delete(); @@ -368,6 +375,7 @@ void SMESHGUI_MinDistance::createPreview( double x1, double y1, double z1, doubl myPreview = SALOME_Actor::New(); myPreview->PickableOff(); myPreview->SetMapper( aMapper ); + myPreview->SetResolveCoincidentTopology(true); aMapper->Delete(); vtkProperty* aProp = vtkProperty::New(); aProp->SetRepresentationToWireframe(); @@ -484,7 +492,7 @@ void SMESHGUI_MinDistance::firstEdited() if ( myFirstActor && selector ) { Handle(SALOME_InteractiveObject) IO = myFirstActor->getIO(); if ( myFirst->checkedId() == NodeTgt || myFirst->checkedId() == ElementTgt ) { - TColStd_MapOfInteger ID; + SVTK_TVtkIDsMap ID; ID.Add( myFirstTgt->text().toLong() ); selector->AddOrRemoveIndex( IO, ID, false ); } @@ -512,7 +520,7 @@ void SMESHGUI_MinDistance::secondEdited() Handle(SALOME_InteractiveObject) IO = mySecondActor->getIO(); if ( mySecond->checkedId() == NodeTgt || mySecond->checkedId() == ElementTgt ) { if ( !text.isEmpty() ) { - TColStd_MapOfInteger ID; + SVTK_TVtkIDsMap ID; ID.Add( text.toLong() ); selector->AddOrRemoveIndex( IO, ID, false ); } @@ -538,7 +546,7 @@ void SMESHGUI_MinDistance::compute() 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(); + SMESH::smIdType_array_var ids = new SMESH::smIdType_array(); ids->length( 1 ); ids[0] = id; SMESH::SMESH_MeshEditor_var me = m->GetMeshEditor(); @@ -557,7 +565,7 @@ void SMESHGUI_MinDistance::compute() 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(); + SMESH::smIdType_array_var ids = new SMESH::smIdType_array(); ids->length( 1 ); ids[0] = id; SMESH::SMESH_MeshEditor_var me = m->GetMeshEditor(); @@ -588,10 +596,14 @@ void SMESHGUI_MinDistance::compute() if ( isOrigin ) { x2 = y2 = z2 = 0.; } - else { + else if ( mySecond->checkedId() == NodeTgt ) { coord = s2->GetMesh()->GetNodeXYZ( result.node2 ); x2 = coord[0]; y2 = coord[1]; z2 = coord[2]; } + else + { + x2 = result.maxX; y2 = result.maxY; z2 = result.maxZ; + } createPreview( x1, y1, z1, x2, y2, z2 ); displayPreview(); } @@ -879,11 +891,12 @@ void SMESHGUI_BoundingBox::createPreview( double minX, double maxX, double minY, aCells->InsertNextCell( anIdList ); aCellTypesArray->InsertNextValue( VTK_LINE ); anIdList->Delete(); - VTKViewer_CellLocationsArray* aCellLocationsArray = VTKViewer_CellLocationsArray::New(); + vtkIdTypeArray* aCellLocationsArray = vtkIdTypeArray::New(); aCellLocationsArray->SetNumberOfComponents( 1 ); aCellLocationsArray->SetNumberOfTuples( 12 ); aCells->InitTraversal(); - for( vtkIdType idType = 0, *pts, npts; aCells->GetNextCell( npts, pts ); idType++ ) + vtkIdType const *pts(nullptr); + for( vtkIdType idType = 0, npts; aCells->GetNextCell( npts, pts ); idType++ ) aCellLocationsArray->SetValue( idType, aCells->GetTraversalLocation( npts ) ); aGrid->SetCells( aCellTypesArray, aCellLocationsArray, aCells ); aCellLocationsArray->Delete(); @@ -1009,7 +1022,7 @@ void SMESHGUI_BoundingBox::sourceEdited() if ( myActor && selector ) { Handle(SALOME_InteractiveObject) IO = myActor->getIO(); if ( mySourceMode->checkedId() == NodesSrc || mySourceMode->checkedId() == ElementsSrc ) { - TColStd_MapOfInteger ID; + SVTK_TVtkIDsMap ID; if ( !mySource->isReadOnly() ) myIDs = mySource->text(); QStringList ids = myIDs.split( " ", QString::SkipEmptyParts ); @@ -1034,7 +1047,7 @@ void SMESHGUI_BoundingBox::compute() SMESH::SMESH_Mesh_var m = mySrc[0]->GetMesh(); QStringList ids = myIDs.split( " ", QString::SkipEmptyParts ); if ( !CORBA::is_nil( m ) && ids.count() > 0 ) { - SMESH::long_array_var ids_in = new SMESH::long_array(); + SMESH::smIdType_array_var ids_in = new SMESH::smIdType_array(); ids_in->length( ids.count() ); for( int i = 0; i < ids.count(); i++ ) ids_in[i] = ids[i].trimmed().toLong(); @@ -1311,6 +1324,367 @@ void SMESHGUI_BasicProperties::clear() myResult->clear(); } +/*! + \class SMESHGUI_Angle + \brief Angle measurement widget. + + Widget to calculate angle between 3 nodes. +*/ + +/*! + \brief Constructor. + \param parent parent widget +*/ +SMESHGUI_Angle::SMESHGUI_Angle( QWidget* parent ) + : QWidget( parent ) +{ + // 3 nodes + + QGroupBox* aNodesGrp = new QGroupBox( tr( "NODES_GROUP" ), this ); + myNodes = new QLineEdit( aNodesGrp ); + myNodes->setValidator( new SMESHGUI_IdValidator( this, 3 )); + QHBoxLayout* aNodesLayout = new QHBoxLayout( aNodesGrp ); + aNodesLayout->addWidget( myNodes ); + + // Compute button + QPushButton* aCompute = new QPushButton( tr( "COMPUTE" ), this ); + + // Angle + + QGroupBox* aResultGrp = new QGroupBox( tr( "RESULT" ), this ); + + myResult = new QLineEdit; + myResult->setReadOnly( true ); + + QHBoxLayout* aResultLayout = new QHBoxLayout( aResultGrp ); + aResultLayout->addWidget( myResult ); + + // Layout + + QGridLayout* aMainLayout = new QGridLayout( this ); + aMainLayout->setMargin( MARGIN ); + aMainLayout->setSpacing( SPACING ); + + aMainLayout->addWidget( aNodesGrp, 0, 0, 1, 2 ); + aMainLayout->addWidget( aCompute, 1, 0 ); + aMainLayout->addWidget( aResultGrp, 2, 0, 1, 2 ); + aMainLayout->setColumnStretch( 1, 5 ); + aMainLayout->setRowStretch( 3, 5 ); + + // Connections + connect( aCompute, SIGNAL( clicked() ), this, SLOT( compute() )); + + // preview + myPreview = 0; + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + { + myPreview = new SMESHGUI_MeshEditPreview( aViewWindow ); + if ( myPreview && myPreview->GetActor() ) + myPreview->GetActor()->GetProperty()->SetLineWidth( 5 ); + } + myActor = 0; +} + +SMESHGUI_Angle::~SMESHGUI_Angle() +{ + if ( myPreview ) + delete myPreview; +} + +/*! + \brief Setup selection mode +*/ +void SMESHGUI_Angle::updateSelection() +{ + LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr(); + + disconnect( selMgr, 0, this, 0 ); + selMgr->clearFilters(); + + SMESH::SetPointRepresentation( true ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->SetSelectionMode( NodeSelection ); + + connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( selectionChanged() )); + connect( myNodes, SIGNAL( textEdited( QString ) ), this, SLOT( nodesEdited() )); + + if ( myPoints.empty() ) + selectionChanged(); +} + +/*! + \brief Called when selection is changed +*/ +void SMESHGUI_Angle::selectionChanged() +{ + clear(); + QString nodesString; + + SVTK_TIndexedMapOfVtkId idsMap; + SALOME_ListIO selected; + SMESHGUI::selectionMgr()->selectedObjects( selected ); + selected.Reverse(); // to keep order of selection + + SALOME_ListIteratorOfListIO ioIterator( selected ); + for ( ; ioIterator.More(); ioIterator.Next() ) + { + Handle(SALOME_InteractiveObject) IO = ioIterator.Value(); + + idsMap.Clear(); + if ( SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector() ) + selector->GetIndex( IO, idsMap ); + + if ( SMESH_Actor* actor = SMESH::FindActorByEntry( IO->getEntry() )) + { + myActor = actor; + for ( int i = 1; i <= idsMap.Extent() && myPoints.size() < 3; ++i ) + if ( addPointByActor( idsMap(i) )) + nodesString += QString(" %1").arg( idsMap(i) ); + idsMap.Clear(); + } + SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface( IO ); + if ( !CORBA::is_nil( obj ) ) + { + myIDSrc = obj; + for ( int i = 1; i <= idsMap.Extent() && myPoints.size() < 3; ++i ) + if ( addPointByIDSource( idsMap(i) )) + nodesString += QString(" %1").arg( idsMap(i) ); + } + } + + myNodes->setText( nodesString ); +} + +//======================================================================= +//function : clear +//purpose : Erase preview and result +//======================================================================= + +void SMESHGUI_Angle::clear() +{ + myPoints.clear(); + myResult->clear(); + if ( myPreview && myPreview->GetActor()) + { + myPreview->GetActor()->SetVisibility( false ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->Repaint(); + } +} + +//======================================================================= +//function : addPointByActor +//purpose : append to myPoints XYZ got from myActor +//======================================================================= + +bool SMESHGUI_Angle::addPointByActor( int id ) +{ + size_t nbP = myPoints.size(); + + if ( myActor ) + { + TVisualObjPtr obj = myActor->GetObject(); + if ( SMDS_Mesh* mesh = obj->GetMesh() ) + if ( const SMDS_MeshNode* node = mesh->FindNode( id )) + { + SMESH::PointStruct p = { node->X(), node->Y(), node->Z() }; + myPoints.push_back( p ); + } + } + return nbP < myPoints.size(); +} + +//======================================================================= +//function : addPointByIDSource +//purpose : append to myPoints XYZ got from myIDSrc +//======================================================================= + +bool SMESHGUI_Angle::addPointByIDSource( int id ) +{ + size_t nbP = myPoints.size(); + + if ( !myIDSrc->_is_nil() ) + { + SMESH::SMESH_Mesh_var mesh = myIDSrc->GetMesh(); + if ( !mesh->_is_nil() ) + { + SMESH::double_array_var xyz = mesh->GetNodeXYZ( id ); + if ( xyz->length() == 3 ) + { + SMESH::PointStruct p = { xyz[0], xyz[1], xyz[2] }; + myPoints.push_back( p ); + } + } + } + return nbP < myPoints.size(); +} + +//======================================================================= +//function : nodesEdited +//purpose : SLOT called when the user types node IDs +//======================================================================= + +void SMESHGUI_Angle::nodesEdited() +{ + clear(); + + SVTK_TVtkIDsMap ID; + QStringList ids = myNodes->text().split( " ", QString::SkipEmptyParts ); + foreach ( QString idStr, ids ) + { + int id = idStr.trimmed().toLong(); + if (( !ID.Contains( id )) && + ( addPointByActor( id ) || addPointByIDSource( id ))) + ID.Add( id ); + } + + SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector(); + if ( myActor && selector ) + { + Handle(SALOME_InteractiveObject) IO = myActor->getIO(); + selector->AddOrRemoveIndex( IO, ID, false ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->highlight( IO, true, true ); + } +} + +//======================================================================= +//function : compute +//purpose : SLOT. Compute angle and show preview +//======================================================================= + +void SMESHGUI_Angle::compute() +{ + if ( myPoints.size() != 3 ) + return; + + // -------------- + // compute angle + // -------------- + + SMESH::Measurements_var measure = SMESHGUI::GetSMESHGen()->CreateMeasurements(); + double radians = measure->Angle( myPoints[0], myPoints[1], myPoints[2] ); + measure->UnRegister(); + if ( radians < 0 ) + return; + + int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 ); + myResult->setText( QString::number( radians * 180 / M_PI, + precision > 0 ? 'f' : 'g', qAbs( precision ))); + + // ------------- + // show preview + // ------------- + + if ( !myPreview || !myPreview->GetActor() ) + return; + + SMESH::MeshPreviewStruct preveiwData; + + const double anglePerSeg = 5 * M_PI/180; // angle per an arc segment + const double arcRadiusFactor = 0.5; // arc position, from p1 + + gp_Pnt p0 ( myPoints[0].x, myPoints[0].y, myPoints[0].z ); + gp_Pnt p1 ( myPoints[1].x, myPoints[1].y, myPoints[1].z ); + gp_Pnt p2 ( myPoints[2].x, myPoints[2].y, myPoints[2].z ); + gp_Vec vec10( p1, p0 ), vec12( p1, p2 ), norm( vec10 ^ vec12 ); + + if ( norm.Magnitude() <= gp::Resolution() ) // 180 degrees + norm = getNormal( vec10 ); + + double len10 = vec10.Magnitude(); + double len12 = vec12.Magnitude(); + double lenMax = Max( len10, len12 ); + double arcRadius = arcRadiusFactor * lenMax; + + p0 = p1.Translated( lenMax * vec10.Normalized() ); + p2 = p1.Translated( lenMax * vec12.Normalized() ); + + gp_Circ arc( gp_Ax2( p1, norm, vec10 ), arcRadius ); + + int nbRadialSegmensts = ceil( radians / anglePerSeg ) + 1; + int nbNodes = 3 + ( nbRadialSegmensts + 1 ); + + // coordinates + preveiwData.nodesXYZ.length( nbNodes ); + int iP = 0; + for ( ; iP < nbRadialSegmensts + 1; ++iP ) + { + double u = double( iP ) / nbRadialSegmensts * radians; + gp_Pnt p = ElCLib::Value( u, arc ); + preveiwData.nodesXYZ[ iP ].x = p.X(); + preveiwData.nodesXYZ[ iP ].y = p.Y(); + preveiwData.nodesXYZ[ iP ].z = p.Z(); + } + int iP0 = iP; + preveiwData.nodesXYZ[ iP ].x = p0.X(); + preveiwData.nodesXYZ[ iP ].y = p0.Y(); + preveiwData.nodesXYZ[ iP ].z = p0.Z(); + int iP1 = ++iP; + preveiwData.nodesXYZ[ iP ].x = p1.X(); + preveiwData.nodesXYZ[ iP ].y = p1.Y(); + preveiwData.nodesXYZ[ iP ].z = p1.Z(); + int iP2 = ++iP; + preveiwData.nodesXYZ[ iP ].x = p2.X(); + preveiwData.nodesXYZ[ iP ].y = p2.Y(); + preveiwData.nodesXYZ[ iP ].z = p2.Z(); + + // connectivity + preveiwData.elementConnectivities.length( 2 * ( 2 + nbRadialSegmensts )); + for ( int iSeg = 0; iSeg < nbRadialSegmensts; ++iSeg ) + { + preveiwData.elementConnectivities[ iSeg * 2 + 0 ] = iSeg; + preveiwData.elementConnectivities[ iSeg * 2 + 1 ] = iSeg + 1; + } + int iSeg = nbRadialSegmensts; + preveiwData.elementConnectivities[ iSeg * 2 + 0 ] = iP0; + preveiwData.elementConnectivities[ iSeg * 2 + 1 ] = iP1; + ++iSeg; + preveiwData.elementConnectivities[ iSeg * 2 + 0 ] = iP1; + preveiwData.elementConnectivities[ iSeg * 2 + 1 ] = iP2; + + // types + preveiwData.elementTypes.length( 2 + nbRadialSegmensts ); + SMESH::ElementSubType type = { SMESH::EDGE, /*isPoly=*/false, /*nbNodesInElement=*/2 }; + for ( CORBA::ULong i = 0; i < preveiwData.elementTypes.length(); ++i ) + preveiwData.elementTypes[ i ] = type; + + myPreview->SetData( preveiwData ); +} + +//================================================================================ +/*! + * \brief Return normal to a plane of drawing in the case of 180 degrees angle + */ +//================================================================================ + +gp_Vec SMESHGUI_Angle::getNormal(const gp_Vec& vec10 ) +{ + gp_XYZ norm; + + // try to get normal by a face at the 2nd node + if ( myActor && myActor->GetObject()->GetMesh() ) + { + QStringList ids = myNodes->text().split( " ", QString::SkipEmptyParts ); + SMDS_Mesh* mesh = myActor->GetObject()->GetMesh(); + if ( const SMDS_MeshNode* n = mesh->FindNode( ids[1].trimmed().toLong() )) + { + SMDS_ElemIteratorPtr faceIt = n->GetInverseElementIterator( SMDSAbs_Face ); + while ( faceIt->more() ) + if ( SMESH_MeshAlgos::FaceNormal( faceIt->next(), norm )) + return norm; + } + } + int iMinCoord = 1; + if ( vec10.Coord( iMinCoord ) > vec10.Y() ) iMinCoord = 2; + if ( vec10.Coord( iMinCoord ) > vec10.Z() ) iMinCoord = 3; + + gp_Vec vec = vec10; + vec.SetCoord( iMinCoord, vec10.Coord( iMinCoord ) + 1. ); + + return vec ^ vec10; +} + /*! \class SMESHGUI_MeshInfoDlg \brief Centralized dialog box for the measurements @@ -1322,7 +1696,7 @@ void SMESHGUI_BasicProperties::clear() \param page specifies the dialog page to be shown at the start-up */ SMESHGUI_MeasureDlg::SMESHGUI_MeasureDlg( QWidget* parent, int page ) -: QDialog( parent ) + : QDialog( parent ) { setModal( false ); setAttribute( Qt::WA_DeleteOnClose, true ); @@ -1348,6 +1722,9 @@ SMESHGUI_MeasureDlg::SMESHGUI_MeasureDlg( QWidget* parent, int page ) myBasicProps = new SMESHGUI_BasicProperties( myTabWidget ); int aBasicPropInd = myTabWidget->addTab( myBasicProps, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_BASIC_PROPS" ) ), tr( "BASIC_PROPERTIES" ) ); + myAngle = new SMESHGUI_Angle( myTabWidget ); + int aAngleInd = myTabWidget->addTab( myAngle, resMgr->loadPixmap( "SMESH", tr( "ICON_MEASURE_ANGLE" ) ), tr( "ANGLE" ) ); + // buttons QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this ); okBtn->setAutoDefault( true ); @@ -1375,6 +1752,8 @@ SMESHGUI_MeasureDlg::SMESHGUI_MeasureDlg( QWidget* parent, int page ) anInd = aMinDistInd; } else if ( page == BoundingBox ) { anInd = aBndBoxInd; + } else if ( page == Angle ) { + anInd = aAngleInd; } else if ( page == Length || page == Area || page == Volume ) { myBasicProps->setMode( (SMESHGUI_BasicProperties::Mode)(page - Length) ); anInd = aBasicPropInd; @@ -1443,6 +1822,8 @@ void SMESHGUI_MeasureDlg::updateSelection() myMinDist->updateSelection(); else if ( myTabWidget->currentIndex() == BoundingBox ) myBndBox->updateSelection(); + else if ( myTabWidget->currentWidget() == myAngle ) + myAngle->updateSelection(); else { myBndBox->erasePreview(); myBasicProps->updateSelection(); @@ -1456,11 +1837,13 @@ void SMESHGUI_MeasureDlg::help() { QString aHelpFile; if ( myTabWidget->currentIndex() == MinDistance ) { - aHelpFile = "measurements_page.html#min_distance_anchor"; + aHelpFile = "measurements.html#min-distance-anchor"; } else if ( myTabWidget->currentIndex() == BoundingBox ) { - aHelpFile = "measurements_page.html#bounding_box_anchor"; + aHelpFile = "measurements.html#bounding-box-anchor"; + } else if ( myTabWidget->currentWidget() == myAngle ) { + aHelpFile = "measurements.html#angle-anchor"; } else { - aHelpFile = "measurements_page.html#basic_properties_anchor"; + aHelpFile = "measurements.html#basic-properties-anchor"; } SMESH::ShowHelpFile( aHelpFile );