From: rnv Date: Sat, 5 Feb 2022 13:06:37 +0000 (+0300) Subject: #26454 [EDF] (2021) SMESH: interactive mesh modification: interactive part X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=54d9151d161a6669b9d0ee696018beadeb7ca140;p=modules%2Fsmesh.git #26454 [EDF] (2021) SMESH: interactive mesh modification: interactive part --- diff --git a/_stash b/_stash deleted file mode 100644 index 2cb3cde9f..000000000 --- a/_stash +++ /dev/null @@ -1,3 +0,0 @@ -1) partial Fix of QuadFromMedialAxis algo -2) Begin fix 19982 EDF 21954 - Compute mesh fails - \ No newline at end of file diff --git a/src/SMESHGUI/CMakeLists.txt b/src/SMESHGUI/CMakeLists.txt index 16eda3a3d..bc4507366 100644 --- a/src/SMESHGUI/CMakeLists.txt +++ b/src/SMESHGUI/CMakeLists.txt @@ -156,6 +156,7 @@ SET(_moc_HEADERS SMESHGUI_RemoveNodeReconnectionDlg.h SMESHGUI_AddNodeOnSegmentDlg.h SMESHGUI_AddNodeOnFaceDlg.h + SMESHGUI_InteractiveOp.h ) # header files / no moc processing @@ -281,6 +282,7 @@ SET(_other_SOURCES SMESHGUI_RemoveNodeReconnectionDlg.cxx SMESHGUI_AddNodeOnSegmentDlg.cxx SMESHGUI_AddNodeOnFaceDlg.cxx + SMESHGUI_InteractiveOp.cxx ) # sources / to compile diff --git a/src/SMESHGUI/SMESHGUI_AddNodeOnFaceDlg.cxx b/src/SMESHGUI/SMESHGUI_AddNodeOnFaceDlg.cxx index 975c5363c..58f029612 100644 --- a/src/SMESHGUI/SMESHGUI_AddNodeOnFaceDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_AddNodeOnFaceDlg.cxx @@ -37,6 +37,7 @@ #include #include #include +#include // SALOME GUI includes #include @@ -49,6 +50,9 @@ #include #include #include +#include +#include +#include // Qt includes #include @@ -65,6 +69,11 @@ // VTK includes #include +#include +#include +#include +#include + // IDL includes #include @@ -74,6 +83,8 @@ #define SPACING 6 #define MARGIN 11 +#define TOLERANCE 1e-3 + //======================================================================= /*! * \brief Dialog to publish a sub-shape of the mesh main shape @@ -147,6 +158,8 @@ QWidget* SMESHGUI_AddNodeOnFaceDlg::createMainFrame (QWidget* theParent) myDestinationY->RangeStepAndValidator(COORD_MIN, COORD_MAX, 10.0, "length_precision"); myDestinationZ->RangeStepAndValidator(COORD_MIN, COORD_MAX, 10.0, "length_precision"); + myPointOnFace = new QCheckBox(tr("XYZ_NODE_ON_FACE"), xyzGrp); + QGridLayout* aDestLayout = new QGridLayout(xyzGrp); aDestLayout->setMargin(MARGIN); aDestLayout->setSpacing(SPACING); @@ -160,9 +173,9 @@ QWidget* SMESHGUI_AddNodeOnFaceDlg::createMainFrame (QWidget* theParent) aDestLayout->setColumnStretch(2, 1); aDestLayout->setColumnStretch(4, 1); aDestLayout->setColumnStretch(6, 1); + aDestLayout->addWidget(myPointOnFace, 1, 0, 1, 6); // Preview - myPreviewChkBox = new QCheckBox( tr("PREVIEW"), aFrame); myPreviewChkBox->setChecked( true ); @@ -209,7 +222,8 @@ void SMESHGUI_AddNodeOnFaceDlg::ButtonToggled (bool on) */ //================================================================================ -SMESHGUI_AddNodeOnFaceOp::SMESHGUI_AddNodeOnFaceOp() +SMESHGUI_AddNodeOnFaceOp::SMESHGUI_AddNodeOnFaceOp() : + SMESHGUI_InteractiveOp() { mySimulation = 0; mySMESHGUI = 0; @@ -217,15 +231,22 @@ SMESHGUI_AddNodeOnFaceOp::SMESHGUI_AddNodeOnFaceOp() myHelpFileName = "add_node_on_face.html"; myNoPreview = false; + myUpdateDestination = false; // connect signals and slots - connect(myDlg->myDestinationX, SIGNAL (valueChanged(double)), this, SLOT(redisplayPreview())); - connect(myDlg->myDestinationY, SIGNAL (valueChanged(double)), this, SLOT(redisplayPreview())); - connect(myDlg->myDestinationZ, SIGNAL (valueChanged(double)), this, SLOT(redisplayPreview())); + connect(myDlg->myDestinationX, SIGNAL (valueChanged(double)), this, SLOT(onDestCoordChanged())); + connect(myDlg->myDestinationY, SIGNAL (valueChanged(double)), this, SLOT(onDestCoordChanged())); + connect(myDlg->myDestinationZ, SIGNAL (valueChanged(double)), this, SLOT(onDestCoordChanged())); connect(myDlg->myId, SIGNAL (textChanged(const QString&)),SLOT(redisplayPreview())); connect(myDlg->myPreviewChkBox, SIGNAL (toggled(bool)), SLOT(redisplayPreview())); connect(myDlg, SIGNAL (selTypeChanged() ), SLOT(onSelTypeChange())); connect(myDlg->myId, SIGNAL (textChanged(const QString&)),SLOT(onTextChange(const QString&))); + connect(myDlg->myPointOnFace, SIGNAL(toggled(bool)), SLOT(pointLocationChanged(bool))); + + myFacePicker = vtkCellPicker::New(); + myFacePicker->SetTolerance(0.005); + myFacePicker->PickFromListOn(); + } //================================================================================ @@ -242,7 +263,14 @@ void SMESHGUI_AddNodeOnFaceOp::onSelTypeChange() } else if ( myDlg->myDestBtn->isChecked() ) { - // TODO: activate picking a point on a selected face + QString msg; + if (isValid(msg)) { + //Disconnect selectionChanged to keep selected element + disconnect(selectionMgr(), SIGNAL(selectionChanged()), this, SLOT(onSelectionDone())); + // Set selection mode to ActorSelection to avoid element's prehighlight during interactive selection + setSelectionMode(ActorSelection); + connect(selectionMgr(), SIGNAL(selectionChanged()), SLOT(onSelectionDone())); + } } else { @@ -275,10 +303,15 @@ void SMESHGUI_AddNodeOnFaceOp::startOperation() aProp->Delete(); SMESHGUI_SelectionOp::startOperation(); + SMESHGUI_InteractiveOp::startOperation(); myDlg->myId->setText(""); + myUpdateDestination = true; myDlg->myDestinationX->SetValue(0); myDlg->myDestinationY->SetValue(0); myDlg->myDestinationZ->SetValue(0); + myUpdateDestination = false; + + addObserver(); myDlg->show(); @@ -309,6 +342,7 @@ void SMESHGUI_AddNodeOnFaceOp::stopOperation() disconnect(mySMESHGUI, SIGNAL (SignalActivatedViewManager()), this, SLOT(onOpenView())); disconnect(mySMESHGUI, SIGNAL (SignalCloseView()), this, SLOT(onCloseView())); SMESHGUI_SelectionOp::stopOperation(); + removeObserver(); } //================================================================================ @@ -429,6 +463,8 @@ void SMESHGUI_AddNodeOnFaceOp::onSelectionDone() return; Handle(SALOME_InteractiveObject) anIO = aList.First(); myMeshActor = SMESH::FindActorByEntry(anIO->getEntry()); + myFacePicker->InitializePickList(); + myFacePicker->AddPickList(myMeshActor); QString aString; int nbElems = SMESH::GetNameOfSelectedElements(selector(),anIO, aString); @@ -442,9 +478,11 @@ void SMESHGUI_AddNodeOnFaceOp::onSelectionDone() for ( int i = 0; i < face->NbCornerNodes(); ++i ) faceGC += SMESH_NodeXYZ( face->GetNode( i )); faceGC /= face->NbCornerNodes(); + myUpdateDestination = true; myDlg->myDestinationX->SetValue(faceGC.X()); myDlg->myDestinationY->SetValue(faceGC.Y()); myDlg->myDestinationZ->SetValue(faceGC.Z()); + myUpdateDestination = false; } } catch (...) { } @@ -590,6 +628,54 @@ SMESHGUI_AddNodeOnFaceOp::~SMESHGUI_AddNodeOnFaceOp() { if ( myDlg ) delete myDlg; if ( mySimulation ) delete mySimulation; + myFacePicker->Delete(); +} + +//================================================================================ +/*! + * \brief SLOT called when destination coordinates are changed +*/ +//================================================================================ +void SMESHGUI_AddNodeOnFaceOp::onDestCoordChanged() +{ + if (myUpdateDestination) + return; + pointLocationChanged(myDlg->myPointOnFace->isChecked()); + redisplayPreview(); +} + +//================================================================================ +/*! + * \brief SLOT called when 'Node on face' checkbox is changed +*/ +//================================================================================ +void SMESHGUI_AddNodeOnFaceOp::pointLocationChanged(bool onFace) { + if (onFace) { + QString msg; + if (myMeshActor && isValid(msg)) { + SMESH::smIdType id = myDlg->myId->text().toLong(); + if (id > 0) { + if (SMDS_Mesh* aMesh = myMeshActor->GetObject()->GetMesh()) { + if (const SMDS_MeshElement* face = aMesh->FindElement(id)) + { + if (face->GetType() == SMDSAbs_Face) { + gp_Pnt point(myDlg->myDestinationX->GetValue(), myDlg->myDestinationY->GetValue(),myDlg->myDestinationZ->GetValue()); + gp_XYZ closestPnt; + double dist = SMESH_MeshAlgos::GetDistance( face, point, &closestPnt); + if (dist > TOLERANCE) { + myUpdateDestination = true; + myDlg->myDestinationX->SetValue(closestPnt.X()); + myDlg->myDestinationY->SetValue(closestPnt.Y()); + myDlg->myDestinationZ->SetValue(closestPnt.Z()); + myUpdateDestination = false; + redisplayPreview(); + } + } + } + } + } + } + } } //================================================================================ @@ -604,3 +690,97 @@ LightApp_Dialog* SMESHGUI_AddNodeOnFaceOp::dlg() const return myDlg; } +//================================================================================ +/* +* \brief Process InteractiveSelectionChanged event +*/ +//================================================================================ +void SMESHGUI_AddNodeOnFaceOp::processStyleEvents(unsigned long theEvent, void* theCallData) +{ + (void*)theCallData; + QString msg; + if (isValid(msg)) { + if (theEvent == SVTK::InteractiveSelectionChanged) { + if (myDlg->myPointOnFace->isChecked()) { + // Pick point on a mesh surface + QString msg; + if (myMeshActor && isValid(msg)) { + SMESH::smIdType id = myDlg->myId->text().toLong(); + if (id > 0) { + if (SMDS_Mesh* aMesh = myMeshActor->GetObject()->GetMesh()) { + if (const SMDS_MeshElement* face = aMesh->FindElement(id)) + { + if (face->GetType() == SMDSAbs_Face) { + int xClick, yClick; // Last event (move or left button bown) position + myRWInteractor->GetDevice()->GetEventPosition(xClick, yClick); + gp_XYZ faceNode(0, 0, 0); + SMDS_Mesh tmp; + double Ni[3]; + std::vector tmpNodes; + for (int i = 0; i < face->NbCornerNodes(); ++i) { + faceNode = SMESH_NodeXYZ(face->GetNode(i)); + vtkInteractorObserver::ComputeWorldToDisplay(myRWInteractor->GetRenderer()->GetDevice(), + faceNode.X(), faceNode.Y(), faceNode.Z(), Ni); + tmpNodes.push_back(tmp.AddNode(Ni[0], Ni[1], 0)); + } + SMDS_MeshFace* face2D = tmp.AddPolygonalFace(tmpNodes); + gp_Pnt point(double(xClick), double(yClick), 0); + gp_XYZ closestPnt; + double dist = SMESH_MeshAlgos::GetDistance(face2D, point, &closestPnt); + double xPick = 0, yPick = 0; + if (dist < TOLERANCE) { + xPick = xClick; + yPick = yClick; + } + else { + xPick = closestPnt.X(); + yPick = closestPnt.Y(); + } + myFacePicker->Pick(xPick, yPick, 0.0, myRWInteractor->GetRenderer()->GetDevice()); + double closest[3]; + myFacePicker->GetPickPosition(closest); + myUpdateDestination = true; + myDlg->myDestinationX->SetValue(closest[0]); + myDlg->myDestinationY->SetValue(closest[1]); + myDlg->myDestinationZ->SetValue(closest[2]); + myUpdateDestination = false; + redisplayPreview(); + } + } + } + } + } + } + else { + double* aCoord = (double*)theCallData; + myUpdateDestination = true; + myDlg->myDestinationX->SetValue(aCoord[0]); + myDlg->myDestinationY->SetValue(aCoord[1]); + myDlg->myDestinationZ->SetValue(aCoord[2]); + myUpdateDestination = false; + redisplayPreview(); + } + } + } +} + +//================================================================================ +/* +* \brief Process LeftButtonPressEvent event: activate interactive selection +*/ +//================================================================================ +void SMESHGUI_AddNodeOnFaceOp::processInteractorEvents(unsigned long theEvent, void* theCallData) +{ + (void*)theCallData; + if (theEvent == vtkCommand::LeftButtonPressEvent && myDlg->myDestBtn->isChecked()) { + bool control = myRWInteractor->GetDevice()->GetControlKey(); + bool shift = myRWInteractor->GetDevice()->GetControlKey(); + SVTK_ViewWindow* svtkViewWindow = SMESH::GetViewWindow(mySMESHGUI); + if (svtkViewWindow && !shift && !control) { + QString msg; + if (isValid(msg)) { + svtkViewWindow->activateInteractiveSelection(); + } + } + } +} diff --git a/src/SMESHGUI/SMESHGUI_AddNodeOnFaceDlg.h b/src/SMESHGUI/SMESHGUI_AddNodeOnFaceDlg.h index 7dc88647a..b7c5a1e83 100644 --- a/src/SMESHGUI/SMESHGUI_AddNodeOnFaceDlg.h +++ b/src/SMESHGUI/SMESHGUI_AddNodeOnFaceDlg.h @@ -30,7 +30,7 @@ #include "SMESH_SMESHGUI.hxx" #include "SMESHGUI_Dialog.h" -#include "SMESHGUI_SelectionOp.h" +#include "SMESHGUI_InteractiveOp.h" class QButtonGroup; class QCheckBox; @@ -41,12 +41,13 @@ class QRadioButton; class SMESHGUI_SpinBox; class SMESHGUI_MeshEditPreview; class SMESHGUI_AddNodeOnFaceDlg; +class vtkCellPicker; /*! * \brief Operation to split a face into triangles by creating a new node * on the face and connecting it to the face nodes */ -class SMESHGUI_EXPORT SMESHGUI_AddNodeOnFaceOp: public SMESHGUI_SelectionOp +class SMESHGUI_EXPORT SMESHGUI_AddNodeOnFaceOp: public SMESHGUI_InteractiveOp { Q_OBJECT @@ -58,13 +59,20 @@ public: protected: - virtual void startOperation(); - virtual void stopOperation(); + virtual void startOperation() override; + virtual void stopOperation() override; - virtual void activateSelection(); + virtual void activateSelection() override; bool isValid( QString& ); + virtual void processStyleEvents(unsigned long event, + void* calldata) override; + + virtual void processInteractorEvents(unsigned long event, + void* calldata) override; + + protected slots: virtual bool onApply(); @@ -73,9 +81,11 @@ private slots: void redisplayPreview(); void onSelTypeChange(); void onTextChange( const QString& ); - void onDestCoordChanged(); +// void onDestCoordChanged(); void onOpenView(); void onCloseView(); + void pointLocationChanged(bool); + void onDestCoordChanged(); private: SMESHGUI_AddNodeOnFaceDlg* myDlg; @@ -87,6 +97,7 @@ private: bool myNoPreview; bool myUpdateDestination; bool myDestCoordChanged; + vtkCellPicker* myFacePicker; }; /*! @@ -112,6 +123,7 @@ private: SMESHGUI_SpinBox* myDestinationX; SMESHGUI_SpinBox* myDestinationY; SMESHGUI_SpinBox* myDestinationZ; + QCheckBox* myPointOnFace; QCheckBox* myPreviewChkBox; QString myHelpFileName; diff --git a/src/SMESHGUI/SMESHGUI_AddNodeOnSegmentDlg.cxx b/src/SMESHGUI/SMESHGUI_AddNodeOnSegmentDlg.cxx index 81aac2703..d400b45c7 100644 --- a/src/SMESHGUI/SMESHGUI_AddNodeOnSegmentDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_AddNodeOnSegmentDlg.cxx @@ -44,6 +44,9 @@ #include #include #include +#include +#include +#include #include // Qt includes @@ -61,6 +64,10 @@ // VTK includes #include +#include +#include +#include +#include // IDL includes #include @@ -70,6 +77,8 @@ #define SPACING 6 #define MARGIN 11 +#define SPIN_TOLERANCE 1e-3 + //======================================================================= /*! * \brief Dialog to split a diagonal of a quadrangle formed by two adjacent triangles @@ -135,8 +144,7 @@ QWidget* SMESHGUI_AddNodeOnSegmentDlg::createMainFrame (QWidget* theParent) myPositionSpin = new SMESHGUI_SpinBox(positionGrp); myPositionSpin->setReadOnly(false); - const double tol = 1e-3; - myPositionSpin->RangeStepAndValidator( tol, 1-tol, 0.1, "length_precision"); + myPositionSpin->RangeStepAndValidator(SPIN_TOLERANCE, 1- SPIN_TOLERANCE, 0.1, "length_precision"); QGridLayout* positionLayout = new QGridLayout(positionGrp); positionLayout->setMargin(MARGIN); @@ -193,7 +201,8 @@ void SMESHGUI_AddNodeOnSegmentDlg::ButtonToggled (bool on) */ //================================================================================ -SMESHGUI_AddNodeOnSegmentOp::SMESHGUI_AddNodeOnSegmentOp() +SMESHGUI_AddNodeOnSegmentOp::SMESHGUI_AddNodeOnSegmentOp() : + SMESHGUI_InteractiveOp() { mySimulation = 0; mySMESHGUI = 0; @@ -224,7 +233,17 @@ void SMESHGUI_AddNodeOnSegmentOp::onSelTypeChange() } else if ( myDlg->myPositionBtn->isChecked() ) { - // TODO: activate picking a point on a selected segment + if (SVTK_ViewWindow* svtkViewWindow = SMESH::GetViewWindow(mySMESHGUI)) { + QString msg; + SMESH::smIdType node1 = 0, node2 = 0; + if (isValid(msg, node1, node2)) { + //Disconnect selectionChanged to keep selected element + disconnect(selectionMgr(), SIGNAL(selectionChanged()), this, SLOT(onSelectionDone())); + // Set selection mode to ActorSelection to avoid element's prehighlight during interactive selection + setSelectionMode(ActorSelection); + connect(selectionMgr(), SIGNAL(selectionChanged()), SLOT(onSelectionDone())); + } + } } else { @@ -257,10 +276,13 @@ void SMESHGUI_AddNodeOnSegmentOp::startOperation() aProp->Delete(); SMESHGUI_SelectionOp::startOperation(); // this method should be called only after filter creation + SMESHGUI_InteractiveOp::startOperation(); myDlg->mySegment->setText(""); myDlg->myPositionSpin->SetValue(0.5); myDlg->myPositionSpin->setReadOnly(false); + addObserver(); + myDlg->show(); onSelectionDone(); // init myMeshActor @@ -291,11 +313,12 @@ void SMESHGUI_AddNodeOnSegmentOp::stopOperation() disconnect(mySMESHGUI, SIGNAL (SignalCloseView()), this, SLOT(onCloseView())); //selectionMgr()->removeFilter( myFilter ); SMESHGUI_SelectionOp::stopOperation(); + removeObserver(); } //================================================================================ /*! - * \brief perform it's intention action: move or create a node + * \brief perform it's intention action: create a node on a segment */ //================================================================================ @@ -603,3 +626,76 @@ LightApp_Dialog* SMESHGUI_AddNodeOnSegmentOp::dlg() const return myDlg; } +//================================================================================ +/* +* \brief Process InteractiveSelectionChanged event +*/ +//================================================================================ +void SMESHGUI_AddNodeOnSegmentOp::processStyleEvents(unsigned long theEvent, void* theCallData) +{ + (void*)theCallData; + QString msg; + SMESH::smIdType node1 = 0, node2 = 0; + if (isValid(msg, node1, node2)) { + if (theEvent == SVTK::InteractiveSelectionChanged) { + if (SMDS_Mesh* mesh = myMeshActor->GetObject()->GetMesh()) + if(myRWInteractor && myRWInteractor->GetDevice() && myInteractorStyle) { + { + double N1[3]; + double N2[3]; + double pos; + double N1_SC[3]; + double N2_SC[3]; + double xyz[3]; + double closest[3]; + + const SMDS_MeshNode* n1 = mesh->FindNode(node1); + const SMDS_MeshNode* n2 = mesh->FindNode(node2); + int xClick, yClick; // Last event (move or left button down) position + myRWInteractor->GetDevice()->GetEventPosition(xClick, yClick); + + n1->GetXYZ(N1); + n2->GetXYZ(N2); + // Get 2D screen coordinates of each node + vtkInteractorObserver::ComputeWorldToDisplay(myRWInteractor->GetRenderer()->GetDevice(), + N1[0], N1[1], N1[2], N1_SC); + vtkInteractorObserver::ComputeWorldToDisplay(myRWInteractor->GetRenderer()->GetDevice(), + N2[0], N2[1], N2[2], N2_SC); + N1_SC[2] = N2_SC[2] = xyz[2] = 0; + xyz[0] = static_cast(xClick); + xyz[1] = static_cast(yClick); + // Parametric position of selected point on a line + vtkLine::DistanceToLine(xyz, N1_SC, N2_SC, pos, closest); + if (pos < 0) + pos = SPIN_TOLERANCE; + else if (pos > 1.0) + pos = 1.0 - SPIN_TOLERANCE; + myDlg->myPositionSpin->SetValue(pos); + redisplayPreview(); + } + } + } + } +} + +//================================================================================ +/* +* \brief Process LeftButtonPressEvent event: activate interactive selection +*/ +//================================================================================ +void SMESHGUI_AddNodeOnSegmentOp::processInteractorEvents(unsigned long theEvent, void* theCallData) +{ + (void*)theCallData; + if (theEvent == vtkCommand::LeftButtonPressEvent && myDlg->myPositionBtn->isChecked()) { + bool control = myRWInteractor->GetDevice()->GetControlKey(); + bool shift = myRWInteractor->GetDevice()->GetControlKey(); + SVTK_ViewWindow* svtkViewWindow = SMESH::GetViewWindow(mySMESHGUI); + if (svtkViewWindow && !shift && ! control) { + QString msg; + SMESH::smIdType node1 = 0, node2 = 0; + if (isValid(msg, node1, node2)) { + svtkViewWindow->activateInteractiveSelection(); + } + } + } +} \ No newline at end of file diff --git a/src/SMESHGUI/SMESHGUI_AddNodeOnSegmentDlg.h b/src/SMESHGUI/SMESHGUI_AddNodeOnSegmentDlg.h index 7c9caaca8..bdf756955 100644 --- a/src/SMESHGUI/SMESHGUI_AddNodeOnSegmentDlg.h +++ b/src/SMESHGUI/SMESHGUI_AddNodeOnSegmentDlg.h @@ -27,7 +27,7 @@ #define SMESHGUI_AddNodeOnSegmentDLG_H #include "SMESHGUI_Dialog.h" -#include "SMESHGUI_SelectionOp.h" +#include "SMESHGUI_InteractiveOp.h" class QButtonGroup; class QCheckBox; @@ -42,7 +42,7 @@ class SMESHGUI_AddNodeOnSegmentDlg; /*! * \brief Operation to make a mesh pass through a point */ -class SMESHGUI_EXPORT SMESHGUI_AddNodeOnSegmentOp: public SMESHGUI_SelectionOp +class SMESHGUI_EXPORT SMESHGUI_AddNodeOnSegmentOp: public SMESHGUI_InteractiveOp { Q_OBJECT @@ -54,22 +54,28 @@ public: protected: - virtual void startOperation(); - virtual void stopOperation(); + virtual void startOperation() override; + virtual void stopOperation() override; virtual void activateSelection(); bool isValid( QString&, SMESH::smIdType& n1, SMESH::smIdType& n2 ); + virtual void processStyleEvents(unsigned long event, + void* calldata) override; + + virtual void processInteractorEvents(unsigned long event, + void* calldata) override; + + protected slots: - virtual bool onApply(); + virtual bool onApply() override; + private slots: void onSelectionDone(); void redisplayPreview(); void onTextChange( const QString& ); - void onPositionClick(); - void onPositionChanged(); void onSelTypeChange(); void onOpenView(); void onCloseView(); diff --git a/src/SMESHGUI/SMESHGUI_InteractiveOp.cxx b/src/SMESHGUI/SMESHGUI_InteractiveOp.cxx new file mode 100644 index 000000000..565fa3d2f --- /dev/null +++ b/src/SMESHGUI/SMESHGUI_InteractiveOp.cxx @@ -0,0 +1,181 @@ +// 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 +// +// 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, or (at your option) any later version. +// +// 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_InteractiveOp.cxx +// Author : Roman NIKOLAEV, Open CASCADE S.A.S. + +// SMESH includes +// +#include "SMESHGUI.h" +#include "SMESHGUI_InteractiveOp.h" +#include "SMESHGUI_VTKUtils.h" + +// GUI includes +#include +#include +#include + +// VTK includes +#include +#include +#include +#include + + +//================================================================================ +/*! + * \brief Constructor +*/ +//================================================================================ + +SMESHGUI_InteractiveOp::SMESHGUI_InteractiveOp() : + SMESHGUI_SelectionOp(), + myInteractorStyle(0), + myRWInteractor(0), + myStyleEventCallbackCommand(vtkCallbackCommand::New()), + myInteractorStypePriority(0.0), + myInteractorEventCallbackCommand(vtkCallbackCommand::New()), + myInteractorPriority(1.0) +{ + myStyleEventCallbackCommand->Delete(); + myStyleEventCallbackCommand->SetClientData(this); + myStyleEventCallbackCommand->SetCallback(SMESHGUI_InteractiveOp::ProcessStyleEvents); + + myInteractorEventCallbackCommand->Delete(); + myInteractorEventCallbackCommand->SetClientData(this); + myInteractorEventCallbackCommand->SetCallback(SMESHGUI_InteractiveOp::ProcessInteractorEvents); +} + +//================================================================================ +/*! + * \brief Destructor +*/ +//================================================================================ +SMESHGUI_InteractiveOp::~SMESHGUI_InteractiveOp() +{ +} + +//======================================================================= +// function : addObserver() +// purpose : Add VTK observers to process SVTK_InteractorStyle and vtkGenericRenderWindowInteractor events +//====================================================================== +void SMESHGUI_InteractiveOp::addObserver() +{ + if (myInteractorStyle && !myInteractorStyle->HasObserver(SVTK::InteractiveSelectionChanged, myStyleEventCallbackCommand.GetPointer())) { + myInteractorStyle->AddObserver(SVTK::InteractiveSelectionChanged, myStyleEventCallbackCommand.GetPointer(), + myInteractorStypePriority); + } + if (myRWInteractor && myRWInteractor->GetDevice() && + !myRWInteractor->GetDevice()->HasObserver(vtkCommand::LeftButtonPressEvent, myInteractorEventCallbackCommand.GetPointer())) { + myRWInteractor->GetDevice()->AddObserver(vtkCommand::LeftButtonPressEvent, myInteractorEventCallbackCommand.GetPointer(), + myInteractorPriority); + } +} + +//======================================================================= +// function : removeObserver() +// purpose : Remove VTK observers +//====================================================================== +void SMESHGUI_InteractiveOp::removeObserver() { + if (myInteractorStyle && myInteractorStyle->HasObserver(SVTK::InteractiveSelectionChanged, myStyleEventCallbackCommand.GetPointer())) { + myInteractorStyle->RemoveObserver(myStyleEventCallbackCommand.GetPointer()); + } + if (myRWInteractor && myRWInteractor->GetDevice() && + myRWInteractor->GetDevice()->HasObserver(vtkCommand::LeftButtonPressEvent, myInteractorEventCallbackCommand.GetPointer())) { + myRWInteractor->GetDevice()->RemoveObserver(myInteractorEventCallbackCommand.GetPointer()); + } +} + +//======================================================================= +// function : startOperation() +// purpose : Init dialog fields, connect signals and slots, show dialog +//======================================================================= + +void SMESHGUI_InteractiveOp::startOperation() +{ + SVTK_ViewWindow* svtkViewWindow = SMESH::GetViewWindow(getSMESHGUI()); + if (svtkViewWindow) { + myInteractorStyle = svtkViewWindow->GetInteractorStyle(); + myRWInteractor = svtkViewWindow->GetInteractor(); + } +} + +//================================================================================ +/*! + * \brief Process interactor style events + Static method. Used by vtkCallbackCommand->SetCallback method. + */ + //=============================================================================== +void SMESHGUI_InteractiveOp::ProcessStyleEvents(vtkObject* vtkNotUsed(theObject), + unsigned long theEvent, + void* theClientData, + void* theCallData) { + SMESHGUI_InteractiveOp* self = reinterpret_cast(theClientData); + if (self) + self->processStyleEvents(theEvent, theCallData); +} + +//================================================================================ +/*! + * \brief Process Generic Render Window Interactor events. + Static method. Used by vtkCallbackCommand->SetCallback method. + */ + //=============================================================================== +void SMESHGUI_InteractiveOp::ProcessInteractorEvents(vtkObject* vtkNotUsed(theObject), + unsigned long theEvent, + void* theClientData, + void* theCallData) { + SMESHGUI_InteractiveOp* self = reinterpret_cast(theClientData); + if (self) + self->processInteractorEvents(theEvent, theCallData); +} + +//================================================================================ +/*! + * \brief Process interactor style events () + Virtual method. Should be overridden in inherited classes. + */ + //=============================================================================== + +void SMESHGUI_InteractiveOp::processStyleEvents(unsigned long theEvent, void* theCallData) { +} + +//================================================================================ +/*! + * \brief Process Generic Render Window Interactor events. + Virtual method. Should be overridden in inherited classes. + */ + //=============================================================================== +void SMESHGUI_InteractiveOp::processInteractorEvents(unsigned long theEvent, void* theCallData) +{ +} + +//================================================================================ +/*! + * \brief Deactivate current operation in active VTK viewer + */ + //=============================================================================== +void SMESHGUI_InteractiveOp::deactivateCurrentViewOperation() { + if (SVTK_ViewWindow* svtkViewWindow = SMESH::GetViewWindow(getSMESHGUI())) { + svtkViewWindow->deactivateCurrectOperation(); + } +} \ No newline at end of file diff --git a/src/SMESHGUI/SMESHGUI_InteractiveOp.h b/src/SMESHGUI/SMESHGUI_InteractiveOp.h new file mode 100644 index 000000000..65894e315 --- /dev/null +++ b/src/SMESHGUI/SMESHGUI_InteractiveOp.h @@ -0,0 +1,88 @@ +// 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 +// +// 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, or (at your option) any later version. +// +// 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_InteractiveOp.h +// Author : Roman NIKOLAEV, Open CASCADE S.A.S. +// + +#pragma once + +// SMESH includes +#include "SMESH_SMESHGUI.hxx" +#include "SMESHGUI_SelectionOp.h" + +// VTK includes +#include + +/* + Class : SMESHGUI_InteractiveOp + Description : Base operation for all interactive operations in the VTK 3D Viewer +*/ + +class vtkInteractorStyle; +class vtkCallbackCommand; +class vtkObject; +class SVTK_RenderWindowInteractor; + +class SMESHGUI_EXPORT SMESHGUI_InteractiveOp: public SMESHGUI_SelectionOp { + Q_OBJECT +public: + SMESHGUI_InteractiveOp(); + virtual ~SMESHGUI_InteractiveOp(); + + virtual void deactivateCurrentViewOperation(); + +protected: + virtual void startOperation() override; + + static void ProcessStyleEvents(vtkObject* object, + unsigned long event, + void* clientdata, + void* calldata); + virtual void processStyleEvents(unsigned long event, + void* calldata); + + static void ProcessInteractorEvents(vtkObject* object, + unsigned long event, + void* clientdata, + void* calldata); + virtual void processInteractorEvents(unsigned long event, + void* calldata); + + virtual void addObserver(); + virtual void removeObserver(); + + +protected: + vtkInteractorStyle* myInteractorStyle; + SVTK_RenderWindowInteractor* myRWInteractor; + + // Priority at which events are processed: + // Interactor Stype events + double myInteractorStypePriority; + // Interactor events + double myInteractorPriority; + + // Used to process events + vtkSmartPointer myStyleEventCallbackCommand; + vtkSmartPointer myInteractorEventCallbackCommand; +}; diff --git a/src/SMESHGUI/SMESHGUI_MakeNodeAtPointDlg.cxx b/src/SMESHGUI/SMESHGUI_MakeNodeAtPointDlg.cxx index 5745d8483..bf33fd2e1 100644 --- a/src/SMESHGUI/SMESHGUI_MakeNodeAtPointDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_MakeNodeAtPointDlg.cxx @@ -48,6 +48,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -74,7 +77,10 @@ #include // VTK includes +#include #include +#include +#include // IDL includes #include @@ -89,6 +95,8 @@ namespace enum { MANUAL_MODE = 0, SEARCH_MODE, INTERACTIVE_MODE }; } +//#define SELECTION_PRECISION 4 + //======================================================================= /*! * \brief Dialog to publish a sub-shape of the mesh main shape @@ -125,7 +133,7 @@ QWidget* SMESHGUI_MakeNodeAtPointDlg::createMainFrame (QWidget* theParent) QPixmap iconMoveWithoutNode (rm->loadPixmap("SMESH", tr("ICON_DLG_MOVE_WITHOUT_NODE"))); QPixmap iconMoveInteractive (rm->loadPixmap("SMESH", tr("ICON_DLG_MOVE_NODE_INTERACTIVE"))); QPixmap iconSelect (rm->loadPixmap("SMESH", tr("ICON_SELECT"))); - + // constructor QGroupBox* aPixGrp = new QGroupBox(tr("MOVE_NODE"), this); aPixGrp->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) ); @@ -349,7 +357,6 @@ void SMESHGUI_MakeNodeAtPointDlg::ConstructorsClicked (int constructorId) break; } } - QApplication::instance()->processEvents(); myMainFrame->hide(); myMainFrame->show(); @@ -363,7 +370,8 @@ void SMESHGUI_MakeNodeAtPointDlg::ConstructorsClicked (int constructorId) */ //================================================================================ -SMESHGUI_MakeNodeAtPointOp::SMESHGUI_MakeNodeAtPointOp(int defaultConstructor) +SMESHGUI_MakeNodeAtPointOp::SMESHGUI_MakeNodeAtPointOp(int defaultConstructor) : + SMESHGUI_InteractiveOp() { myDefaultConstructor = defaultConstructor; mySimulation = 0; @@ -385,7 +393,7 @@ SMESHGUI_MakeNodeAtPointOp::SMESHGUI_MakeNodeAtPointOp(int defaultConstructor) connect(myDlg->myDestDZ, SIGNAL (valueChanged(double)), this, SLOT(onDestCoordChanged())); connect(myDlg->myId, SIGNAL (textChanged(const QString&)),SLOT(redisplayPreview())); connect(myDlg->myPreviewChkBox, SIGNAL (toggled(bool)), SLOT(redisplayPreview())); - connect(myDlg->myButtonGroup, SIGNAL (buttonClicked(int)), SLOT(redisplayPreview())); + connect(myDlg->myButtonGroup, SIGNAL (buttonClicked(int)), SLOT(constructorChanged())); // IPAL22913: TC6.5.0: selected in "Move node" dialog box node is not highlighted // note: this slot seems to be lost together with removed obsolete SMESHGUI_MoveNodesDlg class @@ -419,6 +427,7 @@ void SMESHGUI_MakeNodeAtPointOp::onDestCoordChanged() myDestCoordChanged = true; } + //======================================================================= // function : startOperation() // purpose : Init dialog fields, connect signals and slots, show dialog @@ -432,7 +441,8 @@ void SMESHGUI_MakeNodeAtPointOp::startOperation() // init simulation with a current View if ( mySimulation ) delete mySimulation; mySMESHGUI = getSMESHGUI(); - mySimulation = new SMESHGUI_MeshEditPreview(SMESH::GetViewWindow( mySMESHGUI ) ); + mySimulation = new SMESHGUI_MeshEditPreview(SMESH::GetViewWindow(mySMESHGUI)); + connect(mySMESHGUI, SIGNAL (SignalActivatedViewManager()), this, SLOT(onOpenView())); connect(mySMESHGUI, SIGNAL (SignalCloseView()), this, SLOT(onCloseView())); vtkProperty* aProp = vtkProperty::New(); @@ -455,6 +465,7 @@ void SMESHGUI_MakeNodeAtPointOp::startOperation() // IPAL19360 SMESHGUI_SelectionOp::startOperation(); // this method should be called only after filter creation //activateSelection(); // set filters // called inside of previous statement + SMESHGUI_InteractiveOp::startOperation(); myDlg->myId->setText(""); myDlg->myDestinationX->SetValue(0); myDlg->myDestinationY->SetValue(0); @@ -470,8 +481,10 @@ void SMESHGUI_MakeNodeAtPointOp::startOperation() myDlg->myDestDZ->setReadOnly(true); myDlg->myRButNodeToMove->setChecked(true); - if ( myDefaultConstructor == INTERACTIVE_MODE ) + if ( myDefaultConstructor == INTERACTIVE_MODE ) { + addObserver(); myDlg->myButtonGroup->button( INTERACTIVE_MODE )->setChecked(true); + } myDlg->ConstructorsClicked( GetConstructorId() ); myDlg->show(); @@ -514,6 +527,7 @@ void SMESHGUI_MakeNodeAtPointOp::stopOperation() disconnect(mySMESHGUI, SIGNAL (SignalCloseView()), this, SLOT(onCloseView())); selectionMgr()->removeFilter( myFilter ); SMESHGUI_SelectionOp::stopOperation(); + removeObserver(); } //================================================================================ @@ -871,6 +885,23 @@ void SMESHGUI_MakeNodeAtPointOp::onOpenView() } } +//================================================================================= +/*! + * \brief SLOT called when the creation mode is changed + */ + //================================================================================= + +void SMESHGUI_MakeNodeAtPointOp::constructorChanged() { + redisplayPreview(); + if (GetConstructorId() == INTERACTIVE_MODE) { + addObserver(); + } + else { + removeObserver(); + } +} + + //================================================================================= /*! * \brief SLOT called when the viewer closed @@ -951,3 +982,54 @@ LightApp_Dialog* SMESHGUI_MakeNodeAtPointOp::dlg() const return myDlg; } + +//================================================================================ +/* +* \brief Process InteractiveSelectionChanged event +*/ +//================================================================================ + +void SMESHGUI_MakeNodeAtPointOp::processStyleEvents(unsigned long theEvent, void* theCallData) { + if (theEvent == SVTK::InteractiveSelectionChanged) { + double* aCoord = (double*)theCallData; + myDlg->myDestinationX->SetValue(aCoord[0]); + myDlg->myDestinationY->SetValue(aCoord[1]); + myDlg->myDestinationZ->SetValue(aCoord[2]); + redisplayPreview(); + } +} + +//================================================================================ +/* +* \brief Process LeftButtonPressEvent event +*/ +//================================================================================ +void SMESHGUI_MakeNodeAtPointOp::processInteractorEvents(unsigned long theEvent, void* theCallData) { + (void*)theCallData; + if (theEvent == vtkCommand::LeftButtonPressEvent) { + bool control = myRWInteractor->GetDevice()->GetControlKey(); + bool shift = myRWInteractor->GetDevice()->GetControlKey(); + if (GetConstructorId() == INTERACTIVE_MODE && myDlg->myDestBtn->isChecked() && !shift && !control) { + if (SVTK_ViewWindow* svtkViewWindow = SMESH::GetViewWindow(SMESHGUI::GetSMESHGUI())) { + svtkViewWindow->activateInteractiveSelection(); + } + } + } + /* + if ( myRWInteractor && myRWInteractor->GetDevice() && myInteractorStyle ) { + int xClick, yClick; // Last click position + myRWInteractor->GetDevice()->GetEventPosition(xClick, yClick); + double nodeCoords[3]; + vtkInteractorObserver::ComputeWorldToDisplay(myRWInteractor->GetRenderer()->GetDevice(), + myDlg->myDestinationX->GetValue(), + myDlg->myDestinationY->GetValue(), + myDlg->myDestinationZ->GetValue(), + nodeCoords); + double rad = std::sqrt(std::pow(xClick - nodeCoords[0], 2) + std::pow(yClick - nodeCoords[1], 2)); + if (rad < SELECTION_PRECISION) { + if (SVTK_ViewWindow* svtkViewWindow = SMESH::GetViewWindow(mySMESHGUI)) { + svtkViewWindow->activateInteractiveSelection(); + } + } + }*/ +} diff --git a/src/SMESHGUI/SMESHGUI_MakeNodeAtPointDlg.h b/src/SMESHGUI/SMESHGUI_MakeNodeAtPointDlg.h index 32cb9f0c1..945f08f6e 100644 --- a/src/SMESHGUI/SMESHGUI_MakeNodeAtPointDlg.h +++ b/src/SMESHGUI/SMESHGUI_MakeNodeAtPointDlg.h @@ -30,7 +30,9 @@ #include "SMESH_SMESHGUI.hxx" #include "SMESHGUI_Dialog.h" -#include "SMESHGUI_SelectionOp.h" +#include "SMESHGUI_InteractiveOp.h" + +#include class QButtonGroup; class QCheckBox; @@ -42,10 +44,11 @@ class SMESHGUI_SpinBox; class SMESHGUI_MeshEditPreview; class SMESHGUI_MakeNodeAtPointDlg; + /*! * \brief Operation to make a mesh pass through a point */ -class SMESHGUI_EXPORT SMESHGUI_MakeNodeAtPointOp: public SMESHGUI_SelectionOp +class SMESHGUI_EXPORT SMESHGUI_MakeNodeAtPointOp: public SMESHGUI_InteractiveOp { Q_OBJECT @@ -57,13 +60,19 @@ public: protected: - virtual void startOperation(); - virtual void stopOperation(); + virtual void startOperation() override; + virtual void stopOperation() override; - virtual void activateSelection(); + virtual void activateSelection() override; bool isValid( QString& ); + virtual void processStyleEvents(unsigned long event, + void* calldata) override; + + virtual void processInteractorEvents(unsigned long event, + void* calldata) override; + protected slots: virtual bool onApply(); @@ -75,6 +84,7 @@ private slots: void onDestCoordChanged(); void onOpenView(); void onCloseView(); + void constructorChanged(); private: int GetConstructorId(); diff --git a/src/SMESHGUI/SMESH_msg_en.ts b/src/SMESHGUI/SMESH_msg_en.ts index f5db909ea..7c52712ec 100644 --- a/src/SMESHGUI/SMESH_msg_en.ts +++ b/src/SMESHGUI/SMESH_msg_en.ts @@ -6865,6 +6865,10 @@ Please specify them and try again XYZ_GROUP Node location by mouse click + + XYZ_NODE_ON_FACE + Node on face + SMESHGUI_AddNodeOnFaceOp