0028954: Visualization - implement interactive object for camera manipulations
[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   //
52   myWalkSpeedAbsolute (1.5f),
53   myWalkSpeedRelative (0.1f),
54   myThrustSpeed (0.0f),
55   myHasThrust (false),
56   //
57   myViewAnimation (new AIS_AnimationCamera ("AIS_ViewController_ViewAnimation", Handle(V3d_View)())),
58   myPrevMoveTo (-1, -1),
59   myHasHlrOnBeforeRotation (false),
60   //
61   myMouseClickThreshold (3.0),
62   myMouseDoubleClickInt (0.4),
63   myScrollZoomRatio     (15.0f),
64   myMouseActiveGesture  (AIS_MouseGesture_NONE),
65   myMouseActiveIdleRotation (false),
66   myMouseClickCounter   (0),
67   myMousePressed        (Aspect_VKeyMouse_NONE),
68   myMouseModifiers      (Aspect_VKeyFlags_NONE),
69   myMouseSingleButton   (-1),
70   //
71   myTouchToleranceScale      (1.0f),
72   myTouchRotationThresholdPx (6.0f),
73   myTouchZRotationThreshold  (float(2.0 * M_PI / 180.0)),
74   myTouchPanThresholdPx      (4.0f),
75   myTouchZoomThresholdPx     (6.0f),
76   myTouchZoomRatio           (0.13f),
77   //
78   myNbTouchesLast (0),
79   myUpdateStartPointPan  (true),
80   myUpdateStartPointRot  (true),
81   myUpdateStartPointZRot (true),
82   //
83   myPanPnt3d (Precision::Infinite(), 0.0, 0.0)
84 {
85   myEventTimer.Start();
86
87   myAnchorPointPrs1 = new AIS_Point (new Geom_CartesianPoint (0.0, 0.0, 0.0));
88   myAnchorPointPrs1->SetZLayer (Graphic3d_ZLayerId_Top);
89   myAnchorPointPrs1->SetMutable (true);
90
91   myAnchorPointPrs2 = new AIS_Point (new Geom_CartesianPoint (0.0, 0.0, 0.0));
92   myAnchorPointPrs2->SetZLayer (Graphic3d_ZLayerId_Topmost);
93   myAnchorPointPrs2->SetMutable (true);
94
95   myRubberBand = new AIS_RubberBand (Quantity_NOC_LIGHTBLUE, Aspect_TOL_SOLID, Quantity_NOC_LIGHTBLUE, 0.4, 1.0);
96   myRubberBand->SetZLayer (Graphic3d_ZLayerId_TopOSD);
97   myRubberBand->SetTransformPersistence (new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_UPPER));
98   myRubberBand->SetDisplayMode (0);
99   myRubberBand->SetMutable (true);
100
101   myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton,                           AIS_MouseGesture_RotateOrbit);
102   myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_CTRL,   AIS_MouseGesture_Zoom);
103   myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_SHIFT,  AIS_MouseGesture_Pan);
104   myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_ALT,    AIS_MouseGesture_SelectRectangle);
105
106   myMouseGestureMap.Bind (Aspect_VKeyMouse_RightButton,                          AIS_MouseGesture_Zoom);
107   myMouseGestureMap.Bind (Aspect_VKeyMouse_RightButton | Aspect_VKeyFlags_CTRL,  AIS_MouseGesture_RotateOrbit);
108
109   myMouseGestureMap.Bind (Aspect_VKeyMouse_MiddleButton,                         AIS_MouseGesture_Pan);
110   myMouseGestureMap.Bind (Aspect_VKeyMouse_MiddleButton | Aspect_VKeyFlags_CTRL, AIS_MouseGesture_Pan);
111 }
112
113 // =======================================================================
114 // function : ResetViewInput
115 // purpose  :
116 // =======================================================================
117 void AIS_ViewController::ResetViewInput()
118 {
119   myKeys.Reset();
120   myMousePressed      = Aspect_VKeyMouse_NONE;
121   myMouseModifiers    = Aspect_VKeyFlags_NONE;
122   myMouseSingleButton = -1;
123   myUI.Dragging.ToAbort = true;
124   myMouseActiveGesture = AIS_MouseGesture_NONE;
125   myMouseClickTimer.Stop();
126   myMouseClickCounter = 0;
127 }
128
129 // =======================================================================
130 // function : FlushViewEvents
131 // purpose  :
132 // =======================================================================
133 void AIS_ViewController::FlushViewEvents (const Handle(AIS_InteractiveContext)& theCtx,
134                                           const Handle(V3d_View)& theView,
135                                           Standard_Boolean theToHandle)
136 {
137   flushBuffers (theCtx, theView);
138   flushGestures(theCtx, theView);
139   if (theToHandle)
140   {
141     HandleViewEvents (theCtx, theView);
142   }
143 }
144
145 // =======================================================================
146 // function : flushBuffers
147 // purpose  :
148 // =======================================================================
149 void AIS_ViewController::flushBuffers (const Handle(AIS_InteractiveContext)& ,
150                                        const Handle(V3d_View)& )
151 {
152   myToAskNextFrame = false;
153
154   myGL.IsNewGesture = myUI.IsNewGesture;
155   myUI.IsNewGesture = false;
156
157   myGL.ZoomActions.Clear();
158   myGL.ZoomActions.Append (myUI.ZoomActions);
159   myUI.ZoomActions.Clear();
160
161   myGL.Orientation.ToFitAll = myUI.Orientation.ToFitAll;
162   myUI.Orientation.ToFitAll = false;
163   if (myUI.Orientation.ToSetViewOrient)
164   {
165     myUI.Orientation.ToSetViewOrient = false;
166     myGL.Orientation.ToSetViewOrient = true;
167     myGL.Orientation.ViewOrient      = myUI.Orientation.ViewOrient;
168   }
169
170   if (myUI.MoveTo.ToHilight)
171   {
172     myUI.MoveTo.ToHilight = false;
173     myGL.MoveTo.ToHilight = true;
174     myGL.MoveTo.Point     = myUI.MoveTo.Point;
175   }
176
177   {
178     myGL.Selection.Tool   = myUI.Selection.Tool;
179     myGL.Selection.IsXOR  = myUI.Selection.IsXOR;
180     myGL.Selection.Points = myUI.Selection.Points;
181     myUI.Selection.IsXOR  = false;
182     if (myUI.Selection.Tool == AIS_ViewSelectionTool_Picking)
183     {
184       myUI.Selection.Points.Clear();
185     }
186   }
187
188   if (myUI.Selection.ToApplyTool)
189   {
190     myGL.Selection.ToApplyTool = true;
191     myUI.Selection.ToApplyTool = false;
192     myUI.Selection.Points.Clear();
193   }
194
195   if (myUI.Panning.ToStart)
196   {
197     myUI.Panning.ToStart = false;
198     myGL.Panning.ToStart = true;
199     myGL.Panning.PointStart = myUI.Panning.PointStart;
200   }
201
202   if (myUI.Panning.ToPan)
203   {
204     myUI.Panning.ToPan = false;
205     myGL.Panning.ToPan = true;
206     myGL.Panning.Delta = myUI.Panning.Delta;
207   }
208
209   if (myUI.Dragging.ToAbort)
210   {
211     myUI.Dragging.ToAbort = false;
212     myGL.Dragging.ToAbort = true;
213   }
214   else if (myUI.Dragging.ToStop)
215   {
216     myUI.Dragging.ToStop = false;
217     myGL.Dragging.ToStop = true;
218   }
219   else if (myUI.Dragging.ToStart)
220   {
221     myUI.Dragging.ToStart = false;
222     myGL.Dragging.ToStart = true;
223     myGL.Dragging.PointStart = myUI.Dragging.PointStart;
224   }
225   myGL.Dragging.PointTo = myUI.Dragging.PointTo;
226
227   if (myUI.OrbitRotation.ToStart)
228   {
229     myUI.OrbitRotation.ToStart    = false;
230     myGL.OrbitRotation.ToStart    = true;
231     myGL.OrbitRotation.PointStart = myUI.OrbitRotation.PointStart;
232   }
233
234   if (myUI.OrbitRotation.ToRotate)
235   {
236     myUI.OrbitRotation.ToRotate = false;
237     myGL.OrbitRotation.ToRotate = true;
238     myGL.OrbitRotation.PointTo  = myUI.OrbitRotation.PointTo;
239   }
240
241   if (myUI.ViewRotation.ToStart)
242   {
243     myUI.ViewRotation.ToStart    = false;
244     myGL.ViewRotation.ToStart    = true;
245     myGL.ViewRotation.PointStart = myUI.ViewRotation.PointStart;
246   }
247
248   if (myUI.ViewRotation.ToRotate)
249   {
250     myUI.ViewRotation.ToRotate = false;
251     myGL.ViewRotation.ToRotate = true;
252     myGL.ViewRotation.PointTo  = myUI.ViewRotation.PointTo;
253   }
254
255   if (myUI.ZRotate.ToRotate)
256   {
257     myGL.ZRotate = myUI.ZRotate;
258     myUI.ZRotate.ToRotate = false;
259   }
260 }
261
262 // =======================================================================
263 // function : flushGestures
264 // purpose  :
265 // =======================================================================
266 void AIS_ViewController::flushGestures (const Handle(AIS_InteractiveContext)& ,
267                                         const Handle(V3d_View)& theView)
268 {
269   const Standard_Real    aTolScale = myTouchToleranceScale;
270   const Standard_Integer aTouchNb  = myTouchPoints.Extent();
271   if (myNbTouchesLast != aTouchNb)
272   {
273     myNbTouchesLast = aTouchNb;
274     myGL.IsNewGesture = true;
275   }
276   if (aTouchNb == 1) // touch
277   {
278     Aspect_Touch& aTouch = myTouchPoints.ChangeFromIndex (1);
279     if (myUpdateStartPointRot)
280     {
281       // skip rotation if have active dragged object
282       if (myNavigationMode == AIS_NavigationMode_Orbit)
283       {
284         myGL.OrbitRotation.ToStart = true;
285         myGL.OrbitRotation.PointStart = myStartRotCoord;
286       }
287       else
288       {
289         myGL.ViewRotation.ToStart = true;
290         myGL.ViewRotation.PointStart = myStartRotCoord;
291       }
292
293       myUpdateStartPointRot = false;
294       theView->Invalidate();
295     }
296
297     // rotation
298     const Standard_Real aRotTouchTol = !aTouch.IsPreciseDevice
299                                      ? aTolScale * myTouchRotationThresholdPx
300                                      : gp::Resolution();
301     if (Abs (aTouch.Delta().x()) + Abs(aTouch.Delta().y()) > aRotTouchTol)
302     {
303       const Standard_Real aRotAccel = myNavigationMode == AIS_NavigationMode_FirstPersonWalk ? myMouseAccel : myOrbitAccel;
304       if (myNavigationMode == AIS_NavigationMode_Orbit)
305       {
306         const Graphic3d_Vec2d aRotDelta = aTouch.To - myGL.OrbitRotation.PointStart;
307         myGL.OrbitRotation.ToRotate = true;
308         myGL.OrbitRotation.PointTo  = myGL.OrbitRotation.PointStart + aRotDelta * aRotAccel;
309         myGL.Dragging.PointTo.SetValues ((int )aTouch.To.x(), (int )aTouch.To.y());
310       }
311       else
312       {
313         const Graphic3d_Vec2d aRotDelta = aTouch.To - myGL.ViewRotation.PointStart;
314         myGL.ViewRotation.ToRotate = true;
315         myGL.ViewRotation.PointTo = myGL.ViewRotation.PointStart + aRotDelta * aRotAccel;
316         myGL.Dragging.PointTo.SetValues ((int )aTouch.To.x(), (int )aTouch.To.y());
317       }
318
319       aTouch.From = aTouch.To;
320     }
321   }
322   else if (aTouchNb == 2) // pinch
323   {
324     Aspect_Touch& aFirstTouch = myTouchPoints.ChangeFromIndex (1);
325     Aspect_Touch& aLastTouch  = myTouchPoints.ChangeFromIndex (2);
326     const Graphic3d_Vec2d aFrom[2] = { aFirstTouch.From, aLastTouch.From };
327     const Graphic3d_Vec2d aTo[2]   = { aFirstTouch.To,   aLastTouch.To   };
328
329     Graphic3d_Vec2d aPinchCenterStart ((aFrom[0].x() + aFrom[1].x()) / 2.0,
330                                        (aFrom[0].y() + aFrom[1].y()) / 2.0);
331
332     Standard_Real aPinchCenterXEnd = (aTo[0].x() + aTo[1].x()) / 2.0;
333     Standard_Real aPinchCenterYEnd = (aTo[0].y() + aTo[1].y()) / 2.0;
334
335     Standard_Real aPinchCenterXDev = aPinchCenterXEnd - aPinchCenterStart.x();
336     Standard_Real aPinchCenterYDev = aPinchCenterYEnd - aPinchCenterStart.y();
337
338     Standard_Real aStartSize = (aFrom[0] - aFrom[1]).Modulus();
339     Standard_Real anEndSize  = (  aTo[0] -   aTo[1]).Modulus();
340
341     Standard_Real aDeltaSize = anEndSize - aStartSize;
342
343     bool anIsClearDev = false;
344
345     if (myToAllowTouchZRotation)
346     {
347       Standard_Real A1 = aFrom[0].y() - aFrom[1].y();
348       Standard_Real B1 = aFrom[1].x() - aFrom[0].x();
349
350       Standard_Real A2 = aTo[0].y() - aTo[1].y();
351       Standard_Real B2 = aTo[1].x() - aTo[0].x();
352
353       Standard_Real aRotAngle = 0.0;
354
355       Standard_Real aDenomenator = A1*A2 + B1*B2;
356       if (aDenomenator <= Precision::Confusion())
357       {
358         aRotAngle = 0.0;
359       }
360       else
361       {
362         Standard_Real aNumerator = A1*B2 - A2*B1;
363         aRotAngle = ATan (aNumerator / aDenomenator);
364       }
365
366       if (Abs(aRotAngle) > Standard_Real(myTouchZRotationThreshold))
367       {
368         myGL.ZRotate.ToRotate = true;
369         myGL.ZRotate.Angle = aRotAngle;
370         anIsClearDev = true;
371       }
372     }
373
374     if (Abs(aDeltaSize) > aTolScale * myTouchZoomThresholdPx)
375     {
376       // zoom
377       aDeltaSize *= Standard_Real(myTouchZoomRatio);
378       Aspect_ScrollDelta aParams (Graphic3d_Vec2i (aPinchCenterStart), aDeltaSize);
379       myGL.ZoomActions.Append (aParams);
380       anIsClearDev = true;
381     }
382
383     const Standard_Real aPanTouchTol = !aFirstTouch.IsPreciseDevice
384                                      ? aTolScale * myTouchPanThresholdPx
385                                      : gp::Resolution();
386     if (Abs(aPinchCenterXDev) + Abs(aPinchCenterYDev) > aPanTouchTol)
387     {
388       // pan
389       if (myUpdateStartPointPan)
390       {
391         myGL.Panning.ToStart = true;
392         myGL.Panning.PointStart = Graphic3d_Vec2i (myStartPanCoord);
393         myUpdateStartPointPan = false;
394         theView->Invalidate();
395       }
396
397       myGL.Panning.ToPan = true;
398       myGL.Panning.Delta.x() = int( aPinchCenterXDev);
399       myGL.Panning.Delta.y() = int(-aPinchCenterYDev);
400       anIsClearDev = true;
401     }
402
403     if (anIsClearDev)
404     {
405       aFirstTouch.From = aFirstTouch.To;
406       aLastTouch .From = aLastTouch.To;
407     }
408   }
409 }
410
411 // =======================================================================
412 // function : UpdateViewOrientation
413 // purpose  :
414 // =======================================================================
415 void AIS_ViewController::UpdateViewOrientation (V3d_TypeOfOrientation theOrientation,
416                                                 bool theToFitAll)
417 {
418   myUI.Orientation.ToFitAll = theToFitAll;
419   myUI.Orientation.ToSetViewOrient = true;
420   myUI.Orientation.ViewOrient = theOrientation;
421 }
422
423 // =======================================================================
424 // function : SelectInViewer
425 // purpose  :
426 // =======================================================================
427 void AIS_ViewController::SelectInViewer (const Graphic3d_Vec2i& thePnt,
428                                          const bool theIsXOR)
429 {
430   if (myUI.Selection.Tool != AIS_ViewSelectionTool_Picking)
431   {
432     myUI.Selection.Tool = AIS_ViewSelectionTool_Picking;
433     myUI.Selection.Points.Clear();
434   }
435
436   myUI.Selection.IsXOR = theIsXOR;
437   myUI.Selection.Points.Append (thePnt);
438 }
439
440 // =======================================================================
441 // function : SelectInViewer
442 // purpose  :
443 // =======================================================================
444 void AIS_ViewController::SelectInViewer (const NCollection_Sequence<Graphic3d_Vec2i>& thePnts,
445                                          const bool theIsXOR)
446 {
447   myUI.Selection.IsXOR = theIsXOR;
448   myUI.Selection.Points = thePnts;
449   myUI.Selection.ToApplyTool = true;
450   if (thePnts.Length() == 1)
451   {
452     myUI.Selection.Tool = AIS_ViewSelectionTool_Picking;
453   }
454   else if (thePnts.Length() == 2)
455   {
456     myUI.Selection.Tool = AIS_ViewSelectionTool_RubberBand;
457   }
458   else
459   {
460     myUI.Selection.Tool = AIS_ViewSelectionTool_Polygon;
461   }
462 }
463
464 // =======================================================================
465 // function : UpdateRubberBand
466 // purpose  :
467 // =======================================================================
468 void AIS_ViewController::UpdateRubberBand (const Graphic3d_Vec2i& thePntFrom,
469                                            const Graphic3d_Vec2i& thePntTo,
470                                            const bool theIsXOR)
471 {
472   myUI.Selection.Tool = AIS_ViewSelectionTool_RubberBand;
473   myUI.Selection.IsXOR = theIsXOR;
474   myUI.Selection.Points.Clear();
475   myUI.Selection.Points.Append (thePntFrom);
476   myUI.Selection.Points.Append (thePntTo);
477 }
478
479 // =======================================================================
480 // function : UpdatePolySelection
481 // purpose  :
482 // =======================================================================
483 void AIS_ViewController::UpdatePolySelection (const Graphic3d_Vec2i& thePnt,
484                                               bool theToAppend)
485 {
486   if (myUI.Selection.Tool != AIS_ViewSelectionTool_Polygon)
487   {
488     myUI.Selection.Tool = AIS_ViewSelectionTool_Polygon;
489     myUI.Selection.Points.Clear();
490   }
491
492   if (myUI.Selection.Points.IsEmpty())
493   {
494     myUI.Selection.Points.Append (thePnt);
495   }
496   else if (theToAppend
497         && myUI.Selection.Points.Last() != thePnt)
498   {
499     myUI.Selection.Points.Append (thePnt);
500   }
501   else
502   {
503     myUI.Selection.Points.ChangeLast() = thePnt;
504   }
505 }
506
507 // =======================================================================
508 // function : UpdateZoom
509 // purpose  :
510 // =======================================================================
511 bool AIS_ViewController::UpdateZoom (const Aspect_ScrollDelta& theDelta)
512 {
513   if (!myUI.ZoomActions.IsEmpty())
514   {
515     if (myUI.ZoomActions.ChangeLast().Point == theDelta.Point)
516     {
517       myUI.ZoomActions.ChangeLast().Delta += theDelta.Delta;
518       return false;
519     }
520   }
521
522   myUI.ZoomActions.Append (theDelta);
523   return true;
524 }
525
526 // =======================================================================
527 // function : UpdateZRotation
528 // purpose  :
529 // =======================================================================
530 bool AIS_ViewController::UpdateZRotation (double theAngle)
531 {
532   if (!ToAllowTouchZRotation())
533   {
534     return false;
535   }
536
537   myUI.ZRotate.Angle = myUI.ZRotate.ToRotate
538                      ? myUI.ZRotate.Angle + theAngle
539                      : theAngle;
540   if (myUI.ZRotate.ToRotate)
541   {
542     return false;
543   }
544   myUI.ZRotate.ToRotate = true;
545   return true;
546 }
547
548 // =======================================================================
549 // function : UpdateMouseScroll
550 // purpose  :
551 // =======================================================================
552 bool AIS_ViewController::UpdateMouseScroll (const Aspect_ScrollDelta& theDelta)
553 {
554   Aspect_ScrollDelta aDelta = theDelta;
555   aDelta.Delta *= myScrollZoomRatio;
556   return UpdateZoom (aDelta);
557 }
558
559 // =======================================================================
560 // function : UpdateMouseClick
561 // purpose  :
562 // =======================================================================
563 bool AIS_ViewController::UpdateMouseClick (const Graphic3d_Vec2i& thePoint,
564                                            Aspect_VKeyMouse theButton,
565                                            Aspect_VKeyFlags theModifiers,
566                                            bool theIsDoubleClick)
567 {
568   (void )theIsDoubleClick;
569   if (theButton == Aspect_VKeyMouse_LeftButton)
570   {
571     SelectInViewer (thePoint, (theModifiers & Aspect_VKeyFlags_SHIFT) != 0);
572     return true;
573   }
574   return false;
575 }
576
577 // =======================================================================
578 // function : UpdateMouseButtons
579 // purpose  :
580 // =======================================================================
581 bool AIS_ViewController::UpdateMouseButtons (const Graphic3d_Vec2i& thePoint,
582                                              Aspect_VKeyMouse theButtons,
583                                              Aspect_VKeyFlags theModifiers,
584                                              bool theIsEmulated)
585 {
586   bool toUpdateView = false;
587   const double aTolClick = (theIsEmulated ? myTouchToleranceScale : 1.0) * myMouseClickThreshold;
588   if (theButtons == Aspect_VKeyMouse_NONE
589    && myMouseSingleButton > 0)
590   {
591     const Graphic3d_Vec2i aDelta = thePoint - myMousePressPoint;
592     if (double(aDelta.cwiseAbs().maxComp()) < aTolClick)
593     {
594       ++myMouseClickCounter;
595       const bool isDoubleClick = myMouseClickCounter == 2
596                               && myMouseClickTimer.IsStarted()
597                               && myMouseClickTimer.ElapsedTime() <= myMouseDoubleClickInt;
598
599       myMouseClickTimer.Stop();
600       myMouseClickTimer.Reset();
601       myMouseClickTimer.Start();
602       if (isDoubleClick)
603       {
604         myMouseClickCounter = 0;
605       }
606       toUpdateView = UpdateMouseClick (thePoint, (Aspect_VKeyMouse )myMouseSingleButton, theModifiers, isDoubleClick) || toUpdateView;
607     }
608     else
609     {
610       myMouseClickTimer.Stop();
611       myMouseClickCounter = 0;
612       myUI.Dragging.ToStop = true;
613       toUpdateView = true;
614     }
615     myMouseSingleButton = -1;
616   }
617   else if (theButtons == Aspect_VKeyMouse_NONE)
618   {
619     myMouseSingleButton = -1;
620   }
621   else if (myMouseSingleButton == -1)
622   {
623     if ((theButtons & Aspect_VKeyMouse_LeftButton) == Aspect_VKeyMouse_LeftButton)
624     {
625       myMouseSingleButton = Aspect_VKeyMouse_LeftButton;
626     }
627     else if ((theButtons & Aspect_VKeyMouse_RightButton) == Aspect_VKeyMouse_RightButton)
628     {
629       myMouseSingleButton = Aspect_VKeyMouse_RightButton;
630     }
631     else if ((theButtons & Aspect_VKeyMouse_MiddleButton) == Aspect_VKeyMouse_MiddleButton)
632     {
633       myMouseSingleButton = Aspect_VKeyMouse_MiddleButton;
634     }
635     else
636     {
637       myMouseSingleButton = 0;
638     }
639     if (myMouseSingleButton != 0)
640     {
641       if (myMouseClickCounter == 1)
642       {
643         const Graphic3d_Vec2i aDelta = thePoint - myMousePressPoint;
644         if (double(aDelta.cwiseAbs().maxComp()) >= aTolClick)
645         {
646           myMouseClickTimer.Stop();
647           myMouseClickCounter = 0;
648         }
649       }
650       myMousePressPoint = thePoint;
651     }
652   }
653   else
654   {
655     myMouseSingleButton = 0;
656
657     myUI.Dragging.ToAbort = true;
658     toUpdateView = true;
659   }
660
661   const AIS_MouseGesture aPrevGesture = myMouseActiveGesture;
662   myMouseModifiers = theModifiers;
663   myMousePressed   = theButtons;
664   if (theIsEmulated
665    || myNavigationMode != AIS_NavigationMode_FirstPersonWalk)
666   {
667     myMouseActiveIdleRotation = false;
668     myMouseActiveGesture = AIS_MouseGesture_NONE;
669     if (theButtons != 0)
670     {
671       myMousePressPoint    = thePoint;
672       myMouseProgressPoint = myMousePressPoint;
673     }
674
675     if (myMouseGestureMap.Find (theButtons | theModifiers, myMouseActiveGesture))
676     {
677       switch (myMouseActiveGesture)
678       {
679         case AIS_MouseGesture_RotateView:
680         case AIS_MouseGesture_RotateOrbit:
681         {
682           if (myToAllowRotation)
683           {
684             myUpdateStartPointRot = true;
685           }
686           else
687           {
688             myMouseActiveGesture = AIS_MouseGesture_NONE;
689           }
690           break;
691         }
692         case AIS_MouseGesture_Pan:
693         {
694           if (myToAllowPanning)
695           {
696             myUpdateStartPointPan = true;
697           }
698           else
699           {
700             myMouseActiveGesture = AIS_MouseGesture_NONE;
701           }
702           break;
703         }
704         case AIS_MouseGesture_Zoom:
705         {
706           if (!myToAllowZooming)
707           {
708             myMouseActiveGesture = AIS_MouseGesture_NONE;
709           }
710           break;
711         }
712         case AIS_MouseGesture_SelectRectangle:
713         {
714           break;
715         }
716         case AIS_MouseGesture_SelectLasso:
717         {
718           UpdatePolySelection (thePoint, true);
719           break;
720         }
721         case AIS_MouseGesture_NONE:
722         {
723           break;
724         }
725       }
726     }
727
728     if (theButtons == Aspect_VKeyMouse_LeftButton
729      && theModifiers == Aspect_VKeyFlags_NONE
730      && myToAllowDragging)
731     {
732       myUI.Dragging.ToStart = true;
733       myUI.Dragging.PointStart = thePoint;
734     }
735   }
736
737   if (aPrevGesture != myMouseActiveGesture)
738   {
739     if (aPrevGesture == AIS_MouseGesture_SelectRectangle
740      || aPrevGesture == AIS_MouseGesture_SelectLasso)
741     {
742       myUI.Selection.ToApplyTool = true;
743     }
744
745     myUI.IsNewGesture = true;
746     toUpdateView = true;
747   }
748   return toUpdateView;
749 }
750
751 // =======================================================================
752 // function : UpdateMousePosition
753 // purpose  :
754 // =======================================================================
755 bool AIS_ViewController::UpdateMousePosition (const Graphic3d_Vec2i& thePoint,
756                                               Aspect_VKeyMouse theButtons,
757                                               Aspect_VKeyFlags theModifiers,
758                                               bool theIsEmulated)
759 {
760   myMousePositionLast = thePoint;
761   if (myMouseSingleButton > 0)
762   {
763     const double aTolClick = (theIsEmulated ? myTouchToleranceScale : 1.0) * myMouseClickThreshold;
764     const Graphic3d_Vec2i aPressDelta = thePoint - myMousePressPoint;
765     if (double(aPressDelta.cwiseAbs().maxComp()) >= aTolClick)
766     {
767       myMouseClickTimer.Stop();
768       myMouseClickCounter = 0;
769       myMouseSingleButton = -1;
770     }
771   }
772
773   bool toUpdateView = false;
774   Graphic3d_Vec2i aDelta = thePoint - myMouseProgressPoint;
775   if (!theIsEmulated
776     && myNavigationMode == AIS_NavigationMode_FirstPersonWalk)
777   {
778     if (!myMouseActiveIdleRotation
779       || myMouseActiveGesture != AIS_MouseGesture_RotateView)
780     {
781       myMouseActiveIdleRotation = true;
782       myMouseActiveGesture = AIS_MouseGesture_RotateView;
783       myMousePressPoint     = thePoint;
784       myMouseProgressPoint  = thePoint;
785       myUpdateStartPointRot = false;
786       myUI.ViewRotation.ToStart = true;
787       myUI.ViewRotation.PointStart.SetValues (thePoint.x(), thePoint.y());
788       myUI.ViewRotation.ToRotate = false;
789       aDelta.SetValues (0, 0);
790     }
791   }
792   else
793   {
794     if (myMouseActiveIdleRotation
795      && myMouseActiveGesture == AIS_MouseGesture_RotateView)
796     {
797       myMouseActiveGesture = AIS_MouseGesture_NONE;
798     }
799     myMouseActiveIdleRotation = false;
800   }
801
802   if (myMouseModifiers != theModifiers
803    && UpdateMouseButtons (thePoint, theButtons, theModifiers, theIsEmulated))
804   {
805     toUpdateView = true;
806   }
807
808   switch (myMouseActiveGesture)
809   {
810     case AIS_MouseGesture_SelectRectangle:
811     {
812       UpdateRubberBand (myMousePressPoint, thePoint);
813       toUpdateView = true;
814       break;
815     }
816     case AIS_MouseGesture_SelectLasso:
817     {
818       UpdatePolySelection (thePoint, true);
819       toUpdateView = true;
820       break;
821     }
822     case AIS_MouseGesture_RotateOrbit:
823     case AIS_MouseGesture_RotateView:
824     {
825       if (!myToAllowRotation)
826       {
827         break;
828       }
829       if (myUpdateStartPointRot)
830       {
831         if (myMouseActiveGesture == AIS_MouseGesture_RotateOrbit)
832         {
833           myUI.OrbitRotation.ToStart = true;
834           myUI.OrbitRotation.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y());
835         }
836         else
837         {
838           myUI.ViewRotation.ToStart = true;
839           myUI.ViewRotation.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y());
840         }
841         myUpdateStartPointRot = false;
842       }
843
844       const double aRotTol = theIsEmulated
845                            ? double(myTouchToleranceScale) * myTouchRotationThresholdPx
846                            : 0.0;
847       if (double (Abs (aDelta.x()) + Abs (aDelta.y())) > aRotTol)
848       {
849         const double aRotAccel = myNavigationMode == AIS_NavigationMode_FirstPersonWalk ? myMouseAccel : myOrbitAccel;
850         const Graphic3d_Vec2i aRotDelta = thePoint - myMousePressPoint;
851         if (myMouseActiveGesture == AIS_MouseGesture_RotateOrbit)
852         {
853           myUI.OrbitRotation.ToRotate = true;
854           myUI.OrbitRotation.PointTo = Graphic3d_Vec2d (myMousePressPoint.x(), myMousePressPoint.y())
855                                      + Graphic3d_Vec2d (aRotDelta.x(), aRotDelta.y()) * aRotAccel;
856         }
857         else
858         {
859           myUI.ViewRotation.ToRotate = true;
860           myUI.ViewRotation.PointTo = Graphic3d_Vec2d (myMousePressPoint.x(), myMousePressPoint.y())
861                                     + Graphic3d_Vec2d (aRotDelta.x(), aRotDelta.y()) * aRotAccel;
862         }
863         myUI.Dragging.PointTo = thePoint;
864
865         myMouseProgressPoint = thePoint;
866         toUpdateView = true;
867       }
868       break;
869     }
870     case AIS_MouseGesture_Zoom:
871     {
872       if (!myToAllowZooming)
873       {
874         break;
875       }
876       const double aZoomTol = theIsEmulated
877                             ? double(myTouchToleranceScale) * myTouchZoomThresholdPx
878                             : 0.0;
879       if (double (Abs (aDelta.x())) > aZoomTol)
880       {
881         if (UpdateZoom (Aspect_ScrollDelta (aDelta.x())))
882         {
883           toUpdateView = true;
884         }
885         myMouseProgressPoint = thePoint;
886       }
887       break;
888     }
889     case AIS_MouseGesture_Pan:
890     {
891       if (!myToAllowPanning)
892       {
893         break;
894       }
895       const double aPanTol = theIsEmulated
896                            ? double(myTouchToleranceScale) * myTouchPanThresholdPx
897                            : 0.0;
898       if (double (Abs (aDelta.x()) + Abs (aDelta.y())) > aPanTol)
899       {
900         if (myUpdateStartPointPan)
901         {
902           myUI.Panning.ToStart = true;
903           myUI.Panning.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y());
904           myUpdateStartPointPan = false;
905         }
906
907         aDelta.y() = -aDelta.y();
908         myMouseProgressPoint = thePoint;
909         if (myUI.Panning.ToPan)
910         {
911           myUI.Panning.Delta += aDelta;
912         }
913         else
914         {
915           myUI.Panning.ToPan = true;
916           myUI.Panning.Delta = aDelta;
917         }
918         toUpdateView = true;
919       }
920       break;
921     }
922     default:
923     {
924       break;
925     }
926   }
927
928   if (theButtons == Aspect_VKeyMouse_NONE
929   &&  myNavigationMode != AIS_NavigationMode_FirstPersonWalk
930   && !theIsEmulated
931   && !HasTouchPoints()
932   &&  myToAllowHighlight)
933   {
934     myUI.MoveTo.ToHilight = true;
935     myUI.MoveTo.Point = thePoint;
936     toUpdateView = true;
937   }
938   return toUpdateView;
939 }
940
941 // =======================================================================
942 // function : AddTouchPoint
943 // purpose  :
944 // =======================================================================
945 void AIS_ViewController::AddTouchPoint (Standard_Size theId,
946                                         const Graphic3d_Vec2d& thePnt,
947                                         Standard_Boolean theClearBefore)
948 {
949   myUI.MoveTo.ToHilight = false;
950   if (theClearBefore)
951   {
952     RemoveTouchPoint ((Standard_Size )-1);
953   }
954
955   myTouchPoints.Add (theId, Aspect_Touch (thePnt, false));
956   if (myTouchPoints.Extent() == 1)
957   {
958     myUpdateStartPointRot = true;
959     myStartRotCoord = thePnt;
960     if (myToAllowDragging)
961     {
962       myUI.Dragging.ToStart = true;
963       myUI.Dragging.PointStart.SetValues ((int )thePnt.x(), (int )thePnt.y());
964     }
965   }
966   else if (myTouchPoints.Extent() == 2)
967   {
968     myUI.Dragging.ToAbort = true;
969
970     myUpdateStartPointPan = true;
971     myStartPanCoord = thePnt;
972   }
973   myUI.IsNewGesture = true;
974 }
975
976 // =======================================================================
977 // function : RemoveTouchPoint
978 // purpose  :
979 // =======================================================================
980 bool AIS_ViewController::RemoveTouchPoint (Standard_Size theId,
981                                            Standard_Boolean theClearSelectPnts)
982 {
983   if (theId == (Standard_Size )-1)
984   {
985     myTouchPoints.Clear (false);
986   }
987   else
988   {
989     const Standard_Integer anOldExtent = myTouchPoints.Extent();
990     myTouchPoints.RemoveKey (theId);
991     if (myTouchPoints.Extent() == anOldExtent)
992     {
993       return false;
994     }
995   }
996
997   if (myTouchPoints.Extent() == 1)
998   {
999     // avoid incorrect transition from pinch to one finger
1000     Aspect_Touch& aFirstTouch = myTouchPoints.ChangeFromIndex (1);
1001     aFirstTouch.To = aFirstTouch.From;
1002
1003     myStartRotCoord = aFirstTouch.To;
1004     myUpdateStartPointRot = true;
1005   }
1006   else if (myTouchPoints.Extent() == 2)
1007   {
1008     myStartPanCoord = myTouchPoints.FindFromIndex (1).To;
1009     myUpdateStartPointPan = true;
1010   }
1011   else if (myTouchPoints.IsEmpty())
1012   {
1013     if (theClearSelectPnts)
1014     {
1015       myUI.Selection.ToApplyTool = true;
1016     }
1017
1018     myUI.Dragging.ToStop = true;
1019   }
1020   myUI.IsNewGesture = true;
1021   return true;
1022 }
1023
1024 // =======================================================================
1025 // function : UpdateTouchPoint
1026 // purpose  :
1027 // =======================================================================
1028 void AIS_ViewController::UpdateTouchPoint (Standard_Size theId,
1029                                            const Graphic3d_Vec2d& thePnt)
1030 {
1031   if (Aspect_Touch* aTouch = myTouchPoints.ChangeSeek (theId))
1032   {
1033     aTouch->To = thePnt;
1034   }
1035   else
1036   {
1037     AddTouchPoint (theId, thePnt);
1038   }
1039 }
1040
1041 // =======================================================================
1042 // function : SetNavigationMode
1043 // purpose  :
1044 // =======================================================================
1045 void AIS_ViewController::SetNavigationMode (AIS_NavigationMode theMode)
1046 {
1047   myNavigationMode = theMode;
1048
1049   // abort rotation
1050   myUI.OrbitRotation.ToStart  = false;
1051   myUI.OrbitRotation.ToRotate = false;
1052   myUI.ViewRotation.ToStart   = false;
1053   myUI.ViewRotation.ToRotate  = false;
1054 }
1055
1056 // =======================================================================
1057 // function : KeyDown
1058 // purpose  :
1059 // =======================================================================
1060 void AIS_ViewController::KeyDown (Aspect_VKey theKey,
1061                                   double theTime,
1062                                   double thePressure)
1063 {
1064   myKeys.KeyDown (theKey, theTime, thePressure);
1065 }
1066
1067 // =======================================================================
1068 // function : KeyUp
1069 // purpose  :
1070 // =======================================================================
1071 void AIS_ViewController::KeyUp (Aspect_VKey theKey,
1072                                 double theTime)
1073 {
1074   myKeys.KeyUp (theKey, theTime);
1075 }
1076
1077 // =======================================================================
1078 // function : KeyFromAxis
1079 // purpose  :
1080 // =======================================================================
1081 void AIS_ViewController::KeyFromAxis (Aspect_VKey theNegative,
1082                                       Aspect_VKey thePositive,
1083                                       double theTime,
1084                                       double thePressure)
1085 {
1086   myKeys.KeyFromAxis (theNegative, thePositive, theTime, thePressure);
1087 }
1088
1089 // =======================================================================
1090 // function : FetchNavigationKeys
1091 // purpose  :
1092 // =======================================================================
1093 AIS_WalkDelta AIS_ViewController::FetchNavigationKeys (Standard_Real theCrouchRatio,
1094                                                        Standard_Real theRunRatio)
1095 {
1096   AIS_WalkDelta aWalk;
1097
1098   // navigation keys
1099   double aPrevEventTime = 0.0, aNewEventTime = 0.0;
1100   updateEventsTime (aPrevEventTime, aNewEventTime);
1101
1102   double aDuration = 0.0, aPressure = 1.0;
1103   if (Abs (myThrustSpeed) > gp::Resolution())
1104   {
1105     if (myHasThrust)
1106     {
1107       aWalk[AIS_WalkTranslation_Forward].Value = myThrustSpeed * (aNewEventTime - aPrevEventTime);
1108     }
1109     myHasThrust = true;
1110     myToAskNextFrame = true;
1111   }
1112   else
1113   {
1114     myHasThrust = false;
1115   }
1116
1117   aWalk.SetRunning (theRunRatio > 1.0
1118                  && myKeys.IsKeyDown (Aspect_VKey_Shift));
1119   if (myKeys.HoldDuration (Aspect_VKey_NavJump, aNewEventTime, aDuration))
1120   {
1121     myKeys.KeyUp (Aspect_VKey_NavJump, aNewEventTime);
1122     aWalk.SetJumping (true);
1123   }
1124   if (!aWalk.IsJumping()
1125    && theCrouchRatio < 1.0
1126    && myKeys.HoldDuration (Aspect_VKey_NavCrouch, aNewEventTime, aDuration))
1127   {
1128     aWalk.SetRunning (false);
1129     aWalk.SetCrouching (true);
1130   }
1131
1132   const double aMaxDuration = aNewEventTime - aPrevEventTime;
1133   const double aRunRatio = aWalk.IsRunning()
1134                          ? theRunRatio
1135                          : aWalk.IsCrouching()
1136                           ? theCrouchRatio
1137                           : 1.0;
1138   if (myKeys.HoldDuration (Aspect_VKey_NavForward, aNewEventTime, aDuration, aPressure))
1139   {
1140     double aProgress = Abs (Min (aMaxDuration, aDuration));
1141     aProgress *= aRunRatio;
1142     aWalk[AIS_WalkTranslation_Forward].Value += aProgress;
1143     aWalk[AIS_WalkTranslation_Forward].Pressure = aPressure;
1144     aWalk[AIS_WalkTranslation_Forward].Duration = aDuration;
1145   }
1146   if (myKeys.HoldDuration (Aspect_VKey_NavBackward, aNewEventTime, aDuration, aPressure))
1147   {
1148     double aProgress = Abs (Min (aMaxDuration, aDuration));
1149     aProgress *= aRunRatio;
1150     aWalk[AIS_WalkTranslation_Forward].Value += -aProgress;
1151     aWalk[AIS_WalkTranslation_Forward].Pressure = aPressure;
1152     aWalk[AIS_WalkTranslation_Forward].Duration = aDuration;
1153   }
1154   if (myKeys.HoldDuration (Aspect_VKey_NavSlideLeft, aNewEventTime, aDuration, aPressure))
1155   {
1156     double aProgress = Abs (Min (aMaxDuration, aDuration));
1157     aProgress *= aRunRatio;
1158     aWalk[AIS_WalkTranslation_Side].Value = -aProgress;
1159     aWalk[AIS_WalkTranslation_Side].Pressure = aPressure;
1160     aWalk[AIS_WalkTranslation_Side].Duration = aDuration;
1161   }
1162   if (myKeys.HoldDuration (Aspect_VKey_NavSlideRight, aNewEventTime, aDuration, aPressure))
1163   {
1164     double aProgress = Abs (Min (aMaxDuration, aDuration));
1165     aProgress *= aRunRatio;
1166     aWalk[AIS_WalkTranslation_Side].Value = aProgress;
1167     aWalk[AIS_WalkTranslation_Side].Pressure = aPressure;
1168     aWalk[AIS_WalkTranslation_Side].Duration = aDuration;
1169   }
1170   if (myKeys.HoldDuration (Aspect_VKey_NavLookLeft, aNewEventTime, aDuration, aPressure))
1171   {
1172     double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1173     aWalk[AIS_WalkRotation_Yaw].Value = aProgress;
1174     aWalk[AIS_WalkRotation_Yaw].Pressure = aPressure;
1175     aWalk[AIS_WalkRotation_Yaw].Duration = aDuration;
1176   }
1177   if (myKeys.HoldDuration (Aspect_VKey_NavLookRight, aNewEventTime, aDuration, aPressure))
1178   {
1179     double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1180     aWalk[AIS_WalkRotation_Yaw].Value = -aProgress;
1181     aWalk[AIS_WalkRotation_Yaw].Pressure = aPressure;
1182     aWalk[AIS_WalkRotation_Yaw].Duration = aDuration;
1183   }
1184   if (myKeys.HoldDuration (Aspect_VKey_NavLookUp, aNewEventTime, aDuration, aPressure))
1185   {
1186     double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1187     aWalk[AIS_WalkRotation_Pitch].Value = !myToInvertPitch ? -aProgress : aProgress;
1188     aWalk[AIS_WalkRotation_Pitch].Pressure = aPressure;
1189     aWalk[AIS_WalkRotation_Pitch].Duration = aDuration;
1190   }
1191   if (myKeys.HoldDuration (Aspect_VKey_NavLookDown, aNewEventTime, aDuration, aPressure))
1192   {
1193     double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1194     aWalk[AIS_WalkRotation_Pitch].Value = !myToInvertPitch ? aProgress : -aProgress;
1195     aWalk[AIS_WalkRotation_Pitch].Pressure = aPressure;
1196     aWalk[AIS_WalkRotation_Pitch].Duration = aDuration;
1197   }
1198   if (myKeys.HoldDuration (Aspect_VKey_NavRollCCW, aNewEventTime, aDuration, aPressure))
1199   {
1200     double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1201     aWalk[AIS_WalkRotation_Roll].Value = -aProgress;
1202     aWalk[AIS_WalkRotation_Roll].Pressure = aPressure;
1203     aWalk[AIS_WalkRotation_Roll].Duration = aDuration;
1204   }
1205   if (myKeys.HoldDuration (Aspect_VKey_NavRollCW, aNewEventTime, aDuration, aPressure))
1206   {
1207     double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1208     aWalk[AIS_WalkRotation_Roll].Value = aProgress;
1209     aWalk[AIS_WalkRotation_Roll].Pressure = aPressure;
1210     aWalk[AIS_WalkRotation_Roll].Duration = aDuration;
1211   }
1212   if (myKeys.HoldDuration (Aspect_VKey_NavSlideUp, aNewEventTime, aDuration, aPressure))
1213   {
1214     double aProgress = Abs (Min (aMaxDuration, aDuration));
1215     aWalk[AIS_WalkTranslation_Up].Value = aProgress;
1216     aWalk[AIS_WalkTranslation_Up].Pressure = aPressure;
1217     aWalk[AIS_WalkTranslation_Up].Duration = aDuration;
1218   }
1219   if (myKeys.HoldDuration (Aspect_VKey_NavSlideDown, aNewEventTime, aDuration, aPressure))
1220   {
1221     double aProgress = Abs (Min (aMaxDuration, aDuration));
1222     aWalk[AIS_WalkTranslation_Up].Value = -aProgress;
1223     aWalk[AIS_WalkTranslation_Up].Pressure = aPressure;
1224     aWalk[AIS_WalkTranslation_Up].Duration = aDuration;
1225   }
1226   return aWalk;
1227 }
1228
1229 // =======================================================================
1230 // function : AbortViewAnimation
1231 // purpose  :
1232 // =======================================================================
1233 void AIS_ViewController::AbortViewAnimation()
1234 {
1235   if (!myViewAnimation.IsNull()
1236    && !myViewAnimation->IsStopped())
1237   {
1238     myViewAnimation->Stop();
1239     myViewAnimation->SetView (Handle(V3d_View)());
1240   }
1241 }
1242
1243 // =======================================================================
1244 // function : handlePanning
1245 // purpose  :
1246 // =======================================================================
1247 void AIS_ViewController::handlePanning (const Handle(V3d_View)& theView)
1248 {
1249   if (!myGL.Panning.ToPan
1250    || !myToAllowPanning)
1251   {
1252     return;
1253   }
1254
1255   AbortViewAnimation();
1256
1257   const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1258   if (aCam->IsOrthographic()
1259   || !hasPanningAnchorPoint())
1260   {
1261     theView->Pan (myGL.Panning.Delta.x(), myGL.Panning.Delta.y());
1262     theView->Invalidate();
1263     return;
1264   }
1265
1266   Graphic3d_Vec2i aWinSize;
1267   theView->Window()->Size (aWinSize.x(), aWinSize.y());
1268
1269   const gp_Dir& aDir = aCam->Direction();
1270   const gp_Ax3 aCameraCS (aCam->Center(), aDir.Reversed(), aDir ^ aCam->Up());
1271   const gp_XYZ anEyeToPnt = myPanPnt3d.XYZ() - aCam->Eye().XYZ();
1272   const gp_Pnt aViewDims = aCam->ViewDimensions (anEyeToPnt.Dot (aCam->Direction().XYZ())); // view dimensions at 3D point
1273   const Graphic3d_Vec2d aDxy (-aViewDims.X() * myGL.Panning.Delta.x() / double(aWinSize.x()),
1274                               -aViewDims.X() * myGL.Panning.Delta.y() / double(aWinSize.x()));
1275
1276   //theView->Translate (aCam, aDxy.x(), aDxy.y());
1277   gp_Trsf aPanTrsf;
1278   const gp_Vec aCameraPan = gp_Vec (aCameraCS.XDirection()) * aDxy.x()
1279                           + gp_Vec (aCameraCS.YDirection()) * aDxy.y();
1280   aPanTrsf.SetTranslation (aCameraPan);
1281   aCam->Transform (aPanTrsf);
1282   theView->Invalidate();
1283 }
1284
1285 // =======================================================================
1286 // function : handleZRotate
1287 // purpose  :
1288 // =======================================================================
1289 void AIS_ViewController::handleZRotate (const Handle(V3d_View)& theView)
1290 {
1291   if (!myGL.ZRotate.ToRotate
1292    || !myToAllowRotation)
1293   {
1294     return;
1295   }
1296
1297   AbortViewAnimation();
1298
1299   Graphic3d_Vec2i aViewPort;
1300   theView->Window()->Size (aViewPort.x(), aViewPort.y());
1301   Graphic3d_Vec2d aRotPnt (0.99 * aViewPort.x(),
1302                            0.5  * aViewPort.y());
1303   theView->StartRotation (int(aRotPnt.x()), int(aRotPnt.y()), 0.4);
1304   aRotPnt.y() += myGL.ZRotate.Angle * aViewPort.y();
1305   theView->Rotation (int(aRotPnt.x()), int(aRotPnt.y()));
1306   theView->Invalidate();
1307 }
1308
1309 // =======================================================================
1310 // function : handleZoom
1311 // purpose  :
1312 // =======================================================================
1313 void AIS_ViewController::handleZoom (const Handle(V3d_View)& theView,
1314                                      const Aspect_ScrollDelta& theParams,
1315                                      const gp_Pnt* thePnt)
1316 {
1317   if (!myToAllowZooming)
1318   {
1319     return;
1320   }
1321
1322   AbortViewAnimation();
1323
1324   const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1325   if (thePnt != NULL)
1326   {
1327     const double aViewDist = Max (myMinCamDistance, (thePnt->XYZ() - aCam->Eye().XYZ()).Modulus());
1328     aCam->SetCenter (aCam->Eye().XYZ() + aCam->Direction().XYZ() * aViewDist);
1329   }
1330
1331   if (!theParams.HasPoint())
1332   {
1333     Standard_Real aCoeff = Abs(theParams.Delta) / 100.0 + 1.0;
1334     aCoeff = theParams.Delta > 0.0 ? aCoeff : 1.0 / aCoeff;
1335     theView->SetZoom (aCoeff, true);
1336     theView->Invalidate();
1337     return;
1338   }
1339
1340   // integer delta is too rough for small smooth increments
1341   //theView->StartZoomAtPoint (theParams.Point.x(), theParams.Point.y());
1342   //theView->ZoomAtPoint (0, 0, (int )theParams.Delta, (int )theParams.Delta);
1343
1344   double aDZoom = Abs (theParams.Delta) / 100.0 + 1.0;
1345   aDZoom = (theParams.Delta > 0.0) ? aDZoom : 1.0 / aDZoom;
1346   if (aDZoom <= 0.0)
1347   {
1348     return;
1349   }
1350
1351   const Graphic3d_Vec2d aViewDims (aCam->ViewDimensions().X(), aCam->ViewDimensions().Y());
1352
1353   // ensure that zoom will not be too small or too big
1354   double aCoef = aDZoom;
1355   if (aViewDims.x() < aCoef * Precision::Confusion())
1356   {
1357     aCoef = aViewDims.x() / Precision::Confusion();
1358   }
1359   else if (aViewDims.x() > aCoef * 1e12)
1360   {
1361     aCoef = aViewDims.x() / 1e12;
1362   }
1363   if (aViewDims.y() < aCoef * Precision::Confusion())
1364   {
1365     aCoef = aViewDims.y() / Precision::Confusion();
1366   }
1367   else if (aViewDims.y() > aCoef * 1e12)
1368   {
1369     aCoef = aViewDims.y() / 1e12;
1370   }
1371
1372   Graphic3d_Vec2d aZoomAtPointXYv (0.0, 0.0);
1373   theView->Convert (theParams.Point.x(), theParams.Point.y(),
1374                     aZoomAtPointXYv.x(), aZoomAtPointXYv.y());
1375   Graphic3d_Vec2d aDxy = aZoomAtPointXYv / aCoef;
1376   aCam->SetScale (aCam->Scale() / aCoef);
1377
1378   const gp_Dir& aDir = aCam->Direction();
1379   const gp_Ax3 aCameraCS (aCam->Center(), aDir.Reversed(), aDir ^ aCam->Up());
1380
1381   // pan back to the point
1382   aDxy = aZoomAtPointXYv - aDxy;
1383   if (thePnt != NULL)
1384   {
1385     // zoom at 3D point with perspective projection
1386     const gp_XYZ anEyeToPnt = thePnt->XYZ() - aCam->Eye().XYZ();
1387     aDxy.SetValues (anEyeToPnt.Dot (aCameraCS.XDirection().XYZ()),
1388                     anEyeToPnt.Dot (aCameraCS.YDirection().XYZ()));
1389
1390     // view dimensions at 3D point
1391     const gp_Pnt aViewDims1 = aCam->ViewDimensions (anEyeToPnt.Dot (aCam->Direction().XYZ()));
1392
1393     Graphic3d_Vec2i aWinSize;
1394     theView->Window()->Size (aWinSize.x(), aWinSize.y());
1395     const Graphic3d_Vec2d aPanFromCenterPx (double(theParams.Point.x()) - 0.5 * double(aWinSize.x()),
1396                                             double(theParams.Point.y()) - 0.5 * double(aWinSize.y()));
1397     aDxy.x() += -aViewDims1.X() * aPanFromCenterPx.x() / double(aWinSize.x());
1398     aDxy.y() +=  aViewDims1.X() * aPanFromCenterPx.y() / double(aWinSize.x());
1399   }
1400
1401   //theView->Translate (aCam, aDxy.x(), aDxy.y());
1402   gp_Trsf aPanTrsf;
1403   const gp_Vec aCameraPan = gp_Vec (aCameraCS.XDirection()) * aDxy.x()
1404                           + gp_Vec (aCameraCS.YDirection()) * aDxy.y();
1405   aPanTrsf.SetTranslation (aCameraPan);
1406   aCam->Transform (aPanTrsf);
1407   theView->Invalidate();
1408 }
1409
1410 // =======================================================================
1411 // function : handleZFocusScroll
1412 // purpose  :
1413 // =======================================================================
1414 void AIS_ViewController::handleZFocusScroll (const Handle(V3d_View)& theView,
1415                                              const Aspect_ScrollDelta& theParams)
1416 {
1417   if (!myToAllowZFocus
1418    || !theView->Camera()->IsStereo())
1419   {
1420     return;
1421   }
1422
1423   Standard_Real aFocus = theView->Camera()->ZFocus() + (theParams.Delta > 0.0 ? 0.05 : -0.05);
1424   if (aFocus > 0.2
1425    && aFocus < 2.0)
1426   {
1427     theView->Camera()->SetZFocus (theView->Camera()->ZFocusType(), aFocus);
1428     theView->Redraw();
1429   }
1430 }
1431
1432 // =======================================================================
1433 // function : handleOrbitRotation
1434 // purpose  :
1435 // =======================================================================
1436 void AIS_ViewController::handleOrbitRotation (const Handle(V3d_View)& theView,
1437                                               const gp_Pnt& thePnt,
1438                                               bool theToLockZUp)
1439 {
1440   if (!myToAllowRotation)
1441   {
1442     return;
1443   }
1444
1445   const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1446   if (myGL.OrbitRotation.ToStart)
1447   {
1448     // default alternatives
1449     //if (myRotationMode == AIS_RotationMode_BndBoxActive) theView->StartRotation (myGL.RotateAtPoint.x(), myGL.RotateAtPoint.y());
1450     //theView->Rotate (0.0, 0.0, 0.0, thePnt.X(), thePnt.Y(), thePnt.Z(), true);
1451
1452     myRotatePnt3d      = thePnt;
1453     myCamStartOpUp     = aCam->Up();
1454     myCamStartOpEye    = aCam->Eye();
1455     myCamStartOpCenter = aCam->Center();
1456
1457     gp_Trsf aTrsf;
1458     aTrsf.SetTransformation (gp_Ax3 (myRotatePnt3d, aCam->OrthogonalizedUp(), aCam->Direction()),
1459                              gp_Ax3 (myRotatePnt3d, gp::DZ(), gp::DX()));
1460     const gp_Quaternion aRot = aTrsf.GetRotation();
1461     aRot.GetEulerAngles (gp_YawPitchRoll, myRotateStartYawPitchRoll[0], myRotateStartYawPitchRoll[1], myRotateStartYawPitchRoll[2]);
1462
1463     aTrsf.Invert();
1464     myCamStartOpToEye    = gp_Vec (myRotatePnt3d, aCam->Eye()).Transformed (aTrsf);
1465     myCamStartOpToCenter = gp_Vec (myRotatePnt3d, aCam->Center()).Transformed (aTrsf);
1466
1467     theView->Invalidate();
1468   }
1469
1470   if (!myGL.OrbitRotation.ToRotate)
1471   {
1472     return;
1473   }
1474
1475   AbortViewAnimation();
1476   if (theToLockZUp)
1477   {
1478     // amend camera to exclude roll angle (put camera Up vector to plane containing global Z and view direction)
1479     Graphic3d_Vec2i aWinXY;
1480     theView->Window()->Size (aWinXY.x(), aWinXY.y());
1481     double aYawAngleDelta   =  ((myGL.OrbitRotation.PointStart.x() - myGL.OrbitRotation.PointTo.x()) / double (aWinXY.x())) * (M_PI * 0.5);
1482     double aPitchAngleDelta = -((myGL.OrbitRotation.PointStart.y() - myGL.OrbitRotation.PointTo.y()) / double (aWinXY.y())) * (M_PI * 0.5);
1483     const double aPitchAngleNew = Max (Min (myRotateStartYawPitchRoll[1] + aPitchAngleDelta, M_PI * 0.5 - M_PI / 180.0), -M_PI * 0.5 + M_PI / 180.0);
1484     const double aYawAngleNew   = myRotateStartYawPitchRoll[0] + aYawAngleDelta;
1485     const double aRoll = 0.0;
1486
1487     gp_Quaternion aRot;
1488     aRot.SetEulerAngles (gp_YawPitchRoll, aYawAngleNew, aPitchAngleNew, aRoll);
1489     gp_Trsf aTrsfRot;
1490     aTrsfRot.SetRotation (aRot);
1491
1492     const gp_Dir aNewUp = gp::DZ().Transformed (aTrsfRot);
1493     aCam->SetUp (aNewUp);
1494     aCam->SetCenter(myRotatePnt3d.XYZ() + myCamStartOpToCenter.Transformed (aTrsfRot).XYZ());
1495     aCam->SetEye   (myRotatePnt3d.XYZ() + myCamStartOpToEye   .Transformed (aTrsfRot).XYZ());
1496     aCam->OrthogonalizeUp();
1497   }
1498   else
1499   {
1500     // default alternatives
1501     //if (myRotationMode == AIS_RotationMode_BndBoxActive) theView->Rotation (myGL.RotateToPoint.x(), myGL.RotateToPoint.y());
1502     //theView->Rotate (aDX, aDY, aDZ, myRotatePnt3d.X(), myRotatePnt3d.Y(), myRotatePnt3d.Z(), false);
1503
1504     // restore previous camera state
1505     aCam->SetUp     (myCamStartOpUp);
1506     aCam->SetEye    (myCamStartOpEye);
1507     aCam->SetCenter (myCamStartOpCenter);
1508
1509     Graphic3d_Vec2d aWinXY;
1510     theView->Size (aWinXY.x(), aWinXY.y());
1511     const Standard_Real rx = (Standard_Real )theView->Convert (aWinXY.x());
1512     const Standard_Real ry = (Standard_Real )theView->Convert (aWinXY.y());
1513
1514     const double THE_2PI = M_PI * 2.0;
1515     double aDX = (myGL.OrbitRotation.PointTo.x() - myGL.OrbitRotation.PointStart.x()) * M_PI / rx;
1516     double aDY = (myGL.OrbitRotation.PointStart.y() - myGL.OrbitRotation.PointTo.y()) * M_PI / ry;
1517
1518     if     (aDX > 0.0) { while (aDX >  THE_2PI) { aDX -= THE_2PI; } }
1519     else if(aDX < 0.0) { while (aDX < -THE_2PI) { aDX += THE_2PI; } }
1520     if     (aDY > 0.0) { while (aDY >  THE_2PI) { aDY -= THE_2PI; } }
1521     else if(aDY < 0.0) { while (aDY < -THE_2PI) { aDY += THE_2PI; } }
1522
1523     // rotate camera around 3 initial axes
1524     gp_Dir aCamDir (aCam->Direction().Reversed());
1525     gp_Dir aCamUp  (aCam->Up());
1526     gp_Dir aCamSide(aCamUp.Crossed (aCamDir));
1527
1528     gp_Trsf aRot[2], aTrsf;
1529     aRot[0].SetRotation (gp_Ax1 (myRotatePnt3d, aCamUp),  -aDX);
1530     aRot[1].SetRotation (gp_Ax1 (myRotatePnt3d, aCamSide), aDY);
1531     aTrsf.Multiply (aRot[0]);
1532     aTrsf.Multiply (aRot[1]);
1533
1534     aCam->Transform (aTrsf);
1535   }
1536
1537   theView->Invalidate();
1538 }
1539
1540 // =======================================================================
1541 // function : handleViewRotation
1542 // purpose  :
1543 // =======================================================================
1544 void AIS_ViewController::handleViewRotation (const Handle(V3d_View)& theView,
1545                                              double theYawExtra,
1546                                              double thePitchExtra,
1547                                              double theRoll,
1548                                              bool theToRestartOnIncrement)
1549 {
1550   if (!myToAllowRotation)
1551   {
1552     return;
1553   }
1554
1555   const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1556   const bool toRotateAnyway = Abs (theYawExtra)   > gp::Resolution()
1557                            || Abs (thePitchExtra) > gp::Resolution()
1558                            || Abs (theRoll - myRotateStartYawPitchRoll[2]) > gp::Resolution();
1559   if (toRotateAnyway
1560    && theToRestartOnIncrement)
1561   {
1562     myGL.ViewRotation.ToStart = true;
1563     myGL.ViewRotation.PointTo = myGL.ViewRotation.PointStart;
1564   }
1565   if (myGL.ViewRotation.ToStart)
1566   {
1567     gp_Trsf aTrsf;
1568     aTrsf.SetTransformation (gp_Ax3 (gp::Origin(), aCam->OrthogonalizedUp(), aCam->Direction()),
1569                              gp_Ax3 (gp::Origin(), gp::DZ(), gp::DX()));
1570     const gp_Quaternion aRot = aTrsf.GetRotation();
1571     double aRollDummy = 0.0;
1572     aRot.GetEulerAngles (gp_YawPitchRoll, myRotateStartYawPitchRoll[0], myRotateStartYawPitchRoll[1], aRollDummy);
1573   }
1574   if (toRotateAnyway)
1575   {
1576     myRotateStartYawPitchRoll[0] += theYawExtra;
1577     myRotateStartYawPitchRoll[1] += thePitchExtra;
1578     myRotateStartYawPitchRoll[2]  = theRoll;
1579     myGL.ViewRotation.ToRotate = true;
1580   }
1581
1582   if (!myGL.ViewRotation.ToRotate)
1583   {
1584     return;
1585   }
1586
1587   AbortViewAnimation();
1588
1589   Graphic3d_Vec2i aWinXY;
1590   theView->Window()->Size (aWinXY.x(), aWinXY.y());
1591   double aYawAngleDelta   =  ((myGL.ViewRotation.PointStart.x() - myGL.ViewRotation.PointTo.x()) / double (aWinXY.x())) * (M_PI * 0.5);
1592   double aPitchAngleDelta = -((myGL.ViewRotation.PointStart.y() - myGL.ViewRotation.PointTo.y()) / double (aWinXY.y())) * (M_PI * 0.5);
1593   const double aPitchAngleNew = Max (Min (myRotateStartYawPitchRoll[1] + aPitchAngleDelta, M_PI * 0.5 - M_PI / 180.0), -M_PI * 0.5 + M_PI / 180.0);
1594   const double aYawAngleNew   = myRotateStartYawPitchRoll[0] + aYawAngleDelta;
1595   gp_Quaternion aRot;
1596   aRot.SetEulerAngles (gp_YawPitchRoll, aYawAngleNew, aPitchAngleNew, theRoll);
1597   gp_Trsf aTrsfRot;
1598   aTrsfRot.SetRotation (aRot);
1599
1600   const double aDist   = aCam->Distance();
1601   const gp_Dir aNewUp  = gp::DZ().Transformed (aTrsfRot);
1602   const gp_Dir aNewDir = gp::DX().Transformed (aTrsfRot);
1603   aCam->SetUp     (aNewUp);
1604   aCam->SetCenter (aCam->Eye().Translated (gp_Vec (aNewDir) * aDist));
1605   aCam->OrthogonalizeUp();
1606   theView->Invalidate();
1607 }
1608
1609 // =======================================================================
1610 // function : PickPoint
1611 // purpose  :
1612 // =======================================================================
1613 bool AIS_ViewController::PickPoint (gp_Pnt& thePnt,
1614                                     const Handle(AIS_InteractiveContext)& theCtx,
1615                                     const Handle(V3d_View)& theView,
1616                                     const Graphic3d_Vec2i& theCursor,
1617                                     bool theToStickToPickRay)
1618 {
1619   ResetPreviousMoveTo();
1620
1621   const Handle(StdSelect_ViewerSelector3d)& aSelector = theCtx->MainSelector();
1622   aSelector->Pick (theCursor.x(), theCursor.y(), theView);
1623   if (aSelector->NbPicked() < 1)
1624   {
1625     return false;
1626   }
1627
1628   const SelectMgr_SortCriterion& aPicked = aSelector->PickedData (1);
1629   if (theToStickToPickRay
1630   && !Precision::IsInfinite (aPicked.Depth))
1631   {
1632     thePnt = aSelector->GetManager().DetectedPoint (aPicked.Depth);
1633   }
1634   else
1635   {
1636     thePnt = aSelector->PickedPoint (1);
1637   }
1638   return !Precision::IsInfinite (thePnt.X())
1639       && !Precision::IsInfinite (thePnt.Y())
1640       && !Precision::IsInfinite (thePnt.Z());
1641 }
1642
1643 // =======================================================================
1644 // function : GravityPoint
1645 // purpose  :
1646 // =======================================================================
1647 gp_Pnt AIS_ViewController::GravityPoint (const Handle(AIS_InteractiveContext)& theCtx,
1648                                          const Handle(V3d_View)& theView)
1649 {
1650   switch (myRotationMode)
1651   {
1652     case AIS_RotationMode_PickLast:
1653     case AIS_RotationMode_PickCenter:
1654     {
1655       Graphic3d_Vec2i aCursor ((int )myGL.OrbitRotation.PointStart.x(), (int )myGL.OrbitRotation.PointStart.y());
1656       if (myRotationMode == AIS_RotationMode_PickCenter)
1657       {
1658         Graphic3d_Vec2i aViewPort;
1659         theView->Window()->Size (aViewPort.x(), aViewPort.y());
1660         aCursor = aViewPort / 2;
1661       }
1662
1663       gp_Pnt aPnt;
1664       if (PickPoint (aPnt, theCtx, theView, aCursor, false))
1665       {
1666         return aPnt;
1667       }
1668       break;
1669     }
1670     case AIS_RotationMode_CameraAt:
1671     {
1672       const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1673       return aCam->Center();
1674     }
1675     case AIS_RotationMode_BndBoxScene:
1676     {
1677       Bnd_Box aBndBox = theView->View()->MinMaxValues (false);
1678       if (!aBndBox.IsVoid())
1679       {
1680         return (aBndBox.CornerMin().XYZ() + aBndBox.CornerMax().XYZ()) * 0.5;
1681       }
1682       break;
1683     }
1684     case AIS_RotationMode_BndBoxActive:
1685       break;
1686   }
1687
1688   return theCtx ->GravityPoint (theView);
1689 }
1690
1691 // =======================================================================
1692 // function : handleCameraActions
1693 // purpose  :
1694 // =======================================================================
1695 void AIS_ViewController::handleCameraActions (const Handle(AIS_InteractiveContext)& theCtx,
1696                                               const Handle(V3d_View)& theView,
1697                                               const AIS_WalkDelta& theWalk)
1698 {
1699   // apply view actions
1700   if (myGL.Orientation.ToSetViewOrient)
1701   {
1702     theView->SetProj (myGL.Orientation.ViewOrient);
1703     myGL.Orientation.ToFitAll = true;
1704   }
1705
1706   // apply fit all
1707   if (myGL.Orientation.ToFitAll)
1708   {
1709     const double aFitMargin = 0.01;
1710     theView->FitAll (aFitMargin, false);
1711     theView->Invalidate();
1712     myGL.Orientation.ToFitAll = false;
1713   }
1714
1715   if (myGL.IsNewGesture)
1716   {
1717     if (myAnchorPointPrs1->HasInteractiveContext())
1718     {
1719       theCtx->Remove (myAnchorPointPrs1, false);
1720       if (!theView->Viewer()->ZLayerSettings (myAnchorPointPrs1->ZLayer()).IsImmediate())
1721       {
1722         theView->Invalidate();
1723       }
1724       else
1725       {
1726         theView->InvalidateImmediate();
1727       }
1728     }
1729     if (myAnchorPointPrs2->HasInteractiveContext())
1730     {
1731       theCtx->Remove (myAnchorPointPrs2, false);
1732       if (!theView->Viewer()->ZLayerSettings (myAnchorPointPrs2->ZLayer()).IsImmediate())
1733       {
1734         theView->Invalidate();
1735       }
1736       else
1737       {
1738         theView->InvalidateImmediate();
1739       }
1740     }
1741
1742     if (myHasHlrOnBeforeRotation)
1743     {
1744       myHasHlrOnBeforeRotation = false;
1745       theView->SetComputedMode (true);
1746       theView->Invalidate();
1747     }
1748   }
1749
1750   if (myNavigationMode != AIS_NavigationMode_FirstPersonWalk)
1751   {
1752     if (myGL.Panning.ToStart
1753      && myToAllowPanning)
1754     {
1755       gp_Pnt aPanPnt (Precision::Infinite(), 0.0, 0.0);
1756       if (!theView->Camera()->IsOrthographic())
1757       {
1758         bool toStickToRay = false;
1759         if (myGL.Panning.PointStart.x() >= 0
1760          && myGL.Panning.PointStart.y() >= 0)
1761         {
1762           PickPoint (aPanPnt, theCtx, theView, myGL.Panning.PointStart, toStickToRay);
1763         }
1764         if (Precision::IsInfinite (aPanPnt.X()))
1765         {
1766           Graphic3d_Vec2i aWinSize;
1767           theView->Window()->Size (aWinSize.x(), aWinSize.y());
1768           PickPoint (aPanPnt, theCtx, theView, aWinSize / 2, toStickToRay);
1769         }
1770         if (!Precision::IsInfinite (aPanPnt.X())
1771           && myToShowPanAnchorPoint)
1772         {
1773           gp_Trsf aPntTrsf;
1774           aPntTrsf.SetTranslation (gp_Vec (aPanPnt.XYZ()));
1775           theCtx->SetLocation (myAnchorPointPrs2, aPntTrsf);
1776         }
1777       }
1778       setPanningAnchorPoint (aPanPnt);
1779     }
1780
1781     if (myToShowPanAnchorPoint
1782     &&  hasPanningAnchorPoint()
1783     &&  myGL.Panning.ToPan
1784     && !myGL.IsNewGesture
1785     && !myAnchorPointPrs2->HasInteractiveContext())
1786     {
1787       theCtx->Display (myAnchorPointPrs2, 0, -1, false, AIS_DS_Displayed);
1788     }
1789
1790     handlePanning (theView);
1791     handleZRotate (theView);
1792   }
1793
1794   if ((myNavigationMode == AIS_NavigationMode_Orbit
1795     || myGL.OrbitRotation.ToStart
1796     || myGL.OrbitRotation.ToRotate)
1797    && myToAllowRotation)
1798   {
1799     if (myGL.OrbitRotation.ToStart
1800     && !myHasHlrOnBeforeRotation)
1801     {
1802       myHasHlrOnBeforeRotation = theView->ComputedMode();
1803       if (myHasHlrOnBeforeRotation)
1804       {
1805         theView->SetComputedMode (false);
1806       }
1807     }
1808
1809     gp_Pnt aGravPnt;
1810     if (myGL.OrbitRotation.ToStart)
1811     {
1812       aGravPnt = GravityPoint (theCtx, theView);
1813       if (myToShowRotateCenter)
1814       {
1815         gp_Trsf aPntTrsf;
1816         aPntTrsf.SetTranslation (gp_Vec (aGravPnt.XYZ()));
1817         theCtx->SetLocation (myAnchorPointPrs1, aPntTrsf);
1818         theCtx->SetLocation (myAnchorPointPrs2, aPntTrsf);
1819       }
1820     }
1821
1822     if (myToShowRotateCenter
1823     &&  myGL.OrbitRotation.ToRotate
1824     && !myGL.IsNewGesture
1825     && !myAnchorPointPrs1->HasInteractiveContext())
1826     {
1827       theCtx->Display (myAnchorPointPrs1, 0, -1, false, AIS_DS_Displayed);
1828       theCtx->Display (myAnchorPointPrs2, 0, -1, false, AIS_DS_Displayed);
1829     }
1830     handleOrbitRotation (theView, aGravPnt,
1831                          myToLockOrbitZUp || myNavigationMode != AIS_NavigationMode_Orbit);
1832   }
1833
1834   if ((myNavigationMode != AIS_NavigationMode_Orbit
1835     || myGL.ViewRotation.ToStart
1836     || myGL.ViewRotation.ToRotate)
1837    && myToAllowRotation)
1838   {
1839     if (myGL.ViewRotation.ToStart
1840     && !myHasHlrOnBeforeRotation)
1841     {
1842       myHasHlrOnBeforeRotation = theView->ComputedMode();
1843       if (myHasHlrOnBeforeRotation)
1844       {
1845         theView->SetComputedMode (false);
1846       }
1847     }
1848
1849     double aRoll = 0.0;
1850     if (!theWalk[AIS_WalkRotation_Roll].IsEmpty()
1851      && !myToLockOrbitZUp)
1852     {
1853       aRoll = (M_PI / 12.0) * theWalk[AIS_WalkRotation_Roll].Pressure;
1854       aRoll *= Min (1000.0  * theWalk[AIS_WalkRotation_Roll].Duration, 100.0) / 100.0;
1855       if (theWalk[AIS_WalkRotation_Roll].Value < 0.0)
1856       {
1857         aRoll = -aRoll;
1858       }
1859     }
1860
1861     handleViewRotation (theView, theWalk[AIS_WalkRotation_Yaw].Value, theWalk[AIS_WalkRotation_Pitch].Value, aRoll,
1862                         myNavigationMode == AIS_NavigationMode_FirstPersonFlight);
1863   }
1864
1865   if (!myGL.ZoomActions.IsEmpty())
1866   {
1867     for (NCollection_Sequence<Aspect_ScrollDelta>::Iterator aZoomIter (myGL.ZoomActions); aZoomIter.More(); aZoomIter.Next())
1868     {
1869       Aspect_ScrollDelta aZoomParams = aZoomIter.Value();
1870       if (myToAllowZFocus
1871        && (aZoomParams.Flags & Aspect_VKeyFlags_CTRL) != 0
1872        && theView->Camera()->IsStereo())
1873       {
1874         handleZFocusScroll (theView, aZoomParams);
1875         continue;
1876       }
1877
1878       if (!myToAllowZooming)
1879       {
1880         continue;
1881       }
1882
1883       if (!theView->Camera()->IsOrthographic())
1884       {
1885         // what is more natural to user - point on ray or point exactly on geometry in corner cases?
1886         const bool toStickToRay = false; // true;
1887
1888         gp_Pnt aPnt;
1889         if (aZoomParams.HasPoint()
1890          && PickPoint (aPnt, theCtx, theView, aZoomParams.Point, toStickToRay))
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, toStickToRay))
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 }