0029837: Visualization, Graphic3d_Camera - Fit All operation works incorrectly on...
[occt.git] / src / AIS / AIS_ViewController.cxx
1 // Copyright (c) 2016-2019 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 #include "AIS_ViewController.hxx"
15
16 #include <AIS_AnimationCamera.hxx>
17 #include <AIS_InteractiveContext.hxx>
18 #include <AIS_Manipulator.hxx>
19 #include <AIS_Point.hxx>
20 #include <AIS_RubberBand.hxx>
21 #include <Aspect_Grid.hxx>
22 #include <Geom_CartesianPoint.hxx>
23 #include <Message.hxx>
24 #include <Message_Messenger.hxx>
25 #include <gp_Quaternion.hxx>
26 #include <V3d_View.hxx>
27
28 // =======================================================================
29 // function : AIS_ViewController
30 // purpose  :
31 // =======================================================================
32 AIS_ViewController::AIS_ViewController()
33 : myLastEventsTime    (0.0),
34   myToAskNextFrame    (false),
35   myMinCamDistance    (1.0),
36   myRotationMode      (AIS_RotationMode_BndBoxActive),
37   myNavigationMode    (AIS_NavigationMode_Orbit),
38   myMouseAccel           (1.0f),
39   myOrbitAccel           (1.0f),
40   myToShowPanAnchorPoint (true),
41   myToShowRotateCenter   (true),
42   myToLockOrbitZUp       (false),
43   myToInvertPitch        (false),
44   myToAllowTouchZRotation(false),
45   myToAllowRotation      (true),
46   myToAllowPanning       (true),
47   myToAllowZooming       (true),
48   myToAllowZFocus        (true),
49   myToAllowHighlight     (true),
50   myToAllowDragging      (true),
51   myToStickToRayOnZoom   (true),
52   myToStickToRayOnRotation (true),
53   //
54   myWalkSpeedAbsolute (1.5f),
55   myWalkSpeedRelative (0.1f),
56   myThrustSpeed (0.0f),
57   myHasThrust (false),
58   //
59   myViewAnimation (new AIS_AnimationCamera ("AIS_ViewController_ViewAnimation", Handle(V3d_View)())),
60   myPrevMoveTo (-1, -1),
61   myHasHlrOnBeforeRotation (false),
62   //
63   myMouseClickThreshold (3.0),
64   myMouseDoubleClickInt (0.4),
65   myScrollZoomRatio     (15.0f),
66   myMouseActiveGesture  (AIS_MouseGesture_NONE),
67   myMouseActiveIdleRotation (false),
68   myMouseClickCounter   (0),
69   myMousePressed        (Aspect_VKeyMouse_NONE),
70   myMouseModifiers      (Aspect_VKeyFlags_NONE),
71   myMouseSingleButton   (-1),
72   //
73   myTouchToleranceScale      (1.0f),
74   myTouchRotationThresholdPx (6.0f),
75   myTouchZRotationThreshold  (float(2.0 * M_PI / 180.0)),
76   myTouchPanThresholdPx      (4.0f),
77   myTouchZoomThresholdPx     (6.0f),
78   myTouchZoomRatio           (0.13f),
79   //
80   myNbTouchesLast (0),
81   myUpdateStartPointPan  (true),
82   myUpdateStartPointRot  (true),
83   myUpdateStartPointZRot (true),
84   //
85   myPanPnt3d (Precision::Infinite(), 0.0, 0.0)
86 {
87   myEventTimer.Start();
88
89   myAnchorPointPrs1 = new AIS_Point (new Geom_CartesianPoint (0.0, 0.0, 0.0));
90   myAnchorPointPrs1->SetZLayer (Graphic3d_ZLayerId_Top);
91   myAnchorPointPrs1->SetMutable (true);
92
93   myAnchorPointPrs2 = new AIS_Point (new Geom_CartesianPoint (0.0, 0.0, 0.0));
94   myAnchorPointPrs2->SetZLayer (Graphic3d_ZLayerId_Topmost);
95   myAnchorPointPrs2->SetMutable (true);
96
97   myRubberBand = new AIS_RubberBand (Quantity_NOC_LIGHTBLUE, Aspect_TOL_SOLID, Quantity_NOC_LIGHTBLUE, 0.4, 1.0);
98   myRubberBand->SetZLayer (Graphic3d_ZLayerId_TopOSD);
99   myRubberBand->SetTransformPersistence (new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_UPPER));
100   myRubberBand->SetDisplayMode (0);
101   myRubberBand->SetMutable (true);
102
103   myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton,                           AIS_MouseGesture_RotateOrbit);
104   myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_CTRL,   AIS_MouseGesture_Zoom);
105   myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_SHIFT,  AIS_MouseGesture_Pan);
106   myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_ALT,    AIS_MouseGesture_SelectRectangle);
107
108   myMouseGestureMap.Bind (Aspect_VKeyMouse_RightButton,                          AIS_MouseGesture_Zoom);
109   myMouseGestureMap.Bind (Aspect_VKeyMouse_RightButton | Aspect_VKeyFlags_CTRL,  AIS_MouseGesture_RotateOrbit);
110
111   myMouseGestureMap.Bind (Aspect_VKeyMouse_MiddleButton,                         AIS_MouseGesture_Pan);
112   myMouseGestureMap.Bind (Aspect_VKeyMouse_MiddleButton | Aspect_VKeyFlags_CTRL, AIS_MouseGesture_Pan);
113 }
114
115 // =======================================================================
116 // function : ResetViewInput
117 // purpose  :
118 // =======================================================================
119 void AIS_ViewController::ResetViewInput()
120 {
121   myKeys.Reset();
122   myMousePressed      = Aspect_VKeyMouse_NONE;
123   myMouseModifiers    = Aspect_VKeyFlags_NONE;
124   myMouseSingleButton = -1;
125   myUI.Dragging.ToAbort = true;
126   myMouseActiveGesture = AIS_MouseGesture_NONE;
127   myMouseClickTimer.Stop();
128   myMouseClickCounter = 0;
129 }
130
131 // =======================================================================
132 // function : FlushViewEvents
133 // purpose  :
134 // =======================================================================
135 void AIS_ViewController::FlushViewEvents (const Handle(AIS_InteractiveContext)& theCtx,
136                                           const Handle(V3d_View)& theView,
137                                           Standard_Boolean theToHandle)
138 {
139   flushBuffers (theCtx, theView);
140   flushGestures(theCtx, theView);
141   if (theToHandle)
142   {
143     HandleViewEvents (theCtx, theView);
144   }
145 }
146
147 // =======================================================================
148 // function : flushBuffers
149 // purpose  :
150 // =======================================================================
151 void AIS_ViewController::flushBuffers (const Handle(AIS_InteractiveContext)& ,
152                                        const Handle(V3d_View)& )
153 {
154   myToAskNextFrame = false;
155
156   myGL.IsNewGesture = myUI.IsNewGesture;
157   myUI.IsNewGesture = false;
158
159   myGL.ZoomActions.Clear();
160   myGL.ZoomActions.Append (myUI.ZoomActions);
161   myUI.ZoomActions.Clear();
162
163   myGL.Orientation.ToFitAll = myUI.Orientation.ToFitAll;
164   myUI.Orientation.ToFitAll = false;
165   if (myUI.Orientation.ToSetViewOrient)
166   {
167     myUI.Orientation.ToSetViewOrient = false;
168     myGL.Orientation.ToSetViewOrient = true;
169     myGL.Orientation.ViewOrient      = myUI.Orientation.ViewOrient;
170   }
171
172   if (myUI.MoveTo.ToHilight)
173   {
174     myUI.MoveTo.ToHilight = false;
175     myGL.MoveTo.ToHilight = true;
176     myGL.MoveTo.Point     = myUI.MoveTo.Point;
177   }
178
179   {
180     myGL.Selection.Tool   = myUI.Selection.Tool;
181     myGL.Selection.IsXOR  = myUI.Selection.IsXOR;
182     myGL.Selection.Points = myUI.Selection.Points;
183     myUI.Selection.IsXOR  = false;
184     if (myUI.Selection.Tool == AIS_ViewSelectionTool_Picking)
185     {
186       myUI.Selection.Points.Clear();
187     }
188   }
189
190   if (myUI.Selection.ToApplyTool)
191   {
192     myGL.Selection.ToApplyTool = true;
193     myUI.Selection.ToApplyTool = false;
194     myUI.Selection.Points.Clear();
195   }
196
197   if (myUI.Panning.ToStart)
198   {
199     myUI.Panning.ToStart = false;
200     myGL.Panning.ToStart = true;
201     myGL.Panning.PointStart = myUI.Panning.PointStart;
202   }
203
204   if (myUI.Panning.ToPan)
205   {
206     myUI.Panning.ToPan = false;
207     myGL.Panning.ToPan = true;
208     myGL.Panning.Delta = myUI.Panning.Delta;
209   }
210
211   if (myUI.Dragging.ToAbort)
212   {
213     myUI.Dragging.ToAbort = false;
214     myGL.Dragging.ToAbort = true;
215   }
216   else if (myUI.Dragging.ToStop)
217   {
218     myUI.Dragging.ToStop = false;
219     myGL.Dragging.ToStop = true;
220   }
221   else if (myUI.Dragging.ToStart)
222   {
223     myUI.Dragging.ToStart = false;
224     myGL.Dragging.ToStart = true;
225     myGL.Dragging.PointStart = myUI.Dragging.PointStart;
226   }
227   myGL.Dragging.PointTo = myUI.Dragging.PointTo;
228
229   if (myUI.OrbitRotation.ToStart)
230   {
231     myUI.OrbitRotation.ToStart    = false;
232     myGL.OrbitRotation.ToStart    = true;
233     myGL.OrbitRotation.PointStart = myUI.OrbitRotation.PointStart;
234   }
235
236   if (myUI.OrbitRotation.ToRotate)
237   {
238     myUI.OrbitRotation.ToRotate = false;
239     myGL.OrbitRotation.ToRotate = true;
240     myGL.OrbitRotation.PointTo  = myUI.OrbitRotation.PointTo;
241   }
242
243   if (myUI.ViewRotation.ToStart)
244   {
245     myUI.ViewRotation.ToStart    = false;
246     myGL.ViewRotation.ToStart    = true;
247     myGL.ViewRotation.PointStart = myUI.ViewRotation.PointStart;
248   }
249
250   if (myUI.ViewRotation.ToRotate)
251   {
252     myUI.ViewRotation.ToRotate = false;
253     myGL.ViewRotation.ToRotate = true;
254     myGL.ViewRotation.PointTo  = myUI.ViewRotation.PointTo;
255   }
256
257   if (myUI.ZRotate.ToRotate)
258   {
259     myGL.ZRotate = myUI.ZRotate;
260     myUI.ZRotate.ToRotate = false;
261   }
262 }
263
264 // =======================================================================
265 // function : flushGestures
266 // purpose  :
267 // =======================================================================
268 void AIS_ViewController::flushGestures (const Handle(AIS_InteractiveContext)& ,
269                                         const Handle(V3d_View)& theView)
270 {
271   const Standard_Real    aTolScale = myTouchToleranceScale;
272   const Standard_Integer aTouchNb  = myTouchPoints.Extent();
273   if (myNbTouchesLast != aTouchNb)
274   {
275     myNbTouchesLast = aTouchNb;
276     myGL.IsNewGesture = true;
277   }
278   if (aTouchNb == 1) // touch
279   {
280     Aspect_Touch& aTouch = myTouchPoints.ChangeFromIndex (1);
281     if (myUpdateStartPointRot)
282     {
283       // skip rotation if have active dragged object
284       if (myNavigationMode == AIS_NavigationMode_Orbit)
285       {
286         myGL.OrbitRotation.ToStart = true;
287         myGL.OrbitRotation.PointStart = myStartRotCoord;
288       }
289       else
290       {
291         myGL.ViewRotation.ToStart = true;
292         myGL.ViewRotation.PointStart = myStartRotCoord;
293       }
294
295       myUpdateStartPointRot = false;
296       theView->Invalidate();
297     }
298
299     // rotation
300     const Standard_Real aRotTouchTol = !aTouch.IsPreciseDevice
301                                      ? aTolScale * myTouchRotationThresholdPx
302                                      : gp::Resolution();
303     if (Abs (aTouch.Delta().x()) + Abs(aTouch.Delta().y()) > aRotTouchTol)
304     {
305       const Standard_Real aRotAccel = myNavigationMode == AIS_NavigationMode_FirstPersonWalk ? myMouseAccel : myOrbitAccel;
306       if (myNavigationMode == AIS_NavigationMode_Orbit)
307       {
308         const Graphic3d_Vec2d aRotDelta = aTouch.To - myGL.OrbitRotation.PointStart;
309         myGL.OrbitRotation.ToRotate = true;
310         myGL.OrbitRotation.PointTo  = myGL.OrbitRotation.PointStart + aRotDelta * aRotAccel;
311         myGL.Dragging.PointTo.SetValues ((int )aTouch.To.x(), (int )aTouch.To.y());
312       }
313       else
314       {
315         const Graphic3d_Vec2d aRotDelta = aTouch.To - myGL.ViewRotation.PointStart;
316         myGL.ViewRotation.ToRotate = true;
317         myGL.ViewRotation.PointTo = myGL.ViewRotation.PointStart + aRotDelta * aRotAccel;
318         myGL.Dragging.PointTo.SetValues ((int )aTouch.To.x(), (int )aTouch.To.y());
319       }
320
321       aTouch.From = aTouch.To;
322     }
323   }
324   else if (aTouchNb == 2) // pinch
325   {
326     Aspect_Touch& aFirstTouch = myTouchPoints.ChangeFromIndex (1);
327     Aspect_Touch& aLastTouch  = myTouchPoints.ChangeFromIndex (2);
328     const Graphic3d_Vec2d aFrom[2] = { aFirstTouch.From, aLastTouch.From };
329     const Graphic3d_Vec2d aTo[2]   = { aFirstTouch.To,   aLastTouch.To   };
330
331     Graphic3d_Vec2d aPinchCenterStart ((aFrom[0].x() + aFrom[1].x()) / 2.0,
332                                        (aFrom[0].y() + aFrom[1].y()) / 2.0);
333
334     Standard_Real aPinchCenterXEnd = (aTo[0].x() + aTo[1].x()) / 2.0;
335     Standard_Real aPinchCenterYEnd = (aTo[0].y() + aTo[1].y()) / 2.0;
336
337     Standard_Real aPinchCenterXDev = aPinchCenterXEnd - aPinchCenterStart.x();
338     Standard_Real aPinchCenterYDev = aPinchCenterYEnd - aPinchCenterStart.y();
339
340     Standard_Real aStartSize = (aFrom[0] - aFrom[1]).Modulus();
341     Standard_Real anEndSize  = (  aTo[0] -   aTo[1]).Modulus();
342
343     Standard_Real aDeltaSize = anEndSize - aStartSize;
344
345     bool anIsClearDev = false;
346
347     if (myToAllowTouchZRotation)
348     {
349       Standard_Real A1 = aFrom[0].y() - aFrom[1].y();
350       Standard_Real B1 = aFrom[1].x() - aFrom[0].x();
351
352       Standard_Real A2 = aTo[0].y() - aTo[1].y();
353       Standard_Real B2 = aTo[1].x() - aTo[0].x();
354
355       Standard_Real aRotAngle = 0.0;
356
357       Standard_Real aDenomenator = A1*A2 + B1*B2;
358       if (aDenomenator <= Precision::Confusion())
359       {
360         aRotAngle = 0.0;
361       }
362       else
363       {
364         Standard_Real aNumerator = A1*B2 - A2*B1;
365         aRotAngle = ATan (aNumerator / aDenomenator);
366       }
367
368       if (Abs(aRotAngle) > Standard_Real(myTouchZRotationThreshold))
369       {
370         myGL.ZRotate.ToRotate = true;
371         myGL.ZRotate.Angle = aRotAngle;
372         anIsClearDev = true;
373       }
374     }
375
376     if (Abs(aDeltaSize) > aTolScale * myTouchZoomThresholdPx)
377     {
378       // zoom
379       aDeltaSize *= Standard_Real(myTouchZoomRatio);
380       Aspect_ScrollDelta aParams (Graphic3d_Vec2i (aPinchCenterStart), aDeltaSize);
381       myGL.ZoomActions.Append (aParams);
382       anIsClearDev = true;
383     }
384
385     const Standard_Real aPanTouchTol = !aFirstTouch.IsPreciseDevice
386                                      ? aTolScale * myTouchPanThresholdPx
387                                      : gp::Resolution();
388     if (Abs(aPinchCenterXDev) + Abs(aPinchCenterYDev) > aPanTouchTol)
389     {
390       // pan
391       if (myUpdateStartPointPan)
392       {
393         myGL.Panning.ToStart = true;
394         myGL.Panning.PointStart = Graphic3d_Vec2i (myStartPanCoord);
395         myUpdateStartPointPan = false;
396         theView->Invalidate();
397       }
398
399       myGL.Panning.ToPan = true;
400       myGL.Panning.Delta.x() = int( aPinchCenterXDev);
401       myGL.Panning.Delta.y() = int(-aPinchCenterYDev);
402       anIsClearDev = true;
403     }
404
405     if (anIsClearDev)
406     {
407       aFirstTouch.From = aFirstTouch.To;
408       aLastTouch .From = aLastTouch.To;
409     }
410   }
411 }
412
413 // =======================================================================
414 // function : UpdateViewOrientation
415 // purpose  :
416 // =======================================================================
417 void AIS_ViewController::UpdateViewOrientation (V3d_TypeOfOrientation theOrientation,
418                                                 bool theToFitAll)
419 {
420   myUI.Orientation.ToFitAll = theToFitAll;
421   myUI.Orientation.ToSetViewOrient = true;
422   myUI.Orientation.ViewOrient = theOrientation;
423 }
424
425 // =======================================================================
426 // function : SelectInViewer
427 // purpose  :
428 // =======================================================================
429 void AIS_ViewController::SelectInViewer (const Graphic3d_Vec2i& thePnt,
430                                          const bool theIsXOR)
431 {
432   if (myUI.Selection.Tool != AIS_ViewSelectionTool_Picking)
433   {
434     myUI.Selection.Tool = AIS_ViewSelectionTool_Picking;
435     myUI.Selection.Points.Clear();
436   }
437
438   myUI.Selection.IsXOR = theIsXOR;
439   myUI.Selection.Points.Append (thePnt);
440 }
441
442 // =======================================================================
443 // function : SelectInViewer
444 // purpose  :
445 // =======================================================================
446 void AIS_ViewController::SelectInViewer (const NCollection_Sequence<Graphic3d_Vec2i>& thePnts,
447                                          const bool theIsXOR)
448 {
449   myUI.Selection.IsXOR = theIsXOR;
450   myUI.Selection.Points = thePnts;
451   myUI.Selection.ToApplyTool = true;
452   if (thePnts.Length() == 1)
453   {
454     myUI.Selection.Tool = AIS_ViewSelectionTool_Picking;
455   }
456   else if (thePnts.Length() == 2)
457   {
458     myUI.Selection.Tool = AIS_ViewSelectionTool_RubberBand;
459   }
460   else
461   {
462     myUI.Selection.Tool = AIS_ViewSelectionTool_Polygon;
463   }
464 }
465
466 // =======================================================================
467 // function : UpdateRubberBand
468 // purpose  :
469 // =======================================================================
470 void AIS_ViewController::UpdateRubberBand (const Graphic3d_Vec2i& thePntFrom,
471                                            const Graphic3d_Vec2i& thePntTo,
472                                            const bool theIsXOR)
473 {
474   myUI.Selection.Tool = AIS_ViewSelectionTool_RubberBand;
475   myUI.Selection.IsXOR = theIsXOR;
476   myUI.Selection.Points.Clear();
477   myUI.Selection.Points.Append (thePntFrom);
478   myUI.Selection.Points.Append (thePntTo);
479 }
480
481 // =======================================================================
482 // function : UpdatePolySelection
483 // purpose  :
484 // =======================================================================
485 void AIS_ViewController::UpdatePolySelection (const Graphic3d_Vec2i& thePnt,
486                                               bool theToAppend)
487 {
488   if (myUI.Selection.Tool != AIS_ViewSelectionTool_Polygon)
489   {
490     myUI.Selection.Tool = AIS_ViewSelectionTool_Polygon;
491     myUI.Selection.Points.Clear();
492   }
493
494   if (myUI.Selection.Points.IsEmpty())
495   {
496     myUI.Selection.Points.Append (thePnt);
497   }
498   else if (theToAppend
499         && myUI.Selection.Points.Last() != thePnt)
500   {
501     myUI.Selection.Points.Append (thePnt);
502   }
503   else
504   {
505     myUI.Selection.Points.ChangeLast() = thePnt;
506   }
507 }
508
509 // =======================================================================
510 // function : UpdateZoom
511 // purpose  :
512 // =======================================================================
513 bool AIS_ViewController::UpdateZoom (const Aspect_ScrollDelta& theDelta)
514 {
515   if (!myUI.ZoomActions.IsEmpty())
516   {
517     if (myUI.ZoomActions.ChangeLast().Point == theDelta.Point)
518     {
519       myUI.ZoomActions.ChangeLast().Delta += theDelta.Delta;
520       return false;
521     }
522   }
523
524   myUI.ZoomActions.Append (theDelta);
525   return true;
526 }
527
528 // =======================================================================
529 // function : UpdateZRotation
530 // purpose  :
531 // =======================================================================
532 bool AIS_ViewController::UpdateZRotation (double theAngle)
533 {
534   if (!ToAllowTouchZRotation())
535   {
536     return false;
537   }
538
539   myUI.ZRotate.Angle = myUI.ZRotate.ToRotate
540                      ? myUI.ZRotate.Angle + theAngle
541                      : theAngle;
542   if (myUI.ZRotate.ToRotate)
543   {
544     return false;
545   }
546   myUI.ZRotate.ToRotate = true;
547   return true;
548 }
549
550 // =======================================================================
551 // function : UpdateMouseScroll
552 // purpose  :
553 // =======================================================================
554 bool AIS_ViewController::UpdateMouseScroll (const Aspect_ScrollDelta& theDelta)
555 {
556   Aspect_ScrollDelta aDelta = theDelta;
557   aDelta.Delta *= myScrollZoomRatio;
558   return UpdateZoom (aDelta);
559 }
560
561 // =======================================================================
562 // function : UpdateMouseClick
563 // purpose  :
564 // =======================================================================
565 bool AIS_ViewController::UpdateMouseClick (const Graphic3d_Vec2i& thePoint,
566                                            Aspect_VKeyMouse theButton,
567                                            Aspect_VKeyFlags theModifiers,
568                                            bool theIsDoubleClick)
569 {
570   (void )theIsDoubleClick;
571   if (theButton == Aspect_VKeyMouse_LeftButton)
572   {
573     SelectInViewer (thePoint, (theModifiers & Aspect_VKeyFlags_SHIFT) != 0);
574     return true;
575   }
576   return false;
577 }
578
579 // =======================================================================
580 // function : UpdateMouseButtons
581 // purpose  :
582 // =======================================================================
583 bool AIS_ViewController::UpdateMouseButtons (const Graphic3d_Vec2i& thePoint,
584                                              Aspect_VKeyMouse theButtons,
585                                              Aspect_VKeyFlags theModifiers,
586                                              bool theIsEmulated)
587 {
588   bool toUpdateView = false;
589   const double aTolClick = (theIsEmulated ? myTouchToleranceScale : 1.0) * myMouseClickThreshold;
590   if (theButtons == Aspect_VKeyMouse_NONE
591    && myMouseSingleButton > 0)
592   {
593     const Graphic3d_Vec2i aDelta = thePoint - myMousePressPoint;
594     if (double(aDelta.cwiseAbs().maxComp()) < aTolClick)
595     {
596       ++myMouseClickCounter;
597       const bool isDoubleClick = myMouseClickCounter == 2
598                               && myMouseClickTimer.IsStarted()
599                               && myMouseClickTimer.ElapsedTime() <= myMouseDoubleClickInt;
600
601       myMouseClickTimer.Stop();
602       myMouseClickTimer.Reset();
603       myMouseClickTimer.Start();
604       if (isDoubleClick)
605       {
606         myMouseClickCounter = 0;
607       }
608       toUpdateView = UpdateMouseClick (thePoint, (Aspect_VKeyMouse )myMouseSingleButton, theModifiers, isDoubleClick) || toUpdateView;
609     }
610     else
611     {
612       myMouseClickTimer.Stop();
613       myMouseClickCounter = 0;
614       myUI.Dragging.ToStop = true;
615       toUpdateView = true;
616     }
617     myMouseSingleButton = -1;
618   }
619   else if (theButtons == Aspect_VKeyMouse_NONE)
620   {
621     myMouseSingleButton = -1;
622   }
623   else if (myMouseSingleButton == -1)
624   {
625     if ((theButtons & Aspect_VKeyMouse_LeftButton) == Aspect_VKeyMouse_LeftButton)
626     {
627       myMouseSingleButton = Aspect_VKeyMouse_LeftButton;
628     }
629     else if ((theButtons & Aspect_VKeyMouse_RightButton) == Aspect_VKeyMouse_RightButton)
630     {
631       myMouseSingleButton = Aspect_VKeyMouse_RightButton;
632     }
633     else if ((theButtons & Aspect_VKeyMouse_MiddleButton) == Aspect_VKeyMouse_MiddleButton)
634     {
635       myMouseSingleButton = Aspect_VKeyMouse_MiddleButton;
636     }
637     else
638     {
639       myMouseSingleButton = 0;
640     }
641     if (myMouseSingleButton != 0)
642     {
643       if (myMouseClickCounter == 1)
644       {
645         const Graphic3d_Vec2i aDelta = thePoint - myMousePressPoint;
646         if (double(aDelta.cwiseAbs().maxComp()) >= aTolClick)
647         {
648           myMouseClickTimer.Stop();
649           myMouseClickCounter = 0;
650         }
651       }
652       myMousePressPoint = thePoint;
653     }
654   }
655   else
656   {
657     myMouseSingleButton = 0;
658
659     myUI.Dragging.ToAbort = true;
660     toUpdateView = true;
661   }
662
663   const AIS_MouseGesture aPrevGesture = myMouseActiveGesture;
664   myMouseModifiers = theModifiers;
665   myMousePressed   = theButtons;
666   if (theIsEmulated
667    || myNavigationMode != AIS_NavigationMode_FirstPersonWalk)
668   {
669     myMouseActiveIdleRotation = false;
670     myMouseActiveGesture = AIS_MouseGesture_NONE;
671     if (theButtons != 0)
672     {
673       myMousePressPoint    = thePoint;
674       myMouseProgressPoint = myMousePressPoint;
675     }
676
677     if (myMouseGestureMap.Find (theButtons | theModifiers, myMouseActiveGesture))
678     {
679       switch (myMouseActiveGesture)
680       {
681         case AIS_MouseGesture_RotateView:
682         case AIS_MouseGesture_RotateOrbit:
683         {
684           if (myToAllowRotation)
685           {
686             myUpdateStartPointRot = true;
687           }
688           else
689           {
690             myMouseActiveGesture = AIS_MouseGesture_NONE;
691           }
692           break;
693         }
694         case AIS_MouseGesture_Pan:
695         {
696           if (myToAllowPanning)
697           {
698             myUpdateStartPointPan = true;
699           }
700           else
701           {
702             myMouseActiveGesture = AIS_MouseGesture_NONE;
703           }
704           break;
705         }
706         case AIS_MouseGesture_Zoom:
707         {
708           if (!myToAllowZooming)
709           {
710             myMouseActiveGesture = AIS_MouseGesture_NONE;
711           }
712           break;
713         }
714         case AIS_MouseGesture_SelectRectangle:
715         {
716           break;
717         }
718         case AIS_MouseGesture_SelectLasso:
719         {
720           UpdatePolySelection (thePoint, true);
721           break;
722         }
723         case AIS_MouseGesture_NONE:
724         {
725           break;
726         }
727       }
728     }
729
730     if (theButtons == Aspect_VKeyMouse_LeftButton
731      && theModifiers == Aspect_VKeyFlags_NONE
732      && myToAllowDragging)
733     {
734       myUI.Dragging.ToStart = true;
735       myUI.Dragging.PointStart = thePoint;
736     }
737   }
738
739   if (aPrevGesture != myMouseActiveGesture)
740   {
741     if (aPrevGesture == AIS_MouseGesture_SelectRectangle
742      || aPrevGesture == AIS_MouseGesture_SelectLasso)
743     {
744       myUI.Selection.ToApplyTool = true;
745     }
746
747     myUI.IsNewGesture = true;
748     toUpdateView = true;
749   }
750   return toUpdateView;
751 }
752
753 // =======================================================================
754 // function : UpdateMousePosition
755 // purpose  :
756 // =======================================================================
757 bool AIS_ViewController::UpdateMousePosition (const Graphic3d_Vec2i& thePoint,
758                                               Aspect_VKeyMouse theButtons,
759                                               Aspect_VKeyFlags theModifiers,
760                                               bool theIsEmulated)
761 {
762   myMousePositionLast = thePoint;
763   if (myMouseSingleButton > 0)
764   {
765     const double aTolClick = (theIsEmulated ? myTouchToleranceScale : 1.0) * myMouseClickThreshold;
766     const Graphic3d_Vec2i aPressDelta = thePoint - myMousePressPoint;
767     if (double(aPressDelta.cwiseAbs().maxComp()) >= aTolClick)
768     {
769       myMouseClickTimer.Stop();
770       myMouseClickCounter = 0;
771       myMouseSingleButton = -1;
772     }
773   }
774
775   bool toUpdateView = false;
776   Graphic3d_Vec2i aDelta = thePoint - myMouseProgressPoint;
777   if (!theIsEmulated
778     && myNavigationMode == AIS_NavigationMode_FirstPersonWalk)
779   {
780     if (!myMouseActiveIdleRotation
781       || myMouseActiveGesture != AIS_MouseGesture_RotateView)
782     {
783       myMouseActiveIdleRotation = true;
784       myMouseActiveGesture = AIS_MouseGesture_RotateView;
785       myMousePressPoint     = thePoint;
786       myMouseProgressPoint  = thePoint;
787       myUpdateStartPointRot = false;
788       myUI.ViewRotation.ToStart = true;
789       myUI.ViewRotation.PointStart.SetValues (thePoint.x(), thePoint.y());
790       myUI.ViewRotation.ToRotate = false;
791       aDelta.SetValues (0, 0);
792     }
793   }
794   else
795   {
796     if (myMouseActiveIdleRotation
797      && myMouseActiveGesture == AIS_MouseGesture_RotateView)
798     {
799       myMouseActiveGesture = AIS_MouseGesture_NONE;
800     }
801     myMouseActiveIdleRotation = false;
802   }
803
804   if (myMouseModifiers != theModifiers
805    && UpdateMouseButtons (thePoint, theButtons, theModifiers, theIsEmulated))
806   {
807     toUpdateView = true;
808   }
809
810   switch (myMouseActiveGesture)
811   {
812     case AIS_MouseGesture_SelectRectangle:
813     {
814       UpdateRubberBand (myMousePressPoint, thePoint);
815       toUpdateView = true;
816       break;
817     }
818     case AIS_MouseGesture_SelectLasso:
819     {
820       UpdatePolySelection (thePoint, true);
821       toUpdateView = true;
822       break;
823     }
824     case AIS_MouseGesture_RotateOrbit:
825     case AIS_MouseGesture_RotateView:
826     {
827       if (!myToAllowRotation)
828       {
829         break;
830       }
831       if (myUpdateStartPointRot)
832       {
833         if (myMouseActiveGesture == AIS_MouseGesture_RotateOrbit)
834         {
835           myUI.OrbitRotation.ToStart = true;
836           myUI.OrbitRotation.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y());
837         }
838         else
839         {
840           myUI.ViewRotation.ToStart = true;
841           myUI.ViewRotation.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y());
842         }
843         myUpdateStartPointRot = false;
844       }
845
846       const double aRotTol = theIsEmulated
847                            ? double(myTouchToleranceScale) * myTouchRotationThresholdPx
848                            : 0.0;
849       if (double (Abs (aDelta.x()) + Abs (aDelta.y())) > aRotTol)
850       {
851         const double aRotAccel = myNavigationMode == AIS_NavigationMode_FirstPersonWalk ? myMouseAccel : myOrbitAccel;
852         const Graphic3d_Vec2i aRotDelta = thePoint - myMousePressPoint;
853         if (myMouseActiveGesture == AIS_MouseGesture_RotateOrbit)
854         {
855           myUI.OrbitRotation.ToRotate = true;
856           myUI.OrbitRotation.PointTo = Graphic3d_Vec2d (myMousePressPoint.x(), myMousePressPoint.y())
857                                      + Graphic3d_Vec2d (aRotDelta.x(), aRotDelta.y()) * aRotAccel;
858         }
859         else
860         {
861           myUI.ViewRotation.ToRotate = true;
862           myUI.ViewRotation.PointTo = Graphic3d_Vec2d (myMousePressPoint.x(), myMousePressPoint.y())
863                                     + Graphic3d_Vec2d (aRotDelta.x(), aRotDelta.y()) * aRotAccel;
864         }
865         myUI.Dragging.PointTo = thePoint;
866
867         myMouseProgressPoint = thePoint;
868         toUpdateView = true;
869       }
870       break;
871     }
872     case AIS_MouseGesture_Zoom:
873     {
874       if (!myToAllowZooming)
875       {
876         break;
877       }
878       const double aZoomTol = theIsEmulated
879                             ? double(myTouchToleranceScale) * myTouchZoomThresholdPx
880                             : 0.0;
881       if (double (Abs (aDelta.x())) > aZoomTol)
882       {
883         if (UpdateZoom (Aspect_ScrollDelta (aDelta.x())))
884         {
885           toUpdateView = true;
886         }
887         myMouseProgressPoint = thePoint;
888       }
889       break;
890     }
891     case AIS_MouseGesture_Pan:
892     {
893       if (!myToAllowPanning)
894       {
895         break;
896       }
897       const double aPanTol = theIsEmulated
898                            ? double(myTouchToleranceScale) * myTouchPanThresholdPx
899                            : 0.0;
900       if (double (Abs (aDelta.x()) + Abs (aDelta.y())) > aPanTol)
901       {
902         if (myUpdateStartPointPan)
903         {
904           myUI.Panning.ToStart = true;
905           myUI.Panning.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y());
906           myUpdateStartPointPan = false;
907         }
908
909         aDelta.y() = -aDelta.y();
910         myMouseProgressPoint = thePoint;
911         if (myUI.Panning.ToPan)
912         {
913           myUI.Panning.Delta += aDelta;
914         }
915         else
916         {
917           myUI.Panning.ToPan = true;
918           myUI.Panning.Delta = aDelta;
919         }
920         toUpdateView = true;
921       }
922       break;
923     }
924     default:
925     {
926       break;
927     }
928   }
929
930   if (theButtons == Aspect_VKeyMouse_NONE
931   &&  myNavigationMode != AIS_NavigationMode_FirstPersonWalk
932   && !theIsEmulated
933   && !HasTouchPoints()
934   &&  myToAllowHighlight)
935   {
936     myUI.MoveTo.ToHilight = true;
937     myUI.MoveTo.Point = thePoint;
938     toUpdateView = true;
939   }
940   return toUpdateView;
941 }
942
943 // =======================================================================
944 // function : AddTouchPoint
945 // purpose  :
946 // =======================================================================
947 void AIS_ViewController::AddTouchPoint (Standard_Size theId,
948                                         const Graphic3d_Vec2d& thePnt,
949                                         Standard_Boolean theClearBefore)
950 {
951   myUI.MoveTo.ToHilight = false;
952   if (theClearBefore)
953   {
954     RemoveTouchPoint ((Standard_Size )-1);
955   }
956
957   myTouchPoints.Add (theId, Aspect_Touch (thePnt, false));
958   if (myTouchPoints.Extent() == 1)
959   {
960     myUpdateStartPointRot = true;
961     myStartRotCoord = thePnt;
962     if (myToAllowDragging)
963     {
964       myUI.Dragging.ToStart = true;
965       myUI.Dragging.PointStart.SetValues ((int )thePnt.x(), (int )thePnt.y());
966     }
967   }
968   else if (myTouchPoints.Extent() == 2)
969   {
970     myUI.Dragging.ToAbort = true;
971
972     myUpdateStartPointPan = true;
973     myStartPanCoord = thePnt;
974   }
975   myUI.IsNewGesture = true;
976 }
977
978 // =======================================================================
979 // function : RemoveTouchPoint
980 // purpose  :
981 // =======================================================================
982 bool AIS_ViewController::RemoveTouchPoint (Standard_Size theId,
983                                            Standard_Boolean theClearSelectPnts)
984 {
985   if (theId == (Standard_Size )-1)
986   {
987     myTouchPoints.Clear (false);
988   }
989   else
990   {
991     const Standard_Integer anOldExtent = myTouchPoints.Extent();
992     myTouchPoints.RemoveKey (theId);
993     if (myTouchPoints.Extent() == anOldExtent)
994     {
995       return false;
996     }
997   }
998
999   if (myTouchPoints.Extent() == 1)
1000   {
1001     // avoid incorrect transition from pinch to one finger
1002     Aspect_Touch& aFirstTouch = myTouchPoints.ChangeFromIndex (1);
1003     aFirstTouch.To = aFirstTouch.From;
1004
1005     myStartRotCoord = aFirstTouch.To;
1006     myUpdateStartPointRot = true;
1007   }
1008   else if (myTouchPoints.Extent() == 2)
1009   {
1010     myStartPanCoord = myTouchPoints.FindFromIndex (1).To;
1011     myUpdateStartPointPan = true;
1012   }
1013   else if (myTouchPoints.IsEmpty())
1014   {
1015     if (theClearSelectPnts)
1016     {
1017       myUI.Selection.ToApplyTool = true;
1018     }
1019
1020     myUI.Dragging.ToStop = true;
1021   }
1022   myUI.IsNewGesture = true;
1023   return true;
1024 }
1025
1026 // =======================================================================
1027 // function : UpdateTouchPoint
1028 // purpose  :
1029 // =======================================================================
1030 void AIS_ViewController::UpdateTouchPoint (Standard_Size theId,
1031                                            const Graphic3d_Vec2d& thePnt)
1032 {
1033   if (Aspect_Touch* aTouch = myTouchPoints.ChangeSeek (theId))
1034   {
1035     aTouch->To = thePnt;
1036   }
1037   else
1038   {
1039     AddTouchPoint (theId, thePnt);
1040   }
1041 }
1042
1043 // =======================================================================
1044 // function : SetNavigationMode
1045 // purpose  :
1046 // =======================================================================
1047 void AIS_ViewController::SetNavigationMode (AIS_NavigationMode theMode)
1048 {
1049   myNavigationMode = theMode;
1050
1051   // abort rotation
1052   myUI.OrbitRotation.ToStart  = false;
1053   myUI.OrbitRotation.ToRotate = false;
1054   myUI.ViewRotation.ToStart   = false;
1055   myUI.ViewRotation.ToRotate  = false;
1056 }
1057
1058 // =======================================================================
1059 // function : KeyDown
1060 // purpose  :
1061 // =======================================================================
1062 void AIS_ViewController::KeyDown (Aspect_VKey theKey,
1063                                   double theTime,
1064                                   double thePressure)
1065 {
1066   myKeys.KeyDown (theKey, theTime, thePressure);
1067 }
1068
1069 // =======================================================================
1070 // function : KeyUp
1071 // purpose  :
1072 // =======================================================================
1073 void AIS_ViewController::KeyUp (Aspect_VKey theKey,
1074                                 double theTime)
1075 {
1076   myKeys.KeyUp (theKey, theTime);
1077 }
1078
1079 // =======================================================================
1080 // function : KeyFromAxis
1081 // purpose  :
1082 // =======================================================================
1083 void AIS_ViewController::KeyFromAxis (Aspect_VKey theNegative,
1084                                       Aspect_VKey thePositive,
1085                                       double theTime,
1086                                       double thePressure)
1087 {
1088   myKeys.KeyFromAxis (theNegative, thePositive, theTime, thePressure);
1089 }
1090
1091 // =======================================================================
1092 // function : FetchNavigationKeys
1093 // purpose  :
1094 // =======================================================================
1095 AIS_WalkDelta AIS_ViewController::FetchNavigationKeys (Standard_Real theCrouchRatio,
1096                                                        Standard_Real theRunRatio)
1097 {
1098   AIS_WalkDelta aWalk;
1099
1100   // navigation keys
1101   double aPrevEventTime = 0.0, aNewEventTime = 0.0;
1102   updateEventsTime (aPrevEventTime, aNewEventTime);
1103
1104   double aDuration = 0.0, aPressure = 1.0;
1105   if (Abs (myThrustSpeed) > gp::Resolution())
1106   {
1107     if (myHasThrust)
1108     {
1109       aWalk[AIS_WalkTranslation_Forward].Value = myThrustSpeed * (aNewEventTime - aPrevEventTime);
1110     }
1111     myHasThrust = true;
1112     myToAskNextFrame = true;
1113   }
1114   else
1115   {
1116     myHasThrust = false;
1117   }
1118
1119   aWalk.SetRunning (theRunRatio > 1.0
1120                  && myKeys.IsKeyDown (Aspect_VKey_Shift));
1121   if (myKeys.HoldDuration (Aspect_VKey_NavJump, aNewEventTime, aDuration))
1122   {
1123     myKeys.KeyUp (Aspect_VKey_NavJump, aNewEventTime);
1124     aWalk.SetJumping (true);
1125   }
1126   if (!aWalk.IsJumping()
1127    && theCrouchRatio < 1.0
1128    && myKeys.HoldDuration (Aspect_VKey_NavCrouch, aNewEventTime, aDuration))
1129   {
1130     aWalk.SetRunning (false);
1131     aWalk.SetCrouching (true);
1132   }
1133
1134   const double aMaxDuration = aNewEventTime - aPrevEventTime;
1135   const double aRunRatio = aWalk.IsRunning()
1136                          ? theRunRatio
1137                          : aWalk.IsCrouching()
1138                           ? theCrouchRatio
1139                           : 1.0;
1140   if (myKeys.HoldDuration (Aspect_VKey_NavForward, aNewEventTime, aDuration, aPressure))
1141   {
1142     double aProgress = Abs (Min (aMaxDuration, aDuration));
1143     aProgress *= aRunRatio;
1144     aWalk[AIS_WalkTranslation_Forward].Value += aProgress;
1145     aWalk[AIS_WalkTranslation_Forward].Pressure = aPressure;
1146     aWalk[AIS_WalkTranslation_Forward].Duration = aDuration;
1147   }
1148   if (myKeys.HoldDuration (Aspect_VKey_NavBackward, aNewEventTime, aDuration, aPressure))
1149   {
1150     double aProgress = Abs (Min (aMaxDuration, aDuration));
1151     aProgress *= aRunRatio;
1152     aWalk[AIS_WalkTranslation_Forward].Value += -aProgress;
1153     aWalk[AIS_WalkTranslation_Forward].Pressure = aPressure;
1154     aWalk[AIS_WalkTranslation_Forward].Duration = aDuration;
1155   }
1156   if (myKeys.HoldDuration (Aspect_VKey_NavSlideLeft, aNewEventTime, aDuration, aPressure))
1157   {
1158     double aProgress = Abs (Min (aMaxDuration, aDuration));
1159     aProgress *= aRunRatio;
1160     aWalk[AIS_WalkTranslation_Side].Value = -aProgress;
1161     aWalk[AIS_WalkTranslation_Side].Pressure = aPressure;
1162     aWalk[AIS_WalkTranslation_Side].Duration = aDuration;
1163   }
1164   if (myKeys.HoldDuration (Aspect_VKey_NavSlideRight, aNewEventTime, aDuration, aPressure))
1165   {
1166     double aProgress = Abs (Min (aMaxDuration, aDuration));
1167     aProgress *= aRunRatio;
1168     aWalk[AIS_WalkTranslation_Side].Value = aProgress;
1169     aWalk[AIS_WalkTranslation_Side].Pressure = aPressure;
1170     aWalk[AIS_WalkTranslation_Side].Duration = aDuration;
1171   }
1172   if (myKeys.HoldDuration (Aspect_VKey_NavLookLeft, aNewEventTime, aDuration, aPressure))
1173   {
1174     double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1175     aWalk[AIS_WalkRotation_Yaw].Value = aProgress;
1176     aWalk[AIS_WalkRotation_Yaw].Pressure = aPressure;
1177     aWalk[AIS_WalkRotation_Yaw].Duration = aDuration;
1178   }
1179   if (myKeys.HoldDuration (Aspect_VKey_NavLookRight, aNewEventTime, aDuration, aPressure))
1180   {
1181     double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1182     aWalk[AIS_WalkRotation_Yaw].Value = -aProgress;
1183     aWalk[AIS_WalkRotation_Yaw].Pressure = aPressure;
1184     aWalk[AIS_WalkRotation_Yaw].Duration = aDuration;
1185   }
1186   if (myKeys.HoldDuration (Aspect_VKey_NavLookUp, aNewEventTime, aDuration, aPressure))
1187   {
1188     double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1189     aWalk[AIS_WalkRotation_Pitch].Value = !myToInvertPitch ? -aProgress : aProgress;
1190     aWalk[AIS_WalkRotation_Pitch].Pressure = aPressure;
1191     aWalk[AIS_WalkRotation_Pitch].Duration = aDuration;
1192   }
1193   if (myKeys.HoldDuration (Aspect_VKey_NavLookDown, aNewEventTime, aDuration, aPressure))
1194   {
1195     double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1196     aWalk[AIS_WalkRotation_Pitch].Value = !myToInvertPitch ? aProgress : -aProgress;
1197     aWalk[AIS_WalkRotation_Pitch].Pressure = aPressure;
1198     aWalk[AIS_WalkRotation_Pitch].Duration = aDuration;
1199   }
1200   if (myKeys.HoldDuration (Aspect_VKey_NavRollCCW, aNewEventTime, aDuration, aPressure))
1201   {
1202     double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1203     aWalk[AIS_WalkRotation_Roll].Value = -aProgress;
1204     aWalk[AIS_WalkRotation_Roll].Pressure = aPressure;
1205     aWalk[AIS_WalkRotation_Roll].Duration = aDuration;
1206   }
1207   if (myKeys.HoldDuration (Aspect_VKey_NavRollCW, aNewEventTime, aDuration, aPressure))
1208   {
1209     double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1210     aWalk[AIS_WalkRotation_Roll].Value = aProgress;
1211     aWalk[AIS_WalkRotation_Roll].Pressure = aPressure;
1212     aWalk[AIS_WalkRotation_Roll].Duration = aDuration;
1213   }
1214   if (myKeys.HoldDuration (Aspect_VKey_NavSlideUp, aNewEventTime, aDuration, aPressure))
1215   {
1216     double aProgress = Abs (Min (aMaxDuration, aDuration));
1217     aWalk[AIS_WalkTranslation_Up].Value = aProgress;
1218     aWalk[AIS_WalkTranslation_Up].Pressure = aPressure;
1219     aWalk[AIS_WalkTranslation_Up].Duration = aDuration;
1220   }
1221   if (myKeys.HoldDuration (Aspect_VKey_NavSlideDown, aNewEventTime, aDuration, aPressure))
1222   {
1223     double aProgress = Abs (Min (aMaxDuration, aDuration));
1224     aWalk[AIS_WalkTranslation_Up].Value = -aProgress;
1225     aWalk[AIS_WalkTranslation_Up].Pressure = aPressure;
1226     aWalk[AIS_WalkTranslation_Up].Duration = aDuration;
1227   }
1228   return aWalk;
1229 }
1230
1231 // =======================================================================
1232 // function : AbortViewAnimation
1233 // purpose  :
1234 // =======================================================================
1235 void AIS_ViewController::AbortViewAnimation()
1236 {
1237   if (!myViewAnimation.IsNull()
1238    && !myViewAnimation->IsStopped())
1239   {
1240     myViewAnimation->Stop();
1241     myViewAnimation->SetView (Handle(V3d_View)());
1242   }
1243 }
1244
1245 // =======================================================================
1246 // function : handlePanning
1247 // purpose  :
1248 // =======================================================================
1249 void AIS_ViewController::handlePanning (const Handle(V3d_View)& theView)
1250 {
1251   if (!myGL.Panning.ToPan
1252    || !myToAllowPanning)
1253   {
1254     return;
1255   }
1256
1257   AbortViewAnimation();
1258
1259   const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1260   if (aCam->IsOrthographic()
1261   || !hasPanningAnchorPoint())
1262   {
1263     theView->Pan (myGL.Panning.Delta.x(), myGL.Panning.Delta.y());
1264     theView->Invalidate();
1265     return;
1266   }
1267
1268   Graphic3d_Vec2i aWinSize;
1269   theView->Window()->Size (aWinSize.x(), aWinSize.y());
1270
1271   const gp_Dir& aDir = aCam->Direction();
1272   const gp_Ax3 aCameraCS (aCam->Center(), aDir.Reversed(), aDir ^ aCam->Up());
1273   const gp_XYZ anEyeToPnt = myPanPnt3d.XYZ() - aCam->Eye().XYZ();
1274   const gp_Pnt aViewDims = aCam->ViewDimensions (anEyeToPnt.Dot (aCam->Direction().XYZ())); // view dimensions at 3D point
1275   const Graphic3d_Vec2d aDxy (-aViewDims.X() * myGL.Panning.Delta.x() / double(aWinSize.x()),
1276                               -aViewDims.X() * myGL.Panning.Delta.y() / double(aWinSize.x()));
1277
1278   //theView->Translate (aCam, aDxy.x(), aDxy.y());
1279   gp_Trsf aPanTrsf;
1280   const gp_Vec aCameraPan = gp_Vec (aCameraCS.XDirection()) * aDxy.x()
1281                           + gp_Vec (aCameraCS.YDirection()) * aDxy.y();
1282   aPanTrsf.SetTranslation (aCameraPan);
1283   aCam->Transform (aPanTrsf);
1284   theView->Invalidate();
1285 }
1286
1287 // =======================================================================
1288 // function : handleZRotate
1289 // purpose  :
1290 // =======================================================================
1291 void AIS_ViewController::handleZRotate (const Handle(V3d_View)& theView)
1292 {
1293   if (!myGL.ZRotate.ToRotate
1294    || !myToAllowRotation)
1295   {
1296     return;
1297   }
1298
1299   AbortViewAnimation();
1300
1301   Graphic3d_Vec2i aViewPort;
1302   theView->Window()->Size (aViewPort.x(), aViewPort.y());
1303   Graphic3d_Vec2d aRotPnt (0.99 * aViewPort.x(),
1304                            0.5  * aViewPort.y());
1305   theView->StartRotation (int(aRotPnt.x()), int(aRotPnt.y()), 0.4);
1306   aRotPnt.y() += myGL.ZRotate.Angle * aViewPort.y();
1307   theView->Rotation (int(aRotPnt.x()), int(aRotPnt.y()));
1308   theView->Invalidate();
1309 }
1310
1311 // =======================================================================
1312 // function : handleZoom
1313 // purpose  :
1314 // =======================================================================
1315 void AIS_ViewController::handleZoom (const Handle(V3d_View)& theView,
1316                                      const Aspect_ScrollDelta& theParams,
1317                                      const gp_Pnt* thePnt)
1318 {
1319   if (!myToAllowZooming)
1320   {
1321     return;
1322   }
1323
1324   AbortViewAnimation();
1325
1326   const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1327   if (thePnt != NULL)
1328   {
1329     const double aViewDist = Max (myMinCamDistance, (thePnt->XYZ() - aCam->Eye().XYZ()).Modulus());
1330     aCam->SetCenter (aCam->Eye().XYZ() + aCam->Direction().XYZ() * aViewDist);
1331   }
1332
1333   if (!theParams.HasPoint())
1334   {
1335     Standard_Real aCoeff = Abs(theParams.Delta) / 100.0 + 1.0;
1336     aCoeff = theParams.Delta > 0.0 ? aCoeff : 1.0 / aCoeff;
1337     theView->SetZoom (aCoeff, true);
1338     theView->Invalidate();
1339     return;
1340   }
1341
1342   // integer delta is too rough for small smooth increments
1343   //theView->StartZoomAtPoint (theParams.Point.x(), theParams.Point.y());
1344   //theView->ZoomAtPoint (0, 0, (int )theParams.Delta, (int )theParams.Delta);
1345
1346   double aDZoom = Abs (theParams.Delta) / 100.0 + 1.0;
1347   aDZoom = (theParams.Delta > 0.0) ? aDZoom : 1.0 / aDZoom;
1348   if (aDZoom <= 0.0)
1349   {
1350     return;
1351   }
1352
1353   const Graphic3d_Vec2d aViewDims (aCam->ViewDimensions().X(), aCam->ViewDimensions().Y());
1354
1355   // ensure that zoom will not be too small or too big
1356   double aCoef = aDZoom;
1357   if (aViewDims.x() < aCoef * Precision::Confusion())
1358   {
1359     aCoef = aViewDims.x() / Precision::Confusion();
1360   }
1361   else if (aViewDims.x() > aCoef * 1e12)
1362   {
1363     aCoef = aViewDims.x() / 1e12;
1364   }
1365   if (aViewDims.y() < aCoef * Precision::Confusion())
1366   {
1367     aCoef = aViewDims.y() / Precision::Confusion();
1368   }
1369   else if (aViewDims.y() > aCoef * 1e12)
1370   {
1371     aCoef = aViewDims.y() / 1e12;
1372   }
1373
1374   Graphic3d_Vec2d aZoomAtPointXYv (0.0, 0.0);
1375   theView->Convert (theParams.Point.x(), theParams.Point.y(),
1376                     aZoomAtPointXYv.x(), aZoomAtPointXYv.y());
1377   Graphic3d_Vec2d aDxy = aZoomAtPointXYv / aCoef;
1378   aCam->SetScale (aCam->Scale() / aCoef);
1379
1380   const gp_Dir& aDir = aCam->Direction();
1381   const gp_Ax3 aCameraCS (aCam->Center(), aDir.Reversed(), aDir ^ aCam->Up());
1382
1383   // pan back to the point
1384   aDxy = aZoomAtPointXYv - aDxy;
1385   if (thePnt != NULL)
1386   {
1387     // zoom at 3D point with perspective projection
1388     const gp_XYZ anEyeToPnt = thePnt->XYZ() - aCam->Eye().XYZ();
1389     aDxy.SetValues (anEyeToPnt.Dot (aCameraCS.XDirection().XYZ()),
1390                     anEyeToPnt.Dot (aCameraCS.YDirection().XYZ()));
1391
1392     // view dimensions at 3D point
1393     const gp_Pnt aViewDims1 = aCam->ViewDimensions (anEyeToPnt.Dot (aCam->Direction().XYZ()));
1394
1395     Graphic3d_Vec2i aWinSize;
1396     theView->Window()->Size (aWinSize.x(), aWinSize.y());
1397     const Graphic3d_Vec2d aPanFromCenterPx (double(theParams.Point.x()) - 0.5 * double(aWinSize.x()),
1398                                             double(aWinSize.y() - theParams.Point.y() - 1) - 0.5 * double(aWinSize.y()));
1399     aDxy.x() += -aViewDims1.X() * aPanFromCenterPx.x() / double(aWinSize.x());
1400     aDxy.y() += -aViewDims1.Y() * aPanFromCenterPx.y() / double(aWinSize.y());
1401   }
1402
1403   //theView->Translate (aCam, aDxy.x(), aDxy.y());
1404   gp_Trsf aPanTrsf;
1405   const gp_Vec aCameraPan = gp_Vec (aCameraCS.XDirection()) * aDxy.x()
1406                           + gp_Vec (aCameraCS.YDirection()) * aDxy.y();
1407   aPanTrsf.SetTranslation (aCameraPan);
1408   aCam->Transform (aPanTrsf);
1409   theView->Invalidate();
1410 }
1411
1412 // =======================================================================
1413 // function : handleZFocusScroll
1414 // purpose  :
1415 // =======================================================================
1416 void AIS_ViewController::handleZFocusScroll (const Handle(V3d_View)& theView,
1417                                              const Aspect_ScrollDelta& theParams)
1418 {
1419   if (!myToAllowZFocus
1420    || !theView->Camera()->IsStereo())
1421   {
1422     return;
1423   }
1424
1425   Standard_Real aFocus = theView->Camera()->ZFocus() + (theParams.Delta > 0.0 ? 0.05 : -0.05);
1426   if (aFocus > 0.2
1427    && aFocus < 2.0)
1428   {
1429     theView->Camera()->SetZFocus (theView->Camera()->ZFocusType(), aFocus);
1430     theView->Redraw();
1431   }
1432 }
1433
1434 // =======================================================================
1435 // function : handleOrbitRotation
1436 // purpose  :
1437 // =======================================================================
1438 void AIS_ViewController::handleOrbitRotation (const Handle(V3d_View)& theView,
1439                                               const gp_Pnt& thePnt,
1440                                               bool theToLockZUp)
1441 {
1442   if (!myToAllowRotation)
1443   {
1444     return;
1445   }
1446
1447   const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1448   if (myGL.OrbitRotation.ToStart)
1449   {
1450     // default alternatives
1451     //if (myRotationMode == AIS_RotationMode_BndBoxActive) theView->StartRotation (myGL.RotateAtPoint.x(), myGL.RotateAtPoint.y());
1452     //theView->Rotate (0.0, 0.0, 0.0, thePnt.X(), thePnt.Y(), thePnt.Z(), true);
1453
1454     myRotatePnt3d      = thePnt;
1455     myCamStartOpUp     = aCam->Up();
1456     myCamStartOpDir    = aCam->Direction();
1457     myCamStartOpEye    = aCam->Eye();
1458     myCamStartOpCenter = aCam->Center();
1459
1460     gp_Trsf aTrsf;
1461     aTrsf.SetTransformation (gp_Ax3 (myRotatePnt3d, aCam->OrthogonalizedUp(), aCam->Direction()),
1462                              gp_Ax3 (myRotatePnt3d, gp::DZ(), gp::DX()));
1463     const gp_Quaternion aRot = aTrsf.GetRotation();
1464     aRot.GetEulerAngles (gp_YawPitchRoll, myRotateStartYawPitchRoll[0], myRotateStartYawPitchRoll[1], myRotateStartYawPitchRoll[2]);
1465
1466     aTrsf.Invert();
1467     myCamStartOpToEye    = gp_Vec (myRotatePnt3d, aCam->Eye()).Transformed (aTrsf);
1468     myCamStartOpToCenter = gp_Vec (myRotatePnt3d, aCam->Center()).Transformed (aTrsf);
1469
1470     theView->Invalidate();
1471   }
1472
1473   if (!myGL.OrbitRotation.ToRotate)
1474   {
1475     return;
1476   }
1477
1478   AbortViewAnimation();
1479   if (theToLockZUp)
1480   {
1481     // amend camera to exclude roll angle (put camera Up vector to plane containing global Z and view direction)
1482     Graphic3d_Vec2i aWinXY;
1483     theView->Window()->Size (aWinXY.x(), aWinXY.y());
1484     double aYawAngleDelta   =  ((myGL.OrbitRotation.PointStart.x() - myGL.OrbitRotation.PointTo.x()) / double (aWinXY.x())) * (M_PI * 0.5);
1485     double aPitchAngleDelta = -((myGL.OrbitRotation.PointStart.y() - myGL.OrbitRotation.PointTo.y()) / double (aWinXY.y())) * (M_PI * 0.5);
1486     const double aPitchAngleNew = Max (Min (myRotateStartYawPitchRoll[1] + aPitchAngleDelta, M_PI * 0.5 - M_PI / 180.0), -M_PI * 0.5 + M_PI / 180.0);
1487     const double aYawAngleNew   = myRotateStartYawPitchRoll[0] + aYawAngleDelta;
1488     const double aRoll = 0.0;
1489
1490     gp_Quaternion aRot;
1491     aRot.SetEulerAngles (gp_YawPitchRoll, aYawAngleNew, aPitchAngleNew, aRoll);
1492     gp_Trsf aTrsfRot;
1493     aTrsfRot.SetRotation (aRot);
1494
1495     const gp_Dir aNewUp = gp::DZ().Transformed (aTrsfRot);
1496     aCam->SetUp (aNewUp);
1497     aCam->SetEyeAndCenter (myRotatePnt3d.XYZ() + myCamStartOpToEye   .Transformed (aTrsfRot).XYZ(),
1498                            myRotatePnt3d.XYZ() + myCamStartOpToCenter.Transformed (aTrsfRot).XYZ());
1499
1500     aCam->OrthogonalizeUp();
1501   }
1502   else
1503   {
1504     // default alternatives
1505     //if (myRotationMode == AIS_RotationMode_BndBoxActive) theView->Rotation (myGL.RotateToPoint.x(), myGL.RotateToPoint.y());
1506     //theView->Rotate (aDX, aDY, aDZ, myRotatePnt3d.X(), myRotatePnt3d.Y(), myRotatePnt3d.Z(), false);
1507
1508     // restore previous camera state
1509     aCam->SetEyeAndCenter (myCamStartOpEye, myCamStartOpCenter);
1510     aCam->SetUp (myCamStartOpUp);
1511     aCam->SetDirectionFromEye (myCamStartOpDir);
1512
1513     Graphic3d_Vec2d aWinXY;
1514     theView->Size (aWinXY.x(), aWinXY.y());
1515     const Standard_Real rx = (Standard_Real )theView->Convert (aWinXY.x());
1516     const Standard_Real ry = (Standard_Real )theView->Convert (aWinXY.y());
1517
1518     const double THE_2PI = M_PI * 2.0;
1519     double aDX = (myGL.OrbitRotation.PointTo.x() - myGL.OrbitRotation.PointStart.x()) * M_PI / rx;
1520     double aDY = (myGL.OrbitRotation.PointStart.y() - myGL.OrbitRotation.PointTo.y()) * M_PI / ry;
1521
1522     if     (aDX > 0.0) { while (aDX >  THE_2PI) { aDX -= THE_2PI; } }
1523     else if(aDX < 0.0) { while (aDX < -THE_2PI) { aDX += THE_2PI; } }
1524     if     (aDY > 0.0) { while (aDY >  THE_2PI) { aDY -= THE_2PI; } }
1525     else if(aDY < 0.0) { while (aDY < -THE_2PI) { aDY += THE_2PI; } }
1526
1527     // rotate camera around 3 initial axes
1528     gp_Dir aCamDir (aCam->Direction().Reversed());
1529     gp_Dir aCamUp  (aCam->Up());
1530     gp_Dir aCamSide(aCamUp.Crossed (aCamDir));
1531
1532     gp_Trsf aRot[2], aTrsf;
1533     aRot[0].SetRotation (gp_Ax1 (myRotatePnt3d, aCamUp),  -aDX);
1534     aRot[1].SetRotation (gp_Ax1 (myRotatePnt3d, aCamSide), aDY);
1535     aTrsf.Multiply (aRot[0]);
1536     aTrsf.Multiply (aRot[1]);
1537
1538     aCam->Transform (aTrsf);
1539   }
1540
1541   theView->Invalidate();
1542 }
1543
1544 // =======================================================================
1545 // function : handleViewRotation
1546 // purpose  :
1547 // =======================================================================
1548 void AIS_ViewController::handleViewRotation (const Handle(V3d_View)& theView,
1549                                              double theYawExtra,
1550                                              double thePitchExtra,
1551                                              double theRoll,
1552                                              bool theToRestartOnIncrement)
1553 {
1554   if (!myToAllowRotation)
1555   {
1556     return;
1557   }
1558
1559   const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1560   const bool toRotateAnyway = Abs (theYawExtra)   > gp::Resolution()
1561                            || Abs (thePitchExtra) > gp::Resolution()
1562                            || Abs (theRoll - myRotateStartYawPitchRoll[2]) > gp::Resolution();
1563   if (toRotateAnyway
1564    && theToRestartOnIncrement)
1565   {
1566     myGL.ViewRotation.ToStart = true;
1567     myGL.ViewRotation.PointTo = myGL.ViewRotation.PointStart;
1568   }
1569   if (myGL.ViewRotation.ToStart)
1570   {
1571     gp_Trsf aTrsf;
1572     aTrsf.SetTransformation (gp_Ax3 (gp::Origin(), aCam->OrthogonalizedUp(), aCam->Direction()),
1573                              gp_Ax3 (gp::Origin(), gp::DZ(), gp::DX()));
1574     const gp_Quaternion aRot = aTrsf.GetRotation();
1575     double aRollDummy = 0.0;
1576     aRot.GetEulerAngles (gp_YawPitchRoll, myRotateStartYawPitchRoll[0], myRotateStartYawPitchRoll[1], aRollDummy);
1577   }
1578   if (toRotateAnyway)
1579   {
1580     myRotateStartYawPitchRoll[0] += theYawExtra;
1581     myRotateStartYawPitchRoll[1] += thePitchExtra;
1582     myRotateStartYawPitchRoll[2]  = theRoll;
1583     myGL.ViewRotation.ToRotate = true;
1584   }
1585
1586   if (!myGL.ViewRotation.ToRotate)
1587   {
1588     return;
1589   }
1590
1591   AbortViewAnimation();
1592
1593   Graphic3d_Vec2i aWinXY;
1594   theView->Window()->Size (aWinXY.x(), aWinXY.y());
1595   double aYawAngleDelta   =  ((myGL.ViewRotation.PointStart.x() - myGL.ViewRotation.PointTo.x()) / double (aWinXY.x())) * (M_PI * 0.5);
1596   double aPitchAngleDelta = -((myGL.ViewRotation.PointStart.y() - myGL.ViewRotation.PointTo.y()) / double (aWinXY.y())) * (M_PI * 0.5);
1597   const double aPitchAngleNew = Max (Min (myRotateStartYawPitchRoll[1] + aPitchAngleDelta, M_PI * 0.5 - M_PI / 180.0), -M_PI * 0.5 + M_PI / 180.0);
1598   const double aYawAngleNew   = myRotateStartYawPitchRoll[0] + aYawAngleDelta;
1599   gp_Quaternion aRot;
1600   aRot.SetEulerAngles (gp_YawPitchRoll, aYawAngleNew, aPitchAngleNew, theRoll);
1601   gp_Trsf aTrsfRot;
1602   aTrsfRot.SetRotation (aRot);
1603
1604   const gp_Dir aNewUp  = gp::DZ().Transformed (aTrsfRot);
1605   const gp_Dir aNewDir = gp::DX().Transformed (aTrsfRot);
1606   aCam->SetUp (aNewUp);
1607   aCam->SetDirectionFromEye (aNewDir);
1608   aCam->OrthogonalizeUp();
1609   theView->Invalidate();
1610 }
1611
1612 // =======================================================================
1613 // function : PickPoint
1614 // purpose  :
1615 // =======================================================================
1616 bool AIS_ViewController::PickPoint (gp_Pnt& thePnt,
1617                                     const Handle(AIS_InteractiveContext)& theCtx,
1618                                     const Handle(V3d_View)& theView,
1619                                     const Graphic3d_Vec2i& theCursor,
1620                                     bool theToStickToPickRay)
1621 {
1622   ResetPreviousMoveTo();
1623
1624   const Handle(StdSelect_ViewerSelector3d)& aSelector = theCtx->MainSelector();
1625   aSelector->Pick (theCursor.x(), theCursor.y(), theView);
1626   if (aSelector->NbPicked() < 1)
1627   {
1628     return false;
1629   }
1630
1631   const SelectMgr_SortCriterion& aPicked = aSelector->PickedData (1);
1632   if (theToStickToPickRay
1633   && !Precision::IsInfinite (aPicked.Depth))
1634   {
1635     thePnt = aSelector->GetManager().DetectedPoint (aPicked.Depth);
1636   }
1637   else
1638   {
1639     thePnt = aSelector->PickedPoint (1);
1640   }
1641   return !Precision::IsInfinite (thePnt.X())
1642       && !Precision::IsInfinite (thePnt.Y())
1643       && !Precision::IsInfinite (thePnt.Z());
1644 }
1645
1646 // =======================================================================
1647 // function : GravityPoint
1648 // purpose  :
1649 // =======================================================================
1650 gp_Pnt AIS_ViewController::GravityPoint (const Handle(AIS_InteractiveContext)& theCtx,
1651                                          const Handle(V3d_View)& theView)
1652 {
1653   switch (myRotationMode)
1654   {
1655     case AIS_RotationMode_PickLast:
1656     case AIS_RotationMode_PickCenter:
1657     {
1658       Graphic3d_Vec2i aCursor ((int )myGL.OrbitRotation.PointStart.x(), (int )myGL.OrbitRotation.PointStart.y());
1659       if (myRotationMode == AIS_RotationMode_PickCenter)
1660       {
1661         Graphic3d_Vec2i aViewPort;
1662         theView->Window()->Size (aViewPort.x(), aViewPort.y());
1663         aCursor = aViewPort / 2;
1664       }
1665
1666       gp_Pnt aPnt;
1667       if (PickPoint (aPnt, theCtx, theView, aCursor, myToStickToRayOnRotation))
1668       {
1669         return aPnt;
1670       }
1671       break;
1672     }
1673     case AIS_RotationMode_CameraAt:
1674     {
1675       const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1676       return aCam->Center();
1677     }
1678     case AIS_RotationMode_BndBoxScene:
1679     {
1680       Bnd_Box aBndBox = theView->View()->MinMaxValues (false);
1681       if (!aBndBox.IsVoid())
1682       {
1683         return (aBndBox.CornerMin().XYZ() + aBndBox.CornerMax().XYZ()) * 0.5;
1684       }
1685       break;
1686     }
1687     case AIS_RotationMode_BndBoxActive:
1688       break;
1689   }
1690
1691   return theCtx ->GravityPoint (theView);
1692 }
1693
1694 // =======================================================================
1695 // function : handleCameraActions
1696 // purpose  :
1697 // =======================================================================
1698 void AIS_ViewController::handleCameraActions (const Handle(AIS_InteractiveContext)& theCtx,
1699                                               const Handle(V3d_View)& theView,
1700                                               const AIS_WalkDelta& theWalk)
1701 {
1702   // apply view actions
1703   if (myGL.Orientation.ToSetViewOrient)
1704   {
1705     theView->SetProj (myGL.Orientation.ViewOrient);
1706     myGL.Orientation.ToFitAll = true;
1707   }
1708
1709   // apply fit all
1710   if (myGL.Orientation.ToFitAll)
1711   {
1712     const double aFitMargin = 0.01;
1713     theView->FitAll (aFitMargin, false);
1714     theView->Invalidate();
1715     myGL.Orientation.ToFitAll = false;
1716   }
1717
1718   if (myGL.IsNewGesture)
1719   {
1720     if (myAnchorPointPrs1->HasInteractiveContext())
1721     {
1722       theCtx->Remove (myAnchorPointPrs1, false);
1723       if (!theView->Viewer()->ZLayerSettings (myAnchorPointPrs1->ZLayer()).IsImmediate())
1724       {
1725         theView->Invalidate();
1726       }
1727       else
1728       {
1729         theView->InvalidateImmediate();
1730       }
1731     }
1732     if (myAnchorPointPrs2->HasInteractiveContext())
1733     {
1734       theCtx->Remove (myAnchorPointPrs2, false);
1735       if (!theView->Viewer()->ZLayerSettings (myAnchorPointPrs2->ZLayer()).IsImmediate())
1736       {
1737         theView->Invalidate();
1738       }
1739       else
1740       {
1741         theView->InvalidateImmediate();
1742       }
1743     }
1744
1745     if (myHasHlrOnBeforeRotation)
1746     {
1747       myHasHlrOnBeforeRotation = false;
1748       theView->SetComputedMode (true);
1749       theView->Invalidate();
1750     }
1751   }
1752
1753   if (myNavigationMode != AIS_NavigationMode_FirstPersonWalk)
1754   {
1755     if (myGL.Panning.ToStart
1756      && myToAllowPanning)
1757     {
1758       gp_Pnt aPanPnt (Precision::Infinite(), 0.0, 0.0);
1759       if (!theView->Camera()->IsOrthographic())
1760       {
1761         bool toStickToRay = false;
1762         if (myGL.Panning.PointStart.x() >= 0
1763          && myGL.Panning.PointStart.y() >= 0)
1764         {
1765           PickPoint (aPanPnt, theCtx, theView, myGL.Panning.PointStart, toStickToRay);
1766         }
1767         if (Precision::IsInfinite (aPanPnt.X()))
1768         {
1769           Graphic3d_Vec2i aWinSize;
1770           theView->Window()->Size (aWinSize.x(), aWinSize.y());
1771           PickPoint (aPanPnt, theCtx, theView, aWinSize / 2, toStickToRay);
1772         }
1773         if (!Precision::IsInfinite (aPanPnt.X())
1774           && myToShowPanAnchorPoint)
1775         {
1776           gp_Trsf aPntTrsf;
1777           aPntTrsf.SetTranslation (gp_Vec (aPanPnt.XYZ()));
1778           theCtx->SetLocation (myAnchorPointPrs2, aPntTrsf);
1779         }
1780       }
1781       setPanningAnchorPoint (aPanPnt);
1782     }
1783
1784     if (myToShowPanAnchorPoint
1785     &&  hasPanningAnchorPoint()
1786     &&  myGL.Panning.ToPan
1787     && !myGL.IsNewGesture
1788     && !myAnchorPointPrs2->HasInteractiveContext())
1789     {
1790       theCtx->Display (myAnchorPointPrs2, 0, -1, false, AIS_DS_Displayed);
1791     }
1792
1793     handlePanning (theView);
1794     handleZRotate (theView);
1795   }
1796
1797   if ((myNavigationMode == AIS_NavigationMode_Orbit
1798     || myGL.OrbitRotation.ToStart
1799     || myGL.OrbitRotation.ToRotate)
1800    && myToAllowRotation)
1801   {
1802     if (myGL.OrbitRotation.ToStart
1803     && !myHasHlrOnBeforeRotation)
1804     {
1805       myHasHlrOnBeforeRotation = theView->ComputedMode();
1806       if (myHasHlrOnBeforeRotation)
1807       {
1808         theView->SetComputedMode (false);
1809       }
1810     }
1811
1812     gp_Pnt aGravPnt;
1813     if (myGL.OrbitRotation.ToStart)
1814     {
1815       aGravPnt = GravityPoint (theCtx, theView);
1816       if (myToShowRotateCenter)
1817       {
1818         gp_Trsf aPntTrsf;
1819         aPntTrsf.SetTranslation (gp_Vec (aGravPnt.XYZ()));
1820         theCtx->SetLocation (myAnchorPointPrs1, aPntTrsf);
1821         theCtx->SetLocation (myAnchorPointPrs2, aPntTrsf);
1822       }
1823     }
1824
1825     if (myToShowRotateCenter
1826     &&  myGL.OrbitRotation.ToRotate
1827     && !myGL.IsNewGesture
1828     && !myAnchorPointPrs1->HasInteractiveContext())
1829     {
1830       theCtx->Display (myAnchorPointPrs1, 0, -1, false, AIS_DS_Displayed);
1831       theCtx->Display (myAnchorPointPrs2, 0, -1, false, AIS_DS_Displayed);
1832     }
1833     handleOrbitRotation (theView, aGravPnt,
1834                          myToLockOrbitZUp || myNavigationMode != AIS_NavigationMode_Orbit);
1835   }
1836
1837   if ((myNavigationMode != AIS_NavigationMode_Orbit
1838     || myGL.ViewRotation.ToStart
1839     || myGL.ViewRotation.ToRotate)
1840    && myToAllowRotation)
1841   {
1842     if (myGL.ViewRotation.ToStart
1843     && !myHasHlrOnBeforeRotation)
1844     {
1845       myHasHlrOnBeforeRotation = theView->ComputedMode();
1846       if (myHasHlrOnBeforeRotation)
1847       {
1848         theView->SetComputedMode (false);
1849       }
1850     }
1851
1852     double aRoll = 0.0;
1853     if (!theWalk[AIS_WalkRotation_Roll].IsEmpty()
1854      && !myToLockOrbitZUp)
1855     {
1856       aRoll = (M_PI / 12.0) * theWalk[AIS_WalkRotation_Roll].Pressure;
1857       aRoll *= Min (1000.0  * theWalk[AIS_WalkRotation_Roll].Duration, 100.0) / 100.0;
1858       if (theWalk[AIS_WalkRotation_Roll].Value < 0.0)
1859       {
1860         aRoll = -aRoll;
1861       }
1862     }
1863
1864     handleViewRotation (theView, theWalk[AIS_WalkRotation_Yaw].Value, theWalk[AIS_WalkRotation_Pitch].Value, aRoll,
1865                         myNavigationMode == AIS_NavigationMode_FirstPersonFlight);
1866   }
1867
1868   if (!myGL.ZoomActions.IsEmpty())
1869   {
1870     for (NCollection_Sequence<Aspect_ScrollDelta>::Iterator aZoomIter (myGL.ZoomActions); aZoomIter.More(); aZoomIter.Next())
1871     {
1872       Aspect_ScrollDelta aZoomParams = aZoomIter.Value();
1873       if (myToAllowZFocus
1874        && (aZoomParams.Flags & Aspect_VKeyFlags_CTRL) != 0
1875        && theView->Camera()->IsStereo())
1876       {
1877         handleZFocusScroll (theView, aZoomParams);
1878         continue;
1879       }
1880
1881       if (!myToAllowZooming)
1882       {
1883         continue;
1884       }
1885
1886       if (!theView->Camera()->IsOrthographic())
1887       {
1888         gp_Pnt aPnt;
1889         if (aZoomParams.HasPoint()
1890          && PickPoint (aPnt, theCtx, theView, aZoomParams.Point, myToStickToRayOnZoom))
1891         {
1892           handleZoom (theView, aZoomParams, &aPnt);
1893           continue;
1894         }
1895
1896         Graphic3d_Vec2i aWinSize;
1897         theView->Window()->Size (aWinSize.x(), aWinSize.y());
1898         if (PickPoint (aPnt, theCtx, theView, aWinSize / 2, myToStickToRayOnZoom))
1899         {
1900           aZoomParams.ResetPoint(); // do not pretend to zoom at 'nothing'
1901           handleZoom (theView, aZoomParams, &aPnt);
1902           continue;
1903         }
1904       }
1905       handleZoom (theView, aZoomParams, NULL);
1906     }
1907     myGL.ZoomActions.Clear();
1908   }
1909 }
1910
1911 // =======================================================================
1912 // function : OnSelectionChanged
1913 // purpose  :
1914 // =======================================================================
1915 void AIS_ViewController::OnSelectionChanged (const Handle(AIS_InteractiveContext)& ,
1916                                              const Handle(V3d_View)& )
1917 {
1918   //
1919 }
1920
1921 // =======================================================================
1922 // function : OnObjectDragged
1923 // purpose  :
1924 // =======================================================================
1925 void AIS_ViewController::OnObjectDragged (const Handle(AIS_InteractiveContext)& theCtx,
1926                                           const Handle(V3d_View)& theView,
1927                                           AIS_DragAction theAction)
1928 {
1929   switch (theAction)
1930   {
1931     case AIS_DragAction_Start:
1932     {
1933       myDragObject.Nullify();
1934       if (!theCtx->HasDetected())
1935       {
1936         return;
1937       }
1938
1939       Handle(AIS_InteractiveObject) aPrs = theCtx->DetectedInteractive();
1940       if (Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (aPrs))
1941       {
1942         if (aManip->HasActiveMode())
1943         {
1944           myDragObject = aManip;
1945           aManip->StartTransform (myGL.Dragging.PointStart.x(), myGL.Dragging.PointStart.y(), theView);
1946         }
1947       }
1948       return;
1949     }
1950     case AIS_DragAction_Update:
1951     {
1952       if (myDragObject.IsNull())
1953       {
1954         return;
1955       }
1956
1957       if (Handle(SelectMgr_EntityOwner) aGlobOwner = myDragObject->GlobalSelOwner())
1958       {
1959         theCtx->SetSelectedState (aGlobOwner, true);
1960       }
1961       if (Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (myDragObject))
1962       {
1963         aManip->Transform (myGL.Dragging.PointTo.x(), myGL.Dragging.PointTo.y(), theView);
1964       }
1965       theView->Invalidate();
1966       return;
1967     }
1968     case AIS_DragAction_Abort:
1969     {
1970       if (myDragObject.IsNull())
1971       {
1972         return;
1973       }
1974
1975       myGL.Dragging.PointTo = myGL.Dragging.PointStart;
1976       OnObjectDragged (theCtx, theView, AIS_DragAction_Update);
1977
1978       if (Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (myDragObject))
1979       {
1980         aManip->StopTransform (false);
1981       }
1982       Standard_FALLTHROUGH
1983     }
1984     case AIS_DragAction_Stop:
1985     {
1986       if (myDragObject.IsNull())
1987       {
1988         return;
1989       }
1990
1991       if (Handle(SelectMgr_EntityOwner) aGlobOwner = myDragObject->GlobalSelOwner())
1992       {
1993         theCtx->SetSelectedState (aGlobOwner, false);
1994       }
1995
1996       theView->Invalidate();
1997       myDragObject.Nullify();
1998       return;
1999     }
2000   }
2001 }
2002
2003 // =======================================================================
2004 // function : contextLazyMoveTo
2005 // purpose  :
2006 // =======================================================================
2007 void AIS_ViewController::contextLazyMoveTo (const Handle(AIS_InteractiveContext)& theCtx,
2008                                             const Handle(V3d_View)& theView,
2009                                             const Graphic3d_Vec2i& thePnt)
2010 {
2011   if (myPrevMoveTo == thePnt)
2012   {
2013     return;
2014   }
2015
2016   myPrevMoveTo = thePnt;
2017
2018   Handle(SelectMgr_EntityOwner) aLastPicked = theCtx->DetectedOwner();
2019   theCtx->MoveTo (thePnt.x(), thePnt.y(), theView, false);
2020   Handle(SelectMgr_EntityOwner) aNewPicked = theCtx->DetectedOwner();
2021
2022   if (theView->Viewer()->Grid()->IsActive()
2023    && theView->Viewer()->GridEcho())
2024   {
2025     if (aNewPicked.IsNull())
2026     {
2027       Graphic3d_Vec3d aPnt3d;
2028       theView->ConvertToGrid (thePnt.x(), thePnt.y(), aPnt3d[0], aPnt3d[1], aPnt3d[2]);
2029       theView->Viewer()->ShowGridEcho (theView, Graphic3d_Vertex (aPnt3d[0], aPnt3d[1], aPnt3d[2]));
2030       theView->InvalidateImmediate();
2031     }
2032     else
2033     {
2034       theView->Viewer()->HideGridEcho (theView);
2035       theView->InvalidateImmediate();
2036     }
2037   }
2038
2039   if (aLastPicked != aNewPicked
2040    || (!aNewPicked.IsNull() && aNewPicked->IsForcedHilight()))
2041   {
2042     // dynamic highlight affects all Views
2043     for (V3d_ListOfViewIterator aViewIter (theView->Viewer()->ActiveViewIterator()); aViewIter.More(); aViewIter.Next())
2044     {
2045       const Handle(V3d_View)& aView = aViewIter.Value();
2046       aView->InvalidateImmediate();
2047     }
2048   }
2049 }
2050
2051 // =======================================================================
2052 // function : handleSelectionPick
2053 // purpose  :
2054 // =======================================================================
2055 void AIS_ViewController::handleSelectionPick (const Handle(AIS_InteractiveContext)& theCtx,
2056                                               const Handle(V3d_View)& theView)
2057 {
2058   if (myGL.Selection.Tool == AIS_ViewSelectionTool_Picking
2059   && !myGL.Selection.Points.IsEmpty())
2060   {
2061     for (NCollection_Sequence<Graphic3d_Vec2i>::Iterator aPntIter (myGL.Selection.Points); aPntIter.More(); aPntIter.Next())
2062     {
2063       const bool hadPrevMoveTo = HasPreviousMoveTo();
2064       contextLazyMoveTo (theCtx, theView, aPntIter.Value());
2065       if (!hadPrevMoveTo)
2066       {
2067         ResetPreviousMoveTo();
2068       }
2069
2070       if (myGL.Selection.IsXOR)
2071       {
2072         theCtx->ShiftSelect (false);
2073       }
2074       else
2075       {
2076         theCtx->Select (false);
2077       }
2078
2079       // selection affects all Views
2080       theView->Viewer()->Invalidate();
2081
2082       OnSelectionChanged (theCtx, theView);
2083     }
2084
2085     myGL.Selection.Points.Clear();
2086   }
2087 }
2088
2089 // =======================================================================
2090 // function : handleSelectionPoly
2091 // purpose  :
2092 // =======================================================================
2093 void AIS_ViewController::handleSelectionPoly (const Handle(AIS_InteractiveContext)& theCtx,
2094                                               const Handle(V3d_View)& theView)
2095 {
2096   // rubber-band & window polygon selection
2097   if (myGL.Selection.Tool == AIS_ViewSelectionTool_RubberBand
2098    || myGL.Selection.Tool == AIS_ViewSelectionTool_Polygon)
2099   {
2100     if (!myGL.Selection.Points.IsEmpty())
2101     {
2102       myRubberBand->ClearPoints();
2103       myRubberBand->SetToUpdate();
2104
2105       const bool anIsRubber = myGL.Selection.Tool == AIS_ViewSelectionTool_RubberBand;
2106       if (anIsRubber)
2107       {
2108         myRubberBand->SetRectangle (myGL.Selection.Points.First().x(), -myGL.Selection.Points.First().y(),
2109                                     myGL.Selection.Points.Last().x(),  -myGL.Selection.Points.Last().y());
2110       }
2111       else
2112       {
2113         Graphic3d_Vec2i aPrev (IntegerLast(), IntegerLast());
2114         for (NCollection_Sequence<Graphic3d_Vec2i>::Iterator aSelIter (myGL.Selection.Points); aSelIter.More(); aSelIter.Next())
2115         {
2116           Graphic3d_Vec2i aPntNew = Graphic3d_Vec2i (aSelIter.Value().x(), -aSelIter.Value().y());
2117           if (aPntNew != aPrev)
2118           {
2119             aPrev = aPntNew;
2120             myRubberBand->AddPoint (Graphic3d_Vec2i (aSelIter.Value().x(), -aSelIter.Value().y()));
2121           }
2122         }
2123       }
2124
2125       myRubberBand->SetPolygonClosed (anIsRubber);
2126       try
2127       {
2128         theCtx->Display (myRubberBand, 0, -1, false, AIS_DS_Displayed);
2129       }
2130       catch (const Standard_Failure& theEx)
2131       {
2132         Message::DefaultMessenger()->Send (TCollection_AsciiString ("Internal error while displaying rubber-band: ")
2133                                         + theEx.DynamicType()->Name() + ", " + theEx.GetMessageString(), Message_Warning);
2134         myRubberBand->ClearPoints();
2135       }
2136       if (!theView->Viewer()->ZLayerSettings (myRubberBand->ZLayer()).IsImmediate())
2137       {
2138         theView->Invalidate();
2139       }
2140       else
2141       {
2142         theView->InvalidateImmediate();
2143       }
2144     }
2145     else if (!myRubberBand.IsNull()
2146            && myRubberBand->HasInteractiveContext())
2147     {
2148       theCtx->Remove (myRubberBand, false);
2149       myRubberBand->ClearPoints();
2150     }
2151   }
2152
2153   if (myGL.Selection.ToApplyTool)
2154   {
2155     myGL.Selection.ToApplyTool = false;
2156     if (theCtx->IsDisplayed (myRubberBand))
2157     {
2158       theCtx->Remove (myRubberBand, false);
2159       {
2160         const NCollection_Sequence<Graphic3d_Vec2i>& aPoints = myRubberBand->Points();
2161         if (aPoints.Size() == 4
2162          && aPoints.Value (1).x() == aPoints.Value (2).x()
2163          && aPoints.Value (3).x() == aPoints.Value (4).x()
2164          && aPoints.Value (1).y() == aPoints.Value (4).y()
2165          && aPoints.Value (2).y() == aPoints.Value (3).y())
2166         {
2167           const Graphic3d_Vec2i aPnt1 (aPoints.Value (1).x(), -aPoints.Value (1).y());
2168           const Graphic3d_Vec2i aPnt2 (aPoints.Value (3).x(), -aPoints.Value (3).y());
2169           theCtx->MainSelector()->AllowOverlapDetection (aPnt1.y() != Min (aPnt1.y(), aPnt2.y()));
2170           if (myGL.Selection.IsXOR)
2171           {
2172             theCtx->ShiftSelect (Min (aPnt1.x(), aPnt2.x()), Min (aPnt1.y(), aPnt2.y()),
2173                                  Max (aPnt1.x(), aPnt2.x()), Max (aPnt1.y(), aPnt2.y()),
2174                                  theView, false);
2175           }
2176           else
2177           {
2178             theCtx->Select (Min (aPnt1.x(), aPnt2.x()), Min (aPnt1.y(), aPnt2.y()),
2179                             Max (aPnt1.x(), aPnt2.x()), Max (aPnt1.y(), aPnt2.y()),
2180                             theView, false);
2181           }
2182           theCtx->MainSelector()->AllowOverlapDetection (false);
2183         }
2184         else if (aPoints.Length() >= 3)
2185         {
2186           TColgp_Array1OfPnt2d aPolyline (1, aPoints.Length());
2187           TColgp_Array1OfPnt2d::Iterator aPolyIter (aPolyline);
2188           for (NCollection_Sequence<Graphic3d_Vec2i>::Iterator aSelIter (aPoints);
2189                aSelIter.More(); aSelIter.Next(), aPolyIter.Next())
2190           {
2191             const Graphic3d_Vec2i& aNewPnt = aSelIter.Value();
2192             aPolyIter.ChangeValue() = gp_Pnt2d (aNewPnt.x(), -aNewPnt.y());
2193           }
2194
2195           theCtx->MainSelector()->AllowOverlapDetection (false);
2196           if (myGL.Selection.IsXOR)
2197           {
2198             theCtx->ShiftSelect (aPolyline, theView, false);
2199           }
2200           else
2201           {
2202             theCtx->Select (aPolyline, theView, false);
2203           }
2204         }
2205       }
2206
2207       // selection affects all Views
2208       theView->Viewer()->Invalidate();
2209
2210       myRubberBand->ClearPoints();
2211       OnSelectionChanged (theCtx, theView);
2212     }
2213   }
2214 }
2215
2216 // =======================================================================
2217 // function : handleDynamicHighlight
2218 // purpose  :
2219 // =======================================================================
2220 void AIS_ViewController::handleDynamicHighlight (const Handle(AIS_InteractiveContext)& theCtx,
2221                                                  const Handle(V3d_View)& theView)
2222 {
2223   if ((myGL.MoveTo.ToHilight || myGL.Dragging.ToStart)
2224    && myNavigationMode != AIS_NavigationMode_FirstPersonWalk)
2225   {
2226     const Graphic3d_Vec2i& aMoveToPnt = myGL.MoveTo.ToHilight ? myGL.MoveTo.Point : myGL.Dragging.PointStart;
2227     if (myGL.Dragging.ToStart && (!myGL.MoveTo.ToHilight || !myToAllowHighlight)
2228      && !HasPreviousMoveTo())
2229     {
2230       contextLazyMoveTo (theCtx, theView, aMoveToPnt);
2231       ResetPreviousMoveTo();
2232       OnObjectDragged (theCtx, theView, AIS_DragAction_Start);
2233       theCtx->ClearDetected();
2234     }
2235     else if (myToAllowHighlight)
2236     {
2237       if (myPrevMoveTo != aMoveToPnt
2238        || myGL.OrbitRotation.ToRotate
2239        || myGL.ViewRotation.ToRotate
2240        || theView->IsInvalidated())
2241       {
2242         ResetPreviousMoveTo();
2243         contextLazyMoveTo (theCtx, theView, aMoveToPnt);
2244       }
2245       if (myGL.Dragging.ToStart)
2246       {
2247         OnObjectDragged (theCtx, theView, AIS_DragAction_Start);
2248       }
2249     }
2250
2251     myGL.MoveTo.ToHilight = false;
2252   }
2253
2254   if (!myDragObject.IsNull())
2255   {
2256     if (myGL.Dragging.ToAbort)
2257     {
2258       OnObjectDragged (theCtx, theView, AIS_DragAction_Abort);
2259       myGL.OrbitRotation.ToRotate = false;
2260       myGL.ViewRotation .ToRotate = false;
2261     }
2262     else if (myGL.Dragging.ToStop)
2263     {
2264       OnObjectDragged (theCtx, theView, AIS_DragAction_Stop);
2265       myGL.OrbitRotation.ToRotate = false;
2266       myGL.ViewRotation .ToRotate = false;
2267     }
2268     else if (myGL.OrbitRotation.ToRotate
2269           || myGL.ViewRotation.ToRotate)
2270     {
2271       OnObjectDragged (theCtx, theView, AIS_DragAction_Update);
2272       myGL.OrbitRotation.ToRotate = false;
2273       myGL.ViewRotation .ToRotate = false;
2274     }
2275   }
2276 }
2277
2278 // =======================================================================
2279 // function : handleMoveTo
2280 // purpose  :
2281 // =======================================================================
2282 void AIS_ViewController::handleMoveTo (const Handle(AIS_InteractiveContext)& theCtx,
2283                                        const Handle(V3d_View)& theView)
2284 {
2285   handleSelectionPick   (theCtx, theView);
2286   handleDynamicHighlight(theCtx, theView);
2287   handleSelectionPoly   (theCtx, theView);
2288 }
2289
2290 // =======================================================================
2291 // function : handleViewRedraw
2292 // purpose  :
2293 // =======================================================================
2294 void AIS_ViewController::handleViewRedraw (const Handle(AIS_InteractiveContext)& ,
2295                                            const Handle(V3d_View)& theView)
2296 {
2297   // manage animation state
2298   if (!myViewAnimation.IsNull()
2299    && !myViewAnimation->IsStopped())
2300   {
2301     myViewAnimation->UpdateTimer();
2302     ResetPreviousMoveTo();
2303     setAskNextFrame();
2304   }
2305
2306   for (V3d_ListOfViewIterator aViewIter (theView->Viewer()->ActiveViewIterator()); aViewIter.More(); aViewIter.Next())
2307   {
2308     const Handle(V3d_View)& aView = aViewIter.Value();
2309     if (aView->IsInvalidated()
2310      || myToAskNextFrame)
2311     {
2312       if (aView->ComputedMode())
2313       {
2314         aView->Update();
2315       }
2316       else
2317       {
2318         aView->Redraw();
2319       }
2320     }
2321     else if (aView->IsInvalidatedImmediate())
2322     {
2323       aView->RedrawImmediate();
2324     }
2325   }
2326
2327   if (myToAskNextFrame)
2328   {
2329     // ask more frames
2330     theView->Window()->InvalidateContent (Handle(Aspect_DisplayConnection)());
2331   }
2332 }
2333
2334 // =======================================================================
2335 // function : HandleViewEvents
2336 // purpose  :
2337 // =======================================================================
2338 void AIS_ViewController::HandleViewEvents (const Handle(AIS_InteractiveContext)& theCtx,
2339                                            const Handle(V3d_View)& theView)
2340 {
2341   handleMoveTo (theCtx, theView);
2342
2343   const AIS_WalkDelta aWalk = FetchNavigationKeys (1.0, 1.0);
2344   handleCameraActions (theCtx, theView, aWalk);
2345   handleViewRedraw (theCtx, theView);
2346
2347   // make sure to not process the same events twice
2348   myGL.Reset();
2349   myToAskNextFrame = false;
2350 }