Salome HOME
Merge branch 'V9_9_BR'
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_AddNodeOnSegmentDlg.cxx
1 // Copyright (C) 2007-2022  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 // File   : SMESHGUI_AddNodeOnSegmentDlg.cxx
24 // Author : Edward AGAPOV, Open CASCADE S.A.S.
25 //
26 #include "SMESHGUI_AddNodeOnSegmentDlg.h"
27
28 #include "SMESHGUI.h"
29 #include "SMESHGUI_MeshUtils.h"
30 #include "SMESHGUI_VTKUtils.h"
31 #include "SMESHGUI_SpinBox.h"
32 #include "SMESHGUI_MeshEditPreview.h"
33
34 #include <SMDS_Mesh.hxx>
35 #include <SMESH_Actor.h>
36 #include <SMESH_ActorUtils.h>
37 #include <SMESH_TypeDefs.hxx>
38
39 #include <LightApp_SelectionMgr.h>
40 #include <SALOME_ListIO.hxx>
41 #include <SUIT_Desktop.h>
42 #include <SUIT_MessageBox.h>
43 #include <SUIT_OverrideCursor.h>
44 #include <SUIT_ResourceMgr.h>
45 #include <SVTK_ViewModel.h>
46 #include <SVTK_ViewWindow.h>
47 #include <SVTK_RenderWindowInteractor.h>
48 #include <SVTK_Renderer.h>
49 #include <SVTK_Event.h>
50 #include <SalomeApp_Tools.h>
51
52 // Qt includes
53 #include <QApplication>
54 #include <QGroupBox>
55 #include <QGridLayout>
56 #include <QHBoxLayout>
57 #include <QVBoxLayout>
58 #include <QLineEdit>
59 #include <QPushButton>
60 #include <QLabel>
61 #include <QRadioButton>
62 #include <QCheckBox>
63 #include <QButtonGroup>
64
65 // VTK includes
66 #include <vtkProperty.h>
67 #include <vtkInteractorStyle.h>
68 #include <vtkGenericRenderWindowInteractor.h>
69 #include <vtkInteractorObserver.h>
70 #include <vtkLine.h>
71
72 // IDL includes
73 #include <SALOMEconfig.h>
74 #include CORBA_SERVER_HEADER(SMESH_Mesh)
75 #include CORBA_SERVER_HEADER(SMESH_MeshEditor)
76
77 #define SPACING 6
78 #define MARGIN  11
79
80 #define SPIN_TOLERANCE 1e-3
81
82 //=======================================================================
83 /*!
84  * \brief Dialog to split a diagonal of a quadrangle formed by two adjacent triangles
85  */
86 //=======================================================================
87
88 SMESHGUI_AddNodeOnSegmentDlg::SMESHGUI_AddNodeOnSegmentDlg()
89 : SMESHGUI_Dialog( 0, false, true )
90 {
91   setWindowTitle(tr("CAPTION"));
92
93   QVBoxLayout* aDlgLay = new QVBoxLayout (mainFrame());
94   aDlgLay->setMargin(0);
95   aDlgLay->setSpacing(SPACING);
96   QWidget* mainFr = createMainFrame(mainFrame());
97
98   aDlgLay->addWidget( mainFr );
99
100   aDlgLay->setStretchFactor( mainFr, 1);
101 }
102
103 //=======================================================================
104 // function : createMainFrame()
105 // purpose  : Create frame containing dialog's input fields
106 //=======================================================================
107
108 QWidget* SMESHGUI_AddNodeOnSegmentDlg::createMainFrame (QWidget* theParent)
109 {
110   QWidget* aFrame = new QWidget(theParent);
111
112   SUIT_ResourceMgr* rm = SMESH::GetResourceMgr( SMESHGUI::GetSMESHGUI() );
113   QPixmap iconSelect( rm->loadPixmap("SMESH", tr("ICON_SELECT")));
114
115   // Segment
116
117   QGroupBox* segmentGrp = new QGroupBox(tr("SEGMENT_GROUP"), aFrame);
118   segmentGrp->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) );
119   QLabel* segmentLabel = new QLabel(tr("SEGMENT"), segmentGrp);
120   mySegmentBtn = new QPushButton(segmentGrp);
121   mySegmentBtn->setIcon(iconSelect);
122   mySegmentBtn->setCheckable(true);
123   mySegment = new QLineEdit(segmentGrp);
124   mySegment->setValidator(new QRegExpValidator(QRegExp("[\\d]*-[\\d]*"), this));
125
126   QGridLayout* segmentGrpLayout = new QGridLayout(segmentGrp);
127   segmentGrpLayout->setSpacing(SPACING);
128   segmentGrpLayout->setMargin(MARGIN);
129
130   segmentGrpLayout->addWidget( segmentLabel, 0, 0 );
131   segmentGrpLayout->addWidget( mySegmentBtn, 0, 1 );
132   segmentGrpLayout->addWidget( mySegment,    0, 2 );
133
134   // Position on segment
135
136   QGroupBox* positionGrp = new QGroupBox(tr("POSITION_GROUP"), aFrame);
137   positionGrp->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) );
138
139   myPositionBtn = new QPushButton(positionGrp);
140   myPositionBtn->setIcon(iconSelect);
141   myPositionBtn->setCheckable(true);
142
143   QLabel* positionLbl = new QLabel(tr("POSITION"), positionGrp);
144
145   myPositionSpin = new SMESHGUI_SpinBox(positionGrp);
146   myPositionSpin->setReadOnly(false);
147   myPositionSpin->RangeStepAndValidator(SPIN_TOLERANCE, 1- SPIN_TOLERANCE, 0.1, "length_precision");
148
149   QGridLayout* positionLayout = new QGridLayout(positionGrp);
150   positionLayout->setMargin(MARGIN);
151   positionLayout->setSpacing(SPACING);
152   positionLayout->addWidget(positionLbl, 0, 0);
153   positionLayout->addWidget(myPositionBtn, 0, 1);
154   positionLayout->addWidget(myPositionSpin, 0, 2);
155   positionLayout->setColumnStretch(2, 1);
156
157   // Preview
158
159   myPreviewChkBox = new QCheckBox( tr("PREVIEW"), aFrame);
160   myPreviewChkBox->setChecked( true );
161
162   QVBoxLayout* aLay = new QVBoxLayout(aFrame);
163   aLay->addWidget(segmentGrp);
164   aLay->addWidget(positionGrp);
165   aLay->addWidget(myPreviewChkBox);
166
167   connect(myPositionBtn, SIGNAL (toggled(bool)), this, SLOT(ButtonToggled(bool)));
168   connect(mySegmentBtn,  SIGNAL (toggled(bool)), this, SLOT(ButtonToggled(bool)));
169
170   mySegmentBtn->setChecked(true);
171
172   return aFrame;
173 }
174
175 //================================================================================
176 /*!
177  * \brief SLOT called when any button is toggled
178  * \param bool - on or off
179  */
180 //================================================================================
181
182 void SMESHGUI_AddNodeOnSegmentDlg::ButtonToggled (bool on)
183 {
184   const QObject* aSender = sender();
185   if ( on ) {
186     if ( aSender == myPositionBtn )
187     {
188       mySegmentBtn->setChecked( !on );
189     }
190     else if ( aSender == mySegmentBtn )
191     {
192       myPositionBtn->setChecked( !on );
193     }
194   }
195   emit selTypeChanged();
196 }
197
198 //================================================================================
199 /*!
200  * \brief Constructor
201  */
202 //================================================================================
203
204 SMESHGUI_AddNodeOnSegmentOp::SMESHGUI_AddNodeOnSegmentOp() :
205   SMESHGUI_InteractiveOp()
206 {
207   mySimulation = 0;
208   mySMESHGUI = 0;
209   myDlg = new SMESHGUI_AddNodeOnSegmentDlg;
210   myHelpFileName = "add_node_on_segment.html";
211
212   myNoPreview = false;
213
214   // connect signals and slots
215   connect(myDlg->myPreviewChkBox, SIGNAL (toggled(bool)),              SLOT(redisplayPreview()));
216   connect(myDlg->myPositionSpin,  SIGNAL (valueChanged(double)),       SLOT(redisplayPreview()));
217   connect(myDlg->myPositionSpin,  SIGNAL (textChanged(const QString&)),SLOT(redisplayPreview()));
218   connect(myDlg,                  SIGNAL (selTypeChanged() ),          SLOT(onSelTypeChange()));
219   connect(myDlg->mySegment,       SIGNAL (textChanged(const QString&)),SLOT(onTextChange(const QString&)));
220 }
221
222 //================================================================================
223 /*!
224  * \brief SLOT. Called upon change of selection type
225  */
226 //================================================================================
227
228 void SMESHGUI_AddNodeOnSegmentOp::onSelTypeChange()
229 {
230   if ( myDlg->mySegmentBtn->isChecked() )
231   {
232     setSelectionMode( EdgeOfCellSelection );
233   }
234   else if ( myDlg->myPositionBtn->isChecked() )
235   {
236     if (SVTK_ViewWindow* svtkViewWindow = SMESH::GetViewWindow(mySMESHGUI)) {
237       QString msg;
238       SMESH::smIdType node1 = 0, node2 = 0;
239       if (isValid(msg, node1, node2)) {
240         //Disconnect selectionChanged to keep selected element
241         disconnect(selectionMgr(), SIGNAL(selectionChanged()), this, SLOT(onSelectionDone()));
242         // Set selection mode to ActorSelection to avoid element's prehighlight during interactive selection
243         setSelectionMode(ActorSelection);
244         connect(selectionMgr(), SIGNAL(selectionChanged()), SLOT(onSelectionDone()));
245       }      
246     }
247   }
248   else
249   {
250     setSelectionMode( ActorSelection );
251   }
252 }
253
254 //=======================================================================
255 // function : startOperation()
256 // purpose  : Init dialog fields, connect signals and slots, show dialog
257 //=======================================================================
258
259 void SMESHGUI_AddNodeOnSegmentOp::startOperation()
260 {
261   myNoPreview = false;
262   myMeshActor = 0;
263
264   // init simulation with a current View
265   if ( mySimulation ) delete mySimulation;
266   mySMESHGUI = getSMESHGUI();
267   mySimulation = new SMESHGUI_MeshEditPreview(SMESH::GetViewWindow( mySMESHGUI ) );
268   connect(mySMESHGUI, SIGNAL (SignalActivatedViewManager()), this, SLOT(onOpenView()));
269   connect(mySMESHGUI, SIGNAL (SignalCloseView()), this, SLOT(onCloseView()));
270   vtkProperty* aProp = vtkProperty::New();
271   aProp->SetRepresentationToWireframe();
272   aProp->SetColor(250, 0, 250);
273   aProp->SetPointSize(5);
274   aProp->SetLineWidth( SMESH::GetFloat("SMESH:element_width",1) + 1);
275   mySimulation->GetActor()->SetProperty(aProp);
276   aProp->Delete();
277
278   SMESHGUI_SelectionOp::startOperation(); // this method should be called only after filter creation
279   SMESHGUI_InteractiveOp::startOperation();
280   myDlg->mySegment->setText("");
281   myDlg->myPositionSpin->SetValue(0.5);
282   myDlg->myPositionSpin->setReadOnly(false);
283
284   addObserver();
285
286   myDlg->show();
287
288   onSelectionDone(); // init myMeshActor
289 }
290
291 //================================================================================
292 /*!
293  * \brief Stops operation
294  */
295 //================================================================================
296
297 void SMESHGUI_AddNodeOnSegmentOp::stopOperation()
298 {
299   myNoPreview = true;
300   if ( mySimulation )
301   {
302     mySimulation->SetVisibility(false);
303     delete mySimulation;
304     mySimulation = 0;
305   }
306   if ( myMeshActor ) {
307     myMeshActor = 0;
308   }
309   SMESH::SetPointRepresentation( false );
310   SMESH::RepaintCurrentView();
311
312   disconnect(mySMESHGUI, SIGNAL (SignalActivatedViewManager()), this, SLOT(onOpenView()));
313   disconnect(mySMESHGUI, SIGNAL (SignalCloseView()),            this, SLOT(onCloseView()));
314   //selectionMgr()->removeFilter( myFilter );
315   SMESHGUI_SelectionOp::stopOperation();
316   removeObserver();
317 }
318
319 //================================================================================
320 /*!
321  * \brief perform it's intention action: create a node on a segment
322  */
323 //================================================================================
324
325 bool SMESHGUI_AddNodeOnSegmentOp::onApply()
326 {
327   if( SMESHGUI::isStudyLocked() )
328     return false;
329
330   QString msg;
331   SMESH::smIdType node1= 0, node2 = 0;
332   if ( !isValid( msg, node1, node2 ))
333   {
334     SUIT_MessageBox::warning( dlg(), tr( "SMESH_WRN_WARNING" ),
335                               msg.isEmpty() ? tr("INVALID_ID") : msg );
336     dlg()->show();
337     return false;
338   }
339
340   QStringList aParameters;
341   aParameters << myDlg->myPositionSpin->text();
342
343   try {
344     SMESH::SMESH_Mesh_var aMesh = SMESH::GetMeshByIO( myMeshActor->getIO() );
345     if (aMesh->_is_nil()) {
346       SUIT_MessageBox::information(SMESHGUI::desktop(), tr("SMESH_ERROR"), tr("INVALID_MESH") );
347       return true;
348     }
349     SMESH::SMESH_MeshEditor_var aMeshEditor = aMesh->GetMeshEditor();
350     if (aMeshEditor->_is_nil())
351       return true;
352
353     aMesh->SetParameters( aParameters.join(":").toUtf8().constData() );
354
355     aMeshEditor->AddNodeOnSegment( node1, node2, myDlg->myPositionSpin->GetValue() );
356
357     selector()->ClearIndex();
358     selector()->ClearCompositeIndex();
359     SALOME_ListIO aList;
360     aList.Append( myMeshActor->getIO() );
361     selectionMgr()->setSelectedObjects(aList,false);
362     onSelectionDone();
363     SMESH::UpdateView();
364     SMESHGUI::Modified();
365   }
366   catch (const SALOME::SALOME_Exception& S_ex) {
367     SalomeApp_Tools::QtCatchCorbaException(S_ex);
368   }
369   catch (...) {
370   }
371
372   return true;
373 }
374
375 //================================================================================
376 /*!
377  * \brief Check selected node id validity
378  */
379 //================================================================================
380
381 bool SMESHGUI_AddNodeOnSegmentOp::isValid( QString&          msg,
382                                            SMESH::smIdType & node1,
383                                            SMESH::smIdType & node2 )
384 {
385   bool ok = false;
386   if ( !myMeshActor )
387   {
388     msg = tr("INVALID_MESH");
389   }
390   else
391   {
392     if ( SMDS_Mesh* mesh = myMeshActor->GetObject()->GetMesh() )
393     {
394       QString txt = myDlg->mySegment->text();
395       if ( txt.contains('-'))
396       {
397         QString str1 = txt.section('-', 0, 0, QString::SectionSkipEmpty);
398         QString str2 = txt.section('-', 1, 1, QString::SectionSkipEmpty);
399         node1 = str1.toLong();
400         node2 = str2.toLong();
401         const SMDS_MeshNode* n1 = mesh->FindNode( node1 );
402         const SMDS_MeshNode* n2 = mesh->FindNode( node2 );
403         std::vector<const SMDS_MeshNode *> nodes = { n1, n2 };
404         std::vector<const SMDS_MeshElement *> foundElems;
405         if ( !mesh->GetElementsByNodes( nodes, foundElems ))
406           msg = tr("NO_ELEMENTS");
407         else
408         {
409           for ( const SMDS_MeshElement * elem : foundElems )
410           {
411             if ( elem->GetGeomType() == SMDSGeom_TRIANGLE )
412               ok = true;
413             else
414             {
415               if ( elem->GetType() == SMDSAbs_Volume )
416                 msg = tr("VOLUME_FOUND");
417               if ( elem->GetType() == SMDSAbs_Face )
418                 msg = tr("NOT_TRIANGLE_FACE_FOUND");
419             }
420           }
421           if ( !msg.isEmpty() )
422             ok = false;
423         }
424       }
425     }
426   }
427   if ( !ok && msg.isEmpty() )
428   {
429     node1 = node2 = 0;
430     msg += tr("INVALID_EDGE") + "\n";
431   }
432
433   if ( ok && ! myDlg->myPositionSpin->isValid( msg, /*toCorrect=*/false ))
434   {
435     msg = tr("BAD_POSITION");
436     ok = false;
437   }
438
439   return ok;
440 }
441
442 //================================================================================
443 /*!
444  * \brief SLOT called when selection changed
445  */
446 //================================================================================
447
448 void SMESHGUI_AddNodeOnSegmentOp::onSelectionDone()
449 {
450   if ( !myDlg->isVisible() || !myDlg->isEnabled() )
451     return;
452
453   myNoPreview = true;
454   QString segmentStr;
455   try {
456     SALOME_ListIO aList;
457     selectionMgr()->selectedObjects(aList, SVTK_Viewer::Type());
458     if (aList.Extent() != 1)
459       return;
460     Handle(SALOME_InteractiveObject) anIO = aList.First();
461     if (( myMeshActor = SMESH::FindActorByEntry(anIO->getEntry()) ))
462     {
463       SVTK_IndexedMapOfVtkIds IDs;
464       selector()->GetCompositeIndex( anIO, IDs );
465       if ( IDs.Extent() == 1 && IDs(1).size() == 2 )
466       {
467         SMESH::smIdType id1 = IDs(1)[0];
468         SMESH::smIdType id2 = IDs(1)[1];
469         segmentStr = QString("%1-%2").arg( id1 ).arg( id2 );
470       }
471     }
472   } catch (...) {
473   }
474   myDlg->mySegment->setText( segmentStr );
475
476   myNoPreview = false;
477   redisplayPreview();
478 }
479
480 //================================================================================
481 /*!
482  * \brief update preview
483  */
484 //================================================================================
485
486 void SMESHGUI_AddNodeOnSegmentOp::redisplayPreview()
487 {
488   if ( myNoPreview || !myDlg->myPreviewChkBox->isChecked() )
489   {
490     if ( mySimulation )
491       mySimulation->SetVisibility(false);
492     return;
493   }
494   myNoPreview = true;
495
496   SMESH::MeshPreviewStruct_var aMeshPreviewStruct;
497
498   QString msg;
499   SMESH::smIdType node1, node2;
500   try {
501     if ( isValid( msg, node1, node2 ))
502     {
503       SMESH::SMESH_Mesh_var aMesh = SMESH::GetMeshByIO(myMeshActor->getIO());
504       if ( !aMesh->_is_nil() )
505       {
506         SMESH::SMESH_MeshEditor_var aPreviewer = aMesh->GetMeshEditPreviewer();
507         if ( !aPreviewer->_is_nil() )
508         {
509           SUIT_OverrideCursor aWaitCursor;
510           double pos = myDlg->myPositionSpin->value();
511           aPreviewer->AddNodeOnSegment( node1, node2, pos );
512
513           aMeshPreviewStruct = aPreviewer->GetPreviewData();
514         }
515       }
516     }
517   }
518   catch (...) {
519   }
520
521   if (!mySimulation)
522     mySimulation = new SMESHGUI_MeshEditPreview(SMESH::GetViewWindow( mySMESHGUI ));
523   // display data
524   if ( & aMeshPreviewStruct.in() )
525   {
526     mySimulation->SetData( aMeshPreviewStruct.in() );
527   }
528   else
529   {
530     mySimulation->SetVisibility(false);
531   }
532
533   myNoPreview = false;
534 }
535
536 //=================================================================================
537 /*!
538  * \brief SLOT called when the viewer opened
539  */
540 //=================================================================================
541
542 void SMESHGUI_AddNodeOnSegmentOp::onOpenView()
543 {
544   if ( mySimulation ) {
545     mySimulation->SetVisibility(false);
546     SMESH::SetPointRepresentation(false);
547   }
548   else {
549     mySimulation = new SMESHGUI_MeshEditPreview(SMESH::GetViewWindow( mySMESHGUI ));
550   }
551 }
552
553 //=================================================================================
554 /*!
555  * \brief SLOT called when the viewer closed
556  */
557 //=================================================================================
558
559 void SMESHGUI_AddNodeOnSegmentOp::onCloseView()
560 {
561   delete mySimulation;
562   mySimulation = 0;
563 }
564
565 //================================================================================
566 /*!
567  * \brief SLOT called when the node ids are manually changed
568  */
569 //================================================================================
570
571 void SMESHGUI_AddNodeOnSegmentOp::onTextChange( const QString& /*theText*/ )
572 {
573   QString msg;
574   SMESH::smIdType node1= 0, node2 = 0;
575
576   if (( isValid( msg, node1, node2 )) ||
577       ( node1 && node2 )) // position only can be invalid
578   {
579     // highlight entered segment
580
581     Handle(SALOME_InteractiveObject) anIO = myMeshActor->getIO();
582     SALOME_ListIO aList;
583     aList.Append( anIO );
584     selectionMgr()->setSelectedObjects( aList, false );
585
586     SVTK_ListOfVtk newIndices = { node1, node2 };
587     selector()->AddOrRemoveCompositeIndex( anIO, newIndices, false );
588     SMESH::GetViewWindow(mySMESHGUI)->highlight( anIO, true, true );
589   }
590 }
591
592 //================================================================================
593 /*!
594  * \brief Activate Node selection
595  */
596 //================================================================================
597
598 void SMESHGUI_AddNodeOnSegmentOp::activateSelection()
599 {
600   selectionMgr()->clearFilters();
601   SMESH::SetPointRepresentation( false );
602   onSelTypeChange();
603 }
604
605 //================================================================================
606 /*!
607  * \brief Destructor
608  */
609 //================================================================================
610
611 SMESHGUI_AddNodeOnSegmentOp::~SMESHGUI_AddNodeOnSegmentOp()
612 {
613   if ( myDlg )        delete myDlg;
614   if ( mySimulation ) delete mySimulation;
615 }
616
617 //================================================================================
618 /*!
619  * \brief Gets dialog of this operation
620  * \retval LightApp_Dialog* - pointer to dialog of this operation
621  */
622 //================================================================================
623
624 LightApp_Dialog* SMESHGUI_AddNodeOnSegmentOp::dlg() const
625 {
626   return myDlg;
627 }
628
629 //================================================================================
630 /*
631 * \brief Process InteractiveSelectionChanged event
632 */
633 //================================================================================
634 void SMESHGUI_AddNodeOnSegmentOp::processStyleEvents(unsigned long theEvent, void* theCallData) 
635 {
636   (void*)theCallData;
637   QString msg;
638   SMESH::smIdType node1 = 0, node2 = 0;
639   if (isValid(msg, node1, node2)) {
640     if (theEvent == SVTK::InteractiveSelectionChanged) {
641       if (SMDS_Mesh* mesh = myMeshActor->GetObject()->GetMesh())
642         if(myRWInteractor && myRWInteractor->GetDevice() && myInteractorStyle) {
643         {
644           double N1[3];
645           double N2[3];
646           double pos;
647           double N1_SC[3];
648           double N2_SC[3];
649           double xyz[3];
650           double closest[3];
651
652           const SMDS_MeshNode* n1 = mesh->FindNode(node1);
653           const SMDS_MeshNode* n2 = mesh->FindNode(node2);
654           int xClick, yClick; // Last event (move or left button down) position
655           myRWInteractor->GetDevice()->GetEventPosition(xClick, yClick);
656
657           n1->GetXYZ(N1);
658           n2->GetXYZ(N2);
659           // Get 2D screen coordinates of each node
660           vtkInteractorObserver::ComputeWorldToDisplay(myRWInteractor->GetRenderer()->GetDevice(),
661             N1[0], N1[1], N1[2], N1_SC);
662           vtkInteractorObserver::ComputeWorldToDisplay(myRWInteractor->GetRenderer()->GetDevice(),
663             N2[0], N2[1], N2[2], N2_SC);
664           N1_SC[2] = N2_SC[2] = xyz[2] = 0;
665           xyz[0] = static_cast<double>(xClick);
666           xyz[1] = static_cast<double>(yClick);
667           // Parametric position of selected point on a line
668           vtkLine::DistanceToLine(xyz, N1_SC, N2_SC, pos, closest);
669           if (pos < 0)
670             pos = SPIN_TOLERANCE;
671           else if (pos > 1.0)
672             pos = 1.0 - SPIN_TOLERANCE;
673           myDlg->myPositionSpin->SetValue(pos);
674           redisplayPreview();
675         }
676       }
677     }
678   }
679 }
680
681 //================================================================================
682 /*
683 * \brief Process LeftButtonPressEvent event: activate interactive selection
684 */
685 //================================================================================
686 void SMESHGUI_AddNodeOnSegmentOp::processInteractorEvents(unsigned long theEvent, void* theCallData) 
687 {
688   (void*)theCallData;
689   if (theEvent == vtkCommand::LeftButtonPressEvent && myDlg->myPositionBtn->isChecked()) {
690     bool control = myRWInteractor->GetDevice()->GetControlKey();
691     bool shift = myRWInteractor->GetDevice()->GetControlKey();
692     SVTK_ViewWindow* svtkViewWindow = SMESH::GetViewWindow(mySMESHGUI);
693     if (svtkViewWindow  && !shift && ! control) {
694       QString msg;
695       SMESH::smIdType node1 = 0, node2 = 0;
696       if (isValid(msg, node1, node2)) {
697         svtkViewWindow->activateInteractiveSelection();
698       }
699     }
700   }
701 }