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_Point.hxx>
19 #include <AIS_RubberBand.hxx>
20 #include <AIS_XRTrackedDevice.hxx>
21 #include <Aspect_XRSession.hxx>
22 #include <Aspect_Grid.hxx>
23 #include <Geom_CartesianPoint.hxx>
24 #include <Graphic3d_ArrayOfSegments.hxx>
25 #include <Graphic3d_Texture2Dmanual.hxx>
26 #include <Message.hxx>
27 #include <Message_Messenger.hxx>
28 #include <gp_Quaternion.hxx>
29 #include <V3d_View.hxx>
30 #include <V3d_Viewer.hxx>
31 #include <WNT_HIDSpaceMouse.hxx>
32 
33 // =======================================================================
34 // function : AIS_ViewController
35 // purpose  :
36 // =======================================================================
AIS_ViewController()37 AIS_ViewController::AIS_ViewController()
38 : myLastEventsTime    (0.0),
39   myToAskNextFrame    (false),
40   myIsContinuousRedraw(false),
41   myMinCamDistance    (1.0),
42   myRotationMode      (AIS_RotationMode_BndBoxActive),
43   myNavigationMode    (AIS_NavigationMode_Orbit),
44   myMouseAccel           (1.0f),
45   myOrbitAccel           (1.0f),
46   myToShowPanAnchorPoint (true),
47   myToShowRotateCenter   (true),
48   myToLockOrbitZUp       (false),
49   myToInvertPitch        (false),
50   myToAllowTouchZRotation(false),
51   myToAllowRotation      (true),
52   myToAllowPanning       (true),
53   myToAllowZooming       (true),
54   myToAllowZFocus        (true),
55   myToAllowHighlight     (true),
56   myToAllowDragging      (true),
57   myToStickToRayOnZoom   (true),
58   myToStickToRayOnRotation (true),
59   //
60   myWalkSpeedAbsolute (1.5f),
61   myWalkSpeedRelative (0.1f),
62   myThrustSpeed (0.0f),
63   myHasThrust (false),
64   //
65   myViewAnimation (new AIS_AnimationCamera ("AIS_ViewController_ViewAnimation", Handle(V3d_View)())),
66   myObjAnimation (new AIS_Animation ("AIS_ViewController_ObjectsAnimation")),
67   myToPauseObjAnimation (false),
68   myPrevMoveTo (-1, -1),
69   myHasHlrOnBeforeRotation (false),
70   //
71   myXRPrsDevices (0, 0),
72   myXRLaserTeleColor (Quantity_NOC_GREEN),
73   myXRLaserPickColor (Quantity_NOC_BLUE),
74   myXRLastTeleportHand(Aspect_XRTrackedDeviceRole_Other),
75   myXRLastPickingHand (Aspect_XRTrackedDeviceRole_Other),
76   myXRLastPickDepthLeft (Precision::Infinite()),
77   myXRLastPickDepthRight(Precision::Infinite()),
78   myXRTurnAngle (M_PI_4),
79   myToDisplayXRAuxDevices (false),
80   myToDisplayXRHands (true),
81   //
82   myMouseClickThreshold (3.0),
83   myMouseDoubleClickInt (0.4),
84   myScrollZoomRatio     (15.0f),
85   myMouseActiveGesture  (AIS_MouseGesture_NONE),
86   myMouseActiveIdleRotation (false),
87   myMouseClickCounter   (0),
88   myMouseSingleButton   (-1),
89   myMouseStopDragOnUnclick (false),
90   //
91   myTouchToleranceScale      (1.0f),
92   myTouchClickThresholdPx    (3.0f),
93   myTouchRotationThresholdPx (6.0f),
94   myTouchZRotationThreshold  (float(2.0 * M_PI / 180.0)),
95   myTouchPanThresholdPx      (4.0f),
96   myTouchZoomThresholdPx     (6.0f),
97   myTouchZoomRatio           (0.13f),
98   //
99   myNbTouchesLast (0),
100   myUpdateStartPointPan  (true),
101   myUpdateStartPointRot  (true),
102   myUpdateStartPointZRot (true),
103   //
104   myPanPnt3d (Precision::Infinite(), 0.0, 0.0)
105 {
106   myViewAnimation->SetOwnDuration (0.5);
107 
108   myAnchorPointPrs1 = new AIS_Point (new Geom_CartesianPoint (0.0, 0.0, 0.0));
109   myAnchorPointPrs1->SetZLayer (Graphic3d_ZLayerId_Top);
110   myAnchorPointPrs1->SetMutable (true);
111 
112   myAnchorPointPrs2 = new AIS_Point (new Geom_CartesianPoint (0.0, 0.0, 0.0));
113   myAnchorPointPrs2->SetZLayer (Graphic3d_ZLayerId_Topmost);
114   myAnchorPointPrs2->SetMutable (true);
115 
116   myRubberBand = new AIS_RubberBand (Quantity_NOC_LIGHTBLUE, Aspect_TOL_SOLID, Quantity_NOC_LIGHTBLUE4, 0.5, 1.0);
117   myRubberBand->SetZLayer (Graphic3d_ZLayerId_TopOSD);
118   myRubberBand->SetTransformPersistence (new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_UPPER));
119   myRubberBand->SetDisplayMode (0);
120   myRubberBand->SetMutable (true);
121 
122   myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton,                           AIS_MouseGesture_RotateOrbit);
123   myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_CTRL,   AIS_MouseGesture_Zoom);
124   myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_SHIFT,  AIS_MouseGesture_Pan);
125   myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_ALT,    AIS_MouseGesture_SelectRectangle);
126   myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_ALT | Aspect_VKeyFlags_SHIFT, AIS_MouseGesture_SelectRectangle);
127 
128   myMouseSelectionSchemes.Bind (Aspect_VKeyMouse_LeftButton,                          AIS_SelectionScheme_Replace);
129   myMouseSelectionSchemes.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_ALT,   AIS_SelectionScheme_Replace);
130   myMouseSelectionSchemes.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_SHIFT, AIS_SelectionScheme_XOR);
131   myMouseSelectionSchemes.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_ALT | Aspect_VKeyFlags_SHIFT, AIS_SelectionScheme_XOR);
132 
133   myMouseGestureMap.Bind (Aspect_VKeyMouse_RightButton,                          AIS_MouseGesture_Zoom);
134   myMouseGestureMap.Bind (Aspect_VKeyMouse_RightButton | Aspect_VKeyFlags_CTRL,  AIS_MouseGesture_RotateOrbit);
135 
136   myMouseGestureMap.Bind (Aspect_VKeyMouse_MiddleButton,                         AIS_MouseGesture_Pan);
137   myMouseGestureMap.Bind (Aspect_VKeyMouse_MiddleButton | Aspect_VKeyFlags_CTRL, AIS_MouseGesture_Pan);
138 
139   myXRTeleportHaptic.Duration  = 3600.0f;
140   myXRTeleportHaptic.Frequency = 0.1f;
141   myXRTeleportHaptic.Amplitude = 0.2f;
142 
143   myXRPickingHaptic.Duration  = 0.1f;
144   myXRPickingHaptic.Frequency = 4.0f;
145   myXRPickingHaptic.Amplitude = 0.1f;
146 
147   myXRSelectHaptic.Duration  = 0.2f;
148   myXRSelectHaptic.Frequency = 4.0f;
149   myXRSelectHaptic.Amplitude = 0.5f;
150 }
151 
152 // =======================================================================
153 // function : ~AIS_ViewController
154 // purpose  :
155 // =======================================================================
~AIS_ViewController()156 AIS_ViewController::~AIS_ViewController()
157 {
158   //
159 }
160 
161 // =======================================================================
162 // function : ResetViewInput
163 // purpose  :
164 // =======================================================================
ResetViewInput()165 void AIS_ViewController::ResetViewInput()
166 {
167   myKeys.Reset();
168   myMousePressed      = Aspect_VKeyMouse_NONE;
169   myMouseModifiers    = Aspect_VKeyFlags_NONE;
170   myMouseSingleButton = -1;
171   myUI.Dragging.ToAbort = true;
172   myMouseActiveGesture = AIS_MouseGesture_NONE;
173   myMouseClickTimer.Stop();
174   myMouseClickCounter = 0;
175 }
176 
177 // =======================================================================
178 // function : FlushViewEvents
179 // purpose  :
180 // =======================================================================
FlushViewEvents(const Handle (AIS_InteractiveContext)& theCtx,const Handle (V3d_View)& theView,Standard_Boolean theToHandle)181 void AIS_ViewController::FlushViewEvents (const Handle(AIS_InteractiveContext)& theCtx,
182                                           const Handle(V3d_View)& theView,
183                                           Standard_Boolean theToHandle)
184 {
185   flushBuffers (theCtx, theView);
186   flushGestures(theCtx, theView);
187   if (theToHandle)
188   {
189     HandleViewEvents (theCtx, theView);
190   }
191 }
192 
193 // =======================================================================
194 // function : flushBuffers
195 // purpose  :
196 // =======================================================================
flushBuffers(const Handle (AIS_InteractiveContext)&,const Handle (V3d_View)&)197 void AIS_ViewController::flushBuffers (const Handle(AIS_InteractiveContext)& ,
198                                        const Handle(V3d_View)& )
199 {
200   myToAskNextFrame = false;
201 
202   myGL.IsNewGesture = myUI.IsNewGesture;
203   myUI.IsNewGesture = false;
204 
205   myGL.ZoomActions.Clear();
206   myGL.ZoomActions.Append (myUI.ZoomActions);
207   myUI.ZoomActions.Clear();
208 
209   myGL.Orientation.ToFitAll = myUI.Orientation.ToFitAll;
210   myUI.Orientation.ToFitAll = false;
211   if (myUI.Orientation.ToSetViewOrient)
212   {
213     myUI.Orientation.ToSetViewOrient = false;
214     myGL.Orientation.ToSetViewOrient = true;
215     myGL.Orientation.ViewOrient      = myUI.Orientation.ViewOrient;
216   }
217 
218   if (myUI.MoveTo.ToHilight)
219   {
220     myUI.MoveTo.ToHilight = false;
221     myGL.MoveTo.ToHilight = true;
222     myGL.MoveTo.Point     = myUI.MoveTo.Point;
223   }
224 
225   {
226     myGL.Selection.Tool   = myUI.Selection.Tool;
227     myGL.Selection.Scheme = myUI.Selection.Scheme;
228     myGL.Selection.Points = myUI.Selection.Points;
229     //myGL.Selection.Scheme = AIS_SelectionScheme_UNKNOWN; // no need
230     if (myUI.Selection.Tool == AIS_ViewSelectionTool_Picking)
231     {
232       myUI.Selection.Points.Clear();
233     }
234   }
235 
236   if (myUI.Selection.ToApplyTool)
237   {
238     myGL.Selection.ToApplyTool = true;
239     myUI.Selection.ToApplyTool = false;
240     myUI.Selection.Points.Clear();
241   }
242 
243   if (myUI.Panning.ToStart)
244   {
245     myUI.Panning.ToStart = false;
246     myGL.Panning.ToStart = true;
247     myGL.Panning.PointStart = myUI.Panning.PointStart;
248   }
249 
250   if (myUI.Panning.ToPan)
251   {
252     myUI.Panning.ToPan = false;
253     myGL.Panning.ToPan = true;
254     myGL.Panning.Delta = myUI.Panning.Delta;
255   }
256 
257   if (myUI.Dragging.ToAbort)
258   {
259     myUI.Dragging.ToAbort = false;
260     myGL.Dragging.ToAbort = true;
261   }
262   else if (myUI.Dragging.ToStop)
263   {
264     myUI.Dragging.ToStop = false;
265     myGL.Dragging.ToStop = true;
266   }
267   else if (myUI.Dragging.ToStart)
268   {
269     myUI.Dragging.ToStart = false;
270     myGL.Dragging.ToStart = true;
271     myGL.Dragging.PointStart = myUI.Dragging.PointStart;
272   }
273   myGL.Dragging.PointTo = myUI.Dragging.PointTo;
274 
275   if (myUI.OrbitRotation.ToStart)
276   {
277     myUI.OrbitRotation.ToStart    = false;
278     myGL.OrbitRotation.ToStart    = true;
279     myGL.OrbitRotation.PointStart = myUI.OrbitRotation.PointStart;
280   }
281 
282   if (myUI.OrbitRotation.ToRotate)
283   {
284     myUI.OrbitRotation.ToRotate = false;
285     myGL.OrbitRotation.ToRotate = true;
286     myGL.OrbitRotation.PointTo  = myUI.OrbitRotation.PointTo;
287   }
288 
289   if (myUI.ViewRotation.ToStart)
290   {
291     myUI.ViewRotation.ToStart    = false;
292     myGL.ViewRotation.ToStart    = true;
293     myGL.ViewRotation.PointStart = myUI.ViewRotation.PointStart;
294   }
295 
296   if (myUI.ViewRotation.ToRotate)
297   {
298     myUI.ViewRotation.ToRotate = false;
299     myGL.ViewRotation.ToRotate = true;
300     myGL.ViewRotation.PointTo  = myUI.ViewRotation.PointTo;
301   }
302 
303   if (myUI.ZRotate.ToRotate)
304   {
305     myGL.ZRotate = myUI.ZRotate;
306     myUI.ZRotate.ToRotate = false;
307   }
308 }
309 
310 // =======================================================================
311 // function : flushGestures
312 // purpose  :
313 // =======================================================================
flushGestures(const Handle (AIS_InteractiveContext)&,const Handle (V3d_View)& theView)314 void AIS_ViewController::flushGestures (const Handle(AIS_InteractiveContext)& ,
315                                         const Handle(V3d_View)& theView)
316 {
317   const Standard_Real    aTolScale = myTouchToleranceScale;
318   const Standard_Integer aTouchNb  = myTouchPoints.Extent();
319   if (myNbTouchesLast != aTouchNb)
320   {
321     myNbTouchesLast = aTouchNb;
322     myGL.IsNewGesture = true;
323   }
324   if (aTouchNb == 1) // touch
325   {
326     Aspect_Touch& aTouch = myTouchPoints.ChangeFromIndex (1);
327     if (myUpdateStartPointRot)
328     {
329       // skip rotation if have active dragged object
330       if (myNavigationMode == AIS_NavigationMode_Orbit)
331       {
332         myGL.OrbitRotation.ToStart = true;
333         myGL.OrbitRotation.PointStart = myStartRotCoord;
334       }
335       else
336       {
337         myGL.ViewRotation.ToStart = true;
338         myGL.ViewRotation.PointStart = myStartRotCoord;
339       }
340 
341       myUpdateStartPointRot = false;
342       theView->Invalidate();
343     }
344 
345     // rotation
346     const Standard_Real aRotTouchTol = !aTouch.IsPreciseDevice
347                                      ? aTolScale * myTouchRotationThresholdPx
348                                      : gp::Resolution();
349     if (Abs (aTouch.Delta().x()) + Abs(aTouch.Delta().y()) > aRotTouchTol)
350     {
351       const Standard_Real aRotAccel = myNavigationMode == AIS_NavigationMode_FirstPersonWalk ? myMouseAccel : myOrbitAccel;
352       if (myNavigationMode == AIS_NavigationMode_Orbit)
353       {
354         const Graphic3d_Vec2d aRotDelta = aTouch.To - myGL.OrbitRotation.PointStart;
355         myGL.OrbitRotation.ToRotate = true;
356         myGL.OrbitRotation.PointTo  = myGL.OrbitRotation.PointStart + aRotDelta * aRotAccel;
357         myGL.Dragging.PointTo.SetValues ((int )aTouch.To.x(), (int )aTouch.To.y());
358       }
359       else
360       {
361         const Graphic3d_Vec2d aRotDelta = aTouch.To - myGL.ViewRotation.PointStart;
362         myGL.ViewRotation.ToRotate = true;
363         myGL.ViewRotation.PointTo = myGL.ViewRotation.PointStart + aRotDelta * aRotAccel;
364         myGL.Dragging.PointTo.SetValues ((int )aTouch.To.x(), (int )aTouch.To.y());
365       }
366 
367       aTouch.From = aTouch.To;
368     }
369   }
370   else if (aTouchNb == 2) // pinch
371   {
372     Aspect_Touch& aFirstTouch = myTouchPoints.ChangeFromIndex (1);
373     Aspect_Touch& aLastTouch  = myTouchPoints.ChangeFromIndex (2);
374     const Graphic3d_Vec2d aFrom[2] = { aFirstTouch.From, aLastTouch.From };
375     const Graphic3d_Vec2d aTo[2]   = { aFirstTouch.To,   aLastTouch.To   };
376 
377     Graphic3d_Vec2d aPinchCenterStart ((aFrom[0].x() + aFrom[1].x()) / 2.0,
378                                        (aFrom[0].y() + aFrom[1].y()) / 2.0);
379 
380     Standard_Real aPinchCenterXEnd = (aTo[0].x() + aTo[1].x()) / 2.0;
381     Standard_Real aPinchCenterYEnd = (aTo[0].y() + aTo[1].y()) / 2.0;
382 
383     Standard_Real aPinchCenterXDev = aPinchCenterXEnd - aPinchCenterStart.x();
384     Standard_Real aPinchCenterYDev = aPinchCenterYEnd - aPinchCenterStart.y();
385 
386     Standard_Real aStartSize = (aFrom[0] - aFrom[1]).Modulus();
387     Standard_Real anEndSize  = (  aTo[0] -   aTo[1]).Modulus();
388 
389     Standard_Real aDeltaSize = anEndSize - aStartSize;
390 
391     bool anIsClearDev = false;
392 
393     if (myToAllowTouchZRotation)
394     {
395       Standard_Real A1 = aFrom[0].y() - aFrom[1].y();
396       Standard_Real B1 = aFrom[1].x() - aFrom[0].x();
397 
398       Standard_Real A2 = aTo[0].y() - aTo[1].y();
399       Standard_Real B2 = aTo[1].x() - aTo[0].x();
400 
401       Standard_Real aRotAngle = 0.0;
402 
403       Standard_Real aDenomenator = A1*A2 + B1*B2;
404       if (aDenomenator <= Precision::Confusion())
405       {
406         aRotAngle = 0.0;
407       }
408       else
409       {
410         Standard_Real aNumerator = A1*B2 - A2*B1;
411         aRotAngle = ATan (aNumerator / aDenomenator);
412       }
413 
414       if (Abs(aRotAngle) > Standard_Real(myTouchZRotationThreshold))
415       {
416         myGL.ZRotate.ToRotate = true;
417         myGL.ZRotate.Angle = aRotAngle;
418         anIsClearDev = true;
419       }
420     }
421 
422     if (Abs(aDeltaSize) > aTolScale * myTouchZoomThresholdPx)
423     {
424       // zoom
425       aDeltaSize *= Standard_Real(myTouchZoomRatio);
426       Aspect_ScrollDelta aParams (Graphic3d_Vec2i (aPinchCenterStart), aDeltaSize);
427       myGL.ZoomActions.Append (aParams);
428       anIsClearDev = true;
429     }
430 
431     const Standard_Real aPanTouchTol = !aFirstTouch.IsPreciseDevice
432                                      ? aTolScale * myTouchPanThresholdPx
433                                      : gp::Resolution();
434     if (Abs(aPinchCenterXDev) + Abs(aPinchCenterYDev) > aPanTouchTol)
435     {
436       // pan
437       if (myUpdateStartPointPan)
438       {
439         myGL.Panning.ToStart = true;
440         myGL.Panning.PointStart = Graphic3d_Vec2i (myStartPanCoord);
441         myUpdateStartPointPan = false;
442         theView->Invalidate();
443       }
444 
445       myGL.Panning.ToPan = true;
446       myGL.Panning.Delta.x() = int( aPinchCenterXDev);
447       myGL.Panning.Delta.y() = int(-aPinchCenterYDev);
448       anIsClearDev = true;
449     }
450 
451     if (anIsClearDev)
452     {
453       aFirstTouch.From = aFirstTouch.To;
454       aLastTouch .From = aLastTouch.To;
455     }
456   }
457 }
458 
459 // =======================================================================
460 // function : UpdateViewOrientation
461 // purpose  :
462 // =======================================================================
UpdateViewOrientation(V3d_TypeOfOrientation theOrientation,bool theToFitAll)463 void AIS_ViewController::UpdateViewOrientation (V3d_TypeOfOrientation theOrientation,
464                                                 bool theToFitAll)
465 {
466   myUI.Orientation.ToFitAll = theToFitAll;
467   myUI.Orientation.ToSetViewOrient = true;
468   myUI.Orientation.ViewOrient = theOrientation;
469 }
470 
471 // =======================================================================
472 // function : SelectInViewer
473 // purpose  :
474 // =======================================================================
SelectInViewer(const Graphic3d_Vec2i & thePnt,const AIS_SelectionScheme theScheme)475 void AIS_ViewController::SelectInViewer (const Graphic3d_Vec2i& thePnt,
476                                          const AIS_SelectionScheme theScheme)
477 {
478   if (myUI.Selection.Tool != AIS_ViewSelectionTool_Picking)
479   {
480     myUI.Selection.Tool = AIS_ViewSelectionTool_Picking;
481     myUI.Selection.Points.Clear();
482   }
483 
484   myUI.Selection.Scheme = theScheme;
485   myUI.Selection.Points.Append (thePnt);
486 }
487 
488 // =======================================================================
489 // function : SelectInViewer
490 // purpose  :
491 // =======================================================================
SelectInViewer(const NCollection_Sequence<Graphic3d_Vec2i> & thePnts,const AIS_SelectionScheme theScheme)492 void AIS_ViewController::SelectInViewer (const NCollection_Sequence<Graphic3d_Vec2i>& thePnts,
493                                          const AIS_SelectionScheme theScheme)
494 {
495   myUI.Selection.Scheme = theScheme;
496   myUI.Selection.Points = thePnts;
497   myUI.Selection.ToApplyTool = true;
498   if (thePnts.Length() == 1)
499   {
500     myUI.Selection.Tool = AIS_ViewSelectionTool_Picking;
501   }
502   else if (thePnts.Length() == 2)
503   {
504     myUI.Selection.Tool = AIS_ViewSelectionTool_RubberBand;
505   }
506   else
507   {
508     myUI.Selection.Tool = AIS_ViewSelectionTool_Polygon;
509   }
510 }
511 
512 // =======================================================================
513 // function : UpdateRubberBand
514 // purpose  :
515 // =======================================================================
UpdateRubberBand(const Graphic3d_Vec2i & thePntFrom,const Graphic3d_Vec2i & thePntTo)516 void AIS_ViewController::UpdateRubberBand (const Graphic3d_Vec2i& thePntFrom,
517                                            const Graphic3d_Vec2i& thePntTo)
518 {
519   myUI.Selection.Tool = AIS_ViewSelectionTool_RubberBand;
520   myUI.Selection.Points.Clear();
521   myUI.Selection.Points.Append (thePntFrom);
522   myUI.Selection.Points.Append (thePntTo);
523 }
524 
525 // =======================================================================
526 // function : UpdatePolySelection
527 // purpose  :
528 // =======================================================================
UpdatePolySelection(const Graphic3d_Vec2i & thePnt,bool theToAppend)529 void AIS_ViewController::UpdatePolySelection (const Graphic3d_Vec2i& thePnt,
530                                               bool theToAppend)
531 {
532   if (myUI.Selection.Tool != AIS_ViewSelectionTool_Polygon)
533   {
534     myUI.Selection.Tool = AIS_ViewSelectionTool_Polygon;
535     myUI.Selection.Points.Clear();
536   }
537 
538   if (myUI.Selection.Points.IsEmpty())
539   {
540     myUI.Selection.Points.Append (thePnt);
541   }
542   else if (theToAppend
543         && myUI.Selection.Points.Last() != thePnt)
544   {
545     myUI.Selection.Points.Append (thePnt);
546   }
547   else
548   {
549     myUI.Selection.Points.ChangeLast() = thePnt;
550   }
551 }
552 
553 // =======================================================================
554 // function : UpdateZoom
555 // purpose  :
556 // =======================================================================
UpdateZoom(const Aspect_ScrollDelta & theDelta)557 bool AIS_ViewController::UpdateZoom (const Aspect_ScrollDelta& theDelta)
558 {
559   if (!myUI.ZoomActions.IsEmpty())
560   {
561     if (myUI.ZoomActions.ChangeLast().Point == theDelta.Point)
562     {
563       myUI.ZoomActions.ChangeLast().Delta += theDelta.Delta;
564       return false;
565     }
566   }
567 
568   myUI.ZoomActions.Append (theDelta);
569   return true;
570 }
571 
572 // =======================================================================
573 // function : UpdateZRotation
574 // purpose  :
575 // =======================================================================
UpdateZRotation(double theAngle)576 bool AIS_ViewController::UpdateZRotation (double theAngle)
577 {
578   if (!ToAllowTouchZRotation())
579   {
580     return false;
581   }
582 
583   myUI.ZRotate.Angle = myUI.ZRotate.ToRotate
584                      ? myUI.ZRotate.Angle + theAngle
585                      : theAngle;
586   if (myUI.ZRotate.ToRotate)
587   {
588     return false;
589   }
590   myUI.ZRotate.ToRotate = true;
591   return true;
592 }
593 
594 // =======================================================================
595 // function : UpdateMouseScroll
596 // purpose  :
597 // =======================================================================
UpdateMouseScroll(const Aspect_ScrollDelta & theDelta)598 bool AIS_ViewController::UpdateMouseScroll (const Aspect_ScrollDelta& theDelta)
599 {
600   Aspect_ScrollDelta aDelta = theDelta;
601   aDelta.Delta *= myScrollZoomRatio;
602   return UpdateZoom (aDelta);
603 }
604 
605 // =======================================================================
606 // function : UpdateMouseClick
607 // purpose  :
608 // =======================================================================
UpdateMouseClick(const Graphic3d_Vec2i & thePoint,Aspect_VKeyMouse theButton,Aspect_VKeyFlags theModifiers,bool theIsDoubleClick)609 bool AIS_ViewController::UpdateMouseClick (const Graphic3d_Vec2i& thePoint,
610                                            Aspect_VKeyMouse theButton,
611                                            Aspect_VKeyFlags theModifiers,
612                                            bool theIsDoubleClick)
613 {
614   (void )theIsDoubleClick;
615 
616   if (myToPauseObjAnimation
617   && !myObjAnimation.IsNull()
618   && !myObjAnimation->IsStopped())
619   {
620     myObjAnimation->Pause();
621   }
622 
623   AIS_SelectionScheme aScheme = AIS_SelectionScheme_UNKNOWN;
624   if (myMouseSelectionSchemes.Find (theButton | theModifiers, aScheme))
625   {
626     SelectInViewer (thePoint, aScheme);
627     return true;
628   }
629   return false;
630 }
631 
632 // =======================================================================
633 // function : UpdateMouseButtons
634 // purpose  :
635 // =======================================================================
UpdateMouseButtons(const Graphic3d_Vec2i & thePoint,Aspect_VKeyMouse theButtons,Aspect_VKeyFlags theModifiers,bool theIsEmulated)636 bool AIS_ViewController::UpdateMouseButtons (const Graphic3d_Vec2i& thePoint,
637                                              Aspect_VKeyMouse theButtons,
638                                              Aspect_VKeyFlags theModifiers,
639                                              bool theIsEmulated)
640 {
641   bool toUpdateView = false;
642   const double aTolClick = (theIsEmulated ? myTouchToleranceScale : 1.0) * myMouseClickThreshold;
643   if (theButtons == Aspect_VKeyMouse_NONE
644    && myMouseSingleButton > 0)
645   {
646     const Graphic3d_Vec2i aDelta = thePoint - myMousePressPoint;
647     if (double(aDelta.cwiseAbs().maxComp()) < aTolClick)
648     {
649       ++myMouseClickCounter;
650       const bool isDoubleClick = myMouseClickCounter == 2
651                               && myMouseClickTimer.IsStarted()
652                               && myMouseClickTimer.ElapsedTime() <= myMouseDoubleClickInt;
653 
654       myMouseClickTimer.Stop();
655       myMouseClickTimer.Reset();
656       myMouseClickTimer.Start();
657       if (isDoubleClick)
658       {
659         myMouseClickCounter = 0;
660       }
661       toUpdateView = UpdateMouseClick (thePoint, (Aspect_VKeyMouse )myMouseSingleButton, theModifiers, isDoubleClick) || toUpdateView;
662     }
663     else
664     {
665       myMouseClickTimer.Stop();
666       myMouseClickCounter = 0;
667       myMouseStopDragOnUnclick = false;
668       myUI.Dragging.ToStop = true;
669       toUpdateView = true;
670     }
671     myMouseSingleButton = -1;
672   }
673   else if (theButtons == Aspect_VKeyMouse_NONE)
674   {
675     myMouseSingleButton = -1;
676     if (myMouseStopDragOnUnclick)
677     {
678       myMouseStopDragOnUnclick = false;
679       myUI.Dragging.ToStop = true;
680       toUpdateView = true;
681     }
682   }
683   else if (myMouseSingleButton == -1)
684   {
685     if ((theButtons & Aspect_VKeyMouse_LeftButton) == Aspect_VKeyMouse_LeftButton)
686     {
687       myMouseSingleButton = Aspect_VKeyMouse_LeftButton;
688     }
689     else if ((theButtons & Aspect_VKeyMouse_RightButton) == Aspect_VKeyMouse_RightButton)
690     {
691       myMouseSingleButton = Aspect_VKeyMouse_RightButton;
692     }
693     else if ((theButtons & Aspect_VKeyMouse_MiddleButton) == Aspect_VKeyMouse_MiddleButton)
694     {
695       myMouseSingleButton = Aspect_VKeyMouse_MiddleButton;
696     }
697     else
698     {
699       myMouseSingleButton = 0;
700     }
701     if (myMouseSingleButton != 0)
702     {
703       if (myMouseClickCounter == 1)
704       {
705         const Graphic3d_Vec2i aDelta = thePoint - myMousePressPoint;
706         if (double(aDelta.cwiseAbs().maxComp()) >= aTolClick)
707         {
708           myMouseClickTimer.Stop();
709           myMouseClickCounter = 0;
710         }
711       }
712       myMousePressPoint = thePoint;
713     }
714   }
715   else
716   {
717     myMouseSingleButton = 0;
718 
719     myUI.Dragging.ToAbort = true;
720     toUpdateView = true;
721   }
722 
723   const AIS_MouseGesture aPrevGesture = myMouseActiveGesture;
724   const Aspect_VKeyMouse aPrevButtons = myMousePressed;
725   const Aspect_VKeyFlags aPrevModifiers = myMouseModifiers;
726   myMouseModifiers = theModifiers;
727   myMousePressed   = theButtons;
728   if (theIsEmulated
729    || myNavigationMode != AIS_NavigationMode_FirstPersonWalk)
730   {
731     myMouseActiveIdleRotation = false;
732     myMouseActiveGesture = AIS_MouseGesture_NONE;
733     if (theButtons != 0)
734     {
735       myMousePressPoint    = thePoint;
736       myMouseProgressPoint = myMousePressPoint;
737     }
738 
739     if (myMouseGestureMap.Find (theButtons | theModifiers, myMouseActiveGesture))
740     {
741       switch (myMouseActiveGesture)
742       {
743         case AIS_MouseGesture_RotateView:
744         case AIS_MouseGesture_RotateOrbit:
745         {
746           if (myToAllowRotation)
747           {
748             myUpdateStartPointRot = true;
749           }
750           else
751           {
752             myMouseActiveGesture = AIS_MouseGesture_NONE;
753           }
754           break;
755         }
756         case AIS_MouseGesture_Pan:
757         {
758           if (myToAllowPanning)
759           {
760             myUpdateStartPointPan = true;
761           }
762           else
763           {
764             myMouseActiveGesture = AIS_MouseGesture_NONE;
765           }
766           break;
767         }
768         case AIS_MouseGesture_Zoom:
769         case AIS_MouseGesture_ZoomWindow:
770         {
771           if (!myToAllowZooming)
772           {
773             myMouseActiveGesture = AIS_MouseGesture_NONE;
774           }
775           break;
776         }
777         case AIS_MouseGesture_SelectRectangle:
778         {
779           break;
780         }
781         case AIS_MouseGesture_SelectLasso:
782         {
783           UpdatePolySelection (thePoint, true);
784           break;
785         }
786         case AIS_MouseGesture_NONE:
787         {
788           break;
789         }
790       }
791     }
792 
793     if (theButtons == Aspect_VKeyMouse_LeftButton
794      && theModifiers == Aspect_VKeyFlags_NONE
795      && myToAllowDragging)
796     {
797       myUI.Dragging.ToStart = true;
798       myUI.Dragging.PointStart = thePoint;
799     }
800   }
801 
802   if (aPrevGesture != myMouseActiveGesture)
803   {
804     if (aPrevGesture == AIS_MouseGesture_SelectRectangle
805      || aPrevGesture == AIS_MouseGesture_SelectLasso
806      || aPrevGesture == AIS_MouseGesture_ZoomWindow)
807     {
808       myUI.Selection.ToApplyTool = true;
809       myUI.Selection.Scheme = AIS_SelectionScheme_Replace;
810       myMouseSelectionSchemes.Find (aPrevButtons | aPrevModifiers, myUI.Selection.Scheme);
811     }
812 
813     myUI.IsNewGesture = true;
814     toUpdateView = true;
815   }
816 
817   return toUpdateView;
818 }
819 
820 // =======================================================================
821 // function : UpdateMousePosition
822 // purpose  :
823 // =======================================================================
UpdateMousePosition(const Graphic3d_Vec2i & thePoint,Aspect_VKeyMouse theButtons,Aspect_VKeyFlags theModifiers,bool theIsEmulated)824 bool AIS_ViewController::UpdateMousePosition (const Graphic3d_Vec2i& thePoint,
825                                               Aspect_VKeyMouse theButtons,
826                                               Aspect_VKeyFlags theModifiers,
827                                               bool theIsEmulated)
828 {
829   myMousePositionLast = thePoint;
830   if (myMouseSingleButton > 0)
831   {
832     const double aTolClick = (theIsEmulated ? myTouchToleranceScale : 1.0) * myMouseClickThreshold;
833     const Graphic3d_Vec2i aPressDelta = thePoint - myMousePressPoint;
834     if (double(aPressDelta.cwiseAbs().maxComp()) >= aTolClick)
835     {
836       myMouseClickTimer.Stop();
837       myMouseClickCounter = 0;
838       myMouseSingleButton = -1;
839       myMouseStopDragOnUnclick = true;
840     }
841   }
842 
843   bool toUpdateView = false;
844   Graphic3d_Vec2i aDelta = thePoint - myMouseProgressPoint;
845   if (!theIsEmulated
846     && myNavigationMode == AIS_NavigationMode_FirstPersonWalk)
847   {
848     if (!myMouseActiveIdleRotation
849       || myMouseActiveGesture != AIS_MouseGesture_RotateView)
850     {
851       myMouseActiveIdleRotation = true;
852       myMouseActiveGesture = AIS_MouseGesture_RotateView;
853       myMousePressPoint     = thePoint;
854       myMouseProgressPoint  = thePoint;
855       myUpdateStartPointRot = false;
856       myUI.ViewRotation.ToStart = true;
857       myUI.ViewRotation.PointStart.SetValues (thePoint.x(), thePoint.y());
858       myUI.ViewRotation.ToRotate = false;
859       aDelta.SetValues (0, 0);
860     }
861   }
862   else
863   {
864     if (myMouseActiveIdleRotation
865      && myMouseActiveGesture == AIS_MouseGesture_RotateView)
866     {
867       myMouseActiveGesture = AIS_MouseGesture_NONE;
868     }
869     myMouseActiveIdleRotation = false;
870   }
871 
872   if (myMouseModifiers != theModifiers
873    && UpdateMouseButtons (thePoint, theButtons, theModifiers, theIsEmulated))
874   {
875     toUpdateView = true;
876   }
877 
878   switch (myMouseActiveGesture)
879   {
880     case AIS_MouseGesture_SelectRectangle:
881     case AIS_MouseGesture_ZoomWindow:
882     {
883       UpdateRubberBand (myMousePressPoint, thePoint);
884       if (myMouseActiveGesture == AIS_MouseGesture_ZoomWindow)
885       {
886         myUI.Selection.Tool = AIS_ViewSelectionTool_ZoomWindow;
887       }
888       toUpdateView = true;
889       break;
890     }
891     case AIS_MouseGesture_SelectLasso:
892     {
893       UpdatePolySelection (thePoint, true);
894       toUpdateView = true;
895       break;
896     }
897     case AIS_MouseGesture_RotateOrbit:
898     case AIS_MouseGesture_RotateView:
899     {
900       if (!myToAllowRotation)
901       {
902         break;
903       }
904       if (myUpdateStartPointRot)
905       {
906         if (myMouseActiveGesture == AIS_MouseGesture_RotateOrbit)
907         {
908           myUI.OrbitRotation.ToStart = true;
909           myUI.OrbitRotation.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y());
910         }
911         else
912         {
913           myUI.ViewRotation.ToStart = true;
914           myUI.ViewRotation.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y());
915         }
916         myUpdateStartPointRot = false;
917       }
918 
919       const double aRotTol = theIsEmulated
920                            ? double(myTouchToleranceScale) * myTouchRotationThresholdPx
921                            : 0.0;
922       if (double (Abs (aDelta.x()) + Abs (aDelta.y())) > aRotTol)
923       {
924         const double aRotAccel = myNavigationMode == AIS_NavigationMode_FirstPersonWalk ? myMouseAccel : myOrbitAccel;
925         const Graphic3d_Vec2i aRotDelta = thePoint - myMousePressPoint;
926         if (myMouseActiveGesture == AIS_MouseGesture_RotateOrbit)
927         {
928           myUI.OrbitRotation.ToRotate = true;
929           myUI.OrbitRotation.PointTo = Graphic3d_Vec2d (myMousePressPoint.x(), myMousePressPoint.y())
930                                      + Graphic3d_Vec2d (aRotDelta.x(), aRotDelta.y()) * aRotAccel;
931         }
932         else
933         {
934           myUI.ViewRotation.ToRotate = true;
935           myUI.ViewRotation.PointTo = Graphic3d_Vec2d (myMousePressPoint.x(), myMousePressPoint.y())
936                                     + Graphic3d_Vec2d (aRotDelta.x(), aRotDelta.y()) * aRotAccel;
937         }
938         myUI.Dragging.PointTo = thePoint;
939 
940         myMouseProgressPoint = thePoint;
941         toUpdateView = true;
942       }
943       break;
944     }
945     case AIS_MouseGesture_Zoom:
946     {
947       if (!myToAllowZooming)
948       {
949         break;
950       }
951       const double aZoomTol = theIsEmulated
952                             ? double(myTouchToleranceScale) * myTouchZoomThresholdPx
953                             : 0.0;
954       if (double (Abs (aDelta.x())) > aZoomTol)
955       {
956         if (UpdateZoom (Aspect_ScrollDelta (aDelta.x())))
957         {
958           toUpdateView = true;
959         }
960         myMouseProgressPoint = thePoint;
961       }
962       break;
963     }
964     case AIS_MouseGesture_Pan:
965     {
966       if (!myToAllowPanning)
967       {
968         break;
969       }
970       const double aPanTol = theIsEmulated
971                            ? double(myTouchToleranceScale) * myTouchPanThresholdPx
972                            : 0.0;
973       if (double (Abs (aDelta.x()) + Abs (aDelta.y())) > aPanTol)
974       {
975         if (myUpdateStartPointPan)
976         {
977           myUI.Panning.ToStart = true;
978           myUI.Panning.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y());
979           myUpdateStartPointPan = false;
980         }
981 
982         aDelta.y() = -aDelta.y();
983         myMouseProgressPoint = thePoint;
984         if (myUI.Panning.ToPan)
985         {
986           myUI.Panning.Delta += aDelta;
987         }
988         else
989         {
990           myUI.Panning.ToPan = true;
991           myUI.Panning.Delta = aDelta;
992         }
993         toUpdateView = true;
994       }
995       break;
996     }
997     default:
998     {
999       break;
1000     }
1001   }
1002 
1003   if (theButtons == Aspect_VKeyMouse_NONE
1004   &&  myNavigationMode != AIS_NavigationMode_FirstPersonWalk
1005   && !theIsEmulated
1006   && !HasTouchPoints()
1007   &&  myToAllowHighlight)
1008   {
1009     myUI.MoveTo.ToHilight = true;
1010     myUI.MoveTo.Point = thePoint;
1011     toUpdateView = true;
1012   }
1013   return toUpdateView;
1014 }
1015 
1016 // =======================================================================
1017 // function : AddTouchPoint
1018 // purpose  :
1019 // =======================================================================
AddTouchPoint(Standard_Size theId,const Graphic3d_Vec2d & thePnt,Standard_Boolean theClearBefore)1020 void AIS_ViewController::AddTouchPoint (Standard_Size theId,
1021                                         const Graphic3d_Vec2d& thePnt,
1022                                         Standard_Boolean theClearBefore)
1023 {
1024   myUI.MoveTo.ToHilight = false;
1025   Aspect_WindowInputListener::AddTouchPoint (theId, thePnt, theClearBefore);
1026 
1027   myTouchClick.From = Graphic3d_Vec2d (-1.0);
1028   if (myTouchPoints.Extent() == 1)
1029   {
1030     myTouchClick.From = thePnt;
1031     myUpdateStartPointRot = true;
1032     myStartRotCoord = thePnt;
1033     if (myToAllowDragging)
1034     {
1035       myUI.Dragging.ToStart = true;
1036       myUI.Dragging.PointStart.SetValues ((int )thePnt.x(), (int )thePnt.y());
1037     }
1038   }
1039   else if (myTouchPoints.Extent() == 2)
1040   {
1041     myUI.Dragging.ToAbort = true;
1042 
1043     myUpdateStartPointPan = true;
1044     myStartPanCoord = thePnt;
1045   }
1046   myUI.IsNewGesture = true;
1047 }
1048 
1049 // =======================================================================
1050 // function : RemoveTouchPoint
1051 // purpose  :
1052 // =======================================================================
RemoveTouchPoint(Standard_Size theId,Standard_Boolean theClearSelectPnts)1053 bool AIS_ViewController::RemoveTouchPoint (Standard_Size theId,
1054                                            Standard_Boolean theClearSelectPnts)
1055 {
1056   if (!Aspect_WindowInputListener::RemoveTouchPoint (theId, theClearSelectPnts))
1057   {
1058     return false;
1059   }
1060 
1061   if (myTouchPoints.Extent() == 1)
1062   {
1063     // avoid incorrect transition from pinch to one finger
1064     Aspect_Touch& aFirstTouch = myTouchPoints.ChangeFromIndex (1);
1065     aFirstTouch.To = aFirstTouch.From;
1066 
1067     myStartRotCoord = aFirstTouch.To;
1068     myUpdateStartPointRot = true;
1069   }
1070   else if (myTouchPoints.Extent() == 2)
1071   {
1072     myStartPanCoord = myTouchPoints.FindFromIndex (1).To;
1073     myUpdateStartPointPan = true;
1074   }
1075   else if (myTouchPoints.IsEmpty())
1076   {
1077     if (theClearSelectPnts)
1078     {
1079       myUI.Selection.ToApplyTool = true;
1080     }
1081 
1082     myUI.Dragging.ToStop = true;
1083 
1084     if (theId == (Standard_Size )-1)
1085     {
1086       // abort clicking
1087       myTouchClick.From = Graphic3d_Vec2d (-1);
1088     }
1089     else if (myTouchClick.From.minComp() >= 0.0)
1090     {
1091       bool isDoubleClick = false;
1092       if (myTouchDoubleTapTimer.IsStarted()
1093        && myTouchDoubleTapTimer.ElapsedTime() <= myMouseDoubleClickInt)
1094       {
1095         isDoubleClick = true;
1096       }
1097       else
1098       {
1099         myTouchDoubleTapTimer.Stop();
1100         myTouchDoubleTapTimer.Reset();
1101         myTouchDoubleTapTimer.Start();
1102       }
1103 
1104       // emulate mouse click
1105       UpdateMouseClick (Graphic3d_Vec2i (myTouchClick.From), Aspect_VKeyMouse_LeftButton, Aspect_VKeyFlags_NONE, isDoubleClick);
1106     }
1107   }
1108   myUI.IsNewGesture = true;
1109   return true;
1110 }
1111 
1112 // =======================================================================
1113 // function : UpdateTouchPoint
1114 // purpose  :
1115 // =======================================================================
UpdateTouchPoint(Standard_Size theId,const Graphic3d_Vec2d & thePnt)1116 void AIS_ViewController::UpdateTouchPoint (Standard_Size theId,
1117                                            const Graphic3d_Vec2d& thePnt)
1118 {
1119   Aspect_WindowInputListener::UpdateTouchPoint (theId, thePnt);
1120 
1121   const double aTouchTol = double(myTouchToleranceScale) * double(myTouchClickThresholdPx);
1122   if (myTouchPoints.Extent() == 1
1123    && (myTouchClick.From - thePnt).cwiseAbs().maxComp() > aTouchTol)
1124   {
1125     myTouchClick.From.SetValues (-1.0, -1.0);
1126   }
1127 }
1128 
1129 // =======================================================================
1130 // function : Update3dMouse
1131 // purpose  :
1132 // =======================================================================
Update3dMouse(const WNT_HIDSpaceMouse & theEvent)1133 bool AIS_ViewController::Update3dMouse (const WNT_HIDSpaceMouse& theEvent)
1134 {
1135   bool toUpdate = false;
1136   toUpdate = update3dMouseTranslation (theEvent) || toUpdate;
1137   toUpdate = (myToAllowRotation && update3dMouseRotation (theEvent)) || toUpdate;
1138   toUpdate = update3dMouseKeys (theEvent) || toUpdate;
1139   return toUpdate;
1140 }
1141 
1142 // =======================================================================
1143 // function : SetNavigationMode
1144 // purpose  :
1145 // =======================================================================
SetNavigationMode(AIS_NavigationMode theMode)1146 void AIS_ViewController::SetNavigationMode (AIS_NavigationMode theMode)
1147 {
1148   myNavigationMode = theMode;
1149 
1150   // abort rotation
1151   myUI.OrbitRotation.ToStart  = false;
1152   myUI.OrbitRotation.ToRotate = false;
1153   myUI.ViewRotation.ToStart   = false;
1154   myUI.ViewRotation.ToRotate  = false;
1155 }
1156 
1157 // =======================================================================
1158 // function : KeyDown
1159 // purpose  :
1160 // =======================================================================
KeyDown(Aspect_VKey theKey,double theTime,double thePressure)1161 void AIS_ViewController::KeyDown (Aspect_VKey theKey,
1162                                   double theTime,
1163                                   double thePressure)
1164 {
1165   Aspect_WindowInputListener::KeyDown (theKey, theTime, thePressure);
1166 }
1167 
1168 // =======================================================================
1169 // function : KeyUp
1170 // purpose  :
1171 // =======================================================================
KeyUp(Aspect_VKey theKey,double theTime)1172 void AIS_ViewController::KeyUp (Aspect_VKey theKey,
1173                                 double theTime)
1174 {
1175   Aspect_WindowInputListener::KeyUp (theKey, theTime);
1176 }
1177 
1178 // =======================================================================
1179 // function : KeyFromAxis
1180 // purpose  :
1181 // =======================================================================
KeyFromAxis(Aspect_VKey theNegative,Aspect_VKey thePositive,double theTime,double thePressure)1182 void AIS_ViewController::KeyFromAxis (Aspect_VKey theNegative,
1183                                       Aspect_VKey thePositive,
1184                                       double theTime,
1185                                       double thePressure)
1186 {
1187   Aspect_WindowInputListener::KeyFromAxis (theNegative, thePositive, theTime, thePressure);
1188 }
1189 
1190 // =======================================================================
1191 // function : FetchNavigationKeys
1192 // purpose  :
1193 // =======================================================================
FetchNavigationKeys(Standard_Real theCrouchRatio,Standard_Real theRunRatio)1194 AIS_WalkDelta AIS_ViewController::FetchNavigationKeys (Standard_Real theCrouchRatio,
1195                                                        Standard_Real theRunRatio)
1196 {
1197   AIS_WalkDelta aWalk;
1198 
1199   // navigation keys
1200   double aPrevEventTime = 0.0, aNewEventTime = 0.0;
1201   updateEventsTime (aPrevEventTime, aNewEventTime);
1202 
1203   double aDuration = 0.0, aPressure = 1.0;
1204   if (Abs (myThrustSpeed) > gp::Resolution())
1205   {
1206     if (myHasThrust)
1207     {
1208       aWalk[AIS_WalkTranslation_Forward].Value = myThrustSpeed * (aNewEventTime - aPrevEventTime);
1209     }
1210     myHasThrust = true;
1211     myToAskNextFrame = true;
1212   }
1213   else
1214   {
1215     myHasThrust = false;
1216   }
1217 
1218   aWalk.SetRunning (theRunRatio > 1.0
1219                  && myKeys.IsKeyDown (Aspect_VKey_Shift));
1220   if (myKeys.HoldDuration (Aspect_VKey_NavJump, aNewEventTime, aDuration))
1221   {
1222     myKeys.KeyUp (Aspect_VKey_NavJump, aNewEventTime);
1223     aWalk.SetDefined (true);
1224     aWalk.SetJumping (true);
1225   }
1226   if (!aWalk.IsJumping()
1227    && theCrouchRatio < 1.0
1228    && myKeys.HoldDuration (Aspect_VKey_NavCrouch, aNewEventTime, aDuration))
1229   {
1230     aWalk.SetDefined (true);
1231     aWalk.SetRunning (false);
1232     aWalk.SetCrouching (true);
1233   }
1234 
1235   const double aMaxDuration = aNewEventTime - aPrevEventTime;
1236   const double aRunRatio = aWalk.IsRunning()
1237                          ? theRunRatio
1238                          : aWalk.IsCrouching()
1239                           ? theCrouchRatio
1240                           : 1.0;
1241   if (myKeys.HoldDuration (Aspect_VKey_NavForward, aNewEventTime, aDuration, aPressure))
1242   {
1243     double aProgress = Abs (Min (aMaxDuration, aDuration));
1244     aProgress *= aRunRatio;
1245     aWalk.SetDefined (true);
1246     aWalk[AIS_WalkTranslation_Forward].Value += aProgress;
1247     aWalk[AIS_WalkTranslation_Forward].Pressure = aPressure;
1248     aWalk[AIS_WalkTranslation_Forward].Duration = aDuration;
1249   }
1250   if (myKeys.HoldDuration (Aspect_VKey_NavBackward, aNewEventTime, aDuration, aPressure))
1251   {
1252     double aProgress = Abs (Min (aMaxDuration, aDuration));
1253     aProgress *= aRunRatio;
1254     aWalk.SetDefined (true);
1255     aWalk[AIS_WalkTranslation_Forward].Value += -aProgress;
1256     aWalk[AIS_WalkTranslation_Forward].Pressure = aPressure;
1257     aWalk[AIS_WalkTranslation_Forward].Duration = aDuration;
1258   }
1259   if (myKeys.HoldDuration (Aspect_VKey_NavSlideLeft, aNewEventTime, aDuration, aPressure))
1260   {
1261     double aProgress = Abs (Min (aMaxDuration, aDuration));
1262     aProgress *= aRunRatio;
1263     aWalk.SetDefined (true);
1264     aWalk[AIS_WalkTranslation_Side].Value = -aProgress;
1265     aWalk[AIS_WalkTranslation_Side].Pressure = aPressure;
1266     aWalk[AIS_WalkTranslation_Side].Duration = aDuration;
1267   }
1268   if (myKeys.HoldDuration (Aspect_VKey_NavSlideRight, aNewEventTime, aDuration, aPressure))
1269   {
1270     double aProgress = Abs (Min (aMaxDuration, aDuration));
1271     aProgress *= aRunRatio;
1272     aWalk.SetDefined (true);
1273     aWalk[AIS_WalkTranslation_Side].Value = aProgress;
1274     aWalk[AIS_WalkTranslation_Side].Pressure = aPressure;
1275     aWalk[AIS_WalkTranslation_Side].Duration = aDuration;
1276   }
1277   if (myKeys.HoldDuration (Aspect_VKey_NavLookLeft, aNewEventTime, aDuration, aPressure))
1278   {
1279     double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1280     aWalk.SetDefined (true);
1281     aWalk[AIS_WalkRotation_Yaw].Value = aProgress;
1282     aWalk[AIS_WalkRotation_Yaw].Pressure = aPressure;
1283     aWalk[AIS_WalkRotation_Yaw].Duration = aDuration;
1284   }
1285   if (myKeys.HoldDuration (Aspect_VKey_NavLookRight, aNewEventTime, aDuration, aPressure))
1286   {
1287     double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1288     aWalk.SetDefined (true);
1289     aWalk[AIS_WalkRotation_Yaw].Value = -aProgress;
1290     aWalk[AIS_WalkRotation_Yaw].Pressure = aPressure;
1291     aWalk[AIS_WalkRotation_Yaw].Duration = aDuration;
1292   }
1293   if (myKeys.HoldDuration (Aspect_VKey_NavLookUp, aNewEventTime, aDuration, aPressure))
1294   {
1295     double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1296     aWalk.SetDefined (true);
1297     aWalk[AIS_WalkRotation_Pitch].Value = !myToInvertPitch ? -aProgress : aProgress;
1298     aWalk[AIS_WalkRotation_Pitch].Pressure = aPressure;
1299     aWalk[AIS_WalkRotation_Pitch].Duration = aDuration;
1300   }
1301   if (myKeys.HoldDuration (Aspect_VKey_NavLookDown, aNewEventTime, aDuration, aPressure))
1302   {
1303     double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1304     aWalk.SetDefined (true);
1305     aWalk[AIS_WalkRotation_Pitch].Value = !myToInvertPitch ? aProgress : -aProgress;
1306     aWalk[AIS_WalkRotation_Pitch].Pressure = aPressure;
1307     aWalk[AIS_WalkRotation_Pitch].Duration = aDuration;
1308   }
1309   if (myKeys.HoldDuration (Aspect_VKey_NavRollCCW, aNewEventTime, aDuration, aPressure))
1310   {
1311     double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1312     aWalk.SetDefined (true);
1313     aWalk[AIS_WalkRotation_Roll].Value = -aProgress;
1314     aWalk[AIS_WalkRotation_Roll].Pressure = aPressure;
1315     aWalk[AIS_WalkRotation_Roll].Duration = aDuration;
1316   }
1317   if (myKeys.HoldDuration (Aspect_VKey_NavRollCW, aNewEventTime, aDuration, aPressure))
1318   {
1319     double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1320     aWalk.SetDefined (true);
1321     aWalk[AIS_WalkRotation_Roll].Value = aProgress;
1322     aWalk[AIS_WalkRotation_Roll].Pressure = aPressure;
1323     aWalk[AIS_WalkRotation_Roll].Duration = aDuration;
1324   }
1325   if (myKeys.HoldDuration (Aspect_VKey_NavSlideUp, aNewEventTime, aDuration, aPressure))
1326   {
1327     double aProgress = Abs (Min (aMaxDuration, aDuration));
1328     aWalk.SetDefined (true);
1329     aWalk[AIS_WalkTranslation_Up].Value = aProgress;
1330     aWalk[AIS_WalkTranslation_Up].Pressure = aPressure;
1331     aWalk[AIS_WalkTranslation_Up].Duration = aDuration;
1332   }
1333   if (myKeys.HoldDuration (Aspect_VKey_NavSlideDown, aNewEventTime, aDuration, aPressure))
1334   {
1335     double aProgress = Abs (Min (aMaxDuration, aDuration));
1336     aWalk.SetDefined (true);
1337     aWalk[AIS_WalkTranslation_Up].Value = -aProgress;
1338     aWalk[AIS_WalkTranslation_Up].Pressure = aPressure;
1339     aWalk[AIS_WalkTranslation_Up].Duration = aDuration;
1340   }
1341   return aWalk;
1342 }
1343 
1344 // =======================================================================
1345 // function : AbortViewAnimation
1346 // purpose  :
1347 // =======================================================================
AbortViewAnimation()1348 void AIS_ViewController::AbortViewAnimation()
1349 {
1350   if (!myViewAnimation.IsNull()
1351    && !myViewAnimation->IsStopped())
1352   {
1353     myViewAnimation->Stop();
1354     myViewAnimation->SetView (Handle(V3d_View)());
1355   }
1356 }
1357 
1358 // =======================================================================
1359 // function : handlePanning
1360 // purpose  :
1361 // =======================================================================
handlePanning(const Handle (V3d_View)& theView)1362 void AIS_ViewController::handlePanning (const Handle(V3d_View)& theView)
1363 {
1364   if (!myGL.Panning.ToPan
1365    || !myToAllowPanning)
1366   {
1367     return;
1368   }
1369 
1370   AbortViewAnimation();
1371 
1372   const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1373   if (aCam->IsOrthographic()
1374   || !hasPanningAnchorPoint())
1375   {
1376     theView->Pan (myGL.Panning.Delta.x(), myGL.Panning.Delta.y());
1377     theView->Invalidate();
1378     theView->View()->SynchronizeXRPosedToBaseCamera();
1379     return;
1380   }
1381 
1382   Graphic3d_Vec2i aWinSize;
1383   theView->Window()->Size (aWinSize.x(), aWinSize.y());
1384 
1385   const gp_Dir& aDir = aCam->Direction();
1386   const gp_Ax3 aCameraCS (aCam->Center(), aDir.Reversed(), aDir ^ aCam->Up());
1387   const gp_XYZ anEyeToPnt = myPanPnt3d.XYZ() - aCam->Eye().XYZ();
1388   const gp_Pnt aViewDims = aCam->ViewDimensions (anEyeToPnt.Dot (aCam->Direction().XYZ())); // view dimensions at 3D point
1389   const Graphic3d_Vec2d aDxy (-aViewDims.X() * myGL.Panning.Delta.x() / double(aWinSize.x()),
1390                               -aViewDims.X() * myGL.Panning.Delta.y() / double(aWinSize.x()));
1391 
1392   //theView->Translate (aCam, aDxy.x(), aDxy.y());
1393   gp_Trsf aPanTrsf;
1394   const gp_Vec aCameraPan = gp_Vec (aCameraCS.XDirection()) * aDxy.x()
1395                           + gp_Vec (aCameraCS.YDirection()) * aDxy.y();
1396   aPanTrsf.SetTranslation (aCameraPan);
1397   aCam->Transform (aPanTrsf);
1398   theView->Invalidate();
1399   theView->View()->SynchronizeXRPosedToBaseCamera();
1400 }
1401 
1402 // =======================================================================
1403 // function : handleZRotate
1404 // purpose  :
1405 // =======================================================================
handleZRotate(const Handle (V3d_View)& theView)1406 void AIS_ViewController::handleZRotate (const Handle(V3d_View)& theView)
1407 {
1408   if (!myGL.ZRotate.ToRotate
1409    || !myToAllowRotation)
1410   {
1411     return;
1412   }
1413 
1414   AbortViewAnimation();
1415 
1416   Graphic3d_Vec2i aViewPort;
1417   theView->Window()->Size (aViewPort.x(), aViewPort.y());
1418   Graphic3d_Vec2d aRotPnt (0.99 * aViewPort.x(),
1419                            0.5  * aViewPort.y());
1420   theView->StartRotation (int(aRotPnt.x()), int(aRotPnt.y()), 0.4);
1421   aRotPnt.y() += myGL.ZRotate.Angle * aViewPort.y();
1422   theView->Rotation (int(aRotPnt.x()), int(aRotPnt.y()));
1423   theView->Invalidate();
1424   theView->View()->SynchronizeXRPosedToBaseCamera();
1425 }
1426 
1427 // =======================================================================
1428 // function : handleZoom
1429 // purpose  :
1430 // =======================================================================
handleZoom(const Handle (V3d_View)& theView,const Aspect_ScrollDelta & theParams,const gp_Pnt * thePnt)1431 void AIS_ViewController::handleZoom (const Handle(V3d_View)& theView,
1432                                      const Aspect_ScrollDelta& theParams,
1433                                      const gp_Pnt* thePnt)
1434 {
1435   if (!myToAllowZooming)
1436   {
1437     return;
1438   }
1439 
1440   AbortViewAnimation();
1441 
1442   const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1443   if (thePnt != NULL)
1444   {
1445     const double aViewDist = Max (myMinCamDistance, (thePnt->XYZ() - aCam->Eye().XYZ()).Modulus());
1446     aCam->SetCenter (aCam->Eye().XYZ() + aCam->Direction().XYZ() * aViewDist);
1447   }
1448 
1449   if (!theParams.HasPoint())
1450   {
1451     Standard_Real aCoeff = Abs(theParams.Delta) / 100.0 + 1.0;
1452     aCoeff = theParams.Delta > 0.0 ? aCoeff : 1.0 / aCoeff;
1453     theView->SetZoom (aCoeff, true);
1454     theView->Invalidate();
1455     theView->View()->SynchronizeXRPosedToBaseCamera();
1456     return;
1457   }
1458 
1459   // integer delta is too rough for small smooth increments
1460   //theView->StartZoomAtPoint (theParams.Point.x(), theParams.Point.y());
1461   //theView->ZoomAtPoint (0, 0, (int )theParams.Delta, (int )theParams.Delta);
1462 
1463   double aDZoom = Abs (theParams.Delta) / 100.0 + 1.0;
1464   aDZoom = (theParams.Delta > 0.0) ? aDZoom : 1.0 / aDZoom;
1465   if (aDZoom <= 0.0)
1466   {
1467     return;
1468   }
1469 
1470   const Graphic3d_Vec2d aViewDims (aCam->ViewDimensions().X(), aCam->ViewDimensions().Y());
1471 
1472   // ensure that zoom will not be too small or too big
1473   double aCoef = aDZoom;
1474   if (aViewDims.x() < aCoef * Precision::Confusion())
1475   {
1476     aCoef = aViewDims.x() / Precision::Confusion();
1477   }
1478   else if (aViewDims.x() > aCoef * 1e12)
1479   {
1480     aCoef = aViewDims.x() / 1e12;
1481   }
1482   if (aViewDims.y() < aCoef * Precision::Confusion())
1483   {
1484     aCoef = aViewDims.y() / Precision::Confusion();
1485   }
1486   else if (aViewDims.y() > aCoef * 1e12)
1487   {
1488     aCoef = aViewDims.y() / 1e12;
1489   }
1490 
1491   Graphic3d_Vec2d aZoomAtPointXYv (0.0, 0.0);
1492   theView->Convert (theParams.Point.x(), theParams.Point.y(),
1493                     aZoomAtPointXYv.x(), aZoomAtPointXYv.y());
1494   Graphic3d_Vec2d aDxy = aZoomAtPointXYv / aCoef;
1495   aCam->SetScale (aCam->Scale() / aCoef);
1496 
1497   const gp_Dir& aDir = aCam->Direction();
1498   const gp_Ax3 aCameraCS (aCam->Center(), aDir.Reversed(), aDir ^ aCam->Up());
1499 
1500   // pan back to the point
1501   aDxy = aZoomAtPointXYv - aDxy;
1502   if (thePnt != NULL)
1503   {
1504     // zoom at 3D point with perspective projection
1505     const gp_XYZ anEyeToPnt = thePnt->XYZ() - aCam->Eye().XYZ();
1506     aDxy.SetValues (anEyeToPnt.Dot (aCameraCS.XDirection().XYZ()),
1507                     anEyeToPnt.Dot (aCameraCS.YDirection().XYZ()));
1508 
1509     // view dimensions at 3D point
1510     const gp_Pnt aViewDims1 = aCam->ViewDimensions (anEyeToPnt.Dot (aCam->Direction().XYZ()));
1511 
1512     Graphic3d_Vec2i aWinSize;
1513     theView->Window()->Size (aWinSize.x(), aWinSize.y());
1514     const Graphic3d_Vec2d aPanFromCenterPx (double(theParams.Point.x()) - 0.5 * double(aWinSize.x()),
1515                                             double(aWinSize.y() - theParams.Point.y() - 1) - 0.5 * double(aWinSize.y()));
1516     aDxy.x() += -aViewDims1.X() * aPanFromCenterPx.x() / double(aWinSize.x());
1517     aDxy.y() += -aViewDims1.Y() * aPanFromCenterPx.y() / double(aWinSize.y());
1518   }
1519 
1520   //theView->Translate (aCam, aDxy.x(), aDxy.y());
1521   gp_Trsf aPanTrsf;
1522   const gp_Vec aCameraPan = gp_Vec (aCameraCS.XDirection()) * aDxy.x()
1523                           + gp_Vec (aCameraCS.YDirection()) * aDxy.y();
1524   aPanTrsf.SetTranslation (aCameraPan);
1525   aCam->Transform (aPanTrsf);
1526   theView->Invalidate();
1527   theView->View()->SynchronizeXRPosedToBaseCamera();
1528 }
1529 
1530 // =======================================================================
1531 // function : handleZFocusScroll
1532 // purpose  :
1533 // =======================================================================
handleZFocusScroll(const Handle (V3d_View)& theView,const Aspect_ScrollDelta & theParams)1534 void AIS_ViewController::handleZFocusScroll (const Handle(V3d_View)& theView,
1535                                              const Aspect_ScrollDelta& theParams)
1536 {
1537   if (!myToAllowZFocus
1538    || !theView->Camera()->IsStereo())
1539   {
1540     return;
1541   }
1542 
1543   Standard_Real aFocus = theView->Camera()->ZFocus() + (theParams.Delta > 0.0 ? 0.05 : -0.05);
1544   if (aFocus > 0.2
1545    && aFocus < 2.0)
1546   {
1547     theView->Camera()->SetZFocus (theView->Camera()->ZFocusType(), aFocus);
1548     theView->Invalidate();
1549   }
1550 }
1551 
1552 // =======================================================================
1553 // function : handleOrbitRotation
1554 // purpose  :
1555 // =======================================================================
handleOrbitRotation(const Handle (V3d_View)& theView,const gp_Pnt & thePnt,bool theToLockZUp)1556 void AIS_ViewController::handleOrbitRotation (const Handle(V3d_View)& theView,
1557                                               const gp_Pnt& thePnt,
1558                                               bool theToLockZUp)
1559 {
1560   if (!myToAllowRotation)
1561   {
1562     return;
1563   }
1564 
1565   const Handle(Graphic3d_Camera)& aCam = theView->View()->IsActiveXR()
1566                                        ? theView->View()->BaseXRCamera()
1567                                        : theView->Camera();
1568   if (myGL.OrbitRotation.ToStart)
1569   {
1570     // default alternatives
1571     //if (myRotationMode == AIS_RotationMode_BndBoxActive) theView->StartRotation (myGL.RotateAtPoint.x(), myGL.RotateAtPoint.y());
1572     //theView->Rotate (0.0, 0.0, 0.0, thePnt.X(), thePnt.Y(), thePnt.Z(), true);
1573 
1574     myRotatePnt3d      = thePnt;
1575     myCamStartOpUp     = aCam->Up();
1576     myCamStartOpDir    = aCam->Direction();
1577     myCamStartOpEye    = aCam->Eye();
1578     myCamStartOpCenter = aCam->Center();
1579 
1580     gp_Trsf aTrsf;
1581     aTrsf.SetTransformation (gp_Ax3 (myRotatePnt3d, aCam->OrthogonalizedUp(), aCam->Direction()),
1582                              gp_Ax3 (myRotatePnt3d, gp::DZ(), gp::DX()));
1583     const gp_Quaternion aRot = aTrsf.GetRotation();
1584     aRot.GetEulerAngles (gp_YawPitchRoll, myRotateStartYawPitchRoll[0], myRotateStartYawPitchRoll[1], myRotateStartYawPitchRoll[2]);
1585 
1586     aTrsf.Invert();
1587     myCamStartOpToEye    = gp_Vec (myRotatePnt3d, aCam->Eye()).Transformed (aTrsf);
1588     myCamStartOpToCenter = gp_Vec (myRotatePnt3d, aCam->Center()).Transformed (aTrsf);
1589 
1590     theView->Invalidate();
1591   }
1592 
1593   if (!myGL.OrbitRotation.ToRotate)
1594   {
1595     return;
1596   }
1597 
1598   AbortViewAnimation();
1599   if (theToLockZUp)
1600   {
1601     // amend camera to exclude roll angle (put camera Up vector to plane containing global Z and view direction)
1602     Graphic3d_Vec2i aWinXY;
1603     theView->Window()->Size (aWinXY.x(), aWinXY.y());
1604     double aYawAngleDelta   =  ((myGL.OrbitRotation.PointStart.x() - myGL.OrbitRotation.PointTo.x()) / double (aWinXY.x())) * (M_PI * 0.5);
1605     double aPitchAngleDelta = -((myGL.OrbitRotation.PointStart.y() - myGL.OrbitRotation.PointTo.y()) / double (aWinXY.y())) * (M_PI * 0.5);
1606     double aPitchAngleNew = 0.0, aRoll = 0.0;
1607     const double aYawAngleNew = myRotateStartYawPitchRoll[0] + aYawAngleDelta;
1608     if (!theView->View()->IsActiveXR())
1609     {
1610       aPitchAngleNew = Max (Min (myRotateStartYawPitchRoll[1] + aPitchAngleDelta, M_PI * 0.5 - M_PI / 180.0), -M_PI * 0.5 + M_PI / 180.0);
1611       aRoll = 0.0;
1612     }
1613 
1614     gp_Quaternion aRot;
1615     aRot.SetEulerAngles (gp_YawPitchRoll, aYawAngleNew, aPitchAngleNew, aRoll);
1616     gp_Trsf aTrsfRot;
1617     aTrsfRot.SetRotation (aRot);
1618 
1619     const gp_Dir aNewUp = gp::DZ().Transformed (aTrsfRot);
1620     aCam->SetUp (aNewUp);
1621     aCam->SetEyeAndCenter (myRotatePnt3d.XYZ() + myCamStartOpToEye   .Transformed (aTrsfRot).XYZ(),
1622                            myRotatePnt3d.XYZ() + myCamStartOpToCenter.Transformed (aTrsfRot).XYZ());
1623 
1624     aCam->OrthogonalizeUp();
1625   }
1626   else
1627   {
1628     // default alternatives
1629     //if (myRotationMode == AIS_RotationMode_BndBoxActive) theView->Rotation (myGL.RotateToPoint.x(), myGL.RotateToPoint.y());
1630     //theView->Rotate (aDX, aDY, aDZ, myRotatePnt3d.X(), myRotatePnt3d.Y(), myRotatePnt3d.Z(), false);
1631 
1632     // restore previous camera state
1633     aCam->SetEyeAndCenter (myCamStartOpEye, myCamStartOpCenter);
1634     aCam->SetUp (myCamStartOpUp);
1635     aCam->SetDirectionFromEye (myCamStartOpDir);
1636 
1637     Graphic3d_Vec2d aWinXY;
1638     theView->Size (aWinXY.x(), aWinXY.y());
1639     const Standard_Real rx = (Standard_Real )theView->Convert (aWinXY.x());
1640     const Standard_Real ry = (Standard_Real )theView->Convert (aWinXY.y());
1641 
1642     const double THE_2PI = M_PI * 2.0;
1643     double aDX = (myGL.OrbitRotation.PointTo.x() - myGL.OrbitRotation.PointStart.x()) * M_PI / rx;
1644     double aDY = (myGL.OrbitRotation.PointStart.y() - myGL.OrbitRotation.PointTo.y()) * M_PI / ry;
1645 
1646     if     (aDX > 0.0) { while (aDX >  THE_2PI) { aDX -= THE_2PI; } }
1647     else if(aDX < 0.0) { while (aDX < -THE_2PI) { aDX += THE_2PI; } }
1648     if     (aDY > 0.0) { while (aDY >  THE_2PI) { aDY -= THE_2PI; } }
1649     else if(aDY < 0.0) { while (aDY < -THE_2PI) { aDY += THE_2PI; } }
1650 
1651     // rotate camera around 3 initial axes
1652     gp_Dir aCamDir (aCam->Direction().Reversed());
1653     gp_Dir aCamUp  (aCam->Up());
1654     gp_Dir aCamSide(aCamUp.Crossed (aCamDir));
1655 
1656     gp_Trsf aRot[2], aTrsf;
1657     aRot[0].SetRotation (gp_Ax1 (myRotatePnt3d, aCamUp),  -aDX);
1658     aRot[1].SetRotation (gp_Ax1 (myRotatePnt3d, aCamSide), aDY);
1659     aTrsf.Multiply (aRot[0]);
1660     aTrsf.Multiply (aRot[1]);
1661 
1662     aCam->Transform (aTrsf);
1663   }
1664 
1665   theView->Invalidate();
1666   theView->View()->SynchronizeXRBaseToPosedCamera();
1667 }
1668 
1669 // =======================================================================
1670 // function : handleViewRotation
1671 // purpose  :
1672 // =======================================================================
handleViewRotation(const Handle (V3d_View)& theView,double theYawExtra,double thePitchExtra,double theRoll,bool theToRestartOnIncrement)1673 void AIS_ViewController::handleViewRotation (const Handle(V3d_View)& theView,
1674                                              double theYawExtra,
1675                                              double thePitchExtra,
1676                                              double theRoll,
1677                                              bool theToRestartOnIncrement)
1678 {
1679   if (!myToAllowRotation)
1680   {
1681     return;
1682   }
1683 
1684   const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1685   const bool toRotateAnyway = Abs (theYawExtra)   > gp::Resolution()
1686                            || Abs (thePitchExtra) > gp::Resolution()
1687                            || Abs (theRoll - myRotateStartYawPitchRoll[2]) > gp::Resolution();
1688   if (toRotateAnyway
1689    && theToRestartOnIncrement)
1690   {
1691     myGL.ViewRotation.ToStart = true;
1692     myGL.ViewRotation.PointTo = myGL.ViewRotation.PointStart;
1693   }
1694   if (myGL.ViewRotation.ToStart)
1695   {
1696     gp_Trsf aTrsf;
1697     aTrsf.SetTransformation (gp_Ax3 (gp::Origin(), aCam->OrthogonalizedUp(), aCam->Direction()),
1698                              gp_Ax3 (gp::Origin(), gp::DZ(), gp::DX()));
1699     const gp_Quaternion aRot = aTrsf.GetRotation();
1700     double aRollDummy = 0.0;
1701     aRot.GetEulerAngles (gp_YawPitchRoll, myRotateStartYawPitchRoll[0], myRotateStartYawPitchRoll[1], aRollDummy);
1702   }
1703   if (toRotateAnyway)
1704   {
1705     myRotateStartYawPitchRoll[0] += theYawExtra;
1706     myRotateStartYawPitchRoll[1] += thePitchExtra;
1707     myRotateStartYawPitchRoll[2]  = theRoll;
1708     myGL.ViewRotation.ToRotate = true;
1709   }
1710 
1711   if (!myGL.ViewRotation.ToRotate)
1712   {
1713     return;
1714   }
1715 
1716   AbortViewAnimation();
1717 
1718   Graphic3d_Vec2i aWinXY;
1719   theView->Window()->Size (aWinXY.x(), aWinXY.y());
1720   double aYawAngleDelta   =  ((myGL.ViewRotation.PointStart.x() - myGL.ViewRotation.PointTo.x()) / double (aWinXY.x())) * (M_PI * 0.5);
1721   double aPitchAngleDelta = -((myGL.ViewRotation.PointStart.y() - myGL.ViewRotation.PointTo.y()) / double (aWinXY.y())) * (M_PI * 0.5);
1722   const double aPitchAngleNew = Max (Min (myRotateStartYawPitchRoll[1] + aPitchAngleDelta, M_PI * 0.5 - M_PI / 180.0), -M_PI * 0.5 + M_PI / 180.0);
1723   const double aYawAngleNew   = myRotateStartYawPitchRoll[0] + aYawAngleDelta;
1724   gp_Quaternion aRot;
1725   aRot.SetEulerAngles (gp_YawPitchRoll, aYawAngleNew, aPitchAngleNew, theRoll);
1726   gp_Trsf aTrsfRot;
1727   aTrsfRot.SetRotation (aRot);
1728 
1729   const gp_Dir aNewUp  = gp::DZ().Transformed (aTrsfRot);
1730   const gp_Dir aNewDir = gp::DX().Transformed (aTrsfRot);
1731   aCam->SetUp (aNewUp);
1732   aCam->SetDirectionFromEye (aNewDir);
1733   aCam->OrthogonalizeUp();
1734   theView->Invalidate();
1735 }
1736 
1737 // =======================================================================
1738 // function : PickPoint
1739 // purpose  :
1740 // =======================================================================
PickPoint(gp_Pnt & thePnt,const Handle (AIS_InteractiveContext)& theCtx,const Handle (V3d_View)& theView,const Graphic3d_Vec2i & theCursor,bool theToStickToPickRay)1741 bool AIS_ViewController::PickPoint (gp_Pnt& thePnt,
1742                                     const Handle(AIS_InteractiveContext)& theCtx,
1743                                     const Handle(V3d_View)& theView,
1744                                     const Graphic3d_Vec2i& theCursor,
1745                                     bool theToStickToPickRay)
1746 {
1747   ResetPreviousMoveTo();
1748 
1749   const Handle(StdSelect_ViewerSelector3d)& aSelector = theCtx->MainSelector();
1750   aSelector->Pick (theCursor.x(), theCursor.y(), theView);
1751   if (aSelector->NbPicked() < 1)
1752   {
1753     return false;
1754   }
1755 
1756   const SelectMgr_SortCriterion& aPicked = aSelector->PickedData (1);
1757   if (theToStickToPickRay
1758   && !Precision::IsInfinite (aPicked.Depth))
1759   {
1760     thePnt = aSelector->GetManager().DetectedPoint (aPicked.Depth);
1761   }
1762   else
1763   {
1764     thePnt = aSelector->PickedPoint (1);
1765   }
1766   return !Precision::IsInfinite (thePnt.X())
1767       && !Precision::IsInfinite (thePnt.Y())
1768       && !Precision::IsInfinite (thePnt.Z());
1769 }
1770 
1771 // =======================================================================
1772 // function : PickAxis
1773 // purpose  :
1774 // =======================================================================
PickAxis(gp_Pnt & theTopPnt,const Handle (AIS_InteractiveContext)& theCtx,const Handle (V3d_View)& theView,const gp_Ax1 & theAxis)1775 bool AIS_ViewController::PickAxis (gp_Pnt& theTopPnt,
1776                                    const Handle(AIS_InteractiveContext)& theCtx,
1777                                    const Handle(V3d_View)& theView,
1778                                    const gp_Ax1& theAxis)
1779 {
1780   ResetPreviousMoveTo();
1781 
1782   const Handle(StdSelect_ViewerSelector3d)& aSelector = theCtx->MainSelector();
1783   aSelector->Pick (theAxis, theView);
1784   if (aSelector->NbPicked() < 1)
1785   {
1786     return false;
1787   }
1788 
1789   const SelectMgr_SortCriterion& aPickedData = aSelector->PickedData (1);
1790   theTopPnt = aPickedData.Point;
1791   return !Precision::IsInfinite (theTopPnt.X())
1792       && !Precision::IsInfinite (theTopPnt.Y())
1793       && !Precision::IsInfinite (theTopPnt.Z());
1794 }
1795 
1796 // =======================================================================
1797 // function : GravityPoint
1798 // purpose  :
1799 // =======================================================================
GravityPoint(const Handle (AIS_InteractiveContext)& theCtx,const Handle (V3d_View)& theView)1800 gp_Pnt AIS_ViewController::GravityPoint (const Handle(AIS_InteractiveContext)& theCtx,
1801                                          const Handle(V3d_View)& theView)
1802 {
1803   switch (myRotationMode)
1804   {
1805     case AIS_RotationMode_PickLast:
1806     case AIS_RotationMode_PickCenter:
1807     {
1808       Graphic3d_Vec2i aCursor ((int )myGL.OrbitRotation.PointStart.x(), (int )myGL.OrbitRotation.PointStart.y());
1809       if (myRotationMode == AIS_RotationMode_PickCenter)
1810       {
1811         Graphic3d_Vec2i aViewPort;
1812         theView->Window()->Size (aViewPort.x(), aViewPort.y());
1813         aCursor = aViewPort / 2;
1814       }
1815 
1816       gp_Pnt aPnt;
1817       if (PickPoint (aPnt, theCtx, theView, aCursor, myToStickToRayOnRotation))
1818       {
1819         return aPnt;
1820       }
1821       break;
1822     }
1823     case AIS_RotationMode_CameraAt:
1824     {
1825       const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1826       return aCam->Center();
1827     }
1828     case AIS_RotationMode_BndBoxScene:
1829     {
1830       Bnd_Box aBndBox = theView->View()->MinMaxValues (false);
1831       if (!aBndBox.IsVoid())
1832       {
1833         return (aBndBox.CornerMin().XYZ() + aBndBox.CornerMax().XYZ()) * 0.5;
1834       }
1835       break;
1836     }
1837     case AIS_RotationMode_BndBoxActive:
1838       break;
1839   }
1840 
1841   return theCtx ->GravityPoint (theView);
1842 }
1843 
1844 // =======================================================================
1845 // function : FitAllAuto
1846 // purpose  :
1847 // =======================================================================
FitAllAuto(const Handle (AIS_InteractiveContext)& theCtx,const Handle (V3d_View)& theView)1848 void AIS_ViewController::FitAllAuto (const Handle(AIS_InteractiveContext)& theCtx,
1849                                      const Handle(V3d_View)& theView)
1850 {
1851   const Bnd_Box aBoxSel = theCtx->BoundingBoxOfSelection();
1852   const double aFitMargin = 0.01;
1853   if (aBoxSel.IsVoid())
1854   {
1855     theView->FitAll (aFitMargin, false);
1856     return;
1857   }
1858 
1859   // fit all algorithm is not 100% stable - so compute some precision to compare equal camera values
1860   const double  aFitTol = (aBoxSel.CornerMax().XYZ() - aBoxSel.CornerMin().XYZ()).Modulus() * 0.000001;
1861   const Bnd_Box aBoxAll = theView->View()->MinMaxValues();
1862 
1863   const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1864   Handle(Graphic3d_Camera) aCameraSel = new Graphic3d_Camera (aCam);
1865   Handle(Graphic3d_Camera) aCameraAll = new Graphic3d_Camera (aCam);
1866   theView->FitMinMax (aCameraSel, aBoxSel, aFitMargin);
1867   theView->FitMinMax (aCameraAll, aBoxAll, aFitMargin);
1868   if (aCameraSel->Center().IsEqual (aCam->Center(),     aFitTol)
1869    && Abs (aCameraSel->Scale()    - aCam->Scale())    < aFitTol
1870    && Abs (aCameraSel->Distance() - aCam->Distance()) < aFitTol)
1871   {
1872     // fit all entire view on second FitALL request
1873     aCam->Copy (aCameraAll);
1874   }
1875   else
1876   {
1877     aCam->Copy (aCameraSel);
1878   }
1879 }
1880 
1881 // =======================================================================
1882 // function : handleViewOrientationKeys
1883 // purpose  :
1884 // =======================================================================
handleViewOrientationKeys(const Handle (AIS_InteractiveContext)& theCtx,const Handle (V3d_View)& theView)1885 void AIS_ViewController::handleViewOrientationKeys (const Handle(AIS_InteractiveContext)& theCtx,
1886                                                     const Handle(V3d_View)& theView)
1887 {
1888   if (myNavigationMode == AIS_NavigationMode_FirstPersonWalk)
1889   {
1890     return;
1891   }
1892 
1893   Handle(Graphic3d_Camera) aCameraBack;
1894   struct ViewKeyAction
1895   {
1896     Aspect_VKey Key;
1897     V3d_TypeOfOrientation Orientation;
1898   };
1899   static const ViewKeyAction THE_VIEW_KEYS[] =
1900   {
1901     { Aspect_VKey_ViewTop,          V3d_TypeOfOrientation_Zup_Top },
1902     { Aspect_VKey_ViewBottom,       V3d_TypeOfOrientation_Zup_Bottom },
1903     { Aspect_VKey_ViewLeft,         V3d_TypeOfOrientation_Zup_Left },
1904     { Aspect_VKey_ViewRight,        V3d_TypeOfOrientation_Zup_Right },
1905     { Aspect_VKey_ViewFront,        V3d_TypeOfOrientation_Zup_Front },
1906     { Aspect_VKey_ViewBack,         V3d_TypeOfOrientation_Zup_Back },
1907     { Aspect_VKey_ViewAxoLeftProj,  V3d_TypeOfOrientation_Zup_AxoLeft },
1908     { Aspect_VKey_ViewAxoRightProj, V3d_TypeOfOrientation_Zup_AxoRight },
1909     { Aspect_VKey_ViewRoll90CW,     (V3d_TypeOfOrientation )-1},
1910     { Aspect_VKey_ViewRoll90CCW,    (V3d_TypeOfOrientation )-1},
1911     { Aspect_VKey_ViewFitAll,       (V3d_TypeOfOrientation )-1}
1912   };
1913   {
1914     Standard_Mutex::Sentry aLock (myKeys.Mutex());
1915     const size_t aNbKeys = sizeof(THE_VIEW_KEYS) / sizeof(*THE_VIEW_KEYS);
1916     const double anEventTime = EventTime();
1917     for (size_t aKeyIter = 0; aKeyIter < aNbKeys; ++aKeyIter)
1918     {
1919       const ViewKeyAction& aKeyAction = THE_VIEW_KEYS[aKeyIter];
1920       if (!myKeys.IsKeyDown (aKeyAction.Key))
1921       {
1922         continue;
1923       }
1924 
1925       myKeys.KeyUp (aKeyAction.Key, anEventTime);
1926       if (aCameraBack.IsNull())
1927       {
1928         aCameraBack = theView->Camera();
1929         theView->SetCamera (new Graphic3d_Camera (aCameraBack));
1930       }
1931       if (aKeyAction.Orientation != (V3d_TypeOfOrientation )-1)
1932       {
1933         theView->SetProj (aKeyAction.Orientation);
1934         FitAllAuto (theCtx, theView);
1935       }
1936       else if (aKeyAction.Key == Aspect_VKey_ViewRoll90CW)
1937       {
1938         const double aTwist = theView->Twist() + M_PI / 2.0;
1939         theView->SetTwist (aTwist);
1940       }
1941       else if (aKeyAction.Key == Aspect_VKey_ViewRoll90CCW)
1942       {
1943         const double aTwist = theView->Twist() - M_PI / 2.0;
1944         theView->SetTwist (aTwist);
1945       }
1946       else if (aKeyAction.Key == Aspect_VKey_ViewFitAll)
1947       {
1948         FitAllAuto (theCtx, theView);
1949       }
1950     }
1951   }
1952 
1953   if (aCameraBack.IsNull())
1954   {
1955     return;
1956   }
1957 
1958   Handle(Graphic3d_Camera) aCameraNew = theView->Camera();
1959   theView->SetCamera (aCameraBack);
1960   const Graphic3d_Mat4d anOrientMat1 = aCameraBack->OrientationMatrix();
1961   const Graphic3d_Mat4d anOrientMat2 = aCameraNew ->OrientationMatrix();
1962   if (anOrientMat1 != anOrientMat2)
1963   {
1964     const Handle(AIS_AnimationCamera)& aCamAnim = myViewAnimation;
1965     aCamAnim->SetView (theView);
1966     aCamAnim->SetStartPts (0.0);
1967     aCamAnim->SetCameraStart (new Graphic3d_Camera (aCameraBack));
1968     aCamAnim->SetCameraEnd   (new Graphic3d_Camera (aCameraNew));
1969     aCamAnim->StartTimer (0.0, 1.0, true, false);
1970   }
1971 }
1972 
1973 // =======================================================================
1974 // function : handleNavigationKeys
1975 // purpose  :
1976 // =======================================================================
handleNavigationKeys(const Handle (AIS_InteractiveContext)&,const Handle (V3d_View)& theView)1977 AIS_WalkDelta AIS_ViewController::handleNavigationKeys (const Handle(AIS_InteractiveContext)& ,
1978                                                         const Handle(V3d_View)& theView)
1979 {
1980   // navigation keys
1981   double aCrouchRatio = 1.0, aRunRatio = 1.0;
1982   if (myNavigationMode == AIS_NavigationMode_FirstPersonFlight)
1983   {
1984     aRunRatio = 3.0;
1985   }
1986 
1987   const double aRotSpeed = 0.5;
1988   const double aWalkSpeedCoef = WalkSpeedRelative();
1989   AIS_WalkDelta aWalk = FetchNavigationKeys (aCrouchRatio, aRunRatio);
1990   if (aWalk.IsJumping())
1991   {
1992     // ask more frames
1993     setAskNextFrame();
1994     theView->Invalidate();
1995   }
1996   if (aWalk.IsEmpty())
1997   {
1998     if (aWalk.IsDefined())
1999     {
2000       setAskNextFrame();
2001     }
2002     return aWalk;
2003   }
2004   else if (myGL.OrbitRotation.ToRotate
2005         || myGL.OrbitRotation.ToStart)
2006   {
2007     return aWalk;
2008   }
2009 
2010   gp_XYZ aMin, aMax;
2011   const Bnd_Box aBndBox = theView->View()->MinMaxValues();
2012   if (!aBndBox.IsVoid())
2013   {
2014     aMin = aBndBox.CornerMin().XYZ();
2015     aMax = aBndBox.CornerMax().XYZ();
2016   }
2017   double aBndDiam = Max (Max (aMax.X() - aMin.X(), aMax.Y() - aMin.Y()), aMax.Z() - aMin.Z());
2018   if (aBndDiam <= gp::Resolution())
2019   {
2020     aBndDiam = 0.001;
2021   }
2022 
2023   const double aWalkSpeed = myNavigationMode != AIS_NavigationMode_Orbit
2024                          && myNavigationMode != AIS_NavigationMode_FirstPersonFlight
2025                           ? theView->View()->UnitFactor() * WalkSpeedAbsolute()
2026                           : aWalkSpeedCoef * aBndDiam;
2027   const Handle(Graphic3d_Camera)& aCam = theView->View()->IsActiveXR()
2028                                        ? theView->View()->BaseXRCamera()
2029                                        : theView->Camera();
2030 
2031   // move forward in plane XY and up along Z
2032   const gp_Dir anUp = ToLockOrbitZUp() ? gp::DZ() : aCam->OrthogonalizedUp();
2033   if (aWalk.ToMove()
2034    && myToAllowPanning)
2035   {
2036     const gp_Vec aSide = -aCam->SideRight();
2037     gp_XYZ aFwd = aCam->Direction().XYZ();
2038     aFwd -= anUp.XYZ() * (anUp.XYZ() * aFwd);
2039 
2040     gp_XYZ aMoveVec;
2041     if (!aWalk[AIS_WalkTranslation_Forward].IsEmpty())
2042     {
2043       if (!aCam->IsOrthographic())
2044       {
2045         aMoveVec += aFwd * aWalk[AIS_WalkTranslation_Forward].Value * aWalk[AIS_WalkTranslation_Forward].Pressure * aWalkSpeed;
2046       }
2047     }
2048     if (!aWalk[AIS_WalkTranslation_Side].IsEmpty())
2049     {
2050       aMoveVec += aSide.XYZ() * aWalk[AIS_WalkTranslation_Side].Value * aWalk[AIS_WalkTranslation_Side].Pressure * aWalkSpeed;
2051     }
2052     if (!aWalk[AIS_WalkTranslation_Up].IsEmpty())
2053     {
2054       aMoveVec += anUp.XYZ() * aWalk[AIS_WalkTranslation_Up].Value * aWalk[AIS_WalkTranslation_Up].Pressure * aWalkSpeed;
2055     }
2056     {
2057       if (aCam->IsOrthographic())
2058       {
2059         if (!aWalk[AIS_WalkTranslation_Forward].IsEmpty())
2060         {
2061           const double aZoomDelta = aWalk[AIS_WalkTranslation_Forward].Value * aWalk[AIS_WalkTranslation_Forward].Pressure * aWalkSpeedCoef;
2062           handleZoom (theView, Aspect_ScrollDelta (aZoomDelta * 100.0), NULL);
2063         }
2064       }
2065 
2066       gp_Trsf aTrsfTranslate;
2067       aTrsfTranslate.SetTranslation (aMoveVec);
2068       aCam->Transform (aTrsfTranslate);
2069     }
2070   }
2071 
2072   if (myNavigationMode == AIS_NavigationMode_Orbit
2073    && myToAllowRotation)
2074   {
2075     if (!aWalk[AIS_WalkRotation_Yaw].IsEmpty())
2076     {
2077       gp_Trsf aTrsfRot;
2078       aTrsfRot.SetRotation (gp_Ax1 (aCam->Eye(), anUp), aWalk[AIS_WalkRotation_Yaw].Value * aRotSpeed);
2079       aCam->Transform (aTrsfRot);
2080     }
2081     if (!aWalk[AIS_WalkRotation_Pitch].IsEmpty())
2082     {
2083       const gp_Vec aSide = -aCam->SideRight();
2084       gp_Trsf aTrsfRot;
2085       aTrsfRot.SetRotation (gp_Ax1 (aCam->Eye(), aSide), -aWalk[AIS_WalkRotation_Pitch].Value * aRotSpeed);
2086       aCam->Transform (aTrsfRot);
2087     }
2088     if (!aWalk[AIS_WalkRotation_Roll].IsEmpty()
2089      && !ToLockOrbitZUp())
2090     {
2091       gp_Trsf aTrsfRot;
2092       aTrsfRot.SetRotation (gp_Ax1 (aCam->Center(), aCam->Direction()), aWalk[AIS_WalkRotation_Roll].Value * aRotSpeed);
2093       aCam->Transform (aTrsfRot);
2094     }
2095   }
2096 
2097   // ask more frames
2098   setAskNextFrame();
2099   theView->Invalidate();
2100   theView->View()->SynchronizeXRBaseToPosedCamera();
2101   return aWalk;
2102 }
2103 
2104 // =======================================================================
2105 // function : handleCameraActions
2106 // purpose  :
2107 // =======================================================================
handleCameraActions(const Handle (AIS_InteractiveContext)& theCtx,const Handle (V3d_View)& theView,const AIS_WalkDelta & theWalk)2108 void AIS_ViewController::handleCameraActions (const Handle(AIS_InteractiveContext)& theCtx,
2109                                               const Handle(V3d_View)& theView,
2110                                               const AIS_WalkDelta& theWalk)
2111 {
2112   // apply view actions
2113   if (myGL.Orientation.ToSetViewOrient)
2114   {
2115     theView->SetProj (myGL.Orientation.ViewOrient);
2116     myGL.Orientation.ToFitAll = true;
2117   }
2118 
2119   // apply fit all
2120   if (myGL.Orientation.ToFitAll)
2121   {
2122     const double aFitMargin = 0.01;
2123     theView->FitAll (aFitMargin, false);
2124     theView->Invalidate();
2125     myGL.Orientation.ToFitAll = false;
2126   }
2127 
2128   if (myGL.IsNewGesture)
2129   {
2130     if (myAnchorPointPrs1->HasInteractiveContext())
2131     {
2132       theCtx->Remove (myAnchorPointPrs1, false);
2133       if (!theView->Viewer()->ZLayerSettings (myAnchorPointPrs1->ZLayer()).IsImmediate())
2134       {
2135         theView->Invalidate();
2136       }
2137       else
2138       {
2139         theView->InvalidateImmediate();
2140       }
2141     }
2142     if (myAnchorPointPrs2->HasInteractiveContext())
2143     {
2144       theCtx->Remove (myAnchorPointPrs2, false);
2145       if (!theView->Viewer()->ZLayerSettings (myAnchorPointPrs2->ZLayer()).IsImmediate())
2146       {
2147         theView->Invalidate();
2148       }
2149       else
2150       {
2151         theView->InvalidateImmediate();
2152       }
2153     }
2154 
2155     if (myHasHlrOnBeforeRotation)
2156     {
2157       myHasHlrOnBeforeRotation = false;
2158       theView->SetComputedMode (true);
2159       theView->Invalidate();
2160     }
2161   }
2162 
2163   if (myNavigationMode != AIS_NavigationMode_FirstPersonWalk)
2164   {
2165     if (myGL.Panning.ToStart
2166      && myToAllowPanning)
2167     {
2168       gp_Pnt aPanPnt (Precision::Infinite(), 0.0, 0.0);
2169       if (!theView->Camera()->IsOrthographic())
2170       {
2171         bool toStickToRay = false;
2172         if (myGL.Panning.PointStart.x() >= 0
2173          && myGL.Panning.PointStart.y() >= 0)
2174         {
2175           PickPoint (aPanPnt, theCtx, theView, myGL.Panning.PointStart, toStickToRay);
2176         }
2177         if (Precision::IsInfinite (aPanPnt.X()))
2178         {
2179           Graphic3d_Vec2i aWinSize;
2180           theView->Window()->Size (aWinSize.x(), aWinSize.y());
2181           PickPoint (aPanPnt, theCtx, theView, aWinSize / 2, toStickToRay);
2182         }
2183         if (!Precision::IsInfinite (aPanPnt.X())
2184           && myToShowPanAnchorPoint)
2185         {
2186           gp_Trsf aPntTrsf;
2187           aPntTrsf.SetTranslation (gp_Vec (aPanPnt.XYZ()));
2188           theCtx->SetLocation (myAnchorPointPrs2, aPntTrsf);
2189         }
2190       }
2191       setPanningAnchorPoint (aPanPnt);
2192     }
2193 
2194     if (myToShowPanAnchorPoint
2195     &&  hasPanningAnchorPoint()
2196     &&  myGL.Panning.ToPan
2197     && !myGL.IsNewGesture
2198     && !myAnchorPointPrs2->HasInteractiveContext())
2199     {
2200       theCtx->Display (myAnchorPointPrs2, 0, -1, false, AIS_DS_Displayed);
2201     }
2202 
2203     handlePanning (theView);
2204     handleZRotate (theView);
2205   }
2206 
2207   if ((myNavigationMode == AIS_NavigationMode_Orbit
2208     || myGL.OrbitRotation.ToStart
2209     || myGL.OrbitRotation.ToRotate)
2210    && myToAllowRotation)
2211   {
2212     if (myGL.OrbitRotation.ToStart
2213     && !myHasHlrOnBeforeRotation)
2214     {
2215       myHasHlrOnBeforeRotation = theView->ComputedMode();
2216       if (myHasHlrOnBeforeRotation)
2217       {
2218         theView->SetComputedMode (false);
2219       }
2220     }
2221 
2222     gp_Pnt aGravPnt;
2223     if (myGL.OrbitRotation.ToStart)
2224     {
2225       aGravPnt = GravityPoint (theCtx, theView);
2226       if (myToShowRotateCenter)
2227       {
2228         gp_Trsf aPntTrsf;
2229         aPntTrsf.SetTranslation (gp_Vec (aGravPnt.XYZ()));
2230         theCtx->SetLocation (myAnchorPointPrs1, aPntTrsf);
2231         theCtx->SetLocation (myAnchorPointPrs2, aPntTrsf);
2232       }
2233     }
2234 
2235     if (myToShowRotateCenter
2236     &&  myGL.OrbitRotation.ToRotate
2237     && !myGL.IsNewGesture
2238     && !myAnchorPointPrs1->HasInteractiveContext())
2239     {
2240       theCtx->Display (myAnchorPointPrs1, 0, -1, false, AIS_DS_Displayed);
2241       theCtx->Display (myAnchorPointPrs2, 0, -1, false, AIS_DS_Displayed);
2242     }
2243     handleOrbitRotation (theView, aGravPnt,
2244                          myToLockOrbitZUp || myNavigationMode != AIS_NavigationMode_Orbit);
2245   }
2246 
2247   if ((myNavigationMode != AIS_NavigationMode_Orbit
2248     || myGL.ViewRotation.ToStart
2249     || myGL.ViewRotation.ToRotate)
2250    && myToAllowRotation)
2251   {
2252     if (myGL.ViewRotation.ToStart
2253     && !myHasHlrOnBeforeRotation)
2254     {
2255       myHasHlrOnBeforeRotation = theView->ComputedMode();
2256       if (myHasHlrOnBeforeRotation)
2257       {
2258         theView->SetComputedMode (false);
2259       }
2260     }
2261 
2262     double aRoll = 0.0;
2263     if (!theWalk[AIS_WalkRotation_Roll].IsEmpty()
2264      && !myToLockOrbitZUp)
2265     {
2266       aRoll = (M_PI / 12.0) * theWalk[AIS_WalkRotation_Roll].Pressure;
2267       aRoll *= Min (1000.0  * theWalk[AIS_WalkRotation_Roll].Duration, 100.0) / 100.0;
2268       if (theWalk[AIS_WalkRotation_Roll].Value < 0.0)
2269       {
2270         aRoll = -aRoll;
2271       }
2272     }
2273 
2274     handleViewRotation (theView, theWalk[AIS_WalkRotation_Yaw].Value, theWalk[AIS_WalkRotation_Pitch].Value, aRoll,
2275                         myNavigationMode == AIS_NavigationMode_FirstPersonFlight);
2276   }
2277 
2278   if (!myGL.ZoomActions.IsEmpty())
2279   {
2280     for (NCollection_Sequence<Aspect_ScrollDelta>::Iterator aZoomIter (myGL.ZoomActions); aZoomIter.More(); aZoomIter.Next())
2281     {
2282       Aspect_ScrollDelta aZoomParams = aZoomIter.Value();
2283       if (myToAllowZFocus
2284        && (aZoomParams.Flags & Aspect_VKeyFlags_CTRL) != 0
2285        && theView->Camera()->IsStereo())
2286       {
2287         handleZFocusScroll (theView, aZoomParams);
2288         continue;
2289       }
2290 
2291       if (!myToAllowZooming)
2292       {
2293         continue;
2294       }
2295 
2296       if (!theView->Camera()->IsOrthographic())
2297       {
2298         gp_Pnt aPnt;
2299         if (aZoomParams.HasPoint()
2300          && PickPoint (aPnt, theCtx, theView, aZoomParams.Point, myToStickToRayOnZoom))
2301         {
2302           handleZoom (theView, aZoomParams, &aPnt);
2303           continue;
2304         }
2305 
2306         Graphic3d_Vec2i aWinSize;
2307         theView->Window()->Size (aWinSize.x(), aWinSize.y());
2308         if (PickPoint (aPnt, theCtx, theView, aWinSize / 2, myToStickToRayOnZoom))
2309         {
2310           aZoomParams.ResetPoint(); // do not pretend to zoom at 'nothing'
2311           handleZoom (theView, aZoomParams, &aPnt);
2312           continue;
2313         }
2314       }
2315       handleZoom (theView, aZoomParams, NULL);
2316     }
2317     myGL.ZoomActions.Clear();
2318   }
2319 }
2320 
2321 // =======================================================================
2322 // function : handleXRInput
2323 // purpose  :
2324 // =======================================================================
handleXRInput(const Handle (AIS_InteractiveContext)& theCtx,const Handle (V3d_View)& theView,const AIS_WalkDelta &)2325 void AIS_ViewController::handleXRInput (const Handle(AIS_InteractiveContext)& theCtx,
2326                                         const Handle(V3d_View)& theView,
2327                                         const AIS_WalkDelta& )
2328 {
2329   theView->View()->ProcessXRInput();
2330   if (!theView->View()->IsActiveXR())
2331   {
2332     return;
2333   }
2334   handleXRTurnPad (theCtx, theView);
2335   handleXRTeleport(theCtx, theView);
2336   handleXRPicking (theCtx, theView);
2337 }
2338 
2339 // =======================================================================
2340 // function : handleXRTurnPad
2341 // purpose  :
2342 // =======================================================================
handleXRTurnPad(const Handle (AIS_InteractiveContext)&,const Handle (V3d_View)& theView)2343 void AIS_ViewController::handleXRTurnPad (const Handle(AIS_InteractiveContext)& ,
2344                                           const Handle(V3d_View)& theView)
2345 {
2346   if (myXRTurnAngle <= 0.0
2347   || !theView->View()->IsActiveXR())
2348   {
2349     return;
2350   }
2351 
2352   // turn left/right at 45 degrees on left/right trackpad clicks
2353   for (int aHand = 0; aHand < 2; ++aHand)
2354   {
2355     const Aspect_XRTrackedDeviceRole aRole = aHand == 0 ? Aspect_XRTrackedDeviceRole_RightHand : Aspect_XRTrackedDeviceRole_LeftHand;
2356     const Handle(Aspect_XRAction)& aPadClickAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTrackPadClick);
2357     const Handle(Aspect_XRAction)& aPadPosAct   = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTrackPadPosition);
2358     if (aPadClickAct.IsNull()
2359     ||  aPadPosAct.IsNull())
2360     {
2361       continue;
2362     }
2363 
2364     const Aspect_XRDigitalActionData aPadClick = theView->View()->XRSession()->GetDigitalActionData (aPadClickAct);
2365     const Aspect_XRAnalogActionData  aPadPos   = theView->View()->XRSession()->GetAnalogActionData (aPadPosAct);
2366     if (aPadClick.IsActive
2367      && aPadClick.IsPressed
2368      && aPadClick.IsChanged
2369      && aPadPos.IsActive
2370      && Abs (aPadPos.VecXYZ.y()) < 0.5f
2371      && Abs (aPadPos.VecXYZ.x()) > 0.7f)
2372     {
2373       gp_Trsf aTrsfTurn;
2374       aTrsfTurn.SetRotation (gp_Ax1 (gp::Origin(), theView->View()->BaseXRCamera()->Up()), aPadPos.VecXYZ.x() < 0.0f ? myXRTurnAngle : -myXRTurnAngle);
2375       theView->View()->TurnViewXRCamera (aTrsfTurn);
2376       break;
2377     }
2378   }
2379 }
2380 
2381 // =======================================================================
2382 // function : handleXRTeleport
2383 // purpose  :
2384 // =======================================================================
handleXRTeleport(const Handle (AIS_InteractiveContext)& theCtx,const Handle (V3d_View)& theView)2385 void AIS_ViewController::handleXRTeleport (const Handle(AIS_InteractiveContext)& theCtx,
2386                                            const Handle(V3d_View)& theView)
2387 {
2388   if (!theView->View()->IsActiveXR())
2389   {
2390     return;
2391   }
2392 
2393   // teleport on forward trackpad unclicks
2394   const Aspect_XRTrackedDeviceRole aTeleOld = myXRLastTeleportHand;
2395   myXRLastTeleportHand = Aspect_XRTrackedDeviceRole_Other;
2396   for (int aHand = 0; aHand < 2; ++aHand)
2397   {
2398     const Aspect_XRTrackedDeviceRole aRole = aHand == 0 ? Aspect_XRTrackedDeviceRole_RightHand : Aspect_XRTrackedDeviceRole_LeftHand;
2399     const Standard_Integer aDeviceId = theView->View()->XRSession()->NamedTrackedDevice (aRole);
2400     if (aDeviceId == -1)
2401     {
2402       continue;
2403     }
2404 
2405     const Handle(Aspect_XRAction)& aPadClickAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTrackPadClick);
2406     const Handle(Aspect_XRAction)& aPadPosAct   = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTrackPadPosition);
2407     if (aPadClickAct.IsNull()
2408     ||  aPadPosAct.IsNull())
2409     {
2410       continue;
2411     }
2412 
2413     const Aspect_XRDigitalActionData aPadClick = theView->View()->XRSession()->GetDigitalActionData (aPadClickAct);
2414     const Aspect_XRAnalogActionData  aPadPos   = theView->View()->XRSession()->GetAnalogActionData (aPadPosAct);
2415     const bool isPressed =  aPadClick.IsPressed;
2416     const bool isClicked = !aPadClick.IsPressed
2417                         &&  aPadClick.IsChanged;
2418     if (aPadClick.IsActive
2419      && (isPressed || isClicked)
2420      && aPadPos.IsActive
2421      && aPadPos.VecXYZ.y() > 0.6f
2422      && Abs (aPadPos.VecXYZ.x()) < 0.5f)
2423     {
2424       const Aspect_TrackedDevicePose& aPose = theView->View()->XRSession()->TrackedPoses()[aDeviceId];
2425       if (!aPose.IsValidPose)
2426       {
2427         continue;
2428       }
2429 
2430       myXRLastTeleportHand = aRole;
2431       Standard_Real& aPickDepth = aRole == Aspect_XRTrackedDeviceRole_LeftHand ? myXRLastPickDepthLeft : myXRLastPickDepthRight;
2432       aPickDepth = Precision::Infinite();
2433       Graphic3d_Vec3 aPickNorm;
2434       const gp_Trsf aHandBase = theView->View()->PoseXRToWorld (aPose.Orientation);
2435       const Standard_Real aHeadHeight = theView->View()->XRSession()->HeadPose().TranslationPart().Y();
2436       {
2437         const Standard_Integer aPickedId = handleXRMoveTo (theCtx, theView, aPose.Orientation, false);
2438         if (aPickedId >= 1)
2439         {
2440           const SelectMgr_SortCriterion& aPickedData = theCtx->MainSelector()->PickedData (aPickedId);
2441           aPickNorm = aPickedData.Normal;
2442           if (aPickNorm.SquareModulus() > ShortRealEpsilon())
2443           {
2444             aPickDepth = aPickedData.Point.Distance (aHandBase.TranslationPart());
2445           }
2446         }
2447       }
2448       if (isClicked)
2449       {
2450         myXRLastTeleportHand = Aspect_XRTrackedDeviceRole_Other;
2451         if (!Precision::IsInfinite (aPickDepth))
2452         {
2453           const gp_Dir aTeleDir = -gp::DZ().Transformed (aHandBase);
2454           const gp_Dir anUpDir  = theView->View()->BaseXRCamera()->Up();
2455 
2456           bool isHorizontal = false;
2457           gp_Dir aPickNormDir (aPickNorm.x(), aPickNorm.y(), aPickNorm.z());
2458           if (anUpDir.IsEqual ( aPickNormDir, M_PI_4)
2459            || anUpDir.IsEqual (-aPickNormDir, M_PI_4))
2460           {
2461             isHorizontal = true;
2462           }
2463 
2464           gp_Pnt aNewEye = aHandBase.TranslationPart();
2465           if (isHorizontal)
2466           {
2467             aNewEye  = aHandBase.TranslationPart()
2468                      + aTeleDir.XYZ() * aPickDepth
2469                      + anUpDir.XYZ() * aHeadHeight;
2470           }
2471           else
2472           {
2473             if (aPickNormDir.Dot (aTeleDir) < 0.0)
2474             {
2475               aPickNormDir.Reverse();
2476             }
2477             aNewEye  = aHandBase.TranslationPart()
2478                      + aTeleDir.XYZ() * aPickDepth
2479                      - aPickNormDir.XYZ() * aHeadHeight / 4;
2480           }
2481 
2482           theView->View()->PosedXRCamera()->MoveEyeTo (aNewEye);
2483           theView->View()->ComputeXRBaseCameraFromPosed (theView->View()->PosedXRCamera(), theView->View()->XRSession()->HeadPose());
2484         }
2485       }
2486       break;
2487     }
2488   }
2489 
2490   if (myXRLastTeleportHand != aTeleOld)
2491   {
2492     if (aTeleOld != Aspect_XRTrackedDeviceRole_Other)
2493     {
2494       if (const Handle(Aspect_XRAction)& aHaptic = theView->View()->XRSession()->GenericAction (aTeleOld, Aspect_XRGenericAction_OutputHaptic))
2495       {
2496         theView->View()->XRSession()->AbortHapticVibrationAction (aHaptic);
2497       }
2498     }
2499     if (myXRLastTeleportHand != Aspect_XRTrackedDeviceRole_Other)
2500     {
2501       if (const Handle(Aspect_XRAction)& aHaptic = theView->View()->XRSession()->GenericAction (myXRLastTeleportHand, Aspect_XRGenericAction_OutputHaptic))
2502       {
2503         theView->View()->XRSession()->TriggerHapticVibrationAction (aHaptic, myXRTeleportHaptic);
2504       }
2505     }
2506   }
2507 }
2508 
2509 // =======================================================================
2510 // function : handleXRPicking
2511 // purpose  :
2512 // =======================================================================
handleXRPicking(const Handle (AIS_InteractiveContext)& theCtx,const Handle (V3d_View)& theView)2513 void AIS_ViewController::handleXRPicking (const Handle(AIS_InteractiveContext)& theCtx,
2514                                           const Handle(V3d_View)& theView)
2515 {
2516   if (!theView->View()->IsActiveXR())
2517   {
2518     return;
2519   }
2520 
2521   // handle selection on trigger clicks
2522   Aspect_XRTrackedDeviceRole aPickDevOld = myXRLastPickingHand;
2523   myXRLastPickingHand = Aspect_XRTrackedDeviceRole_Other;
2524   for (int aHand = 0; aHand < 2; ++aHand)
2525   {
2526     const Aspect_XRTrackedDeviceRole aRole = aHand == 0 ? Aspect_XRTrackedDeviceRole_RightHand : Aspect_XRTrackedDeviceRole_LeftHand;
2527     const Handle(Aspect_XRAction)& aTrigClickAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTriggerClick);
2528     const Handle(Aspect_XRAction)& aTrigPullAct  = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTriggerPull);
2529     if (aTrigClickAct.IsNull()
2530     ||  aTrigPullAct.IsNull())
2531     {
2532       continue;
2533     }
2534 
2535     const Aspect_XRDigitalActionData aTrigClick = theView->View()->XRSession()->GetDigitalActionData (aTrigClickAct);
2536     const Aspect_XRAnalogActionData  aTrigPos   = theView->View()->XRSession()->GetAnalogActionData (aTrigPullAct);
2537     if (aTrigPos.IsActive
2538      && Abs (aTrigPos.VecXYZ.x()) > 0.1f)
2539     {
2540       myXRLastPickingHand = aRole;
2541       handleXRHighlight (theCtx, theView);
2542       if (aTrigClick.IsActive
2543        && aTrigClick.IsPressed
2544        && aTrigClick.IsChanged)
2545       {
2546         theCtx->SelectDetected();
2547         OnSelectionChanged (theCtx, theView);
2548         if (const Handle(Aspect_XRAction)& aHaptic = theView->View()->XRSession()->GenericAction (myXRLastPickingHand, Aspect_XRGenericAction_OutputHaptic))
2549         {
2550           theView->View()->XRSession()->TriggerHapticVibrationAction (aHaptic, myXRSelectHaptic);
2551         }
2552       }
2553       break;
2554     }
2555   }
2556   if (myXRLastPickingHand != aPickDevOld)
2557   {
2558     theCtx->ClearDetected();
2559   }
2560 }
2561 
2562 // =======================================================================
2563 // function : OnSelectionChanged
2564 // purpose  :
2565 // =======================================================================
OnSelectionChanged(const Handle (AIS_InteractiveContext)&,const Handle (V3d_View)&)2566 void AIS_ViewController::OnSelectionChanged (const Handle(AIS_InteractiveContext)& ,
2567                                              const Handle(V3d_View)& )
2568 {
2569   //
2570 }
2571 
2572 // =======================================================================
2573 // function : OnObjectDragged
2574 // purpose  :
2575 // =======================================================================
OnObjectDragged(const Handle (AIS_InteractiveContext)& theCtx,const Handle (V3d_View)& theView,AIS_DragAction theAction)2576 void AIS_ViewController::OnObjectDragged (const Handle(AIS_InteractiveContext)& theCtx,
2577                                           const Handle(V3d_View)& theView,
2578                                           AIS_DragAction theAction)
2579 {
2580   switch (theAction)
2581   {
2582     case AIS_DragAction_Start:
2583     {
2584       myDragObject.Nullify();
2585       myDragOwner.Nullify();
2586       if (!theCtx->HasDetected())
2587       {
2588         return;
2589       }
2590 
2591       const Handle(SelectMgr_EntityOwner)& aDetectedOwner = theCtx->DetectedOwner();
2592       Handle(AIS_InteractiveObject) aDetectedPrs = Handle(AIS_InteractiveObject)::DownCast (aDetectedOwner->Selectable());
2593 
2594       if (aDetectedPrs->ProcessDragging (theCtx, theView, aDetectedOwner, myGL.Dragging.PointStart,
2595                                          myGL.Dragging.PointTo, theAction))
2596       {
2597         myDragObject = aDetectedPrs;
2598         myDragOwner = aDetectedOwner;
2599       }
2600       return;
2601     }
2602     case AIS_DragAction_Update:
2603     {
2604       if (myDragObject.IsNull())
2605       {
2606         return;
2607       }
2608 
2609       if (Handle(SelectMgr_EntityOwner) aGlobOwner = myDragObject->GlobalSelOwner())
2610       {
2611         theCtx->SetSelectedState (aGlobOwner, true);
2612       }
2613 
2614       myDragObject->ProcessDragging (theCtx, theView, myDragOwner, myGL.Dragging.PointStart,
2615                                      myGL.Dragging.PointTo, theAction);
2616       theView->Invalidate();
2617       return;
2618     }
2619     case AIS_DragAction_Abort:
2620     {
2621       if (myDragObject.IsNull())
2622       {
2623         return;
2624       }
2625 
2626       myGL.Dragging.PointTo = myGL.Dragging.PointStart;
2627       OnObjectDragged (theCtx, theView, AIS_DragAction_Update);
2628 
2629       myDragObject->ProcessDragging (theCtx, theView, myDragOwner, myGL.Dragging.PointStart,
2630                                      myGL.Dragging.PointTo, theAction);
2631       Standard_FALLTHROUGH
2632     }
2633     case AIS_DragAction_Stop:
2634     {
2635       if (myDragObject.IsNull())
2636       {
2637         return;
2638       }
2639 
2640       if (Handle(SelectMgr_EntityOwner) aGlobOwner = myDragObject->GlobalSelOwner())
2641       {
2642         theCtx->SetSelectedState (aGlobOwner, false);
2643       }
2644 
2645       myDragObject->ProcessDragging (theCtx, theView, myDragOwner, myGL.Dragging.PointStart,
2646                                      myGL.Dragging.PointTo, theAction);
2647       theView->Invalidate();
2648       myDragObject.Nullify();
2649       myDragOwner.Nullify();
2650       return;
2651     }
2652   }
2653 }
2654 
2655 // =======================================================================
2656 // function : contextLazyMoveTo
2657 // purpose  :
2658 // =======================================================================
contextLazyMoveTo(const Handle (AIS_InteractiveContext)& theCtx,const Handle (V3d_View)& theView,const Graphic3d_Vec2i & thePnt)2659 void AIS_ViewController::contextLazyMoveTo (const Handle(AIS_InteractiveContext)& theCtx,
2660                                             const Handle(V3d_View)& theView,
2661                                             const Graphic3d_Vec2i& thePnt)
2662 {
2663   if (myPrevMoveTo == thePnt
2664    || myHasHlrOnBeforeRotation) // ignore highlighting in-between rotation of HLR view
2665   {
2666     return;
2667   }
2668 
2669   myPrevMoveTo = thePnt;
2670 
2671   Handle(SelectMgr_EntityOwner) aLastPicked = theCtx->DetectedOwner();
2672 
2673   // Picking relies on the camera frustum (including Z-range) - so make temporary AutoZFit()
2674   // and then restore previous frustum to avoid immediate layer rendering issues if View has not been invalidated.
2675   const Standard_Real aZNear = theView->Camera()->ZNear(), aZFar = theView->Camera()->ZFar();
2676   theView->AutoZFit();
2677   theCtx->MoveTo (thePnt.x(), thePnt.y(), theView, false);
2678   theView->Camera()->SetZRange (aZNear, aZFar);
2679 
2680   Handle(SelectMgr_EntityOwner) aNewPicked = theCtx->DetectedOwner();
2681 
2682   if (theView->Viewer()->IsGridActive()
2683    && theView->Viewer()->GridEcho())
2684   {
2685     if (aNewPicked.IsNull())
2686     {
2687       Graphic3d_Vec3d aPnt3d;
2688       theView->ConvertToGrid (thePnt.x(), thePnt.y(), aPnt3d[0], aPnt3d[1], aPnt3d[2]);
2689       theView->Viewer()->ShowGridEcho (theView, Graphic3d_Vertex (aPnt3d[0], aPnt3d[1], aPnt3d[2]));
2690       theView->InvalidateImmediate();
2691     }
2692     else
2693     {
2694       theView->Viewer()->HideGridEcho (theView);
2695       theView->InvalidateImmediate();
2696     }
2697   }
2698 
2699   if (aLastPicked != aNewPicked
2700    || (!aNewPicked.IsNull() && aNewPicked->IsForcedHilight()))
2701   {
2702     // dynamic highlight affects all Views
2703     for (V3d_ListOfViewIterator aViewIter (theView->Viewer()->ActiveViewIterator()); aViewIter.More(); aViewIter.Next())
2704     {
2705       const Handle(V3d_View)& aView = aViewIter.Value();
2706       aView->InvalidateImmediate();
2707     }
2708   }
2709 }
2710 
2711 // =======================================================================
2712 // function : handleSelectionPick
2713 // purpose  :
2714 // =======================================================================
handleSelectionPick(const Handle (AIS_InteractiveContext)& theCtx,const Handle (V3d_View)& theView)2715 void AIS_ViewController::handleSelectionPick (const Handle(AIS_InteractiveContext)& theCtx,
2716                                               const Handle(V3d_View)& theView)
2717 {
2718   if (myGL.Selection.Tool == AIS_ViewSelectionTool_Picking
2719   && !myGL.Selection.Points.IsEmpty())
2720   {
2721     for (NCollection_Sequence<Graphic3d_Vec2i>::Iterator aPntIter (myGL.Selection.Points); aPntIter.More(); aPntIter.Next())
2722     {
2723       const bool hadPrevMoveTo = HasPreviousMoveTo();
2724       contextLazyMoveTo (theCtx, theView, aPntIter.Value());
2725       if (!hadPrevMoveTo)
2726       {
2727         ResetPreviousMoveTo();
2728       }
2729 
2730       theCtx->SelectDetected (myGL.Selection.Scheme);
2731 
2732       // selection affects all Views
2733       theView->Viewer()->Invalidate();
2734 
2735       OnSelectionChanged (theCtx, theView);
2736     }
2737 
2738     myGL.Selection.Points.Clear();
2739   }
2740 }
2741 
2742 // =======================================================================
2743 // function : handleSelectionPoly
2744 // purpose  :
2745 // =======================================================================
handleSelectionPoly(const Handle (AIS_InteractiveContext)& theCtx,const Handle (V3d_View)& theView)2746 void AIS_ViewController::handleSelectionPoly (const Handle(AIS_InteractiveContext)& theCtx,
2747                                               const Handle(V3d_View)& theView)
2748 {
2749   // rubber-band & window polygon selection
2750   if (myGL.Selection.Tool == AIS_ViewSelectionTool_RubberBand
2751    || myGL.Selection.Tool == AIS_ViewSelectionTool_Polygon
2752    || myGL.Selection.Tool == AIS_ViewSelectionTool_ZoomWindow)
2753   {
2754     if (!myGL.Selection.Points.IsEmpty())
2755     {
2756       myRubberBand->ClearPoints();
2757       myRubberBand->SetToUpdate();
2758 
2759       const bool anIsRubber = myGL.Selection.Tool == AIS_ViewSelectionTool_RubberBand
2760                            || myGL.Selection.Tool == AIS_ViewSelectionTool_ZoomWindow;
2761       if (anIsRubber)
2762       {
2763         myRubberBand->SetRectangle (myGL.Selection.Points.First().x(), -myGL.Selection.Points.First().y(),
2764                                     myGL.Selection.Points.Last().x(),  -myGL.Selection.Points.Last().y());
2765       }
2766       else
2767       {
2768         Graphic3d_Vec2i aPrev (IntegerLast(), IntegerLast());
2769         for (NCollection_Sequence<Graphic3d_Vec2i>::Iterator aSelIter (myGL.Selection.Points); aSelIter.More(); aSelIter.Next())
2770         {
2771           Graphic3d_Vec2i aPntNew = Graphic3d_Vec2i (aSelIter.Value().x(), -aSelIter.Value().y());
2772           if (aPntNew != aPrev)
2773           {
2774             aPrev = aPntNew;
2775             myRubberBand->AddPoint (Graphic3d_Vec2i (aSelIter.Value().x(), -aSelIter.Value().y()));
2776           }
2777         }
2778       }
2779 
2780       myRubberBand->SetPolygonClosed (anIsRubber);
2781       try
2782       {
2783         theCtx->Display (myRubberBand, 0, -1, false, AIS_DS_Displayed);
2784       }
2785       catch (const Standard_Failure& theEx)
2786       {
2787         Message::SendWarning (TCollection_AsciiString ("Internal error while displaying rubber-band: ")
2788                             + theEx.DynamicType()->Name() + ", " + theEx.GetMessageString());
2789         myRubberBand->ClearPoints();
2790       }
2791       if (!theView->Viewer()->ZLayerSettings (myRubberBand->ZLayer()).IsImmediate())
2792       {
2793         theView->Invalidate();
2794       }
2795       else
2796       {
2797         theView->InvalidateImmediate();
2798       }
2799     }
2800     else if (!myRubberBand.IsNull()
2801            && myRubberBand->HasInteractiveContext())
2802     {
2803       theCtx->Remove (myRubberBand, false);
2804       myRubberBand->ClearPoints();
2805     }
2806   }
2807 
2808   if (myGL.Selection.ToApplyTool)
2809   {
2810     myGL.Selection.ToApplyTool = false;
2811     if (theCtx->IsDisplayed (myRubberBand))
2812     {
2813       theCtx->Remove (myRubberBand, false);
2814       {
2815         const NCollection_Sequence<Graphic3d_Vec2i>& aPoints = myRubberBand->Points();
2816         if (aPoints.Size() == 4
2817          && aPoints.Value (1).x() == aPoints.Value (2).x()
2818          && aPoints.Value (3).x() == aPoints.Value (4).x()
2819          && aPoints.Value (1).y() == aPoints.Value (4).y()
2820          && aPoints.Value (2).y() == aPoints.Value (3).y())
2821         {
2822           const Graphic3d_Vec2i aPnt1 (aPoints.Value (1).x(), -aPoints.Value (1).y());
2823           const Graphic3d_Vec2i aPnt2 (aPoints.Value (3).x(), -aPoints.Value (3).y());
2824           if (myGL.Selection.Tool == AIS_ViewSelectionTool_ZoomWindow)
2825           {
2826             theView->WindowFitAll (aPnt1.x(), aPnt1.y(), aPnt2.x(), aPnt2.y());
2827             theView->Invalidate();
2828           }
2829           else
2830           {
2831             theCtx->MainSelector()->AllowOverlapDetection (aPnt1.y() != Min (aPnt1.y(), aPnt2.y()));
2832             theCtx->SelectRectangle (Graphic3d_Vec2i (Min (aPnt1.x(), aPnt2.x()), Min (aPnt1.y(), aPnt2.y())),
2833                                      Graphic3d_Vec2i (Max (aPnt1.x(), aPnt2.x()), Max (aPnt1.y(), aPnt2.y())),
2834                                      theView,
2835                                      myGL.Selection.Scheme);
2836             theCtx->MainSelector()->AllowOverlapDetection (false);
2837           }
2838         }
2839         else if (aPoints.Length() >= 3)
2840         {
2841           TColgp_Array1OfPnt2d aPolyline (1, aPoints.Length());
2842           TColgp_Array1OfPnt2d::Iterator aPolyIter (aPolyline);
2843           for (NCollection_Sequence<Graphic3d_Vec2i>::Iterator aSelIter (aPoints);
2844                aSelIter.More(); aSelIter.Next(), aPolyIter.Next())
2845           {
2846             const Graphic3d_Vec2i& aNewPnt = aSelIter.Value();
2847             aPolyIter.ChangeValue() = gp_Pnt2d (aNewPnt.x(), -aNewPnt.y());
2848           }
2849 
2850           theCtx->SelectPolygon (aPolyline, theView, myGL.Selection.Scheme);
2851           theCtx->MainSelector()->AllowOverlapDetection (false);
2852         }
2853       }
2854 
2855       myRubberBand->ClearPoints();
2856       if (myGL.Selection.Tool != AIS_ViewSelectionTool_ZoomWindow)
2857       {
2858         // selection affects all Views
2859         theView->Viewer()->Invalidate();
2860         OnSelectionChanged (theCtx, theView);
2861       }
2862     }
2863   }
2864 }
2865 
2866 // =======================================================================
2867 // function : handleDynamicHighlight
2868 // purpose  :
2869 // =======================================================================
handleDynamicHighlight(const Handle (AIS_InteractiveContext)& theCtx,const Handle (V3d_View)& theView)2870 void AIS_ViewController::handleDynamicHighlight (const Handle(AIS_InteractiveContext)& theCtx,
2871                                                  const Handle(V3d_View)& theView)
2872 {
2873   if ((myGL.MoveTo.ToHilight || myGL.Dragging.ToStart)
2874    && myNavigationMode != AIS_NavigationMode_FirstPersonWalk)
2875   {
2876     const Graphic3d_Vec2i& aMoveToPnt = myGL.MoveTo.ToHilight ? myGL.MoveTo.Point : myGL.Dragging.PointStart;
2877     if (myGL.Dragging.ToStart && (!myGL.MoveTo.ToHilight || !myToAllowHighlight)
2878      && !HasPreviousMoveTo())
2879     {
2880       contextLazyMoveTo (theCtx, theView, aMoveToPnt);
2881       ResetPreviousMoveTo();
2882       OnObjectDragged (theCtx, theView, AIS_DragAction_Start);
2883       theCtx->ClearDetected();
2884     }
2885     else if (myToAllowHighlight)
2886     {
2887       if (myPrevMoveTo != aMoveToPnt
2888        || (!theView->View()->IsActiveXR()
2889         && (myGL.OrbitRotation.ToRotate
2890          || myGL.ViewRotation.ToRotate
2891          || theView->IsInvalidated())))
2892       {
2893         ResetPreviousMoveTo();
2894         contextLazyMoveTo (theCtx, theView, aMoveToPnt);
2895       }
2896       if (myGL.Dragging.ToStart)
2897       {
2898         OnObjectDragged (theCtx, theView, AIS_DragAction_Start);
2899       }
2900     }
2901 
2902     myGL.MoveTo.ToHilight = false;
2903   }
2904 
2905   if (!myDragObject.IsNull())
2906   {
2907     if (myGL.Dragging.ToAbort)
2908     {
2909       OnObjectDragged (theCtx, theView, AIS_DragAction_Abort);
2910       myGL.OrbitRotation.ToRotate = false;
2911       myGL.ViewRotation .ToRotate = false;
2912     }
2913     else if (myGL.Dragging.ToStop)
2914     {
2915       OnObjectDragged (theCtx, theView, AIS_DragAction_Stop);
2916       myGL.OrbitRotation.ToRotate = false;
2917       myGL.ViewRotation .ToRotate = false;
2918     }
2919     else if (myGL.OrbitRotation.ToRotate
2920           || myGL.ViewRotation.ToRotate)
2921     {
2922       OnObjectDragged (theCtx, theView, AIS_DragAction_Update);
2923       myGL.OrbitRotation.ToRotate = false;
2924       myGL.ViewRotation .ToRotate = false;
2925     }
2926   }
2927 }
2928 
2929 // =======================================================================
2930 // function : handleMoveTo
2931 // purpose  :
2932 // =======================================================================
handleMoveTo(const Handle (AIS_InteractiveContext)& theCtx,const Handle (V3d_View)& theView)2933 void AIS_ViewController::handleMoveTo (const Handle(AIS_InteractiveContext)& theCtx,
2934                                        const Handle(V3d_View)& theView)
2935 {
2936   handleSelectionPick   (theCtx, theView);
2937   handleDynamicHighlight(theCtx, theView);
2938   handleSelectionPoly   (theCtx, theView);
2939 }
2940 
2941 // =======================================================================
2942 // function : handleViewRedraw
2943 // purpose  :
2944 // =======================================================================
handleViewRedraw(const Handle (AIS_InteractiveContext)&,const Handle (V3d_View)& theView)2945 void AIS_ViewController::handleViewRedraw (const Handle(AIS_InteractiveContext)& ,
2946                                            const Handle(V3d_View)& theView)
2947 {
2948   // manage animation state
2949   if (!myViewAnimation.IsNull()
2950    && !myViewAnimation->IsStopped())
2951   {
2952     myViewAnimation->UpdateTimer();
2953     ResetPreviousMoveTo();
2954     setAskNextFrame();
2955   }
2956 
2957   if (!myObjAnimation.IsNull()
2958    && !myObjAnimation->IsStopped())
2959   {
2960     myObjAnimation->UpdateTimer();
2961     ResetPreviousMoveTo();
2962     setAskNextFrame();
2963   }
2964 
2965   if (myIsContinuousRedraw)
2966   {
2967     myToAskNextFrame = true;
2968   }
2969   if (theView->View()->IsActiveXR())
2970   {
2971     // VR requires continuous rendering
2972     myToAskNextFrame = true;
2973   }
2974 
2975   for (V3d_ListOfViewIterator aViewIter (theView->Viewer()->ActiveViewIterator()); aViewIter.More(); aViewIter.Next())
2976   {
2977     const Handle(V3d_View)& aView = aViewIter.Value();
2978     if (aView->IsInvalidated()
2979      || (myToAskNextFrame && aView == theView))
2980     {
2981       if (aView->ComputedMode())
2982       {
2983         aView->Update();
2984       }
2985       else
2986       {
2987         aView->Redraw();
2988       }
2989     }
2990     else if (aView->IsInvalidatedImmediate())
2991     {
2992       aView->RedrawImmediate();
2993     }
2994   }
2995 
2996   if (myToAskNextFrame)
2997   {
2998     // ask more frames
2999     theView->Window()->InvalidateContent (Handle(Aspect_DisplayConnection)());
3000   }
3001 }
3002 
3003 // =======================================================================
3004 // function : handleXRMoveTo
3005 // purpose  :
3006 // =======================================================================
handleXRMoveTo(const Handle (AIS_InteractiveContext)& theCtx,const Handle (V3d_View)& theView,const gp_Trsf & thePose,const Standard_Boolean theToHighlight)3007 Standard_Integer AIS_ViewController::handleXRMoveTo (const Handle(AIS_InteractiveContext)& theCtx,
3008                                                      const Handle(V3d_View)& theView,
3009                                                      const gp_Trsf& thePose,
3010                                                      const Standard_Boolean theToHighlight)
3011 {
3012   //ResetPreviousMoveTo();
3013   const gp_Ax1 aViewAxis = theView->View()->ViewAxisInWorld (thePose);
3014   Standard_Integer aPickResult = 0;
3015   if (theToHighlight)
3016   {
3017     theCtx->MoveTo (aViewAxis, theView, false);
3018     if (!theCtx->DetectedOwner().IsNull())
3019     {
3020       aPickResult = 1;
3021     }
3022   }
3023   else
3024   {
3025     theCtx->MainSelector()->Pick (aViewAxis, theView);
3026     if (theCtx->MainSelector()->NbPicked() >= 1)
3027     {
3028       aPickResult = 1;
3029     }
3030   }
3031 
3032   return aPickResult;
3033 }
3034 
3035 // =======================================================================
3036 // function : handleXRHighlight
3037 // purpose  :
3038 // =======================================================================
handleXRHighlight(const Handle (AIS_InteractiveContext)& theCtx,const Handle (V3d_View)& theView)3039 void AIS_ViewController::handleXRHighlight (const Handle(AIS_InteractiveContext)& theCtx,
3040                                             const Handle(V3d_View)& theView)
3041 {
3042   if (myXRLastPickingHand != Aspect_XRTrackedDeviceRole_LeftHand
3043    && myXRLastPickingHand != Aspect_XRTrackedDeviceRole_RightHand)
3044   {
3045     return;
3046   }
3047 
3048   const Standard_Integer aDeviceId = theView->View()->XRSession()->NamedTrackedDevice (myXRLastPickingHand);
3049   if (aDeviceId == -1)
3050   {
3051     return;
3052   }
3053 
3054   const Aspect_TrackedDevicePose& aPose = theView->View()->XRSession()->TrackedPoses()[aDeviceId];
3055   if (!aPose.IsValidPose)
3056   {
3057     return;
3058   }
3059 
3060   Handle(SelectMgr_EntityOwner) aDetOld = theCtx->DetectedOwner();
3061   handleXRMoveTo (theCtx, theView, aPose.Orientation, true);
3062   if (!theCtx->DetectedOwner().IsNull()
3063     && theCtx->DetectedOwner() != aDetOld)
3064   {
3065     if (const Handle(Aspect_XRAction)& aHaptic = theView->View()->XRSession()->GenericAction (myXRLastPickingHand, Aspect_XRGenericAction_OutputHaptic))
3066     {
3067       theView->View()->XRSession()->TriggerHapticVibrationAction (aHaptic, myXRPickingHaptic);
3068     }
3069   }
3070 
3071   Standard_Real& aPickDepth = myXRLastPickingHand == Aspect_XRTrackedDeviceRole_LeftHand ? myXRLastPickDepthLeft : myXRLastPickDepthRight;
3072   aPickDepth = Precision::Infinite();
3073   if (theCtx->MainSelector()->NbPicked() > 0)
3074   {
3075     const gp_Trsf aHandBase = theView->View()->PoseXRToWorld (aPose.Orientation);
3076     const SelectMgr_SortCriterion& aPicked = theCtx->MainSelector()->PickedData (1);
3077     aPickDepth = aPicked.Point.Distance (aHandBase.TranslationPart());
3078   }
3079 }
3080 
3081 // =======================================================================
3082 // function : handleXRPresentations
3083 // purpose  :
3084 // =======================================================================
handleXRPresentations(const Handle (AIS_InteractiveContext)& theCtx,const Handle (V3d_View)& theView)3085 void AIS_ViewController::handleXRPresentations (const Handle(AIS_InteractiveContext)& theCtx,
3086                                                 const Handle(V3d_View)& theView)
3087 {
3088   if (!theView->View()->IsActiveXR()
3089    || (!myToDisplayXRAuxDevices
3090     && !myToDisplayXRHands))
3091   {
3092     for (NCollection_Array1<Handle(AIS_XRTrackedDevice)>::Iterator aPrsIter (myXRPrsDevices); aPrsIter.More(); aPrsIter.Next())
3093     {
3094       if (!aPrsIter.Value().IsNull()
3095         && aPrsIter.Value()->HasInteractiveContext())
3096       {
3097         theCtx->Remove (aPrsIter.Value(), false);
3098       }
3099       aPrsIter.ChangeValue().Nullify();
3100     }
3101     return;
3102   }
3103 
3104   if (myXRPrsDevices.Length() != theView->View()->XRSession()->TrackedPoses().Length())
3105   {
3106     for (NCollection_Array1<Handle(AIS_XRTrackedDevice)>::Iterator aPrsIter (myXRPrsDevices); aPrsIter.More(); aPrsIter.Next())
3107     {
3108       if (!aPrsIter.Value().IsNull())
3109       {
3110         theCtx->Remove (aPrsIter.Value(), false);
3111       }
3112     }
3113     myXRPrsDevices.Resize (theView->View()->XRSession()->TrackedPoses().Lower(), theView->View()->XRSession()->TrackedPoses().Upper(), false);
3114   }
3115 
3116   const Standard_Integer aHeadDevice  = theView->View()->XRSession()->NamedTrackedDevice (Aspect_XRTrackedDeviceRole_Head);
3117   const Standard_Integer aLeftDevice  = theView->View()->XRSession()->NamedTrackedDevice (Aspect_XRTrackedDeviceRole_LeftHand);
3118   const Standard_Integer aRightDevice = theView->View()->XRSession()->NamedTrackedDevice (Aspect_XRTrackedDeviceRole_RightHand);
3119   for (Standard_Integer aDeviceIter = theView->View()->XRSession()->TrackedPoses().Lower(); aDeviceIter <= theView->View()->XRSession()->TrackedPoses().Upper(); ++aDeviceIter)
3120   {
3121     const Aspect_TrackedDevicePose& aPose = theView->View()->XRSession()->TrackedPoses()[aDeviceIter];
3122     Handle(AIS_XRTrackedDevice)& aPosePrs = myXRPrsDevices[aDeviceIter];
3123     if (!aPose.IsValidPose)
3124     {
3125       continue;
3126     }
3127 
3128     const bool isHand = aDeviceIter == aLeftDevice
3129                      || aDeviceIter == aRightDevice;
3130     if ((!myToDisplayXRHands && isHand)
3131      || (!myToDisplayXRAuxDevices && !isHand))
3132     {
3133       if (!aPosePrs.IsNull()
3134         && aPosePrs->HasInteractiveContext())
3135       {
3136         theCtx->Remove (aPosePrs, false);
3137       }
3138       continue;
3139     }
3140 
3141     Aspect_XRTrackedDeviceRole aRole = Aspect_XRTrackedDeviceRole_Other;
3142     if (aDeviceIter == aLeftDevice)
3143     {
3144       aRole = Aspect_XRTrackedDeviceRole_LeftHand;
3145     }
3146     else if (aDeviceIter == aRightDevice)
3147     {
3148       aRole = Aspect_XRTrackedDeviceRole_RightHand;
3149     }
3150 
3151     if (!aPosePrs.IsNull()
3152       && aPosePrs->UnitFactor() != (float )theView->View()->UnitFactor())
3153     {
3154       theCtx->Remove (aPosePrs, false);
3155       aPosePrs.Nullify();
3156     }
3157 
3158     if (aPosePrs.IsNull())
3159     {
3160       Handle(Image_Texture) aTexture;
3161       Handle(Graphic3d_ArrayOfTriangles) aTris;
3162       if (aDeviceIter != aHeadDevice)
3163       {
3164         aTris = theView->View()->XRSession()->LoadRenderModel (aDeviceIter, aTexture);
3165       }
3166       if (!aTris.IsNull())
3167       {
3168         aPosePrs = new AIS_XRTrackedDevice (aTris, aTexture);
3169       }
3170       else
3171       {
3172         aPosePrs = new AIS_XRTrackedDevice();
3173       }
3174       aPosePrs->SetUnitFactor ((float )theView->View()->UnitFactor());
3175       aPosePrs->SetMutable (true);
3176       aPosePrs->SetInfiniteState (true);
3177     }
3178     aPosePrs->SetRole (aRole);
3179 
3180     if (!aPosePrs->HasInteractiveContext())
3181     {
3182       theCtx->Display (aPosePrs, 0, -1, false);
3183     }
3184 
3185     gp_Trsf aPoseLocal = aPose.Orientation;
3186     if (aDeviceIter == aHeadDevice)
3187     {
3188       // show headset position on floor level
3189       aPoseLocal.SetTranslationPart (gp_Vec (aPoseLocal.TranslationPart().X(), 0.0, aPoseLocal.TranslationPart().Z()));
3190     }
3191     const gp_Trsf aPoseWorld = theView->View()->PoseXRToWorld (aPoseLocal);
3192     theCtx->SetLocation (aPosePrs, aPoseWorld);
3193 
3194     Standard_Real aLaserLen = 0.0;
3195     if (isHand
3196       && aPosePrs->Role() == myXRLastPickingHand)
3197     {
3198       aLaserLen = myXRLastPickingHand == Aspect_XRTrackedDeviceRole_LeftHand ? myXRLastPickDepthLeft : myXRLastPickDepthRight;
3199       if (Precision::IsInfinite (aLaserLen))
3200       {
3201         const Bnd_Box aViewBox = theView->View()->MinMaxValues (true);
3202         if (!aViewBox.IsVoid())
3203         {
3204           aLaserLen = Sqrt (aViewBox.SquareExtent());
3205         }
3206         else
3207         {
3208           aLaserLen = 100.0;
3209         }
3210       }
3211       aPosePrs->SetLaserColor (myXRLaserPickColor);
3212     }
3213     else if (isHand
3214           && aPosePrs->Role() == myXRLastTeleportHand)
3215     {
3216       aLaserLen = myXRLastTeleportHand == Aspect_XRTrackedDeviceRole_LeftHand ? myXRLastPickDepthLeft : myXRLastPickDepthRight;
3217       if (Precision::IsInfinite (aLaserLen))
3218       {
3219         const Bnd_Box aViewBox = theView->View()->MinMaxValues (true);
3220         if (!aViewBox.IsVoid())
3221         {
3222           aLaserLen = Sqrt (aViewBox.SquareExtent());
3223         }
3224         else
3225         {
3226           aLaserLen = 100.0;
3227         }
3228       }
3229       aPosePrs->SetLaserColor (myXRLaserTeleColor);
3230     }
3231     aPosePrs->SetLaserLength ((float )aLaserLen);
3232   }
3233 }
3234 
3235 // =======================================================================
3236 // function : HandleViewEvents
3237 // purpose  :
3238 // =======================================================================
HandleViewEvents(const Handle (AIS_InteractiveContext)& theCtx,const Handle (V3d_View)& theView)3239 void AIS_ViewController::HandleViewEvents (const Handle(AIS_InteractiveContext)& theCtx,
3240                                            const Handle(V3d_View)& theView)
3241 {
3242   const bool wasImmediateUpdate = theView->SetImmediateUpdate (false);
3243 
3244   handleViewOrientationKeys (theCtx, theView);
3245   const AIS_WalkDelta aWalk = handleNavigationKeys (theCtx, theView);
3246   handleXRInput (theCtx, theView, aWalk);
3247   if (theView->View()->IsActiveXR())
3248   {
3249     theView->View()->SetupXRPosedCamera();
3250   }
3251   handleMoveTo (theCtx, theView);
3252   handleCameraActions (theCtx, theView, aWalk);
3253   theView->View()->SynchronizeXRPosedToBaseCamera(); // handleCameraActions() may modify posed camera position - copy this modifications also to the base camera
3254   handleXRPresentations (theCtx, theView);
3255 
3256   handleViewRedraw (theCtx, theView);
3257   theView->View()->UnsetXRPosedCamera();
3258 
3259   theView->SetImmediateUpdate (wasImmediateUpdate);
3260 
3261   // make sure to not process the same events twice
3262   myGL.Reset();
3263   myToAskNextFrame = false;
3264 }
3265