1 // Copyright (c) 2016-2019 OPEN CASCADE SAS
3 // This file is part of Open CASCADE Technology software library.
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.
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
14 #include "AIS_ViewController.hxx"
16 #include <AIS_AnimationCamera.hxx>
17 #include <AIS_InteractiveContext.hxx>
18 #include <AIS_Manipulator.hxx>
19 #include <AIS_Point.hxx>
20 #include <AIS_RubberBand.hxx>
21 #include <AIS_XRTrackedDevice.hxx>
22 #include <Aspect_XRSession.hxx>
23 #include <Aspect_Grid.hxx>
24 #include <Geom_CartesianPoint.hxx>
25 #include <Graphic3d_ArrayOfSegments.hxx>
26 #include <Graphic3d_Texture2Dmanual.hxx>
27 #include <Message.hxx>
28 #include <Message_Messenger.hxx>
29 #include <gp_Quaternion.hxx>
30 #include <V3d_View.hxx>
32 // =======================================================================
33 // function : AIS_ViewController
35 // =======================================================================
36 AIS_ViewController::AIS_ViewController()
37 : myLastEventsTime (0.0),
38 myToAskNextFrame (false),
39 myMinCamDistance (1.0),
40 myRotationMode (AIS_RotationMode_BndBoxActive),
41 myNavigationMode (AIS_NavigationMode_Orbit),
44 myToShowPanAnchorPoint (true),
45 myToShowRotateCenter (true),
46 myToLockOrbitZUp (false),
47 myToInvertPitch (false),
48 myToAllowTouchZRotation(false),
49 myToAllowRotation (true),
50 myToAllowPanning (true),
51 myToAllowZooming (true),
52 myToAllowZFocus (true),
53 myToAllowHighlight (true),
54 myToAllowDragging (true),
55 myToStickToRayOnZoom (true),
56 myToStickToRayOnRotation (true),
58 myWalkSpeedAbsolute (1.5f),
59 myWalkSpeedRelative (0.1f),
63 myViewAnimation (new AIS_AnimationCamera ("AIS_ViewController_ViewAnimation", Handle(V3d_View)())),
64 myPrevMoveTo (-1, -1),
65 myHasHlrOnBeforeRotation (false),
67 myXRPrsDevices (0, 0),
68 myXRLaserTeleColor (Quantity_NOC_GREEN),
69 myXRLaserPickColor (Quantity_NOC_BLUE),
70 myXRLastTeleportHand(Aspect_XRTrackedDeviceRole_Other),
71 myXRLastPickingHand (Aspect_XRTrackedDeviceRole_Other),
72 myXRLastPickDepthLeft (Precision::Infinite()),
73 myXRLastPickDepthRight(Precision::Infinite()),
74 myXRTurnAngle (M_PI_4),
75 myToDisplayXRAuxDevices (false),
76 myToDisplayXRHands (true),
78 myMouseClickThreshold (3.0),
79 myMouseDoubleClickInt (0.4),
80 myScrollZoomRatio (15.0f),
81 myMouseActiveGesture (AIS_MouseGesture_NONE),
82 myMouseActiveIdleRotation (false),
83 myMouseClickCounter (0),
84 myMousePressed (Aspect_VKeyMouse_NONE),
85 myMouseModifiers (Aspect_VKeyFlags_NONE),
86 myMouseSingleButton (-1),
87 myMouseStopDragOnUnclick (false),
89 myTouchToleranceScale (1.0f),
90 myTouchRotationThresholdPx (6.0f),
91 myTouchZRotationThreshold (float(2.0 * M_PI / 180.0)),
92 myTouchPanThresholdPx (4.0f),
93 myTouchZoomThresholdPx (6.0f),
94 myTouchZoomRatio (0.13f),
97 myUpdateStartPointPan (true),
98 myUpdateStartPointRot (true),
99 myUpdateStartPointZRot (true),
101 myPanPnt3d (Precision::Infinite(), 0.0, 0.0)
103 myEventTimer.Start();
105 myAnchorPointPrs1 = new AIS_Point (new Geom_CartesianPoint (0.0, 0.0, 0.0));
106 myAnchorPointPrs1->SetZLayer (Graphic3d_ZLayerId_Top);
107 myAnchorPointPrs1->SetMutable (true);
109 myAnchorPointPrs2 = new AIS_Point (new Geom_CartesianPoint (0.0, 0.0, 0.0));
110 myAnchorPointPrs2->SetZLayer (Graphic3d_ZLayerId_Topmost);
111 myAnchorPointPrs2->SetMutable (true);
113 myRubberBand = new AIS_RubberBand (Quantity_NOC_LIGHTBLUE, Aspect_TOL_SOLID, Quantity_NOC_LIGHTBLUE, 0.4, 1.0);
114 myRubberBand->SetZLayer (Graphic3d_ZLayerId_TopOSD);
115 myRubberBand->SetTransformPersistence (new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_UPPER));
116 myRubberBand->SetDisplayMode (0);
117 myRubberBand->SetMutable (true);
119 myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton, AIS_MouseGesture_RotateOrbit);
120 myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_CTRL, AIS_MouseGesture_Zoom);
121 myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_SHIFT, AIS_MouseGesture_Pan);
122 myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_ALT, AIS_MouseGesture_SelectRectangle);
124 myMouseGestureMap.Bind (Aspect_VKeyMouse_RightButton, AIS_MouseGesture_Zoom);
125 myMouseGestureMap.Bind (Aspect_VKeyMouse_RightButton | Aspect_VKeyFlags_CTRL, AIS_MouseGesture_RotateOrbit);
127 myMouseGestureMap.Bind (Aspect_VKeyMouse_MiddleButton, AIS_MouseGesture_Pan);
128 myMouseGestureMap.Bind (Aspect_VKeyMouse_MiddleButton | Aspect_VKeyFlags_CTRL, AIS_MouseGesture_Pan);
130 myXRTeleportHaptic.Duration = 3600.0f;
131 myXRTeleportHaptic.Frequency = 0.1f;
132 myXRTeleportHaptic.Amplitude = 0.2f;
134 myXRPickingHaptic.Duration = 0.1f;
135 myXRPickingHaptic.Frequency = 4.0f;
136 myXRPickingHaptic.Amplitude = 0.1f;
138 myXRSelectHaptic.Duration = 0.2f;
139 myXRSelectHaptic.Frequency = 4.0f;
140 myXRSelectHaptic.Amplitude = 0.5f;
143 // =======================================================================
144 // function : ~AIS_ViewController
146 // =======================================================================
147 AIS_ViewController::~AIS_ViewController()
152 // =======================================================================
153 // function : ResetViewInput
155 // =======================================================================
156 void AIS_ViewController::ResetViewInput()
159 myMousePressed = Aspect_VKeyMouse_NONE;
160 myMouseModifiers = Aspect_VKeyFlags_NONE;
161 myMouseSingleButton = -1;
162 myUI.Dragging.ToAbort = true;
163 myMouseActiveGesture = AIS_MouseGesture_NONE;
164 myMouseClickTimer.Stop();
165 myMouseClickCounter = 0;
168 // =======================================================================
169 // function : FlushViewEvents
171 // =======================================================================
172 void AIS_ViewController::FlushViewEvents (const Handle(AIS_InteractiveContext)& theCtx,
173 const Handle(V3d_View)& theView,
174 Standard_Boolean theToHandle)
176 flushBuffers (theCtx, theView);
177 flushGestures(theCtx, theView);
180 HandleViewEvents (theCtx, theView);
184 // =======================================================================
185 // function : flushBuffers
187 // =======================================================================
188 void AIS_ViewController::flushBuffers (const Handle(AIS_InteractiveContext)& ,
189 const Handle(V3d_View)& )
191 myToAskNextFrame = false;
193 myGL.IsNewGesture = myUI.IsNewGesture;
194 myUI.IsNewGesture = false;
196 myGL.ZoomActions.Clear();
197 myGL.ZoomActions.Append (myUI.ZoomActions);
198 myUI.ZoomActions.Clear();
200 myGL.Orientation.ToFitAll = myUI.Orientation.ToFitAll;
201 myUI.Orientation.ToFitAll = false;
202 if (myUI.Orientation.ToSetViewOrient)
204 myUI.Orientation.ToSetViewOrient = false;
205 myGL.Orientation.ToSetViewOrient = true;
206 myGL.Orientation.ViewOrient = myUI.Orientation.ViewOrient;
209 if (myUI.MoveTo.ToHilight)
211 myUI.MoveTo.ToHilight = false;
212 myGL.MoveTo.ToHilight = true;
213 myGL.MoveTo.Point = myUI.MoveTo.Point;
217 myGL.Selection.Tool = myUI.Selection.Tool;
218 myGL.Selection.IsXOR = myUI.Selection.IsXOR;
219 myGL.Selection.Points = myUI.Selection.Points;
220 myUI.Selection.IsXOR = false;
221 if (myUI.Selection.Tool == AIS_ViewSelectionTool_Picking)
223 myUI.Selection.Points.Clear();
227 if (myUI.Selection.ToApplyTool)
229 myGL.Selection.ToApplyTool = true;
230 myUI.Selection.ToApplyTool = false;
231 myUI.Selection.Points.Clear();
234 if (myUI.Panning.ToStart)
236 myUI.Panning.ToStart = false;
237 myGL.Panning.ToStart = true;
238 myGL.Panning.PointStart = myUI.Panning.PointStart;
241 if (myUI.Panning.ToPan)
243 myUI.Panning.ToPan = false;
244 myGL.Panning.ToPan = true;
245 myGL.Panning.Delta = myUI.Panning.Delta;
248 if (myUI.Dragging.ToAbort)
250 myUI.Dragging.ToAbort = false;
251 myGL.Dragging.ToAbort = true;
253 else if (myUI.Dragging.ToStop)
255 myUI.Dragging.ToStop = false;
256 myGL.Dragging.ToStop = true;
258 else if (myUI.Dragging.ToStart)
260 myUI.Dragging.ToStart = false;
261 myGL.Dragging.ToStart = true;
262 myGL.Dragging.PointStart = myUI.Dragging.PointStart;
264 myGL.Dragging.PointTo = myUI.Dragging.PointTo;
266 if (myUI.OrbitRotation.ToStart)
268 myUI.OrbitRotation.ToStart = false;
269 myGL.OrbitRotation.ToStart = true;
270 myGL.OrbitRotation.PointStart = myUI.OrbitRotation.PointStart;
273 if (myUI.OrbitRotation.ToRotate)
275 myUI.OrbitRotation.ToRotate = false;
276 myGL.OrbitRotation.ToRotate = true;
277 myGL.OrbitRotation.PointTo = myUI.OrbitRotation.PointTo;
280 if (myUI.ViewRotation.ToStart)
282 myUI.ViewRotation.ToStart = false;
283 myGL.ViewRotation.ToStart = true;
284 myGL.ViewRotation.PointStart = myUI.ViewRotation.PointStart;
287 if (myUI.ViewRotation.ToRotate)
289 myUI.ViewRotation.ToRotate = false;
290 myGL.ViewRotation.ToRotate = true;
291 myGL.ViewRotation.PointTo = myUI.ViewRotation.PointTo;
294 if (myUI.ZRotate.ToRotate)
296 myGL.ZRotate = myUI.ZRotate;
297 myUI.ZRotate.ToRotate = false;
301 // =======================================================================
302 // function : flushGestures
304 // =======================================================================
305 void AIS_ViewController::flushGestures (const Handle(AIS_InteractiveContext)& ,
306 const Handle(V3d_View)& theView)
308 const Standard_Real aTolScale = myTouchToleranceScale;
309 const Standard_Integer aTouchNb = myTouchPoints.Extent();
310 if (myNbTouchesLast != aTouchNb)
312 myNbTouchesLast = aTouchNb;
313 myGL.IsNewGesture = true;
315 if (aTouchNb == 1) // touch
317 Aspect_Touch& aTouch = myTouchPoints.ChangeFromIndex (1);
318 if (myUpdateStartPointRot)
320 // skip rotation if have active dragged object
321 if (myNavigationMode == AIS_NavigationMode_Orbit)
323 myGL.OrbitRotation.ToStart = true;
324 myGL.OrbitRotation.PointStart = myStartRotCoord;
328 myGL.ViewRotation.ToStart = true;
329 myGL.ViewRotation.PointStart = myStartRotCoord;
332 myUpdateStartPointRot = false;
333 theView->Invalidate();
337 const Standard_Real aRotTouchTol = !aTouch.IsPreciseDevice
338 ? aTolScale * myTouchRotationThresholdPx
340 if (Abs (aTouch.Delta().x()) + Abs(aTouch.Delta().y()) > aRotTouchTol)
342 const Standard_Real aRotAccel = myNavigationMode == AIS_NavigationMode_FirstPersonWalk ? myMouseAccel : myOrbitAccel;
343 if (myNavigationMode == AIS_NavigationMode_Orbit)
345 const Graphic3d_Vec2d aRotDelta = aTouch.To - myGL.OrbitRotation.PointStart;
346 myGL.OrbitRotation.ToRotate = true;
347 myGL.OrbitRotation.PointTo = myGL.OrbitRotation.PointStart + aRotDelta * aRotAccel;
348 myGL.Dragging.PointTo.SetValues ((int )aTouch.To.x(), (int )aTouch.To.y());
352 const Graphic3d_Vec2d aRotDelta = aTouch.To - myGL.ViewRotation.PointStart;
353 myGL.ViewRotation.ToRotate = true;
354 myGL.ViewRotation.PointTo = myGL.ViewRotation.PointStart + aRotDelta * aRotAccel;
355 myGL.Dragging.PointTo.SetValues ((int )aTouch.To.x(), (int )aTouch.To.y());
358 aTouch.From = aTouch.To;
361 else if (aTouchNb == 2) // pinch
363 Aspect_Touch& aFirstTouch = myTouchPoints.ChangeFromIndex (1);
364 Aspect_Touch& aLastTouch = myTouchPoints.ChangeFromIndex (2);
365 const Graphic3d_Vec2d aFrom[2] = { aFirstTouch.From, aLastTouch.From };
366 const Graphic3d_Vec2d aTo[2] = { aFirstTouch.To, aLastTouch.To };
368 Graphic3d_Vec2d aPinchCenterStart ((aFrom[0].x() + aFrom[1].x()) / 2.0,
369 (aFrom[0].y() + aFrom[1].y()) / 2.0);
371 Standard_Real aPinchCenterXEnd = (aTo[0].x() + aTo[1].x()) / 2.0;
372 Standard_Real aPinchCenterYEnd = (aTo[0].y() + aTo[1].y()) / 2.0;
374 Standard_Real aPinchCenterXDev = aPinchCenterXEnd - aPinchCenterStart.x();
375 Standard_Real aPinchCenterYDev = aPinchCenterYEnd - aPinchCenterStart.y();
377 Standard_Real aStartSize = (aFrom[0] - aFrom[1]).Modulus();
378 Standard_Real anEndSize = ( aTo[0] - aTo[1]).Modulus();
380 Standard_Real aDeltaSize = anEndSize - aStartSize;
382 bool anIsClearDev = false;
384 if (myToAllowTouchZRotation)
386 Standard_Real A1 = aFrom[0].y() - aFrom[1].y();
387 Standard_Real B1 = aFrom[1].x() - aFrom[0].x();
389 Standard_Real A2 = aTo[0].y() - aTo[1].y();
390 Standard_Real B2 = aTo[1].x() - aTo[0].x();
392 Standard_Real aRotAngle = 0.0;
394 Standard_Real aDenomenator = A1*A2 + B1*B2;
395 if (aDenomenator <= Precision::Confusion())
401 Standard_Real aNumerator = A1*B2 - A2*B1;
402 aRotAngle = ATan (aNumerator / aDenomenator);
405 if (Abs(aRotAngle) > Standard_Real(myTouchZRotationThreshold))
407 myGL.ZRotate.ToRotate = true;
408 myGL.ZRotate.Angle = aRotAngle;
413 if (Abs(aDeltaSize) > aTolScale * myTouchZoomThresholdPx)
416 aDeltaSize *= Standard_Real(myTouchZoomRatio);
417 Aspect_ScrollDelta aParams (Graphic3d_Vec2i (aPinchCenterStart), aDeltaSize);
418 myGL.ZoomActions.Append (aParams);
422 const Standard_Real aPanTouchTol = !aFirstTouch.IsPreciseDevice
423 ? aTolScale * myTouchPanThresholdPx
425 if (Abs(aPinchCenterXDev) + Abs(aPinchCenterYDev) > aPanTouchTol)
428 if (myUpdateStartPointPan)
430 myGL.Panning.ToStart = true;
431 myGL.Panning.PointStart = Graphic3d_Vec2i (myStartPanCoord);
432 myUpdateStartPointPan = false;
433 theView->Invalidate();
436 myGL.Panning.ToPan = true;
437 myGL.Panning.Delta.x() = int( aPinchCenterXDev);
438 myGL.Panning.Delta.y() = int(-aPinchCenterYDev);
444 aFirstTouch.From = aFirstTouch.To;
445 aLastTouch .From = aLastTouch.To;
450 // =======================================================================
451 // function : UpdateViewOrientation
453 // =======================================================================
454 void AIS_ViewController::UpdateViewOrientation (V3d_TypeOfOrientation theOrientation,
457 myUI.Orientation.ToFitAll = theToFitAll;
458 myUI.Orientation.ToSetViewOrient = true;
459 myUI.Orientation.ViewOrient = theOrientation;
462 // =======================================================================
463 // function : SelectInViewer
465 // =======================================================================
466 void AIS_ViewController::SelectInViewer (const Graphic3d_Vec2i& thePnt,
469 if (myUI.Selection.Tool != AIS_ViewSelectionTool_Picking)
471 myUI.Selection.Tool = AIS_ViewSelectionTool_Picking;
472 myUI.Selection.Points.Clear();
475 myUI.Selection.IsXOR = theIsXOR;
476 myUI.Selection.Points.Append (thePnt);
479 // =======================================================================
480 // function : SelectInViewer
482 // =======================================================================
483 void AIS_ViewController::SelectInViewer (const NCollection_Sequence<Graphic3d_Vec2i>& thePnts,
486 myUI.Selection.IsXOR = theIsXOR;
487 myUI.Selection.Points = thePnts;
488 myUI.Selection.ToApplyTool = true;
489 if (thePnts.Length() == 1)
491 myUI.Selection.Tool = AIS_ViewSelectionTool_Picking;
493 else if (thePnts.Length() == 2)
495 myUI.Selection.Tool = AIS_ViewSelectionTool_RubberBand;
499 myUI.Selection.Tool = AIS_ViewSelectionTool_Polygon;
503 // =======================================================================
504 // function : UpdateRubberBand
506 // =======================================================================
507 void AIS_ViewController::UpdateRubberBand (const Graphic3d_Vec2i& thePntFrom,
508 const Graphic3d_Vec2i& thePntTo,
511 myUI.Selection.Tool = AIS_ViewSelectionTool_RubberBand;
512 myUI.Selection.IsXOR = theIsXOR;
513 myUI.Selection.Points.Clear();
514 myUI.Selection.Points.Append (thePntFrom);
515 myUI.Selection.Points.Append (thePntTo);
518 // =======================================================================
519 // function : UpdatePolySelection
521 // =======================================================================
522 void AIS_ViewController::UpdatePolySelection (const Graphic3d_Vec2i& thePnt,
525 if (myUI.Selection.Tool != AIS_ViewSelectionTool_Polygon)
527 myUI.Selection.Tool = AIS_ViewSelectionTool_Polygon;
528 myUI.Selection.Points.Clear();
531 if (myUI.Selection.Points.IsEmpty())
533 myUI.Selection.Points.Append (thePnt);
536 && myUI.Selection.Points.Last() != thePnt)
538 myUI.Selection.Points.Append (thePnt);
542 myUI.Selection.Points.ChangeLast() = thePnt;
546 // =======================================================================
547 // function : UpdateZoom
549 // =======================================================================
550 bool AIS_ViewController::UpdateZoom (const Aspect_ScrollDelta& theDelta)
552 if (!myUI.ZoomActions.IsEmpty())
554 if (myUI.ZoomActions.ChangeLast().Point == theDelta.Point)
556 myUI.ZoomActions.ChangeLast().Delta += theDelta.Delta;
561 myUI.ZoomActions.Append (theDelta);
565 // =======================================================================
566 // function : UpdateZRotation
568 // =======================================================================
569 bool AIS_ViewController::UpdateZRotation (double theAngle)
571 if (!ToAllowTouchZRotation())
576 myUI.ZRotate.Angle = myUI.ZRotate.ToRotate
577 ? myUI.ZRotate.Angle + theAngle
579 if (myUI.ZRotate.ToRotate)
583 myUI.ZRotate.ToRotate = true;
587 // =======================================================================
588 // function : UpdateMouseScroll
590 // =======================================================================
591 bool AIS_ViewController::UpdateMouseScroll (const Aspect_ScrollDelta& theDelta)
593 Aspect_ScrollDelta aDelta = theDelta;
594 aDelta.Delta *= myScrollZoomRatio;
595 return UpdateZoom (aDelta);
598 // =======================================================================
599 // function : UpdateMouseClick
601 // =======================================================================
602 bool AIS_ViewController::UpdateMouseClick (const Graphic3d_Vec2i& thePoint,
603 Aspect_VKeyMouse theButton,
604 Aspect_VKeyFlags theModifiers,
605 bool theIsDoubleClick)
607 (void )theIsDoubleClick;
608 if (theButton == Aspect_VKeyMouse_LeftButton)
610 SelectInViewer (thePoint, (theModifiers & Aspect_VKeyFlags_SHIFT) != 0);
616 // =======================================================================
617 // function : UpdateMouseButtons
619 // =======================================================================
620 bool AIS_ViewController::UpdateMouseButtons (const Graphic3d_Vec2i& thePoint,
621 Aspect_VKeyMouse theButtons,
622 Aspect_VKeyFlags theModifiers,
625 bool toUpdateView = false;
626 const double aTolClick = (theIsEmulated ? myTouchToleranceScale : 1.0) * myMouseClickThreshold;
627 if (theButtons == Aspect_VKeyMouse_NONE
628 && myMouseSingleButton > 0)
630 const Graphic3d_Vec2i aDelta = thePoint - myMousePressPoint;
631 if (double(aDelta.cwiseAbs().maxComp()) < aTolClick)
633 ++myMouseClickCounter;
634 const bool isDoubleClick = myMouseClickCounter == 2
635 && myMouseClickTimer.IsStarted()
636 && myMouseClickTimer.ElapsedTime() <= myMouseDoubleClickInt;
638 myMouseClickTimer.Stop();
639 myMouseClickTimer.Reset();
640 myMouseClickTimer.Start();
643 myMouseClickCounter = 0;
645 toUpdateView = UpdateMouseClick (thePoint, (Aspect_VKeyMouse )myMouseSingleButton, theModifiers, isDoubleClick) || toUpdateView;
649 myMouseClickTimer.Stop();
650 myMouseClickCounter = 0;
651 myMouseStopDragOnUnclick = false;
652 myUI.Dragging.ToStop = true;
655 myMouseSingleButton = -1;
657 else if (theButtons == Aspect_VKeyMouse_NONE)
659 myMouseSingleButton = -1;
660 if (myMouseStopDragOnUnclick)
662 myMouseStopDragOnUnclick = false;
663 myUI.Dragging.ToStop = true;
667 else if (myMouseSingleButton == -1)
669 if ((theButtons & Aspect_VKeyMouse_LeftButton) == Aspect_VKeyMouse_LeftButton)
671 myMouseSingleButton = Aspect_VKeyMouse_LeftButton;
673 else if ((theButtons & Aspect_VKeyMouse_RightButton) == Aspect_VKeyMouse_RightButton)
675 myMouseSingleButton = Aspect_VKeyMouse_RightButton;
677 else if ((theButtons & Aspect_VKeyMouse_MiddleButton) == Aspect_VKeyMouse_MiddleButton)
679 myMouseSingleButton = Aspect_VKeyMouse_MiddleButton;
683 myMouseSingleButton = 0;
685 if (myMouseSingleButton != 0)
687 if (myMouseClickCounter == 1)
689 const Graphic3d_Vec2i aDelta = thePoint - myMousePressPoint;
690 if (double(aDelta.cwiseAbs().maxComp()) >= aTolClick)
692 myMouseClickTimer.Stop();
693 myMouseClickCounter = 0;
696 myMousePressPoint = thePoint;
701 myMouseSingleButton = 0;
703 myUI.Dragging.ToAbort = true;
707 const AIS_MouseGesture aPrevGesture = myMouseActiveGesture;
708 myMouseModifiers = theModifiers;
709 myMousePressed = theButtons;
711 || myNavigationMode != AIS_NavigationMode_FirstPersonWalk)
713 myMouseActiveIdleRotation = false;
714 myMouseActiveGesture = AIS_MouseGesture_NONE;
717 myMousePressPoint = thePoint;
718 myMouseProgressPoint = myMousePressPoint;
721 if (myMouseGestureMap.Find (theButtons | theModifiers, myMouseActiveGesture))
723 switch (myMouseActiveGesture)
725 case AIS_MouseGesture_RotateView:
726 case AIS_MouseGesture_RotateOrbit:
728 if (myToAllowRotation)
730 myUpdateStartPointRot = true;
734 myMouseActiveGesture = AIS_MouseGesture_NONE;
738 case AIS_MouseGesture_Pan:
740 if (myToAllowPanning)
742 myUpdateStartPointPan = true;
746 myMouseActiveGesture = AIS_MouseGesture_NONE;
750 case AIS_MouseGesture_Zoom:
751 case AIS_MouseGesture_ZoomWindow:
753 if (!myToAllowZooming)
755 myMouseActiveGesture = AIS_MouseGesture_NONE;
759 case AIS_MouseGesture_SelectRectangle:
763 case AIS_MouseGesture_SelectLasso:
765 UpdatePolySelection (thePoint, true);
768 case AIS_MouseGesture_NONE:
775 if (theButtons == Aspect_VKeyMouse_LeftButton
776 && theModifiers == Aspect_VKeyFlags_NONE
777 && myToAllowDragging)
779 myUI.Dragging.ToStart = true;
780 myUI.Dragging.PointStart = thePoint;
784 if (aPrevGesture != myMouseActiveGesture)
786 if (aPrevGesture == AIS_MouseGesture_SelectRectangle
787 || aPrevGesture == AIS_MouseGesture_SelectLasso
788 || aPrevGesture == AIS_MouseGesture_ZoomWindow)
790 myUI.Selection.ToApplyTool = true;
793 myUI.IsNewGesture = true;
799 // =======================================================================
800 // function : UpdateMousePosition
802 // =======================================================================
803 bool AIS_ViewController::UpdateMousePosition (const Graphic3d_Vec2i& thePoint,
804 Aspect_VKeyMouse theButtons,
805 Aspect_VKeyFlags theModifiers,
808 myMousePositionLast = thePoint;
809 if (myMouseSingleButton > 0)
811 const double aTolClick = (theIsEmulated ? myTouchToleranceScale : 1.0) * myMouseClickThreshold;
812 const Graphic3d_Vec2i aPressDelta = thePoint - myMousePressPoint;
813 if (double(aPressDelta.cwiseAbs().maxComp()) >= aTolClick)
815 myMouseClickTimer.Stop();
816 myMouseClickCounter = 0;
817 myMouseSingleButton = -1;
818 myMouseStopDragOnUnclick = true;
822 bool toUpdateView = false;
823 Graphic3d_Vec2i aDelta = thePoint - myMouseProgressPoint;
825 && myNavigationMode == AIS_NavigationMode_FirstPersonWalk)
827 if (!myMouseActiveIdleRotation
828 || myMouseActiveGesture != AIS_MouseGesture_RotateView)
830 myMouseActiveIdleRotation = true;
831 myMouseActiveGesture = AIS_MouseGesture_RotateView;
832 myMousePressPoint = thePoint;
833 myMouseProgressPoint = thePoint;
834 myUpdateStartPointRot = false;
835 myUI.ViewRotation.ToStart = true;
836 myUI.ViewRotation.PointStart.SetValues (thePoint.x(), thePoint.y());
837 myUI.ViewRotation.ToRotate = false;
838 aDelta.SetValues (0, 0);
843 if (myMouseActiveIdleRotation
844 && myMouseActiveGesture == AIS_MouseGesture_RotateView)
846 myMouseActiveGesture = AIS_MouseGesture_NONE;
848 myMouseActiveIdleRotation = false;
851 if (myMouseModifiers != theModifiers
852 && UpdateMouseButtons (thePoint, theButtons, theModifiers, theIsEmulated))
857 switch (myMouseActiveGesture)
859 case AIS_MouseGesture_SelectRectangle:
860 case AIS_MouseGesture_ZoomWindow:
862 UpdateRubberBand (myMousePressPoint, thePoint);
863 if (myMouseActiveGesture == AIS_MouseGesture_ZoomWindow)
865 myUI.Selection.Tool = AIS_ViewSelectionTool_ZoomWindow;
870 case AIS_MouseGesture_SelectLasso:
872 UpdatePolySelection (thePoint, true);
876 case AIS_MouseGesture_RotateOrbit:
877 case AIS_MouseGesture_RotateView:
879 if (!myToAllowRotation)
883 if (myUpdateStartPointRot)
885 if (myMouseActiveGesture == AIS_MouseGesture_RotateOrbit)
887 myUI.OrbitRotation.ToStart = true;
888 myUI.OrbitRotation.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y());
892 myUI.ViewRotation.ToStart = true;
893 myUI.ViewRotation.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y());
895 myUpdateStartPointRot = false;
898 const double aRotTol = theIsEmulated
899 ? double(myTouchToleranceScale) * myTouchRotationThresholdPx
901 if (double (Abs (aDelta.x()) + Abs (aDelta.y())) > aRotTol)
903 const double aRotAccel = myNavigationMode == AIS_NavigationMode_FirstPersonWalk ? myMouseAccel : myOrbitAccel;
904 const Graphic3d_Vec2i aRotDelta = thePoint - myMousePressPoint;
905 if (myMouseActiveGesture == AIS_MouseGesture_RotateOrbit)
907 myUI.OrbitRotation.ToRotate = true;
908 myUI.OrbitRotation.PointTo = Graphic3d_Vec2d (myMousePressPoint.x(), myMousePressPoint.y())
909 + Graphic3d_Vec2d (aRotDelta.x(), aRotDelta.y()) * aRotAccel;
913 myUI.ViewRotation.ToRotate = true;
914 myUI.ViewRotation.PointTo = Graphic3d_Vec2d (myMousePressPoint.x(), myMousePressPoint.y())
915 + Graphic3d_Vec2d (aRotDelta.x(), aRotDelta.y()) * aRotAccel;
917 myUI.Dragging.PointTo = thePoint;
919 myMouseProgressPoint = thePoint;
924 case AIS_MouseGesture_Zoom:
926 if (!myToAllowZooming)
930 const double aZoomTol = theIsEmulated
931 ? double(myTouchToleranceScale) * myTouchZoomThresholdPx
933 if (double (Abs (aDelta.x())) > aZoomTol)
935 if (UpdateZoom (Aspect_ScrollDelta (aDelta.x())))
939 myMouseProgressPoint = thePoint;
943 case AIS_MouseGesture_Pan:
945 if (!myToAllowPanning)
949 const double aPanTol = theIsEmulated
950 ? double(myTouchToleranceScale) * myTouchPanThresholdPx
952 if (double (Abs (aDelta.x()) + Abs (aDelta.y())) > aPanTol)
954 if (myUpdateStartPointPan)
956 myUI.Panning.ToStart = true;
957 myUI.Panning.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y());
958 myUpdateStartPointPan = false;
961 aDelta.y() = -aDelta.y();
962 myMouseProgressPoint = thePoint;
963 if (myUI.Panning.ToPan)
965 myUI.Panning.Delta += aDelta;
969 myUI.Panning.ToPan = true;
970 myUI.Panning.Delta = aDelta;
982 if (theButtons == Aspect_VKeyMouse_NONE
983 && myNavigationMode != AIS_NavigationMode_FirstPersonWalk
986 && myToAllowHighlight)
988 myUI.MoveTo.ToHilight = true;
989 myUI.MoveTo.Point = thePoint;
995 // =======================================================================
996 // function : AddTouchPoint
998 // =======================================================================
999 void AIS_ViewController::AddTouchPoint (Standard_Size theId,
1000 const Graphic3d_Vec2d& thePnt,
1001 Standard_Boolean theClearBefore)
1003 myUI.MoveTo.ToHilight = false;
1006 RemoveTouchPoint ((Standard_Size )-1);
1009 myTouchPoints.Add (theId, Aspect_Touch (thePnt, false));
1010 if (myTouchPoints.Extent() == 1)
1012 myUpdateStartPointRot = true;
1013 myStartRotCoord = thePnt;
1014 if (myToAllowDragging)
1016 myUI.Dragging.ToStart = true;
1017 myUI.Dragging.PointStart.SetValues ((int )thePnt.x(), (int )thePnt.y());
1020 else if (myTouchPoints.Extent() == 2)
1022 myUI.Dragging.ToAbort = true;
1024 myUpdateStartPointPan = true;
1025 myStartPanCoord = thePnt;
1027 myUI.IsNewGesture = true;
1030 // =======================================================================
1031 // function : RemoveTouchPoint
1033 // =======================================================================
1034 bool AIS_ViewController::RemoveTouchPoint (Standard_Size theId,
1035 Standard_Boolean theClearSelectPnts)
1037 if (theId == (Standard_Size )-1)
1039 myTouchPoints.Clear (false);
1043 const Standard_Integer anOldExtent = myTouchPoints.Extent();
1044 myTouchPoints.RemoveKey (theId);
1045 if (myTouchPoints.Extent() == anOldExtent)
1051 if (myTouchPoints.Extent() == 1)
1053 // avoid incorrect transition from pinch to one finger
1054 Aspect_Touch& aFirstTouch = myTouchPoints.ChangeFromIndex (1);
1055 aFirstTouch.To = aFirstTouch.From;
1057 myStartRotCoord = aFirstTouch.To;
1058 myUpdateStartPointRot = true;
1060 else if (myTouchPoints.Extent() == 2)
1062 myStartPanCoord = myTouchPoints.FindFromIndex (1).To;
1063 myUpdateStartPointPan = true;
1065 else if (myTouchPoints.IsEmpty())
1067 if (theClearSelectPnts)
1069 myUI.Selection.ToApplyTool = true;
1072 myUI.Dragging.ToStop = true;
1074 myUI.IsNewGesture = true;
1078 // =======================================================================
1079 // function : UpdateTouchPoint
1081 // =======================================================================
1082 void AIS_ViewController::UpdateTouchPoint (Standard_Size theId,
1083 const Graphic3d_Vec2d& thePnt)
1085 if (Aspect_Touch* aTouch = myTouchPoints.ChangeSeek (theId))
1087 aTouch->To = thePnt;
1091 AddTouchPoint (theId, thePnt);
1095 // =======================================================================
1096 // function : SetNavigationMode
1098 // =======================================================================
1099 void AIS_ViewController::SetNavigationMode (AIS_NavigationMode theMode)
1101 myNavigationMode = theMode;
1104 myUI.OrbitRotation.ToStart = false;
1105 myUI.OrbitRotation.ToRotate = false;
1106 myUI.ViewRotation.ToStart = false;
1107 myUI.ViewRotation.ToRotate = false;
1110 // =======================================================================
1111 // function : KeyDown
1113 // =======================================================================
1114 void AIS_ViewController::KeyDown (Aspect_VKey theKey,
1118 myKeys.KeyDown (theKey, theTime, thePressure);
1121 // =======================================================================
1124 // =======================================================================
1125 void AIS_ViewController::KeyUp (Aspect_VKey theKey,
1128 myKeys.KeyUp (theKey, theTime);
1131 // =======================================================================
1132 // function : KeyFromAxis
1134 // =======================================================================
1135 void AIS_ViewController::KeyFromAxis (Aspect_VKey theNegative,
1136 Aspect_VKey thePositive,
1140 myKeys.KeyFromAxis (theNegative, thePositive, theTime, thePressure);
1143 // =======================================================================
1144 // function : FetchNavigationKeys
1146 // =======================================================================
1147 AIS_WalkDelta AIS_ViewController::FetchNavigationKeys (Standard_Real theCrouchRatio,
1148 Standard_Real theRunRatio)
1150 AIS_WalkDelta aWalk;
1153 double aPrevEventTime = 0.0, aNewEventTime = 0.0;
1154 updateEventsTime (aPrevEventTime, aNewEventTime);
1156 double aDuration = 0.0, aPressure = 1.0;
1157 if (Abs (myThrustSpeed) > gp::Resolution())
1161 aWalk[AIS_WalkTranslation_Forward].Value = myThrustSpeed * (aNewEventTime - aPrevEventTime);
1164 myToAskNextFrame = true;
1168 myHasThrust = false;
1171 aWalk.SetRunning (theRunRatio > 1.0
1172 && myKeys.IsKeyDown (Aspect_VKey_Shift));
1173 if (myKeys.HoldDuration (Aspect_VKey_NavJump, aNewEventTime, aDuration))
1175 myKeys.KeyUp (Aspect_VKey_NavJump, aNewEventTime);
1176 aWalk.SetJumping (true);
1178 if (!aWalk.IsJumping()
1179 && theCrouchRatio < 1.0
1180 && myKeys.HoldDuration (Aspect_VKey_NavCrouch, aNewEventTime, aDuration))
1182 aWalk.SetRunning (false);
1183 aWalk.SetCrouching (true);
1186 const double aMaxDuration = aNewEventTime - aPrevEventTime;
1187 const double aRunRatio = aWalk.IsRunning()
1189 : aWalk.IsCrouching()
1192 if (myKeys.HoldDuration (Aspect_VKey_NavForward, aNewEventTime, aDuration, aPressure))
1194 double aProgress = Abs (Min (aMaxDuration, aDuration));
1195 aProgress *= aRunRatio;
1196 aWalk[AIS_WalkTranslation_Forward].Value += aProgress;
1197 aWalk[AIS_WalkTranslation_Forward].Pressure = aPressure;
1198 aWalk[AIS_WalkTranslation_Forward].Duration = aDuration;
1200 if (myKeys.HoldDuration (Aspect_VKey_NavBackward, aNewEventTime, aDuration, aPressure))
1202 double aProgress = Abs (Min (aMaxDuration, aDuration));
1203 aProgress *= aRunRatio;
1204 aWalk[AIS_WalkTranslation_Forward].Value += -aProgress;
1205 aWalk[AIS_WalkTranslation_Forward].Pressure = aPressure;
1206 aWalk[AIS_WalkTranslation_Forward].Duration = aDuration;
1208 if (myKeys.HoldDuration (Aspect_VKey_NavSlideLeft, aNewEventTime, aDuration, aPressure))
1210 double aProgress = Abs (Min (aMaxDuration, aDuration));
1211 aProgress *= aRunRatio;
1212 aWalk[AIS_WalkTranslation_Side].Value = -aProgress;
1213 aWalk[AIS_WalkTranslation_Side].Pressure = aPressure;
1214 aWalk[AIS_WalkTranslation_Side].Duration = aDuration;
1216 if (myKeys.HoldDuration (Aspect_VKey_NavSlideRight, aNewEventTime, aDuration, aPressure))
1218 double aProgress = Abs (Min (aMaxDuration, aDuration));
1219 aProgress *= aRunRatio;
1220 aWalk[AIS_WalkTranslation_Side].Value = aProgress;
1221 aWalk[AIS_WalkTranslation_Side].Pressure = aPressure;
1222 aWalk[AIS_WalkTranslation_Side].Duration = aDuration;
1224 if (myKeys.HoldDuration (Aspect_VKey_NavLookLeft, aNewEventTime, aDuration, aPressure))
1226 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1227 aWalk[AIS_WalkRotation_Yaw].Value = aProgress;
1228 aWalk[AIS_WalkRotation_Yaw].Pressure = aPressure;
1229 aWalk[AIS_WalkRotation_Yaw].Duration = aDuration;
1231 if (myKeys.HoldDuration (Aspect_VKey_NavLookRight, aNewEventTime, aDuration, aPressure))
1233 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1234 aWalk[AIS_WalkRotation_Yaw].Value = -aProgress;
1235 aWalk[AIS_WalkRotation_Yaw].Pressure = aPressure;
1236 aWalk[AIS_WalkRotation_Yaw].Duration = aDuration;
1238 if (myKeys.HoldDuration (Aspect_VKey_NavLookUp, aNewEventTime, aDuration, aPressure))
1240 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1241 aWalk[AIS_WalkRotation_Pitch].Value = !myToInvertPitch ? -aProgress : aProgress;
1242 aWalk[AIS_WalkRotation_Pitch].Pressure = aPressure;
1243 aWalk[AIS_WalkRotation_Pitch].Duration = aDuration;
1245 if (myKeys.HoldDuration (Aspect_VKey_NavLookDown, aNewEventTime, aDuration, aPressure))
1247 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1248 aWalk[AIS_WalkRotation_Pitch].Value = !myToInvertPitch ? aProgress : -aProgress;
1249 aWalk[AIS_WalkRotation_Pitch].Pressure = aPressure;
1250 aWalk[AIS_WalkRotation_Pitch].Duration = aDuration;
1252 if (myKeys.HoldDuration (Aspect_VKey_NavRollCCW, aNewEventTime, aDuration, aPressure))
1254 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1255 aWalk[AIS_WalkRotation_Roll].Value = -aProgress;
1256 aWalk[AIS_WalkRotation_Roll].Pressure = aPressure;
1257 aWalk[AIS_WalkRotation_Roll].Duration = aDuration;
1259 if (myKeys.HoldDuration (Aspect_VKey_NavRollCW, aNewEventTime, aDuration, aPressure))
1261 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1262 aWalk[AIS_WalkRotation_Roll].Value = aProgress;
1263 aWalk[AIS_WalkRotation_Roll].Pressure = aPressure;
1264 aWalk[AIS_WalkRotation_Roll].Duration = aDuration;
1266 if (myKeys.HoldDuration (Aspect_VKey_NavSlideUp, aNewEventTime, aDuration, aPressure))
1268 double aProgress = Abs (Min (aMaxDuration, aDuration));
1269 aWalk[AIS_WalkTranslation_Up].Value = aProgress;
1270 aWalk[AIS_WalkTranslation_Up].Pressure = aPressure;
1271 aWalk[AIS_WalkTranslation_Up].Duration = aDuration;
1273 if (myKeys.HoldDuration (Aspect_VKey_NavSlideDown, aNewEventTime, aDuration, aPressure))
1275 double aProgress = Abs (Min (aMaxDuration, aDuration));
1276 aWalk[AIS_WalkTranslation_Up].Value = -aProgress;
1277 aWalk[AIS_WalkTranslation_Up].Pressure = aPressure;
1278 aWalk[AIS_WalkTranslation_Up].Duration = aDuration;
1283 // =======================================================================
1284 // function : AbortViewAnimation
1286 // =======================================================================
1287 void AIS_ViewController::AbortViewAnimation()
1289 if (!myViewAnimation.IsNull()
1290 && !myViewAnimation->IsStopped())
1292 myViewAnimation->Stop();
1293 myViewAnimation->SetView (Handle(V3d_View)());
1297 // =======================================================================
1298 // function : handlePanning
1300 // =======================================================================
1301 void AIS_ViewController::handlePanning (const Handle(V3d_View)& theView)
1303 if (!myGL.Panning.ToPan
1304 || !myToAllowPanning)
1309 AbortViewAnimation();
1311 const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1312 if (aCam->IsOrthographic()
1313 || !hasPanningAnchorPoint())
1315 theView->Pan (myGL.Panning.Delta.x(), myGL.Panning.Delta.y());
1316 theView->Invalidate();
1317 theView->View()->SynchronizeXRPosedToBaseCamera();
1321 Graphic3d_Vec2i aWinSize;
1322 theView->Window()->Size (aWinSize.x(), aWinSize.y());
1324 const gp_Dir& aDir = aCam->Direction();
1325 const gp_Ax3 aCameraCS (aCam->Center(), aDir.Reversed(), aDir ^ aCam->Up());
1326 const gp_XYZ anEyeToPnt = myPanPnt3d.XYZ() - aCam->Eye().XYZ();
1327 const gp_Pnt aViewDims = aCam->ViewDimensions (anEyeToPnt.Dot (aCam->Direction().XYZ())); // view dimensions at 3D point
1328 const Graphic3d_Vec2d aDxy (-aViewDims.X() * myGL.Panning.Delta.x() / double(aWinSize.x()),
1329 -aViewDims.X() * myGL.Panning.Delta.y() / double(aWinSize.x()));
1331 //theView->Translate (aCam, aDxy.x(), aDxy.y());
1333 const gp_Vec aCameraPan = gp_Vec (aCameraCS.XDirection()) * aDxy.x()
1334 + gp_Vec (aCameraCS.YDirection()) * aDxy.y();
1335 aPanTrsf.SetTranslation (aCameraPan);
1336 aCam->Transform (aPanTrsf);
1337 theView->Invalidate();
1338 theView->View()->SynchronizeXRPosedToBaseCamera();
1341 // =======================================================================
1342 // function : handleZRotate
1344 // =======================================================================
1345 void AIS_ViewController::handleZRotate (const Handle(V3d_View)& theView)
1347 if (!myGL.ZRotate.ToRotate
1348 || !myToAllowRotation)
1353 AbortViewAnimation();
1355 Graphic3d_Vec2i aViewPort;
1356 theView->Window()->Size (aViewPort.x(), aViewPort.y());
1357 Graphic3d_Vec2d aRotPnt (0.99 * aViewPort.x(),
1358 0.5 * aViewPort.y());
1359 theView->StartRotation (int(aRotPnt.x()), int(aRotPnt.y()), 0.4);
1360 aRotPnt.y() += myGL.ZRotate.Angle * aViewPort.y();
1361 theView->Rotation (int(aRotPnt.x()), int(aRotPnt.y()));
1362 theView->Invalidate();
1363 theView->View()->SynchronizeXRPosedToBaseCamera();
1366 // =======================================================================
1367 // function : handleZoom
1369 // =======================================================================
1370 void AIS_ViewController::handleZoom (const Handle(V3d_View)& theView,
1371 const Aspect_ScrollDelta& theParams,
1372 const gp_Pnt* thePnt)
1374 if (!myToAllowZooming)
1379 AbortViewAnimation();
1381 const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1384 const double aViewDist = Max (myMinCamDistance, (thePnt->XYZ() - aCam->Eye().XYZ()).Modulus());
1385 aCam->SetCenter (aCam->Eye().XYZ() + aCam->Direction().XYZ() * aViewDist);
1388 if (!theParams.HasPoint())
1390 Standard_Real aCoeff = Abs(theParams.Delta) / 100.0 + 1.0;
1391 aCoeff = theParams.Delta > 0.0 ? aCoeff : 1.0 / aCoeff;
1392 theView->SetZoom (aCoeff, true);
1393 theView->Invalidate();
1394 theView->View()->SynchronizeXRPosedToBaseCamera();
1398 // integer delta is too rough for small smooth increments
1399 //theView->StartZoomAtPoint (theParams.Point.x(), theParams.Point.y());
1400 //theView->ZoomAtPoint (0, 0, (int )theParams.Delta, (int )theParams.Delta);
1402 double aDZoom = Abs (theParams.Delta) / 100.0 + 1.0;
1403 aDZoom = (theParams.Delta > 0.0) ? aDZoom : 1.0 / aDZoom;
1409 const Graphic3d_Vec2d aViewDims (aCam->ViewDimensions().X(), aCam->ViewDimensions().Y());
1411 // ensure that zoom will not be too small or too big
1412 double aCoef = aDZoom;
1413 if (aViewDims.x() < aCoef * Precision::Confusion())
1415 aCoef = aViewDims.x() / Precision::Confusion();
1417 else if (aViewDims.x() > aCoef * 1e12)
1419 aCoef = aViewDims.x() / 1e12;
1421 if (aViewDims.y() < aCoef * Precision::Confusion())
1423 aCoef = aViewDims.y() / Precision::Confusion();
1425 else if (aViewDims.y() > aCoef * 1e12)
1427 aCoef = aViewDims.y() / 1e12;
1430 Graphic3d_Vec2d aZoomAtPointXYv (0.0, 0.0);
1431 theView->Convert (theParams.Point.x(), theParams.Point.y(),
1432 aZoomAtPointXYv.x(), aZoomAtPointXYv.y());
1433 Graphic3d_Vec2d aDxy = aZoomAtPointXYv / aCoef;
1434 aCam->SetScale (aCam->Scale() / aCoef);
1436 const gp_Dir& aDir = aCam->Direction();
1437 const gp_Ax3 aCameraCS (aCam->Center(), aDir.Reversed(), aDir ^ aCam->Up());
1439 // pan back to the point
1440 aDxy = aZoomAtPointXYv - aDxy;
1443 // zoom at 3D point with perspective projection
1444 const gp_XYZ anEyeToPnt = thePnt->XYZ() - aCam->Eye().XYZ();
1445 aDxy.SetValues (anEyeToPnt.Dot (aCameraCS.XDirection().XYZ()),
1446 anEyeToPnt.Dot (aCameraCS.YDirection().XYZ()));
1448 // view dimensions at 3D point
1449 const gp_Pnt aViewDims1 = aCam->ViewDimensions (anEyeToPnt.Dot (aCam->Direction().XYZ()));
1451 Graphic3d_Vec2i aWinSize;
1452 theView->Window()->Size (aWinSize.x(), aWinSize.y());
1453 const Graphic3d_Vec2d aPanFromCenterPx (double(theParams.Point.x()) - 0.5 * double(aWinSize.x()),
1454 double(aWinSize.y() - theParams.Point.y() - 1) - 0.5 * double(aWinSize.y()));
1455 aDxy.x() += -aViewDims1.X() * aPanFromCenterPx.x() / double(aWinSize.x());
1456 aDxy.y() += -aViewDims1.Y() * aPanFromCenterPx.y() / double(aWinSize.y());
1459 //theView->Translate (aCam, aDxy.x(), aDxy.y());
1461 const gp_Vec aCameraPan = gp_Vec (aCameraCS.XDirection()) * aDxy.x()
1462 + gp_Vec (aCameraCS.YDirection()) * aDxy.y();
1463 aPanTrsf.SetTranslation (aCameraPan);
1464 aCam->Transform (aPanTrsf);
1465 theView->Invalidate();
1466 theView->View()->SynchronizeXRPosedToBaseCamera();
1469 // =======================================================================
1470 // function : handleZFocusScroll
1472 // =======================================================================
1473 void AIS_ViewController::handleZFocusScroll (const Handle(V3d_View)& theView,
1474 const Aspect_ScrollDelta& theParams)
1476 if (!myToAllowZFocus
1477 || !theView->Camera()->IsStereo())
1482 Standard_Real aFocus = theView->Camera()->ZFocus() + (theParams.Delta > 0.0 ? 0.05 : -0.05);
1486 theView->Camera()->SetZFocus (theView->Camera()->ZFocusType(), aFocus);
1487 theView->Invalidate();
1491 // =======================================================================
1492 // function : handleOrbitRotation
1494 // =======================================================================
1495 void AIS_ViewController::handleOrbitRotation (const Handle(V3d_View)& theView,
1496 const gp_Pnt& thePnt,
1499 if (!myToAllowRotation)
1504 const Handle(Graphic3d_Camera)& aCam = theView->View()->IsActiveXR()
1505 ? theView->View()->BaseXRCamera()
1506 : theView->Camera();
1507 if (myGL.OrbitRotation.ToStart)
1509 // default alternatives
1510 //if (myRotationMode == AIS_RotationMode_BndBoxActive) theView->StartRotation (myGL.RotateAtPoint.x(), myGL.RotateAtPoint.y());
1511 //theView->Rotate (0.0, 0.0, 0.0, thePnt.X(), thePnt.Y(), thePnt.Z(), true);
1513 myRotatePnt3d = thePnt;
1514 myCamStartOpUp = aCam->Up();
1515 myCamStartOpDir = aCam->Direction();
1516 myCamStartOpEye = aCam->Eye();
1517 myCamStartOpCenter = aCam->Center();
1520 aTrsf.SetTransformation (gp_Ax3 (myRotatePnt3d, aCam->OrthogonalizedUp(), aCam->Direction()),
1521 gp_Ax3 (myRotatePnt3d, gp::DZ(), gp::DX()));
1522 const gp_Quaternion aRot = aTrsf.GetRotation();
1523 aRot.GetEulerAngles (gp_YawPitchRoll, myRotateStartYawPitchRoll[0], myRotateStartYawPitchRoll[1], myRotateStartYawPitchRoll[2]);
1526 myCamStartOpToEye = gp_Vec (myRotatePnt3d, aCam->Eye()).Transformed (aTrsf);
1527 myCamStartOpToCenter = gp_Vec (myRotatePnt3d, aCam->Center()).Transformed (aTrsf);
1529 theView->Invalidate();
1532 if (!myGL.OrbitRotation.ToRotate)
1537 AbortViewAnimation();
1540 // amend camera to exclude roll angle (put camera Up vector to plane containing global Z and view direction)
1541 Graphic3d_Vec2i aWinXY;
1542 theView->Window()->Size (aWinXY.x(), aWinXY.y());
1543 double aYawAngleDelta = ((myGL.OrbitRotation.PointStart.x() - myGL.OrbitRotation.PointTo.x()) / double (aWinXY.x())) * (M_PI * 0.5);
1544 double aPitchAngleDelta = -((myGL.OrbitRotation.PointStart.y() - myGL.OrbitRotation.PointTo.y()) / double (aWinXY.y())) * (M_PI * 0.5);
1545 double aPitchAngleNew = 0.0, aRoll = 0.0;
1546 const double aYawAngleNew = myRotateStartYawPitchRoll[0] + aYawAngleDelta;
1547 if (!theView->View()->IsActiveXR())
1549 aPitchAngleNew = Max (Min (myRotateStartYawPitchRoll[1] + aPitchAngleDelta, M_PI * 0.5 - M_PI / 180.0), -M_PI * 0.5 + M_PI / 180.0);
1554 aRot.SetEulerAngles (gp_YawPitchRoll, aYawAngleNew, aPitchAngleNew, aRoll);
1556 aTrsfRot.SetRotation (aRot);
1558 const gp_Dir aNewUp = gp::DZ().Transformed (aTrsfRot);
1559 aCam->SetUp (aNewUp);
1560 aCam->SetEyeAndCenter (myRotatePnt3d.XYZ() + myCamStartOpToEye .Transformed (aTrsfRot).XYZ(),
1561 myRotatePnt3d.XYZ() + myCamStartOpToCenter.Transformed (aTrsfRot).XYZ());
1563 aCam->OrthogonalizeUp();
1567 // default alternatives
1568 //if (myRotationMode == AIS_RotationMode_BndBoxActive) theView->Rotation (myGL.RotateToPoint.x(), myGL.RotateToPoint.y());
1569 //theView->Rotate (aDX, aDY, aDZ, myRotatePnt3d.X(), myRotatePnt3d.Y(), myRotatePnt3d.Z(), false);
1571 // restore previous camera state
1572 aCam->SetEyeAndCenter (myCamStartOpEye, myCamStartOpCenter);
1573 aCam->SetUp (myCamStartOpUp);
1574 aCam->SetDirectionFromEye (myCamStartOpDir);
1576 Graphic3d_Vec2d aWinXY;
1577 theView->Size (aWinXY.x(), aWinXY.y());
1578 const Standard_Real rx = (Standard_Real )theView->Convert (aWinXY.x());
1579 const Standard_Real ry = (Standard_Real )theView->Convert (aWinXY.y());
1581 const double THE_2PI = M_PI * 2.0;
1582 double aDX = (myGL.OrbitRotation.PointTo.x() - myGL.OrbitRotation.PointStart.x()) * M_PI / rx;
1583 double aDY = (myGL.OrbitRotation.PointStart.y() - myGL.OrbitRotation.PointTo.y()) * M_PI / ry;
1585 if (aDX > 0.0) { while (aDX > THE_2PI) { aDX -= THE_2PI; } }
1586 else if(aDX < 0.0) { while (aDX < -THE_2PI) { aDX += THE_2PI; } }
1587 if (aDY > 0.0) { while (aDY > THE_2PI) { aDY -= THE_2PI; } }
1588 else if(aDY < 0.0) { while (aDY < -THE_2PI) { aDY += THE_2PI; } }
1590 // rotate camera around 3 initial axes
1591 gp_Dir aCamDir (aCam->Direction().Reversed());
1592 gp_Dir aCamUp (aCam->Up());
1593 gp_Dir aCamSide(aCamUp.Crossed (aCamDir));
1595 gp_Trsf aRot[2], aTrsf;
1596 aRot[0].SetRotation (gp_Ax1 (myRotatePnt3d, aCamUp), -aDX);
1597 aRot[1].SetRotation (gp_Ax1 (myRotatePnt3d, aCamSide), aDY);
1598 aTrsf.Multiply (aRot[0]);
1599 aTrsf.Multiply (aRot[1]);
1601 aCam->Transform (aTrsf);
1604 theView->Invalidate();
1605 theView->View()->SynchronizeXRBaseToPosedCamera();
1608 // =======================================================================
1609 // function : handleViewRotation
1611 // =======================================================================
1612 void AIS_ViewController::handleViewRotation (const Handle(V3d_View)& theView,
1614 double thePitchExtra,
1616 bool theToRestartOnIncrement)
1618 if (!myToAllowRotation)
1623 const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1624 const bool toRotateAnyway = Abs (theYawExtra) > gp::Resolution()
1625 || Abs (thePitchExtra) > gp::Resolution()
1626 || Abs (theRoll - myRotateStartYawPitchRoll[2]) > gp::Resolution();
1628 && theToRestartOnIncrement)
1630 myGL.ViewRotation.ToStart = true;
1631 myGL.ViewRotation.PointTo = myGL.ViewRotation.PointStart;
1633 if (myGL.ViewRotation.ToStart)
1636 aTrsf.SetTransformation (gp_Ax3 (gp::Origin(), aCam->OrthogonalizedUp(), aCam->Direction()),
1637 gp_Ax3 (gp::Origin(), gp::DZ(), gp::DX()));
1638 const gp_Quaternion aRot = aTrsf.GetRotation();
1639 double aRollDummy = 0.0;
1640 aRot.GetEulerAngles (gp_YawPitchRoll, myRotateStartYawPitchRoll[0], myRotateStartYawPitchRoll[1], aRollDummy);
1644 myRotateStartYawPitchRoll[0] += theYawExtra;
1645 myRotateStartYawPitchRoll[1] += thePitchExtra;
1646 myRotateStartYawPitchRoll[2] = theRoll;
1647 myGL.ViewRotation.ToRotate = true;
1650 if (!myGL.ViewRotation.ToRotate)
1655 AbortViewAnimation();
1657 Graphic3d_Vec2i aWinXY;
1658 theView->Window()->Size (aWinXY.x(), aWinXY.y());
1659 double aYawAngleDelta = ((myGL.ViewRotation.PointStart.x() - myGL.ViewRotation.PointTo.x()) / double (aWinXY.x())) * (M_PI * 0.5);
1660 double aPitchAngleDelta = -((myGL.ViewRotation.PointStart.y() - myGL.ViewRotation.PointTo.y()) / double (aWinXY.y())) * (M_PI * 0.5);
1661 const double aPitchAngleNew = Max (Min (myRotateStartYawPitchRoll[1] + aPitchAngleDelta, M_PI * 0.5 - M_PI / 180.0), -M_PI * 0.5 + M_PI / 180.0);
1662 const double aYawAngleNew = myRotateStartYawPitchRoll[0] + aYawAngleDelta;
1664 aRot.SetEulerAngles (gp_YawPitchRoll, aYawAngleNew, aPitchAngleNew, theRoll);
1666 aTrsfRot.SetRotation (aRot);
1668 const gp_Dir aNewUp = gp::DZ().Transformed (aTrsfRot);
1669 const gp_Dir aNewDir = gp::DX().Transformed (aTrsfRot);
1670 aCam->SetUp (aNewUp);
1671 aCam->SetDirectionFromEye (aNewDir);
1672 aCam->OrthogonalizeUp();
1673 theView->Invalidate();
1676 // =======================================================================
1677 // function : PickPoint
1679 // =======================================================================
1680 bool AIS_ViewController::PickPoint (gp_Pnt& thePnt,
1681 const Handle(AIS_InteractiveContext)& theCtx,
1682 const Handle(V3d_View)& theView,
1683 const Graphic3d_Vec2i& theCursor,
1684 bool theToStickToPickRay)
1686 ResetPreviousMoveTo();
1688 const Handle(StdSelect_ViewerSelector3d)& aSelector = theCtx->MainSelector();
1689 aSelector->Pick (theCursor.x(), theCursor.y(), theView);
1690 if (aSelector->NbPicked() < 1)
1695 const SelectMgr_SortCriterion& aPicked = aSelector->PickedData (1);
1696 if (theToStickToPickRay
1697 && !Precision::IsInfinite (aPicked.Depth))
1699 thePnt = aSelector->GetManager().DetectedPoint (aPicked.Depth);
1703 thePnt = aSelector->PickedPoint (1);
1705 return !Precision::IsInfinite (thePnt.X())
1706 && !Precision::IsInfinite (thePnt.Y())
1707 && !Precision::IsInfinite (thePnt.Z());
1710 // =======================================================================
1711 // function : GravityPoint
1713 // =======================================================================
1714 gp_Pnt AIS_ViewController::GravityPoint (const Handle(AIS_InteractiveContext)& theCtx,
1715 const Handle(V3d_View)& theView)
1717 switch (myRotationMode)
1719 case AIS_RotationMode_PickLast:
1720 case AIS_RotationMode_PickCenter:
1722 Graphic3d_Vec2i aCursor ((int )myGL.OrbitRotation.PointStart.x(), (int )myGL.OrbitRotation.PointStart.y());
1723 if (myRotationMode == AIS_RotationMode_PickCenter)
1725 Graphic3d_Vec2i aViewPort;
1726 theView->Window()->Size (aViewPort.x(), aViewPort.y());
1727 aCursor = aViewPort / 2;
1731 if (PickPoint (aPnt, theCtx, theView, aCursor, myToStickToRayOnRotation))
1737 case AIS_RotationMode_CameraAt:
1739 const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1740 return aCam->Center();
1742 case AIS_RotationMode_BndBoxScene:
1744 Bnd_Box aBndBox = theView->View()->MinMaxValues (false);
1745 if (!aBndBox.IsVoid())
1747 return (aBndBox.CornerMin().XYZ() + aBndBox.CornerMax().XYZ()) * 0.5;
1751 case AIS_RotationMode_BndBoxActive:
1755 return theCtx ->GravityPoint (theView);
1758 // =======================================================================
1759 // function : handleCameraActions
1761 // =======================================================================
1762 void AIS_ViewController::handleCameraActions (const Handle(AIS_InteractiveContext)& theCtx,
1763 const Handle(V3d_View)& theView,
1764 const AIS_WalkDelta& theWalk)
1766 // apply view actions
1767 if (myGL.Orientation.ToSetViewOrient)
1769 theView->SetProj (myGL.Orientation.ViewOrient);
1770 myGL.Orientation.ToFitAll = true;
1774 if (myGL.Orientation.ToFitAll)
1776 const double aFitMargin = 0.01;
1777 theView->FitAll (aFitMargin, false);
1778 theView->Invalidate();
1779 myGL.Orientation.ToFitAll = false;
1782 if (myGL.IsNewGesture)
1784 if (myAnchorPointPrs1->HasInteractiveContext())
1786 theCtx->Remove (myAnchorPointPrs1, false);
1787 if (!theView->Viewer()->ZLayerSettings (myAnchorPointPrs1->ZLayer()).IsImmediate())
1789 theView->Invalidate();
1793 theView->InvalidateImmediate();
1796 if (myAnchorPointPrs2->HasInteractiveContext())
1798 theCtx->Remove (myAnchorPointPrs2, false);
1799 if (!theView->Viewer()->ZLayerSettings (myAnchorPointPrs2->ZLayer()).IsImmediate())
1801 theView->Invalidate();
1805 theView->InvalidateImmediate();
1809 if (myHasHlrOnBeforeRotation)
1811 myHasHlrOnBeforeRotation = false;
1812 theView->SetComputedMode (true);
1813 theView->Invalidate();
1817 if (myNavigationMode != AIS_NavigationMode_FirstPersonWalk)
1819 if (myGL.Panning.ToStart
1820 && myToAllowPanning)
1822 gp_Pnt aPanPnt (Precision::Infinite(), 0.0, 0.0);
1823 if (!theView->Camera()->IsOrthographic())
1825 bool toStickToRay = false;
1826 if (myGL.Panning.PointStart.x() >= 0
1827 && myGL.Panning.PointStart.y() >= 0)
1829 PickPoint (aPanPnt, theCtx, theView, myGL.Panning.PointStart, toStickToRay);
1831 if (Precision::IsInfinite (aPanPnt.X()))
1833 Graphic3d_Vec2i aWinSize;
1834 theView->Window()->Size (aWinSize.x(), aWinSize.y());
1835 PickPoint (aPanPnt, theCtx, theView, aWinSize / 2, toStickToRay);
1837 if (!Precision::IsInfinite (aPanPnt.X())
1838 && myToShowPanAnchorPoint)
1841 aPntTrsf.SetTranslation (gp_Vec (aPanPnt.XYZ()));
1842 theCtx->SetLocation (myAnchorPointPrs2, aPntTrsf);
1845 setPanningAnchorPoint (aPanPnt);
1848 if (myToShowPanAnchorPoint
1849 && hasPanningAnchorPoint()
1850 && myGL.Panning.ToPan
1851 && !myGL.IsNewGesture
1852 && !myAnchorPointPrs2->HasInteractiveContext())
1854 theCtx->Display (myAnchorPointPrs2, 0, -1, false, AIS_DS_Displayed);
1857 handlePanning (theView);
1858 handleZRotate (theView);
1861 if ((myNavigationMode == AIS_NavigationMode_Orbit
1862 || myGL.OrbitRotation.ToStart
1863 || myGL.OrbitRotation.ToRotate)
1864 && myToAllowRotation)
1866 if (myGL.OrbitRotation.ToStart
1867 && !myHasHlrOnBeforeRotation)
1869 myHasHlrOnBeforeRotation = theView->ComputedMode();
1870 if (myHasHlrOnBeforeRotation)
1872 theView->SetComputedMode (false);
1877 if (myGL.OrbitRotation.ToStart)
1879 aGravPnt = GravityPoint (theCtx, theView);
1880 if (myToShowRotateCenter)
1883 aPntTrsf.SetTranslation (gp_Vec (aGravPnt.XYZ()));
1884 theCtx->SetLocation (myAnchorPointPrs1, aPntTrsf);
1885 theCtx->SetLocation (myAnchorPointPrs2, aPntTrsf);
1889 if (myToShowRotateCenter
1890 && myGL.OrbitRotation.ToRotate
1891 && !myGL.IsNewGesture
1892 && !myAnchorPointPrs1->HasInteractiveContext())
1894 theCtx->Display (myAnchorPointPrs1, 0, -1, false, AIS_DS_Displayed);
1895 theCtx->Display (myAnchorPointPrs2, 0, -1, false, AIS_DS_Displayed);
1897 handleOrbitRotation (theView, aGravPnt,
1898 myToLockOrbitZUp || myNavigationMode != AIS_NavigationMode_Orbit);
1901 if ((myNavigationMode != AIS_NavigationMode_Orbit
1902 || myGL.ViewRotation.ToStart
1903 || myGL.ViewRotation.ToRotate)
1904 && myToAllowRotation)
1906 if (myGL.ViewRotation.ToStart
1907 && !myHasHlrOnBeforeRotation)
1909 myHasHlrOnBeforeRotation = theView->ComputedMode();
1910 if (myHasHlrOnBeforeRotation)
1912 theView->SetComputedMode (false);
1917 if (!theWalk[AIS_WalkRotation_Roll].IsEmpty()
1918 && !myToLockOrbitZUp)
1920 aRoll = (M_PI / 12.0) * theWalk[AIS_WalkRotation_Roll].Pressure;
1921 aRoll *= Min (1000.0 * theWalk[AIS_WalkRotation_Roll].Duration, 100.0) / 100.0;
1922 if (theWalk[AIS_WalkRotation_Roll].Value < 0.0)
1928 handleViewRotation (theView, theWalk[AIS_WalkRotation_Yaw].Value, theWalk[AIS_WalkRotation_Pitch].Value, aRoll,
1929 myNavigationMode == AIS_NavigationMode_FirstPersonFlight);
1932 if (!myGL.ZoomActions.IsEmpty())
1934 for (NCollection_Sequence<Aspect_ScrollDelta>::Iterator aZoomIter (myGL.ZoomActions); aZoomIter.More(); aZoomIter.Next())
1936 Aspect_ScrollDelta aZoomParams = aZoomIter.Value();
1938 && (aZoomParams.Flags & Aspect_VKeyFlags_CTRL) != 0
1939 && theView->Camera()->IsStereo())
1941 handleZFocusScroll (theView, aZoomParams);
1945 if (!myToAllowZooming)
1950 if (!theView->Camera()->IsOrthographic())
1953 if (aZoomParams.HasPoint()
1954 && PickPoint (aPnt, theCtx, theView, aZoomParams.Point, myToStickToRayOnZoom))
1956 handleZoom (theView, aZoomParams, &aPnt);
1960 Graphic3d_Vec2i aWinSize;
1961 theView->Window()->Size (aWinSize.x(), aWinSize.y());
1962 if (PickPoint (aPnt, theCtx, theView, aWinSize / 2, myToStickToRayOnZoom))
1964 aZoomParams.ResetPoint(); // do not pretend to zoom at 'nothing'
1965 handleZoom (theView, aZoomParams, &aPnt);
1969 handleZoom (theView, aZoomParams, NULL);
1971 myGL.ZoomActions.Clear();
1975 // =======================================================================
1976 // function : handleXRInput
1978 // =======================================================================
1979 void AIS_ViewController::handleXRInput (const Handle(AIS_InteractiveContext)& theCtx,
1980 const Handle(V3d_View)& theView,
1981 const AIS_WalkDelta& )
1983 theView->View()->ProcessXRInput();
1984 if (!theView->View()->IsActiveXR())
1988 if (myXRCameraTmp.IsNull())
1990 myXRCameraTmp = new Graphic3d_Camera();
1992 handleXRTurnPad (theCtx, theView);
1993 handleXRTeleport(theCtx, theView);
1994 handleXRPicking (theCtx, theView);
1997 // =======================================================================
1998 // function : handleXRTurnPad
2000 // =======================================================================
2001 void AIS_ViewController::handleXRTurnPad (const Handle(AIS_InteractiveContext)& ,
2002 const Handle(V3d_View)& theView)
2004 if (myXRTurnAngle <= 0.0
2005 || !theView->View()->IsActiveXR())
2010 // turn left/right at 45 degrees on left/right trackpad clicks
2011 for (int aHand = 0; aHand < 2; ++aHand)
2013 const Aspect_XRTrackedDeviceRole aRole = aHand == 0 ? Aspect_XRTrackedDeviceRole_RightHand : Aspect_XRTrackedDeviceRole_LeftHand;
2014 const Handle(Aspect_XRAction)& aPadClickAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTrackPadClick);
2015 const Handle(Aspect_XRAction)& aPadPosAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTrackPadPosition);
2016 if (aPadClickAct.IsNull()
2017 || aPadPosAct.IsNull())
2022 const Aspect_XRDigitalActionData aPadClick = theView->View()->XRSession()->GetDigitalActionData (aPadClickAct);
2023 const Aspect_XRAnalogActionData aPadPos = theView->View()->XRSession()->GetAnalogActionData (aPadPosAct);
2024 if (aPadClick.IsActive
2025 && aPadClick.IsPressed
2026 && aPadClick.IsChanged
2028 && Abs (aPadPos.VecXYZ.y()) < 0.5f
2029 && Abs (aPadPos.VecXYZ.x()) > 0.7f)
2032 aTrsfTurn.SetRotation (gp_Ax1 (gp::Origin(), theView->View()->BaseXRCamera()->Up()), aPadPos.VecXYZ.x() < 0.0f ? myXRTurnAngle : -myXRTurnAngle);
2033 theView->View()->TurnViewXRCamera (aTrsfTurn);
2039 // =======================================================================
2040 // function : handleXRTeleport
2042 // =======================================================================
2043 void AIS_ViewController::handleXRTeleport (const Handle(AIS_InteractiveContext)& theCtx,
2044 const Handle(V3d_View)& theView)
2046 if (!theView->View()->IsActiveXR())
2051 // teleport on forward trackpad unclicks
2052 const Aspect_XRTrackedDeviceRole aTeleOld = myXRLastTeleportHand;
2053 myXRLastTeleportHand = Aspect_XRTrackedDeviceRole_Other;
2054 for (int aHand = 0; aHand < 2; ++aHand)
2056 const Aspect_XRTrackedDeviceRole aRole = aHand == 0 ? Aspect_XRTrackedDeviceRole_RightHand : Aspect_XRTrackedDeviceRole_LeftHand;
2057 const Standard_Integer aDeviceId = theView->View()->XRSession()->NamedTrackedDevice (aRole);
2058 if (aDeviceId == -1)
2063 const Handle(Aspect_XRAction)& aPadClickAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTrackPadClick);
2064 const Handle(Aspect_XRAction)& aPadPosAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTrackPadPosition);
2065 if (aPadClickAct.IsNull()
2066 || aPadPosAct.IsNull())
2071 const Aspect_XRDigitalActionData aPadClick = theView->View()->XRSession()->GetDigitalActionData (aPadClickAct);
2072 const Aspect_XRAnalogActionData aPadPos = theView->View()->XRSession()->GetAnalogActionData (aPadPosAct);
2073 const bool isPressed = aPadClick.IsPressed;
2074 const bool isClicked = !aPadClick.IsPressed
2075 && aPadClick.IsChanged;
2076 if (aPadClick.IsActive
2077 && (isPressed || isClicked)
2079 && aPadPos.VecXYZ.y() > 0.6f
2080 && Abs (aPadPos.VecXYZ.x()) < 0.5f)
2082 const Aspect_TrackedDevicePose& aPose = theView->View()->XRSession()->TrackedPoses()[aDeviceId];
2083 if (!aPose.IsValidPose)
2088 myXRLastTeleportHand = aRole;
2089 Standard_Real& aPickDepth = aRole == Aspect_XRTrackedDeviceRole_LeftHand ? myXRLastPickDepthLeft : myXRLastPickDepthRight;
2090 aPickDepth = Precision::Infinite();
2091 Graphic3d_Vec3 aPickNorm;
2092 const gp_Trsf aHandBase = theView->View()->PoseXRToWorld (aPose.Orientation);
2093 const Standard_Real aHeadHeight = theView->View()->XRSession()->HeadPose().TranslationPart().Y();
2095 const Standard_Integer aPickedId = handleXRMoveTo (theCtx, theView, aPose.Orientation, false);
2098 const SelectMgr_SortCriterion& aPickedData = theCtx->MainSelector()->PickedData (aPickedId);
2099 aPickNorm = aPickedData.Normal;
2100 if (aPickNorm.SquareModulus() > ShortRealEpsilon())
2102 aPickDepth = aPickedData.Point.Distance (aHandBase.TranslationPart());
2108 myXRLastTeleportHand = Aspect_XRTrackedDeviceRole_Other;
2109 if (!Precision::IsInfinite (aPickDepth))
2111 const gp_Dir aTeleDir = -gp::DZ().Transformed (aHandBase);
2112 const gp_Dir anUpDir = theView->View()->BaseXRCamera()->Up();
2114 bool isHorizontal = false;
2115 gp_Dir aPickNormDir (aPickNorm.x(), aPickNorm.y(), aPickNorm.z());
2116 if (anUpDir.IsEqual ( aPickNormDir, M_PI_4)
2117 || anUpDir.IsEqual (-aPickNormDir, M_PI_4))
2119 isHorizontal = true;
2122 gp_Pnt aNewEye = aHandBase.TranslationPart();
2125 aNewEye = aHandBase.TranslationPart()
2126 + aTeleDir.XYZ() * aPickDepth
2127 + anUpDir.XYZ() * aHeadHeight;
2131 if (aPickNormDir.Dot (aTeleDir) < 0.0)
2133 aPickNormDir.Reverse();
2135 aNewEye = aHandBase.TranslationPart()
2136 + aTeleDir.XYZ() * aPickDepth
2137 - aPickNormDir.XYZ() * aHeadHeight / 4;
2140 theView->View()->PosedXRCamera()->MoveEyeTo (aNewEye);
2141 theView->View()->ComputeXRBaseCameraFromPosed (theView->View()->PosedXRCamera(), theView->View()->XRSession()->HeadPose());
2148 if (myXRLastTeleportHand != aTeleOld)
2150 if (aTeleOld != Aspect_XRTrackedDeviceRole_Other)
2152 if (const Handle(Aspect_XRAction)& aHaptic = theView->View()->XRSession()->GenericAction (aTeleOld, Aspect_XRGenericAction_OutputHaptic))
2154 theView->View()->XRSession()->AbortHapticVibrationAction (aHaptic);
2157 if (myXRLastTeleportHand != Aspect_XRTrackedDeviceRole_Other)
2159 if (const Handle(Aspect_XRAction)& aHaptic = theView->View()->XRSession()->GenericAction (myXRLastTeleportHand, Aspect_XRGenericAction_OutputHaptic))
2161 theView->View()->XRSession()->TriggerHapticVibrationAction (aHaptic, myXRTeleportHaptic);
2167 // =======================================================================
2168 // function : handleXRPicking
2170 // =======================================================================
2171 void AIS_ViewController::handleXRPicking (const Handle(AIS_InteractiveContext)& theCtx,
2172 const Handle(V3d_View)& theView)
2174 if (!theView->View()->IsActiveXR())
2179 // handle selection on trigger clicks
2180 Aspect_XRTrackedDeviceRole aPickDevOld = myXRLastPickingHand;
2181 myXRLastPickingHand = Aspect_XRTrackedDeviceRole_Other;
2182 for (int aHand = 0; aHand < 2; ++aHand)
2184 const Aspect_XRTrackedDeviceRole aRole = aHand == 0 ? Aspect_XRTrackedDeviceRole_RightHand : Aspect_XRTrackedDeviceRole_LeftHand;
2185 const Handle(Aspect_XRAction)& aTrigClickAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTriggerClick);
2186 const Handle(Aspect_XRAction)& aTrigPullAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTriggerPull);
2187 if (aTrigClickAct.IsNull()
2188 || aTrigPullAct.IsNull())
2193 const Aspect_XRDigitalActionData aTrigClick = theView->View()->XRSession()->GetDigitalActionData (aTrigClickAct);
2194 const Aspect_XRAnalogActionData aTrigPos = theView->View()->XRSession()->GetAnalogActionData (aTrigPullAct);
2195 if (aTrigPos.IsActive
2196 && Abs (aTrigPos.VecXYZ.x()) > 0.1f)
2198 myXRLastPickingHand = aRole;
2199 handleXRHighlight (theCtx, theView);
2200 if (aTrigClick.IsActive
2201 && aTrigClick.IsPressed
2202 && aTrigClick.IsChanged)
2204 theCtx->Select (false);
2205 OnSelectionChanged (theCtx, theView);
2206 if (const Handle(Aspect_XRAction)& aHaptic = theView->View()->XRSession()->GenericAction (myXRLastPickingHand, Aspect_XRGenericAction_OutputHaptic))
2208 theView->View()->XRSession()->TriggerHapticVibrationAction (aHaptic, myXRSelectHaptic);
2214 if (myXRLastPickingHand != aPickDevOld)
2216 theCtx->ClearDetected();
2220 // =======================================================================
2221 // function : OnSelectionChanged
2223 // =======================================================================
2224 void AIS_ViewController::OnSelectionChanged (const Handle(AIS_InteractiveContext)& ,
2225 const Handle(V3d_View)& )
2230 // =======================================================================
2231 // function : OnObjectDragged
2233 // =======================================================================
2234 void AIS_ViewController::OnObjectDragged (const Handle(AIS_InteractiveContext)& theCtx,
2235 const Handle(V3d_View)& theView,
2236 AIS_DragAction theAction)
2240 case AIS_DragAction_Start:
2242 myDragObject.Nullify();
2243 if (!theCtx->HasDetected())
2248 Handle(AIS_InteractiveObject) aPrs = theCtx->DetectedInteractive();
2249 if (Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (aPrs))
2251 if (aManip->HasActiveMode())
2253 myDragObject = aManip;
2254 aManip->StartTransform (myGL.Dragging.PointStart.x(), myGL.Dragging.PointStart.y(), theView);
2259 case AIS_DragAction_Update:
2261 if (myDragObject.IsNull())
2266 if (Handle(SelectMgr_EntityOwner) aGlobOwner = myDragObject->GlobalSelOwner())
2268 theCtx->SetSelectedState (aGlobOwner, true);
2270 if (Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (myDragObject))
2272 aManip->Transform (myGL.Dragging.PointTo.x(), myGL.Dragging.PointTo.y(), theView);
2274 theView->Invalidate();
2277 case AIS_DragAction_Abort:
2279 if (myDragObject.IsNull())
2284 myGL.Dragging.PointTo = myGL.Dragging.PointStart;
2285 OnObjectDragged (theCtx, theView, AIS_DragAction_Update);
2287 if (Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (myDragObject))
2289 aManip->StopTransform (false);
2291 Standard_FALLTHROUGH
2293 case AIS_DragAction_Stop:
2295 if (myDragObject.IsNull())
2300 if (Handle(SelectMgr_EntityOwner) aGlobOwner = myDragObject->GlobalSelOwner())
2302 theCtx->SetSelectedState (aGlobOwner, false);
2305 theView->Invalidate();
2306 myDragObject.Nullify();
2312 // =======================================================================
2313 // function : contextLazyMoveTo
2315 // =======================================================================
2316 void AIS_ViewController::contextLazyMoveTo (const Handle(AIS_InteractiveContext)& theCtx,
2317 const Handle(V3d_View)& theView,
2318 const Graphic3d_Vec2i& thePnt)
2320 if (myPrevMoveTo == thePnt)
2325 myPrevMoveTo = thePnt;
2327 Handle(SelectMgr_EntityOwner) aLastPicked = theCtx->DetectedOwner();
2328 theView->AutoZFit();
2329 theCtx->MoveTo (thePnt.x(), thePnt.y(), theView, false);
2330 Handle(SelectMgr_EntityOwner) aNewPicked = theCtx->DetectedOwner();
2332 if (theView->Viewer()->Grid()->IsActive()
2333 && theView->Viewer()->GridEcho())
2335 if (aNewPicked.IsNull())
2337 Graphic3d_Vec3d aPnt3d;
2338 theView->ConvertToGrid (thePnt.x(), thePnt.y(), aPnt3d[0], aPnt3d[1], aPnt3d[2]);
2339 theView->Viewer()->ShowGridEcho (theView, Graphic3d_Vertex (aPnt3d[0], aPnt3d[1], aPnt3d[2]));
2340 theView->InvalidateImmediate();
2344 theView->Viewer()->HideGridEcho (theView);
2345 theView->InvalidateImmediate();
2349 if (aLastPicked != aNewPicked
2350 || (!aNewPicked.IsNull() && aNewPicked->IsForcedHilight()))
2352 // dynamic highlight affects all Views
2353 for (V3d_ListOfViewIterator aViewIter (theView->Viewer()->ActiveViewIterator()); aViewIter.More(); aViewIter.Next())
2355 const Handle(V3d_View)& aView = aViewIter.Value();
2356 aView->InvalidateImmediate();
2361 // =======================================================================
2362 // function : handleSelectionPick
2364 // =======================================================================
2365 void AIS_ViewController::handleSelectionPick (const Handle(AIS_InteractiveContext)& theCtx,
2366 const Handle(V3d_View)& theView)
2368 if (myGL.Selection.Tool == AIS_ViewSelectionTool_Picking
2369 && !myGL.Selection.Points.IsEmpty())
2371 for (NCollection_Sequence<Graphic3d_Vec2i>::Iterator aPntIter (myGL.Selection.Points); aPntIter.More(); aPntIter.Next())
2373 const bool hadPrevMoveTo = HasPreviousMoveTo();
2374 contextLazyMoveTo (theCtx, theView, aPntIter.Value());
2377 ResetPreviousMoveTo();
2380 if (myGL.Selection.IsXOR)
2382 theCtx->ShiftSelect (false);
2386 theCtx->Select (false);
2389 // selection affects all Views
2390 theView->Viewer()->Invalidate();
2392 OnSelectionChanged (theCtx, theView);
2395 myGL.Selection.Points.Clear();
2399 // =======================================================================
2400 // function : handleSelectionPoly
2402 // =======================================================================
2403 void AIS_ViewController::handleSelectionPoly (const Handle(AIS_InteractiveContext)& theCtx,
2404 const Handle(V3d_View)& theView)
2406 // rubber-band & window polygon selection
2407 if (myGL.Selection.Tool == AIS_ViewSelectionTool_RubberBand
2408 || myGL.Selection.Tool == AIS_ViewSelectionTool_Polygon
2409 || myGL.Selection.Tool == AIS_ViewSelectionTool_ZoomWindow)
2411 if (!myGL.Selection.Points.IsEmpty())
2413 myRubberBand->ClearPoints();
2414 myRubberBand->SetToUpdate();
2416 const bool anIsRubber = myGL.Selection.Tool == AIS_ViewSelectionTool_RubberBand
2417 || myGL.Selection.Tool == AIS_ViewSelectionTool_ZoomWindow;
2420 myRubberBand->SetRectangle (myGL.Selection.Points.First().x(), -myGL.Selection.Points.First().y(),
2421 myGL.Selection.Points.Last().x(), -myGL.Selection.Points.Last().y());
2425 Graphic3d_Vec2i aPrev (IntegerLast(), IntegerLast());
2426 for (NCollection_Sequence<Graphic3d_Vec2i>::Iterator aSelIter (myGL.Selection.Points); aSelIter.More(); aSelIter.Next())
2428 Graphic3d_Vec2i aPntNew = Graphic3d_Vec2i (aSelIter.Value().x(), -aSelIter.Value().y());
2429 if (aPntNew != aPrev)
2432 myRubberBand->AddPoint (Graphic3d_Vec2i (aSelIter.Value().x(), -aSelIter.Value().y()));
2437 myRubberBand->SetPolygonClosed (anIsRubber);
2440 theCtx->Display (myRubberBand, 0, -1, false, AIS_DS_Displayed);
2442 catch (const Standard_Failure& theEx)
2444 Message::SendWarning (TCollection_AsciiString ("Internal error while displaying rubber-band: ")
2445 + theEx.DynamicType()->Name() + ", " + theEx.GetMessageString());
2446 myRubberBand->ClearPoints();
2448 if (!theView->Viewer()->ZLayerSettings (myRubberBand->ZLayer()).IsImmediate())
2450 theView->Invalidate();
2454 theView->InvalidateImmediate();
2457 else if (!myRubberBand.IsNull()
2458 && myRubberBand->HasInteractiveContext())
2460 theCtx->Remove (myRubberBand, false);
2461 myRubberBand->ClearPoints();
2465 if (myGL.Selection.ToApplyTool)
2467 myGL.Selection.ToApplyTool = false;
2468 if (theCtx->IsDisplayed (myRubberBand))
2470 theCtx->Remove (myRubberBand, false);
2472 const NCollection_Sequence<Graphic3d_Vec2i>& aPoints = myRubberBand->Points();
2473 if (aPoints.Size() == 4
2474 && aPoints.Value (1).x() == aPoints.Value (2).x()
2475 && aPoints.Value (3).x() == aPoints.Value (4).x()
2476 && aPoints.Value (1).y() == aPoints.Value (4).y()
2477 && aPoints.Value (2).y() == aPoints.Value (3).y())
2479 const Graphic3d_Vec2i aPnt1 (aPoints.Value (1).x(), -aPoints.Value (1).y());
2480 const Graphic3d_Vec2i aPnt2 (aPoints.Value (3).x(), -aPoints.Value (3).y());
2481 if (myGL.Selection.Tool == AIS_ViewSelectionTool_ZoomWindow)
2483 theView->WindowFitAll (aPnt1.x(), aPnt1.y(), aPnt2.x(), aPnt2.y());
2484 theView->Invalidate();
2488 theCtx->MainSelector()->AllowOverlapDetection (aPnt1.y() != Min (aPnt1.y(), aPnt2.y()));
2489 if (myGL.Selection.IsXOR)
2491 theCtx->ShiftSelect (Min (aPnt1.x(), aPnt2.x()), Min (aPnt1.y(), aPnt2.y()),
2492 Max (aPnt1.x(), aPnt2.x()), Max (aPnt1.y(), aPnt2.y()),
2497 theCtx->Select (Min (aPnt1.x(), aPnt2.x()), Min (aPnt1.y(), aPnt2.y()),
2498 Max (aPnt1.x(), aPnt2.x()), Max (aPnt1.y(), aPnt2.y()),
2501 theCtx->MainSelector()->AllowOverlapDetection (false);
2504 else if (aPoints.Length() >= 3)
2506 TColgp_Array1OfPnt2d aPolyline (1, aPoints.Length());
2507 TColgp_Array1OfPnt2d::Iterator aPolyIter (aPolyline);
2508 for (NCollection_Sequence<Graphic3d_Vec2i>::Iterator aSelIter (aPoints);
2509 aSelIter.More(); aSelIter.Next(), aPolyIter.Next())
2511 const Graphic3d_Vec2i& aNewPnt = aSelIter.Value();
2512 aPolyIter.ChangeValue() = gp_Pnt2d (aNewPnt.x(), -aNewPnt.y());
2515 if (myGL.Selection.IsXOR)
2517 theCtx->ShiftSelect (aPolyline, theView, false);
2521 theCtx->Select (aPolyline, theView, false);
2523 theCtx->MainSelector()->AllowOverlapDetection (false);
2527 myRubberBand->ClearPoints();
2528 if (myGL.Selection.Tool != AIS_ViewSelectionTool_ZoomWindow)
2530 // selection affects all Views
2531 theView->Viewer()->Invalidate();
2532 OnSelectionChanged (theCtx, theView);
2538 // =======================================================================
2539 // function : handleDynamicHighlight
2541 // =======================================================================
2542 void AIS_ViewController::handleDynamicHighlight (const Handle(AIS_InteractiveContext)& theCtx,
2543 const Handle(V3d_View)& theView)
2545 if ((myGL.MoveTo.ToHilight || myGL.Dragging.ToStart)
2546 && myNavigationMode != AIS_NavigationMode_FirstPersonWalk)
2548 const Graphic3d_Vec2i& aMoveToPnt = myGL.MoveTo.ToHilight ? myGL.MoveTo.Point : myGL.Dragging.PointStart;
2549 if (myGL.Dragging.ToStart && (!myGL.MoveTo.ToHilight || !myToAllowHighlight)
2550 && !HasPreviousMoveTo())
2552 contextLazyMoveTo (theCtx, theView, aMoveToPnt);
2553 ResetPreviousMoveTo();
2554 OnObjectDragged (theCtx, theView, AIS_DragAction_Start);
2555 theCtx->ClearDetected();
2557 else if (myToAllowHighlight)
2559 if (myPrevMoveTo != aMoveToPnt
2560 || (!theView->View()->IsActiveXR()
2561 && (myGL.OrbitRotation.ToRotate
2562 || myGL.ViewRotation.ToRotate
2563 || theView->IsInvalidated())))
2565 ResetPreviousMoveTo();
2566 contextLazyMoveTo (theCtx, theView, aMoveToPnt);
2568 if (myGL.Dragging.ToStart)
2570 OnObjectDragged (theCtx, theView, AIS_DragAction_Start);
2574 myGL.MoveTo.ToHilight = false;
2577 if (!myDragObject.IsNull())
2579 if (myGL.Dragging.ToAbort)
2581 OnObjectDragged (theCtx, theView, AIS_DragAction_Abort);
2582 myGL.OrbitRotation.ToRotate = false;
2583 myGL.ViewRotation .ToRotate = false;
2585 else if (myGL.Dragging.ToStop)
2587 OnObjectDragged (theCtx, theView, AIS_DragAction_Stop);
2588 myGL.OrbitRotation.ToRotate = false;
2589 myGL.ViewRotation .ToRotate = false;
2591 else if (myGL.OrbitRotation.ToRotate
2592 || myGL.ViewRotation.ToRotate)
2594 OnObjectDragged (theCtx, theView, AIS_DragAction_Update);
2595 myGL.OrbitRotation.ToRotate = false;
2596 myGL.ViewRotation .ToRotate = false;
2601 // =======================================================================
2602 // function : handleMoveTo
2604 // =======================================================================
2605 void AIS_ViewController::handleMoveTo (const Handle(AIS_InteractiveContext)& theCtx,
2606 const Handle(V3d_View)& theView)
2608 handleSelectionPick (theCtx, theView);
2609 handleDynamicHighlight(theCtx, theView);
2610 handleSelectionPoly (theCtx, theView);
2613 // =======================================================================
2614 // function : handleViewRedraw
2616 // =======================================================================
2617 void AIS_ViewController::handleViewRedraw (const Handle(AIS_InteractiveContext)& ,
2618 const Handle(V3d_View)& theView)
2620 // manage animation state
2621 if (!myViewAnimation.IsNull()
2622 && !myViewAnimation->IsStopped())
2624 myViewAnimation->UpdateTimer();
2625 ResetPreviousMoveTo();
2629 if (theView->View()->IsActiveXR())
2631 // VR requires continuous rendering
2632 myToAskNextFrame = true;
2635 for (V3d_ListOfViewIterator aViewIter (theView->Viewer()->ActiveViewIterator()); aViewIter.More(); aViewIter.Next())
2637 const Handle(V3d_View)& aView = aViewIter.Value();
2638 if (aView->IsInvalidated()
2639 || myToAskNextFrame)
2641 if (aView->ComputedMode())
2650 else if (aView->IsInvalidatedImmediate())
2652 aView->RedrawImmediate();
2656 if (myToAskNextFrame)
2659 theView->Window()->InvalidateContent (Handle(Aspect_DisplayConnection)());
2663 // =======================================================================
2664 // function : handleXRMoveTo
2666 // =======================================================================
2667 Standard_Integer AIS_ViewController::handleXRMoveTo (const Handle(AIS_InteractiveContext)& theCtx,
2668 const Handle(V3d_View)& theView,
2669 const gp_Trsf& thePose,
2670 const Standard_Boolean theToHighlight)
2672 //ResetPreviousMoveTo();
2673 Standard_Integer aPickResult = 0;
2675 Handle(Graphic3d_Camera) aCamBack = theView->Camera();
2676 myXRCameraTmp->Copy (aCamBack);
2677 theView->View()->ComputeXRPosedCameraFromBase (*myXRCameraTmp, thePose);
2678 theView->SetCamera (myXRCameraTmp);
2679 Graphic3d_Vec2i aPickPixel;
2680 theView->Window()->Size (aPickPixel.x(), aPickPixel.y());
2682 const Standard_Integer aSelTolerBack = theCtx->MainSelector()->CustomPixelTolerance();
2683 theCtx->MainSelector()->SetPixelTolerance (1);
2684 theView->AutoZFit();
2687 theCtx->MoveTo (aPickPixel.x(), aPickPixel.y(), theView, false);
2688 if (!theCtx->DetectedOwner().IsNull())
2690 // ignore 2D objects
2691 for (aPickResult = 1; !theCtx->DetectedOwner()->Selectable()->TransformPersistence().IsNull(); ++aPickResult)
2693 if (theCtx->HilightNextDetected (theView, false) <= 1)
2695 theCtx->ClearDetected();
2704 theCtx->MainSelector()->Pick (aPickPixel.x(), aPickPixel.y(), theView);
2705 for (Standard_Integer aPickIter = 1; aPickIter <= theCtx->MainSelector()->NbPicked(); ++aPickIter)
2707 const SelectMgr_SortCriterion& aPickedData = theCtx->MainSelector()->PickedData (aPickIter);
2708 if (!aPickedData.Entity->OwnerId()->Selectable()->TransformPersistence().IsNull())
2714 aPickResult = aPickIter;
2718 theCtx->MainSelector()->SetPixelTolerance (aSelTolerBack);
2719 theView->SetCamera (aCamBack);
2723 // =======================================================================
2724 // function : handleXRHighlight
2726 // =======================================================================
2727 void AIS_ViewController::handleXRHighlight (const Handle(AIS_InteractiveContext)& theCtx,
2728 const Handle(V3d_View)& theView)
2730 if (myXRLastPickingHand != Aspect_XRTrackedDeviceRole_LeftHand
2731 && myXRLastPickingHand != Aspect_XRTrackedDeviceRole_RightHand)
2736 const Standard_Integer aDeviceId = theView->View()->XRSession()->NamedTrackedDevice (myXRLastPickingHand);
2737 if (aDeviceId == -1)
2742 const Aspect_TrackedDevicePose& aPose = theView->View()->XRSession()->TrackedPoses()[aDeviceId];
2743 if (!aPose.IsValidPose)
2748 Handle(SelectMgr_EntityOwner) aDetOld = theCtx->DetectedOwner();
2749 handleXRMoveTo (theCtx, theView, aPose.Orientation, true);
2750 if (!theCtx->DetectedOwner().IsNull()
2751 && theCtx->DetectedOwner() != aDetOld)
2753 if (const Handle(Aspect_XRAction)& aHaptic = theView->View()->XRSession()->GenericAction (myXRLastPickingHand, Aspect_XRGenericAction_OutputHaptic))
2755 theView->View()->XRSession()->TriggerHapticVibrationAction (aHaptic, myXRPickingHaptic);
2759 Standard_Real& aPickDepth = myXRLastPickingHand == Aspect_XRTrackedDeviceRole_LeftHand ? myXRLastPickDepthLeft : myXRLastPickDepthRight;
2760 aPickDepth = Precision::Infinite();
2761 if (theCtx->MainSelector()->NbPicked() > 0)
2763 const gp_Trsf aHandBase = theView->View()->PoseXRToWorld (aPose.Orientation);
2764 const SelectMgr_SortCriterion& aPicked = theCtx->MainSelector()->PickedData (1);
2765 aPickDepth = aPicked.Point.Distance (aHandBase.TranslationPart());
2769 // =======================================================================
2770 // function : handleXRPresentations
2772 // =======================================================================
2773 void AIS_ViewController::handleXRPresentations (const Handle(AIS_InteractiveContext)& theCtx,
2774 const Handle(V3d_View)& theView)
2776 if (!theView->View()->IsActiveXR()
2777 || (!myToDisplayXRAuxDevices
2778 && !myToDisplayXRHands))
2780 for (NCollection_Array1<Handle(AIS_XRTrackedDevice)>::Iterator aPrsIter (myXRPrsDevices); aPrsIter.More(); aPrsIter.Next())
2782 if (!aPrsIter.Value().IsNull()
2783 && aPrsIter.Value()->HasInteractiveContext())
2785 theCtx->Remove (aPrsIter.Value(), false);
2787 aPrsIter.ChangeValue().Nullify();
2792 if (myXRPrsDevices.Length() != theView->View()->XRSession()->TrackedPoses().Length())
2794 for (NCollection_Array1<Handle(AIS_XRTrackedDevice)>::Iterator aPrsIter (myXRPrsDevices); aPrsIter.More(); aPrsIter.Next())
2796 if (!aPrsIter.Value().IsNull())
2798 theCtx->Remove (aPrsIter.Value(), false);
2801 myXRPrsDevices.Resize (theView->View()->XRSession()->TrackedPoses().Lower(), theView->View()->XRSession()->TrackedPoses().Upper(), false);
2804 const Standard_Integer aHeadDevice = theView->View()->XRSession()->NamedTrackedDevice (Aspect_XRTrackedDeviceRole_Head);
2805 const Standard_Integer aLeftDevice = theView->View()->XRSession()->NamedTrackedDevice (Aspect_XRTrackedDeviceRole_LeftHand);
2806 const Standard_Integer aRightDevice = theView->View()->XRSession()->NamedTrackedDevice (Aspect_XRTrackedDeviceRole_RightHand);
2807 for (Standard_Integer aDeviceIter = theView->View()->XRSession()->TrackedPoses().Lower(); aDeviceIter <= theView->View()->XRSession()->TrackedPoses().Upper(); ++aDeviceIter)
2809 const Aspect_TrackedDevicePose& aPose = theView->View()->XRSession()->TrackedPoses()[aDeviceIter];
2810 Handle(AIS_XRTrackedDevice)& aPosePrs = myXRPrsDevices[aDeviceIter];
2811 if (!aPose.IsValidPose)
2816 const bool isHand = aDeviceIter == aLeftDevice
2817 || aDeviceIter == aRightDevice;
2818 if ((!myToDisplayXRHands && isHand)
2819 || (!myToDisplayXRAuxDevices && !isHand))
2821 if (!aPosePrs.IsNull()
2822 && aPosePrs->HasInteractiveContext())
2824 theCtx->Remove (aPosePrs, false);
2829 Aspect_XRTrackedDeviceRole aRole = Aspect_XRTrackedDeviceRole_Other;
2830 if (aDeviceIter == aLeftDevice)
2832 aRole = Aspect_XRTrackedDeviceRole_LeftHand;
2834 else if (aDeviceIter == aRightDevice)
2836 aRole = Aspect_XRTrackedDeviceRole_RightHand;
2839 if (!aPosePrs.IsNull()
2840 && aPosePrs->UnitFactor() != (float )theView->View()->UnitFactor())
2842 theCtx->Remove (aPosePrs, false);
2846 if (aPosePrs.IsNull())
2848 Handle(Image_Texture) aTexture;
2849 Handle(Graphic3d_ArrayOfTriangles) aTris;
2850 if (aDeviceIter != aHeadDevice)
2852 aTris = theView->View()->XRSession()->LoadRenderModel (aDeviceIter, aTexture);
2854 if (!aTris.IsNull())
2856 aPosePrs = new AIS_XRTrackedDevice (aTris, aTexture);
2860 aPosePrs = new AIS_XRTrackedDevice();
2862 aPosePrs->SetUnitFactor ((float )theView->View()->UnitFactor());
2863 aPosePrs->SetMutable (true);
2864 aPosePrs->SetInfiniteState (true);
2866 aPosePrs->SetRole (aRole);
2868 if (!aPosePrs->HasInteractiveContext())
2870 theCtx->Display (aPosePrs, 0, -1, false);
2873 gp_Trsf aPoseLocal = aPose.Orientation;
2874 if (aDeviceIter == aHeadDevice)
2876 // show headset position on floor level
2877 aPoseLocal.SetTranslationPart (gp_Vec (aPoseLocal.TranslationPart().X(), 0.0, aPoseLocal.TranslationPart().Z()));
2879 const gp_Trsf aPoseWorld = theView->View()->PoseXRToWorld (aPoseLocal);
2880 theCtx->SetLocation (aPosePrs, aPoseWorld);
2882 Standard_Real aLaserLen = 0.0;
2884 && aPosePrs->Role() == myXRLastPickingHand)
2886 aLaserLen = myXRLastPickingHand == Aspect_XRTrackedDeviceRole_LeftHand ? myXRLastPickDepthLeft : myXRLastPickDepthRight;
2887 if (Precision::IsInfinite (aLaserLen))
2889 const Bnd_Box aViewBox = theView->View()->MinMaxValues (true);
2890 if (!aViewBox.IsVoid())
2892 aLaserLen = Sqrt (aViewBox.SquareExtent());
2899 aPosePrs->SetLaserColor (myXRLaserPickColor);
2902 && aPosePrs->Role() == myXRLastTeleportHand)
2904 aLaserLen = myXRLastTeleportHand == Aspect_XRTrackedDeviceRole_LeftHand ? myXRLastPickDepthLeft : myXRLastPickDepthRight;
2905 if (Precision::IsInfinite (aLaserLen))
2907 const Bnd_Box aViewBox = theView->View()->MinMaxValues (true);
2908 if (!aViewBox.IsVoid())
2910 aLaserLen = Sqrt (aViewBox.SquareExtent());
2917 aPosePrs->SetLaserColor (myXRLaserTeleColor);
2919 aPosePrs->SetLaserLength ((float )aLaserLen);
2923 // =======================================================================
2924 // function : HandleViewEvents
2926 // =======================================================================
2927 void AIS_ViewController::HandleViewEvents (const Handle(AIS_InteractiveContext)& theCtx,
2928 const Handle(V3d_View)& theView)
2930 const bool wasImmediateUpdate = theView->SetImmediateUpdate (false);
2932 const AIS_WalkDelta aWalk = FetchNavigationKeys (1.0, 1.0);
2933 handleXRInput (theCtx, theView, aWalk);
2934 if (theView->View()->IsActiveXR())
2936 theView->View()->SetupXRPosedCamera();
2938 handleMoveTo (theCtx, theView);
2939 handleCameraActions (theCtx, theView, aWalk);
2940 theView->View()->SynchronizeXRPosedToBaseCamera(); // handleCameraActions() may modify posed camera position - copy this modifications also to the base camera
2941 handleXRPresentations (theCtx, theView);
2943 handleViewRedraw (theCtx, theView);
2944 theView->View()->UnsetXRPosedCamera();
2946 theView->SetImmediateUpdate (wasImmediateUpdate);
2948 // make sure to not process the same events twice
2950 myToAskNextFrame = false;