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_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>
33 // =======================================================================
34 // function : AIS_ViewController
36 // =======================================================================
37 AIS_ViewController::AIS_ViewController()
38 : myLastEventsTime (0.0),
39 myToAskNextFrame (false),
40 myMinCamDistance (1.0),
41 myRotationMode (AIS_RotationMode_BndBoxActive),
42 myNavigationMode (AIS_NavigationMode_Orbit),
45 myToShowPanAnchorPoint (true),
46 myToShowRotateCenter (true),
47 myToLockOrbitZUp (false),
48 myToInvertPitch (false),
49 myToAllowTouchZRotation(false),
50 myToAllowRotation (true),
51 myToAllowPanning (true),
52 myToAllowZooming (true),
53 myToAllowZFocus (true),
54 myToAllowHighlight (true),
55 myToAllowDragging (true),
56 myToStickToRayOnZoom (true),
57 myToStickToRayOnRotation (true),
59 myWalkSpeedAbsolute (1.5f),
60 myWalkSpeedRelative (0.1f),
64 myViewAnimation (new AIS_AnimationCamera ("AIS_ViewController_ViewAnimation", Handle(V3d_View)())),
65 myPrevMoveTo (-1, -1),
66 myHasHlrOnBeforeRotation (false),
68 myXRPrsDevices (0, 0),
69 myXRLaserTeleColor (Quantity_NOC_GREEN),
70 myXRLaserPickColor (Quantity_NOC_BLUE),
71 myXRLastTeleportHand(Aspect_XRTrackedDeviceRole_Other),
72 myXRLastPickingHand (Aspect_XRTrackedDeviceRole_Other),
73 myXRLastPickDepthLeft (Precision::Infinite()),
74 myXRLastPickDepthRight(Precision::Infinite()),
75 myXRTurnAngle (M_PI_4),
76 myToDisplayXRAuxDevices (false),
77 myToDisplayXRHands (true),
79 myMouseClickThreshold (3.0),
80 myMouseDoubleClickInt (0.4),
81 myScrollZoomRatio (15.0f),
82 myMouseActiveGesture (AIS_MouseGesture_NONE),
83 myMouseActiveIdleRotation (false),
84 myMouseClickCounter (0),
85 myMouseSingleButton (-1),
86 myMouseStopDragOnUnclick (false),
88 myTouchToleranceScale (1.0f),
89 myTouchClickThresholdPx (3.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 myViewAnimation->SetOwnDuration (0.5);
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_LIGHTBLUE4, 0.5, 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);
123 myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_ALT | Aspect_VKeyFlags_SHIFT, AIS_MouseGesture_SelectRectangle);
125 myMouseSelectionSchemes.Bind (Aspect_VKeyMouse_LeftButton, AIS_SelectionScheme_Replace);
126 myMouseSelectionSchemes.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_ALT, AIS_SelectionScheme_Replace);
127 myMouseSelectionSchemes.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_SHIFT, AIS_SelectionScheme_XOR);
128 myMouseSelectionSchemes.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_ALT | Aspect_VKeyFlags_SHIFT, AIS_SelectionScheme_XOR);
130 myMouseGestureMap.Bind (Aspect_VKeyMouse_RightButton, AIS_MouseGesture_Zoom);
131 myMouseGestureMap.Bind (Aspect_VKeyMouse_RightButton | Aspect_VKeyFlags_CTRL, AIS_MouseGesture_RotateOrbit);
133 myMouseGestureMap.Bind (Aspect_VKeyMouse_MiddleButton, AIS_MouseGesture_Pan);
134 myMouseGestureMap.Bind (Aspect_VKeyMouse_MiddleButton | Aspect_VKeyFlags_CTRL, AIS_MouseGesture_Pan);
136 myXRTeleportHaptic.Duration = 3600.0f;
137 myXRTeleportHaptic.Frequency = 0.1f;
138 myXRTeleportHaptic.Amplitude = 0.2f;
140 myXRPickingHaptic.Duration = 0.1f;
141 myXRPickingHaptic.Frequency = 4.0f;
142 myXRPickingHaptic.Amplitude = 0.1f;
144 myXRSelectHaptic.Duration = 0.2f;
145 myXRSelectHaptic.Frequency = 4.0f;
146 myXRSelectHaptic.Amplitude = 0.5f;
149 // =======================================================================
150 // function : ~AIS_ViewController
152 // =======================================================================
153 AIS_ViewController::~AIS_ViewController()
158 // =======================================================================
159 // function : ResetViewInput
161 // =======================================================================
162 void AIS_ViewController::ResetViewInput()
165 myMousePressed = Aspect_VKeyMouse_NONE;
166 myMouseModifiers = Aspect_VKeyFlags_NONE;
167 myMouseSingleButton = -1;
168 myUI.Dragging.ToAbort = true;
169 myMouseActiveGesture = AIS_MouseGesture_NONE;
170 myMouseClickTimer.Stop();
171 myMouseClickCounter = 0;
174 // =======================================================================
175 // function : FlushViewEvents
177 // =======================================================================
178 void AIS_ViewController::FlushViewEvents (const Handle(AIS_InteractiveContext)& theCtx,
179 const Handle(V3d_View)& theView,
180 Standard_Boolean theToHandle)
182 flushBuffers (theCtx, theView);
183 flushGestures(theCtx, theView);
186 HandleViewEvents (theCtx, theView);
190 // =======================================================================
191 // function : flushBuffers
193 // =======================================================================
194 void AIS_ViewController::flushBuffers (const Handle(AIS_InteractiveContext)& ,
195 const Handle(V3d_View)& )
197 myToAskNextFrame = false;
199 myGL.IsNewGesture = myUI.IsNewGesture;
200 myUI.IsNewGesture = false;
202 myGL.ZoomActions.Clear();
203 myGL.ZoomActions.Append (myUI.ZoomActions);
204 myUI.ZoomActions.Clear();
206 myGL.Orientation.ToFitAll = myUI.Orientation.ToFitAll;
207 myUI.Orientation.ToFitAll = false;
208 if (myUI.Orientation.ToSetViewOrient)
210 myUI.Orientation.ToSetViewOrient = false;
211 myGL.Orientation.ToSetViewOrient = true;
212 myGL.Orientation.ViewOrient = myUI.Orientation.ViewOrient;
215 if (myUI.MoveTo.ToHilight)
217 myUI.MoveTo.ToHilight = false;
218 myGL.MoveTo.ToHilight = true;
219 myGL.MoveTo.Point = myUI.MoveTo.Point;
223 myGL.Selection.Tool = myUI.Selection.Tool;
224 myGL.Selection.Scheme = myUI.Selection.Scheme;
225 myGL.Selection.Points = myUI.Selection.Points;
226 //myGL.Selection.Scheme = AIS_SelectionScheme_UNKNOWN; // no need
227 if (myUI.Selection.Tool == AIS_ViewSelectionTool_Picking)
229 myUI.Selection.Points.Clear();
233 if (myUI.Selection.ToApplyTool)
235 myGL.Selection.ToApplyTool = true;
236 myUI.Selection.ToApplyTool = false;
237 myUI.Selection.Points.Clear();
240 if (myUI.Panning.ToStart)
242 myUI.Panning.ToStart = false;
243 myGL.Panning.ToStart = true;
244 myGL.Panning.PointStart = myUI.Panning.PointStart;
247 if (myUI.Panning.ToPan)
249 myUI.Panning.ToPan = false;
250 myGL.Panning.ToPan = true;
251 myGL.Panning.Delta = myUI.Panning.Delta;
254 if (myUI.Dragging.ToAbort)
256 myUI.Dragging.ToAbort = false;
257 myGL.Dragging.ToAbort = true;
259 else if (myUI.Dragging.ToStop)
261 myUI.Dragging.ToStop = false;
262 myGL.Dragging.ToStop = true;
264 else if (myUI.Dragging.ToStart)
266 myUI.Dragging.ToStart = false;
267 myGL.Dragging.ToStart = true;
268 myGL.Dragging.PointStart = myUI.Dragging.PointStart;
270 myGL.Dragging.PointTo = myUI.Dragging.PointTo;
272 if (myUI.OrbitRotation.ToStart)
274 myUI.OrbitRotation.ToStart = false;
275 myGL.OrbitRotation.ToStart = true;
276 myGL.OrbitRotation.PointStart = myUI.OrbitRotation.PointStart;
279 if (myUI.OrbitRotation.ToRotate)
281 myUI.OrbitRotation.ToRotate = false;
282 myGL.OrbitRotation.ToRotate = true;
283 myGL.OrbitRotation.PointTo = myUI.OrbitRotation.PointTo;
286 if (myUI.ViewRotation.ToStart)
288 myUI.ViewRotation.ToStart = false;
289 myGL.ViewRotation.ToStart = true;
290 myGL.ViewRotation.PointStart = myUI.ViewRotation.PointStart;
293 if (myUI.ViewRotation.ToRotate)
295 myUI.ViewRotation.ToRotate = false;
296 myGL.ViewRotation.ToRotate = true;
297 myGL.ViewRotation.PointTo = myUI.ViewRotation.PointTo;
300 if (myUI.ZRotate.ToRotate)
302 myGL.ZRotate = myUI.ZRotate;
303 myUI.ZRotate.ToRotate = false;
307 // =======================================================================
308 // function : flushGestures
310 // =======================================================================
311 void AIS_ViewController::flushGestures (const Handle(AIS_InteractiveContext)& ,
312 const Handle(V3d_View)& theView)
314 const Standard_Real aTolScale = myTouchToleranceScale;
315 const Standard_Integer aTouchNb = myTouchPoints.Extent();
316 if (myNbTouchesLast != aTouchNb)
318 myNbTouchesLast = aTouchNb;
319 myGL.IsNewGesture = true;
321 if (aTouchNb == 1) // touch
323 Aspect_Touch& aTouch = myTouchPoints.ChangeFromIndex (1);
324 if (myUpdateStartPointRot)
326 // skip rotation if have active dragged object
327 if (myNavigationMode == AIS_NavigationMode_Orbit)
329 myGL.OrbitRotation.ToStart = true;
330 myGL.OrbitRotation.PointStart = myStartRotCoord;
334 myGL.ViewRotation.ToStart = true;
335 myGL.ViewRotation.PointStart = myStartRotCoord;
338 myUpdateStartPointRot = false;
339 theView->Invalidate();
343 const Standard_Real aRotTouchTol = !aTouch.IsPreciseDevice
344 ? aTolScale * myTouchRotationThresholdPx
346 if (Abs (aTouch.Delta().x()) + Abs(aTouch.Delta().y()) > aRotTouchTol)
348 const Standard_Real aRotAccel = myNavigationMode == AIS_NavigationMode_FirstPersonWalk ? myMouseAccel : myOrbitAccel;
349 if (myNavigationMode == AIS_NavigationMode_Orbit)
351 const Graphic3d_Vec2d aRotDelta = aTouch.To - myGL.OrbitRotation.PointStart;
352 myGL.OrbitRotation.ToRotate = true;
353 myGL.OrbitRotation.PointTo = myGL.OrbitRotation.PointStart + aRotDelta * aRotAccel;
354 myGL.Dragging.PointTo.SetValues ((int )aTouch.To.x(), (int )aTouch.To.y());
358 const Graphic3d_Vec2d aRotDelta = aTouch.To - myGL.ViewRotation.PointStart;
359 myGL.ViewRotation.ToRotate = true;
360 myGL.ViewRotation.PointTo = myGL.ViewRotation.PointStart + aRotDelta * aRotAccel;
361 myGL.Dragging.PointTo.SetValues ((int )aTouch.To.x(), (int )aTouch.To.y());
364 aTouch.From = aTouch.To;
367 else if (aTouchNb == 2) // pinch
369 Aspect_Touch& aFirstTouch = myTouchPoints.ChangeFromIndex (1);
370 Aspect_Touch& aLastTouch = myTouchPoints.ChangeFromIndex (2);
371 const Graphic3d_Vec2d aFrom[2] = { aFirstTouch.From, aLastTouch.From };
372 const Graphic3d_Vec2d aTo[2] = { aFirstTouch.To, aLastTouch.To };
374 Graphic3d_Vec2d aPinchCenterStart ((aFrom[0].x() + aFrom[1].x()) / 2.0,
375 (aFrom[0].y() + aFrom[1].y()) / 2.0);
377 Standard_Real aPinchCenterXEnd = (aTo[0].x() + aTo[1].x()) / 2.0;
378 Standard_Real aPinchCenterYEnd = (aTo[0].y() + aTo[1].y()) / 2.0;
380 Standard_Real aPinchCenterXDev = aPinchCenterXEnd - aPinchCenterStart.x();
381 Standard_Real aPinchCenterYDev = aPinchCenterYEnd - aPinchCenterStart.y();
383 Standard_Real aStartSize = (aFrom[0] - aFrom[1]).Modulus();
384 Standard_Real anEndSize = ( aTo[0] - aTo[1]).Modulus();
386 Standard_Real aDeltaSize = anEndSize - aStartSize;
388 bool anIsClearDev = false;
390 if (myToAllowTouchZRotation)
392 Standard_Real A1 = aFrom[0].y() - aFrom[1].y();
393 Standard_Real B1 = aFrom[1].x() - aFrom[0].x();
395 Standard_Real A2 = aTo[0].y() - aTo[1].y();
396 Standard_Real B2 = aTo[1].x() - aTo[0].x();
398 Standard_Real aRotAngle = 0.0;
400 Standard_Real aDenomenator = A1*A2 + B1*B2;
401 if (aDenomenator <= Precision::Confusion())
407 Standard_Real aNumerator = A1*B2 - A2*B1;
408 aRotAngle = ATan (aNumerator / aDenomenator);
411 if (Abs(aRotAngle) > Standard_Real(myTouchZRotationThreshold))
413 myGL.ZRotate.ToRotate = true;
414 myGL.ZRotate.Angle = aRotAngle;
419 if (Abs(aDeltaSize) > aTolScale * myTouchZoomThresholdPx)
422 aDeltaSize *= Standard_Real(myTouchZoomRatio);
423 Aspect_ScrollDelta aParams (Graphic3d_Vec2i (aPinchCenterStart), aDeltaSize);
424 myGL.ZoomActions.Append (aParams);
428 const Standard_Real aPanTouchTol = !aFirstTouch.IsPreciseDevice
429 ? aTolScale * myTouchPanThresholdPx
431 if (Abs(aPinchCenterXDev) + Abs(aPinchCenterYDev) > aPanTouchTol)
434 if (myUpdateStartPointPan)
436 myGL.Panning.ToStart = true;
437 myGL.Panning.PointStart = Graphic3d_Vec2i (myStartPanCoord);
438 myUpdateStartPointPan = false;
439 theView->Invalidate();
442 myGL.Panning.ToPan = true;
443 myGL.Panning.Delta.x() = int( aPinchCenterXDev);
444 myGL.Panning.Delta.y() = int(-aPinchCenterYDev);
450 aFirstTouch.From = aFirstTouch.To;
451 aLastTouch .From = aLastTouch.To;
456 // =======================================================================
457 // function : UpdateViewOrientation
459 // =======================================================================
460 void AIS_ViewController::UpdateViewOrientation (V3d_TypeOfOrientation theOrientation,
463 myUI.Orientation.ToFitAll = theToFitAll;
464 myUI.Orientation.ToSetViewOrient = true;
465 myUI.Orientation.ViewOrient = theOrientation;
468 // =======================================================================
469 // function : SelectInViewer
471 // =======================================================================
472 void AIS_ViewController::SelectInViewer (const Graphic3d_Vec2i& thePnt,
473 const AIS_SelectionScheme theScheme)
475 if (myUI.Selection.Tool != AIS_ViewSelectionTool_Picking)
477 myUI.Selection.Tool = AIS_ViewSelectionTool_Picking;
478 myUI.Selection.Points.Clear();
481 myUI.Selection.Scheme = theScheme;
482 myUI.Selection.Points.Append (thePnt);
485 // =======================================================================
486 // function : SelectInViewer
488 // =======================================================================
489 void AIS_ViewController::SelectInViewer (const NCollection_Sequence<Graphic3d_Vec2i>& thePnts,
490 const AIS_SelectionScheme theScheme)
492 myUI.Selection.Scheme = theScheme;
493 myUI.Selection.Points = thePnts;
494 myUI.Selection.ToApplyTool = true;
495 if (thePnts.Length() == 1)
497 myUI.Selection.Tool = AIS_ViewSelectionTool_Picking;
499 else if (thePnts.Length() == 2)
501 myUI.Selection.Tool = AIS_ViewSelectionTool_RubberBand;
505 myUI.Selection.Tool = AIS_ViewSelectionTool_Polygon;
509 // =======================================================================
510 // function : UpdateRubberBand
512 // =======================================================================
513 void AIS_ViewController::UpdateRubberBand (const Graphic3d_Vec2i& thePntFrom,
514 const Graphic3d_Vec2i& thePntTo)
516 myUI.Selection.Tool = AIS_ViewSelectionTool_RubberBand;
517 myUI.Selection.Points.Clear();
518 myUI.Selection.Points.Append (thePntFrom);
519 myUI.Selection.Points.Append (thePntTo);
522 // =======================================================================
523 // function : UpdatePolySelection
525 // =======================================================================
526 void AIS_ViewController::UpdatePolySelection (const Graphic3d_Vec2i& thePnt,
529 if (myUI.Selection.Tool != AIS_ViewSelectionTool_Polygon)
531 myUI.Selection.Tool = AIS_ViewSelectionTool_Polygon;
532 myUI.Selection.Points.Clear();
535 if (myUI.Selection.Points.IsEmpty())
537 myUI.Selection.Points.Append (thePnt);
540 && myUI.Selection.Points.Last() != thePnt)
542 myUI.Selection.Points.Append (thePnt);
546 myUI.Selection.Points.ChangeLast() = thePnt;
550 // =======================================================================
551 // function : UpdateZoom
553 // =======================================================================
554 bool AIS_ViewController::UpdateZoom (const Aspect_ScrollDelta& theDelta)
556 if (!myUI.ZoomActions.IsEmpty())
558 if (myUI.ZoomActions.ChangeLast().Point == theDelta.Point)
560 myUI.ZoomActions.ChangeLast().Delta += theDelta.Delta;
565 myUI.ZoomActions.Append (theDelta);
569 // =======================================================================
570 // function : UpdateZRotation
572 // =======================================================================
573 bool AIS_ViewController::UpdateZRotation (double theAngle)
575 if (!ToAllowTouchZRotation())
580 myUI.ZRotate.Angle = myUI.ZRotate.ToRotate
581 ? myUI.ZRotate.Angle + theAngle
583 if (myUI.ZRotate.ToRotate)
587 myUI.ZRotate.ToRotate = true;
591 // =======================================================================
592 // function : UpdateMouseScroll
594 // =======================================================================
595 bool AIS_ViewController::UpdateMouseScroll (const Aspect_ScrollDelta& theDelta)
597 Aspect_ScrollDelta aDelta = theDelta;
598 aDelta.Delta *= myScrollZoomRatio;
599 return UpdateZoom (aDelta);
602 // =======================================================================
603 // function : UpdateMouseClick
605 // =======================================================================
606 bool AIS_ViewController::UpdateMouseClick (const Graphic3d_Vec2i& thePoint,
607 Aspect_VKeyMouse theButton,
608 Aspect_VKeyFlags theModifiers,
609 bool theIsDoubleClick)
611 (void )theIsDoubleClick;
612 AIS_SelectionScheme aScheme = AIS_SelectionScheme_UNKNOWN;
613 if (myMouseSelectionSchemes.Find (theButton | theModifiers, aScheme))
615 SelectInViewer (thePoint, aScheme);
621 // =======================================================================
622 // function : UpdateMouseButtons
624 // =======================================================================
625 bool AIS_ViewController::UpdateMouseButtons (const Graphic3d_Vec2i& thePoint,
626 Aspect_VKeyMouse theButtons,
627 Aspect_VKeyFlags theModifiers,
630 bool toUpdateView = false;
631 const double aTolClick = (theIsEmulated ? myTouchToleranceScale : 1.0) * myMouseClickThreshold;
632 if (theButtons == Aspect_VKeyMouse_NONE
633 && myMouseSingleButton > 0)
635 const Graphic3d_Vec2i aDelta = thePoint - myMousePressPoint;
636 if (double(aDelta.cwiseAbs().maxComp()) < aTolClick)
638 ++myMouseClickCounter;
639 const bool isDoubleClick = myMouseClickCounter == 2
640 && myMouseClickTimer.IsStarted()
641 && myMouseClickTimer.ElapsedTime() <= myMouseDoubleClickInt;
643 myMouseClickTimer.Stop();
644 myMouseClickTimer.Reset();
645 myMouseClickTimer.Start();
648 myMouseClickCounter = 0;
650 toUpdateView = UpdateMouseClick (thePoint, (Aspect_VKeyMouse )myMouseSingleButton, theModifiers, isDoubleClick) || toUpdateView;
654 myMouseClickTimer.Stop();
655 myMouseClickCounter = 0;
656 myMouseStopDragOnUnclick = false;
657 myUI.Dragging.ToStop = true;
660 myMouseSingleButton = -1;
662 else if (theButtons == Aspect_VKeyMouse_NONE)
664 myMouseSingleButton = -1;
665 if (myMouseStopDragOnUnclick)
667 myMouseStopDragOnUnclick = false;
668 myUI.Dragging.ToStop = true;
672 else if (myMouseSingleButton == -1)
674 if ((theButtons & Aspect_VKeyMouse_LeftButton) == Aspect_VKeyMouse_LeftButton)
676 myMouseSingleButton = Aspect_VKeyMouse_LeftButton;
678 else if ((theButtons & Aspect_VKeyMouse_RightButton) == Aspect_VKeyMouse_RightButton)
680 myMouseSingleButton = Aspect_VKeyMouse_RightButton;
682 else if ((theButtons & Aspect_VKeyMouse_MiddleButton) == Aspect_VKeyMouse_MiddleButton)
684 myMouseSingleButton = Aspect_VKeyMouse_MiddleButton;
688 myMouseSingleButton = 0;
690 if (myMouseSingleButton != 0)
692 if (myMouseClickCounter == 1)
694 const Graphic3d_Vec2i aDelta = thePoint - myMousePressPoint;
695 if (double(aDelta.cwiseAbs().maxComp()) >= aTolClick)
697 myMouseClickTimer.Stop();
698 myMouseClickCounter = 0;
701 myMousePressPoint = thePoint;
706 myMouseSingleButton = 0;
708 myUI.Dragging.ToAbort = true;
712 const AIS_MouseGesture aPrevGesture = myMouseActiveGesture;
713 const Aspect_VKeyMouse aPrevButtons = myMousePressed;
714 const Aspect_VKeyFlags aPrevModifiers = myMouseModifiers;
715 myMouseModifiers = theModifiers;
716 myMousePressed = theButtons;
718 || myNavigationMode != AIS_NavigationMode_FirstPersonWalk)
720 myMouseActiveIdleRotation = false;
721 myMouseActiveGesture = AIS_MouseGesture_NONE;
724 myMousePressPoint = thePoint;
725 myMouseProgressPoint = myMousePressPoint;
728 if (myMouseGestureMap.Find (theButtons | theModifiers, myMouseActiveGesture))
730 switch (myMouseActiveGesture)
732 case AIS_MouseGesture_RotateView:
733 case AIS_MouseGesture_RotateOrbit:
735 if (myToAllowRotation)
737 myUpdateStartPointRot = true;
741 myMouseActiveGesture = AIS_MouseGesture_NONE;
745 case AIS_MouseGesture_Pan:
747 if (myToAllowPanning)
749 myUpdateStartPointPan = true;
753 myMouseActiveGesture = AIS_MouseGesture_NONE;
757 case AIS_MouseGesture_Zoom:
758 case AIS_MouseGesture_ZoomWindow:
760 if (!myToAllowZooming)
762 myMouseActiveGesture = AIS_MouseGesture_NONE;
766 case AIS_MouseGesture_SelectRectangle:
770 case AIS_MouseGesture_SelectLasso:
772 UpdatePolySelection (thePoint, true);
775 case AIS_MouseGesture_NONE:
782 if (theButtons == Aspect_VKeyMouse_LeftButton
783 && theModifiers == Aspect_VKeyFlags_NONE
784 && myToAllowDragging)
786 myUI.Dragging.ToStart = true;
787 myUI.Dragging.PointStart = thePoint;
791 if (aPrevGesture != myMouseActiveGesture)
793 if (aPrevGesture == AIS_MouseGesture_SelectRectangle
794 || aPrevGesture == AIS_MouseGesture_SelectLasso
795 || aPrevGesture == AIS_MouseGesture_ZoomWindow)
797 myUI.Selection.ToApplyTool = true;
798 myUI.Selection.Scheme = AIS_SelectionScheme_Replace;
799 myMouseSelectionSchemes.Find (aPrevButtons | aPrevModifiers, myUI.Selection.Scheme);
802 myUI.IsNewGesture = true;
809 // =======================================================================
810 // function : UpdateMousePosition
812 // =======================================================================
813 bool AIS_ViewController::UpdateMousePosition (const Graphic3d_Vec2i& thePoint,
814 Aspect_VKeyMouse theButtons,
815 Aspect_VKeyFlags theModifiers,
818 myMousePositionLast = thePoint;
819 if (myMouseSingleButton > 0)
821 const double aTolClick = (theIsEmulated ? myTouchToleranceScale : 1.0) * myMouseClickThreshold;
822 const Graphic3d_Vec2i aPressDelta = thePoint - myMousePressPoint;
823 if (double(aPressDelta.cwiseAbs().maxComp()) >= aTolClick)
825 myMouseClickTimer.Stop();
826 myMouseClickCounter = 0;
827 myMouseSingleButton = -1;
828 myMouseStopDragOnUnclick = true;
832 bool toUpdateView = false;
833 Graphic3d_Vec2i aDelta = thePoint - myMouseProgressPoint;
835 && myNavigationMode == AIS_NavigationMode_FirstPersonWalk)
837 if (!myMouseActiveIdleRotation
838 || myMouseActiveGesture != AIS_MouseGesture_RotateView)
840 myMouseActiveIdleRotation = true;
841 myMouseActiveGesture = AIS_MouseGesture_RotateView;
842 myMousePressPoint = thePoint;
843 myMouseProgressPoint = thePoint;
844 myUpdateStartPointRot = false;
845 myUI.ViewRotation.ToStart = true;
846 myUI.ViewRotation.PointStart.SetValues (thePoint.x(), thePoint.y());
847 myUI.ViewRotation.ToRotate = false;
848 aDelta.SetValues (0, 0);
853 if (myMouseActiveIdleRotation
854 && myMouseActiveGesture == AIS_MouseGesture_RotateView)
856 myMouseActiveGesture = AIS_MouseGesture_NONE;
858 myMouseActiveIdleRotation = false;
861 if (myMouseModifiers != theModifiers
862 && UpdateMouseButtons (thePoint, theButtons, theModifiers, theIsEmulated))
867 switch (myMouseActiveGesture)
869 case AIS_MouseGesture_SelectRectangle:
870 case AIS_MouseGesture_ZoomWindow:
872 UpdateRubberBand (myMousePressPoint, thePoint);
873 if (myMouseActiveGesture == AIS_MouseGesture_ZoomWindow)
875 myUI.Selection.Tool = AIS_ViewSelectionTool_ZoomWindow;
880 case AIS_MouseGesture_SelectLasso:
882 UpdatePolySelection (thePoint, true);
886 case AIS_MouseGesture_RotateOrbit:
887 case AIS_MouseGesture_RotateView:
889 if (!myToAllowRotation)
893 if (myUpdateStartPointRot)
895 if (myMouseActiveGesture == AIS_MouseGesture_RotateOrbit)
897 myUI.OrbitRotation.ToStart = true;
898 myUI.OrbitRotation.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y());
902 myUI.ViewRotation.ToStart = true;
903 myUI.ViewRotation.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y());
905 myUpdateStartPointRot = false;
908 const double aRotTol = theIsEmulated
909 ? double(myTouchToleranceScale) * myTouchRotationThresholdPx
911 if (double (Abs (aDelta.x()) + Abs (aDelta.y())) > aRotTol)
913 const double aRotAccel = myNavigationMode == AIS_NavigationMode_FirstPersonWalk ? myMouseAccel : myOrbitAccel;
914 const Graphic3d_Vec2i aRotDelta = thePoint - myMousePressPoint;
915 if (myMouseActiveGesture == AIS_MouseGesture_RotateOrbit)
917 myUI.OrbitRotation.ToRotate = true;
918 myUI.OrbitRotation.PointTo = Graphic3d_Vec2d (myMousePressPoint.x(), myMousePressPoint.y())
919 + Graphic3d_Vec2d (aRotDelta.x(), aRotDelta.y()) * aRotAccel;
923 myUI.ViewRotation.ToRotate = true;
924 myUI.ViewRotation.PointTo = Graphic3d_Vec2d (myMousePressPoint.x(), myMousePressPoint.y())
925 + Graphic3d_Vec2d (aRotDelta.x(), aRotDelta.y()) * aRotAccel;
927 myUI.Dragging.PointTo = thePoint;
929 myMouseProgressPoint = thePoint;
934 case AIS_MouseGesture_Zoom:
936 if (!myToAllowZooming)
940 const double aZoomTol = theIsEmulated
941 ? double(myTouchToleranceScale) * myTouchZoomThresholdPx
943 if (double (Abs (aDelta.x())) > aZoomTol)
945 if (UpdateZoom (Aspect_ScrollDelta (aDelta.x())))
949 myMouseProgressPoint = thePoint;
953 case AIS_MouseGesture_Pan:
955 if (!myToAllowPanning)
959 const double aPanTol = theIsEmulated
960 ? double(myTouchToleranceScale) * myTouchPanThresholdPx
962 if (double (Abs (aDelta.x()) + Abs (aDelta.y())) > aPanTol)
964 if (myUpdateStartPointPan)
966 myUI.Panning.ToStart = true;
967 myUI.Panning.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y());
968 myUpdateStartPointPan = false;
971 aDelta.y() = -aDelta.y();
972 myMouseProgressPoint = thePoint;
973 if (myUI.Panning.ToPan)
975 myUI.Panning.Delta += aDelta;
979 myUI.Panning.ToPan = true;
980 myUI.Panning.Delta = aDelta;
992 if (theButtons == Aspect_VKeyMouse_NONE
993 && myNavigationMode != AIS_NavigationMode_FirstPersonWalk
996 && myToAllowHighlight)
998 myUI.MoveTo.ToHilight = true;
999 myUI.MoveTo.Point = thePoint;
1000 toUpdateView = true;
1002 return toUpdateView;
1005 // =======================================================================
1006 // function : AddTouchPoint
1008 // =======================================================================
1009 void AIS_ViewController::AddTouchPoint (Standard_Size theId,
1010 const Graphic3d_Vec2d& thePnt,
1011 Standard_Boolean theClearBefore)
1013 myUI.MoveTo.ToHilight = false;
1014 Aspect_WindowInputListener::AddTouchPoint (theId, thePnt, theClearBefore);
1016 myTouchClick.From = Graphic3d_Vec2d (-1.0);
1017 if (myTouchPoints.Extent() == 1)
1019 myTouchClick.From = thePnt;
1020 myUpdateStartPointRot = true;
1021 myStartRotCoord = thePnt;
1022 if (myToAllowDragging)
1024 myUI.Dragging.ToStart = true;
1025 myUI.Dragging.PointStart.SetValues ((int )thePnt.x(), (int )thePnt.y());
1028 else if (myTouchPoints.Extent() == 2)
1030 myUI.Dragging.ToAbort = true;
1032 myUpdateStartPointPan = true;
1033 myStartPanCoord = thePnt;
1035 myUI.IsNewGesture = true;
1038 // =======================================================================
1039 // function : RemoveTouchPoint
1041 // =======================================================================
1042 bool AIS_ViewController::RemoveTouchPoint (Standard_Size theId,
1043 Standard_Boolean theClearSelectPnts)
1045 if (!Aspect_WindowInputListener::RemoveTouchPoint (theId, theClearSelectPnts))
1050 if (myTouchPoints.Extent() == 1)
1052 // avoid incorrect transition from pinch to one finger
1053 Aspect_Touch& aFirstTouch = myTouchPoints.ChangeFromIndex (1);
1054 aFirstTouch.To = aFirstTouch.From;
1056 myStartRotCoord = aFirstTouch.To;
1057 myUpdateStartPointRot = true;
1059 else if (myTouchPoints.Extent() == 2)
1061 myStartPanCoord = myTouchPoints.FindFromIndex (1).To;
1062 myUpdateStartPointPan = true;
1064 else if (myTouchPoints.IsEmpty())
1066 if (theClearSelectPnts)
1068 myUI.Selection.ToApplyTool = true;
1071 myUI.Dragging.ToStop = true;
1073 if (theId == (Standard_Size )-1)
1076 myTouchClick.From = Graphic3d_Vec2d (-1);
1078 else if (myTouchClick.From.minComp() >= 0.0)
1080 bool isDoubleClick = false;
1081 if (myTouchDoubleTapTimer.IsStarted()
1082 && myTouchDoubleTapTimer.ElapsedTime() <= myMouseDoubleClickInt)
1084 isDoubleClick = true;
1088 myTouchDoubleTapTimer.Stop();
1089 myTouchDoubleTapTimer.Reset();
1090 myTouchDoubleTapTimer.Start();
1093 // emulate mouse click
1094 UpdateMouseClick (Graphic3d_Vec2i (myTouchClick.From), Aspect_VKeyMouse_LeftButton, Aspect_VKeyFlags_NONE, isDoubleClick);
1097 myUI.IsNewGesture = true;
1101 // =======================================================================
1102 // function : UpdateTouchPoint
1104 // =======================================================================
1105 void AIS_ViewController::UpdateTouchPoint (Standard_Size theId,
1106 const Graphic3d_Vec2d& thePnt)
1108 Aspect_WindowInputListener::UpdateTouchPoint (theId, thePnt);
1110 const double aTouchTol = double(myTouchToleranceScale) * double(myTouchClickThresholdPx);
1111 if (myTouchPoints.Extent() == 1
1112 && (myTouchClick.From - thePnt).cwiseAbs().maxComp() > aTouchTol)
1114 myTouchClick.From.SetValues (-1.0, -1.0);
1118 // =======================================================================
1119 // function : Update3dMouse
1121 // =======================================================================
1122 bool AIS_ViewController::Update3dMouse (const WNT_HIDSpaceMouse& theEvent)
1124 bool toUpdate = false;
1125 toUpdate = update3dMouseTranslation (theEvent) || toUpdate;
1126 toUpdate = (myToAllowRotation && update3dMouseRotation (theEvent)) || toUpdate;
1127 toUpdate = update3dMouseKeys (theEvent) || toUpdate;
1131 // =======================================================================
1132 // function : SetNavigationMode
1134 // =======================================================================
1135 void AIS_ViewController::SetNavigationMode (AIS_NavigationMode theMode)
1137 myNavigationMode = theMode;
1140 myUI.OrbitRotation.ToStart = false;
1141 myUI.OrbitRotation.ToRotate = false;
1142 myUI.ViewRotation.ToStart = false;
1143 myUI.ViewRotation.ToRotate = false;
1146 // =======================================================================
1147 // function : KeyDown
1149 // =======================================================================
1150 void AIS_ViewController::KeyDown (Aspect_VKey theKey,
1154 Aspect_WindowInputListener::KeyDown (theKey, theTime, thePressure);
1157 // =======================================================================
1160 // =======================================================================
1161 void AIS_ViewController::KeyUp (Aspect_VKey theKey,
1164 Aspect_WindowInputListener::KeyUp (theKey, theTime);
1167 // =======================================================================
1168 // function : KeyFromAxis
1170 // =======================================================================
1171 void AIS_ViewController::KeyFromAxis (Aspect_VKey theNegative,
1172 Aspect_VKey thePositive,
1176 Aspect_WindowInputListener::KeyFromAxis (theNegative, thePositive, theTime, thePressure);
1179 // =======================================================================
1180 // function : FetchNavigationKeys
1182 // =======================================================================
1183 AIS_WalkDelta AIS_ViewController::FetchNavigationKeys (Standard_Real theCrouchRatio,
1184 Standard_Real theRunRatio)
1186 AIS_WalkDelta aWalk;
1189 double aPrevEventTime = 0.0, aNewEventTime = 0.0;
1190 updateEventsTime (aPrevEventTime, aNewEventTime);
1192 double aDuration = 0.0, aPressure = 1.0;
1193 if (Abs (myThrustSpeed) > gp::Resolution())
1197 aWalk[AIS_WalkTranslation_Forward].Value = myThrustSpeed * (aNewEventTime - aPrevEventTime);
1200 myToAskNextFrame = true;
1204 myHasThrust = false;
1207 aWalk.SetRunning (theRunRatio > 1.0
1208 && myKeys.IsKeyDown (Aspect_VKey_Shift));
1209 if (myKeys.HoldDuration (Aspect_VKey_NavJump, aNewEventTime, aDuration))
1211 myKeys.KeyUp (Aspect_VKey_NavJump, aNewEventTime);
1212 aWalk.SetDefined (true);
1213 aWalk.SetJumping (true);
1215 if (!aWalk.IsJumping()
1216 && theCrouchRatio < 1.0
1217 && myKeys.HoldDuration (Aspect_VKey_NavCrouch, aNewEventTime, aDuration))
1219 aWalk.SetDefined (true);
1220 aWalk.SetRunning (false);
1221 aWalk.SetCrouching (true);
1224 const double aMaxDuration = aNewEventTime - aPrevEventTime;
1225 const double aRunRatio = aWalk.IsRunning()
1227 : aWalk.IsCrouching()
1230 if (myKeys.HoldDuration (Aspect_VKey_NavForward, aNewEventTime, aDuration, aPressure))
1232 double aProgress = Abs (Min (aMaxDuration, aDuration));
1233 aProgress *= aRunRatio;
1234 aWalk.SetDefined (true);
1235 aWalk[AIS_WalkTranslation_Forward].Value += aProgress;
1236 aWalk[AIS_WalkTranslation_Forward].Pressure = aPressure;
1237 aWalk[AIS_WalkTranslation_Forward].Duration = aDuration;
1239 if (myKeys.HoldDuration (Aspect_VKey_NavBackward, aNewEventTime, aDuration, aPressure))
1241 double aProgress = Abs (Min (aMaxDuration, aDuration));
1242 aProgress *= aRunRatio;
1243 aWalk.SetDefined (true);
1244 aWalk[AIS_WalkTranslation_Forward].Value += -aProgress;
1245 aWalk[AIS_WalkTranslation_Forward].Pressure = aPressure;
1246 aWalk[AIS_WalkTranslation_Forward].Duration = aDuration;
1248 if (myKeys.HoldDuration (Aspect_VKey_NavSlideLeft, aNewEventTime, aDuration, aPressure))
1250 double aProgress = Abs (Min (aMaxDuration, aDuration));
1251 aProgress *= aRunRatio;
1252 aWalk.SetDefined (true);
1253 aWalk[AIS_WalkTranslation_Side].Value = -aProgress;
1254 aWalk[AIS_WalkTranslation_Side].Pressure = aPressure;
1255 aWalk[AIS_WalkTranslation_Side].Duration = aDuration;
1257 if (myKeys.HoldDuration (Aspect_VKey_NavSlideRight, aNewEventTime, aDuration, aPressure))
1259 double aProgress = Abs (Min (aMaxDuration, aDuration));
1260 aProgress *= aRunRatio;
1261 aWalk.SetDefined (true);
1262 aWalk[AIS_WalkTranslation_Side].Value = aProgress;
1263 aWalk[AIS_WalkTranslation_Side].Pressure = aPressure;
1264 aWalk[AIS_WalkTranslation_Side].Duration = aDuration;
1266 if (myKeys.HoldDuration (Aspect_VKey_NavLookLeft, aNewEventTime, aDuration, aPressure))
1268 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1269 aWalk.SetDefined (true);
1270 aWalk[AIS_WalkRotation_Yaw].Value = aProgress;
1271 aWalk[AIS_WalkRotation_Yaw].Pressure = aPressure;
1272 aWalk[AIS_WalkRotation_Yaw].Duration = aDuration;
1274 if (myKeys.HoldDuration (Aspect_VKey_NavLookRight, aNewEventTime, aDuration, aPressure))
1276 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1277 aWalk.SetDefined (true);
1278 aWalk[AIS_WalkRotation_Yaw].Value = -aProgress;
1279 aWalk[AIS_WalkRotation_Yaw].Pressure = aPressure;
1280 aWalk[AIS_WalkRotation_Yaw].Duration = aDuration;
1282 if (myKeys.HoldDuration (Aspect_VKey_NavLookUp, aNewEventTime, aDuration, aPressure))
1284 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1285 aWalk.SetDefined (true);
1286 aWalk[AIS_WalkRotation_Pitch].Value = !myToInvertPitch ? -aProgress : aProgress;
1287 aWalk[AIS_WalkRotation_Pitch].Pressure = aPressure;
1288 aWalk[AIS_WalkRotation_Pitch].Duration = aDuration;
1290 if (myKeys.HoldDuration (Aspect_VKey_NavLookDown, aNewEventTime, aDuration, aPressure))
1292 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1293 aWalk.SetDefined (true);
1294 aWalk[AIS_WalkRotation_Pitch].Value = !myToInvertPitch ? aProgress : -aProgress;
1295 aWalk[AIS_WalkRotation_Pitch].Pressure = aPressure;
1296 aWalk[AIS_WalkRotation_Pitch].Duration = aDuration;
1298 if (myKeys.HoldDuration (Aspect_VKey_NavRollCCW, aNewEventTime, aDuration, aPressure))
1300 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1301 aWalk.SetDefined (true);
1302 aWalk[AIS_WalkRotation_Roll].Value = -aProgress;
1303 aWalk[AIS_WalkRotation_Roll].Pressure = aPressure;
1304 aWalk[AIS_WalkRotation_Roll].Duration = aDuration;
1306 if (myKeys.HoldDuration (Aspect_VKey_NavRollCW, aNewEventTime, aDuration, aPressure))
1308 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1309 aWalk.SetDefined (true);
1310 aWalk[AIS_WalkRotation_Roll].Value = aProgress;
1311 aWalk[AIS_WalkRotation_Roll].Pressure = aPressure;
1312 aWalk[AIS_WalkRotation_Roll].Duration = aDuration;
1314 if (myKeys.HoldDuration (Aspect_VKey_NavSlideUp, aNewEventTime, aDuration, aPressure))
1316 double aProgress = Abs (Min (aMaxDuration, aDuration));
1317 aWalk.SetDefined (true);
1318 aWalk[AIS_WalkTranslation_Up].Value = aProgress;
1319 aWalk[AIS_WalkTranslation_Up].Pressure = aPressure;
1320 aWalk[AIS_WalkTranslation_Up].Duration = aDuration;
1322 if (myKeys.HoldDuration (Aspect_VKey_NavSlideDown, aNewEventTime, aDuration, aPressure))
1324 double aProgress = Abs (Min (aMaxDuration, aDuration));
1325 aWalk.SetDefined (true);
1326 aWalk[AIS_WalkTranslation_Up].Value = -aProgress;
1327 aWalk[AIS_WalkTranslation_Up].Pressure = aPressure;
1328 aWalk[AIS_WalkTranslation_Up].Duration = aDuration;
1333 // =======================================================================
1334 // function : AbortViewAnimation
1336 // =======================================================================
1337 void AIS_ViewController::AbortViewAnimation()
1339 if (!myViewAnimation.IsNull()
1340 && !myViewAnimation->IsStopped())
1342 myViewAnimation->Stop();
1343 myViewAnimation->SetView (Handle(V3d_View)());
1347 // =======================================================================
1348 // function : handlePanning
1350 // =======================================================================
1351 void AIS_ViewController::handlePanning (const Handle(V3d_View)& theView)
1353 if (!myGL.Panning.ToPan
1354 || !myToAllowPanning)
1359 AbortViewAnimation();
1361 const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1362 if (aCam->IsOrthographic()
1363 || !hasPanningAnchorPoint())
1365 theView->Pan (myGL.Panning.Delta.x(), myGL.Panning.Delta.y());
1366 theView->Invalidate();
1367 theView->View()->SynchronizeXRPosedToBaseCamera();
1371 Graphic3d_Vec2i aWinSize;
1372 theView->Window()->Size (aWinSize.x(), aWinSize.y());
1374 const gp_Dir& aDir = aCam->Direction();
1375 const gp_Ax3 aCameraCS (aCam->Center(), aDir.Reversed(), aDir ^ aCam->Up());
1376 const gp_XYZ anEyeToPnt = myPanPnt3d.XYZ() - aCam->Eye().XYZ();
1377 const gp_Pnt aViewDims = aCam->ViewDimensions (anEyeToPnt.Dot (aCam->Direction().XYZ())); // view dimensions at 3D point
1378 const Graphic3d_Vec2d aDxy (-aViewDims.X() * myGL.Panning.Delta.x() / double(aWinSize.x()),
1379 -aViewDims.X() * myGL.Panning.Delta.y() / double(aWinSize.x()));
1381 //theView->Translate (aCam, aDxy.x(), aDxy.y());
1383 const gp_Vec aCameraPan = gp_Vec (aCameraCS.XDirection()) * aDxy.x()
1384 + gp_Vec (aCameraCS.YDirection()) * aDxy.y();
1385 aPanTrsf.SetTranslation (aCameraPan);
1386 aCam->Transform (aPanTrsf);
1387 theView->Invalidate();
1388 theView->View()->SynchronizeXRPosedToBaseCamera();
1391 // =======================================================================
1392 // function : handleZRotate
1394 // =======================================================================
1395 void AIS_ViewController::handleZRotate (const Handle(V3d_View)& theView)
1397 if (!myGL.ZRotate.ToRotate
1398 || !myToAllowRotation)
1403 AbortViewAnimation();
1405 Graphic3d_Vec2i aViewPort;
1406 theView->Window()->Size (aViewPort.x(), aViewPort.y());
1407 Graphic3d_Vec2d aRotPnt (0.99 * aViewPort.x(),
1408 0.5 * aViewPort.y());
1409 theView->StartRotation (int(aRotPnt.x()), int(aRotPnt.y()), 0.4);
1410 aRotPnt.y() += myGL.ZRotate.Angle * aViewPort.y();
1411 theView->Rotation (int(aRotPnt.x()), int(aRotPnt.y()));
1412 theView->Invalidate();
1413 theView->View()->SynchronizeXRPosedToBaseCamera();
1416 // =======================================================================
1417 // function : handleZoom
1419 // =======================================================================
1420 void AIS_ViewController::handleZoom (const Handle(V3d_View)& theView,
1421 const Aspect_ScrollDelta& theParams,
1422 const gp_Pnt* thePnt)
1424 if (!myToAllowZooming)
1429 AbortViewAnimation();
1431 const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1434 const double aViewDist = Max (myMinCamDistance, (thePnt->XYZ() - aCam->Eye().XYZ()).Modulus());
1435 aCam->SetCenter (aCam->Eye().XYZ() + aCam->Direction().XYZ() * aViewDist);
1438 if (!theParams.HasPoint())
1440 Standard_Real aCoeff = Abs(theParams.Delta) / 100.0 + 1.0;
1441 aCoeff = theParams.Delta > 0.0 ? aCoeff : 1.0 / aCoeff;
1442 theView->SetZoom (aCoeff, true);
1443 theView->Invalidate();
1444 theView->View()->SynchronizeXRPosedToBaseCamera();
1448 // integer delta is too rough for small smooth increments
1449 //theView->StartZoomAtPoint (theParams.Point.x(), theParams.Point.y());
1450 //theView->ZoomAtPoint (0, 0, (int )theParams.Delta, (int )theParams.Delta);
1452 double aDZoom = Abs (theParams.Delta) / 100.0 + 1.0;
1453 aDZoom = (theParams.Delta > 0.0) ? aDZoom : 1.0 / aDZoom;
1459 const Graphic3d_Vec2d aViewDims (aCam->ViewDimensions().X(), aCam->ViewDimensions().Y());
1461 // ensure that zoom will not be too small or too big
1462 double aCoef = aDZoom;
1463 if (aViewDims.x() < aCoef * Precision::Confusion())
1465 aCoef = aViewDims.x() / Precision::Confusion();
1467 else if (aViewDims.x() > aCoef * 1e12)
1469 aCoef = aViewDims.x() / 1e12;
1471 if (aViewDims.y() < aCoef * Precision::Confusion())
1473 aCoef = aViewDims.y() / Precision::Confusion();
1475 else if (aViewDims.y() > aCoef * 1e12)
1477 aCoef = aViewDims.y() / 1e12;
1480 Graphic3d_Vec2d aZoomAtPointXYv (0.0, 0.0);
1481 theView->Convert (theParams.Point.x(), theParams.Point.y(),
1482 aZoomAtPointXYv.x(), aZoomAtPointXYv.y());
1483 Graphic3d_Vec2d aDxy = aZoomAtPointXYv / aCoef;
1484 aCam->SetScale (aCam->Scale() / aCoef);
1486 const gp_Dir& aDir = aCam->Direction();
1487 const gp_Ax3 aCameraCS (aCam->Center(), aDir.Reversed(), aDir ^ aCam->Up());
1489 // pan back to the point
1490 aDxy = aZoomAtPointXYv - aDxy;
1493 // zoom at 3D point with perspective projection
1494 const gp_XYZ anEyeToPnt = thePnt->XYZ() - aCam->Eye().XYZ();
1495 aDxy.SetValues (anEyeToPnt.Dot (aCameraCS.XDirection().XYZ()),
1496 anEyeToPnt.Dot (aCameraCS.YDirection().XYZ()));
1498 // view dimensions at 3D point
1499 const gp_Pnt aViewDims1 = aCam->ViewDimensions (anEyeToPnt.Dot (aCam->Direction().XYZ()));
1501 Graphic3d_Vec2i aWinSize;
1502 theView->Window()->Size (aWinSize.x(), aWinSize.y());
1503 const Graphic3d_Vec2d aPanFromCenterPx (double(theParams.Point.x()) - 0.5 * double(aWinSize.x()),
1504 double(aWinSize.y() - theParams.Point.y() - 1) - 0.5 * double(aWinSize.y()));
1505 aDxy.x() += -aViewDims1.X() * aPanFromCenterPx.x() / double(aWinSize.x());
1506 aDxy.y() += -aViewDims1.Y() * aPanFromCenterPx.y() / double(aWinSize.y());
1509 //theView->Translate (aCam, aDxy.x(), aDxy.y());
1511 const gp_Vec aCameraPan = gp_Vec (aCameraCS.XDirection()) * aDxy.x()
1512 + gp_Vec (aCameraCS.YDirection()) * aDxy.y();
1513 aPanTrsf.SetTranslation (aCameraPan);
1514 aCam->Transform (aPanTrsf);
1515 theView->Invalidate();
1516 theView->View()->SynchronizeXRPosedToBaseCamera();
1519 // =======================================================================
1520 // function : handleZFocusScroll
1522 // =======================================================================
1523 void AIS_ViewController::handleZFocusScroll (const Handle(V3d_View)& theView,
1524 const Aspect_ScrollDelta& theParams)
1526 if (!myToAllowZFocus
1527 || !theView->Camera()->IsStereo())
1532 Standard_Real aFocus = theView->Camera()->ZFocus() + (theParams.Delta > 0.0 ? 0.05 : -0.05);
1536 theView->Camera()->SetZFocus (theView->Camera()->ZFocusType(), aFocus);
1537 theView->Invalidate();
1541 // =======================================================================
1542 // function : handleOrbitRotation
1544 // =======================================================================
1545 void AIS_ViewController::handleOrbitRotation (const Handle(V3d_View)& theView,
1546 const gp_Pnt& thePnt,
1549 if (!myToAllowRotation)
1554 const Handle(Graphic3d_Camera)& aCam = theView->View()->IsActiveXR()
1555 ? theView->View()->BaseXRCamera()
1556 : theView->Camera();
1557 if (myGL.OrbitRotation.ToStart)
1559 // default alternatives
1560 //if (myRotationMode == AIS_RotationMode_BndBoxActive) theView->StartRotation (myGL.RotateAtPoint.x(), myGL.RotateAtPoint.y());
1561 //theView->Rotate (0.0, 0.0, 0.0, thePnt.X(), thePnt.Y(), thePnt.Z(), true);
1563 myRotatePnt3d = thePnt;
1564 myCamStartOpUp = aCam->Up();
1565 myCamStartOpDir = aCam->Direction();
1566 myCamStartOpEye = aCam->Eye();
1567 myCamStartOpCenter = aCam->Center();
1570 aTrsf.SetTransformation (gp_Ax3 (myRotatePnt3d, aCam->OrthogonalizedUp(), aCam->Direction()),
1571 gp_Ax3 (myRotatePnt3d, gp::DZ(), gp::DX()));
1572 const gp_Quaternion aRot = aTrsf.GetRotation();
1573 aRot.GetEulerAngles (gp_YawPitchRoll, myRotateStartYawPitchRoll[0], myRotateStartYawPitchRoll[1], myRotateStartYawPitchRoll[2]);
1576 myCamStartOpToEye = gp_Vec (myRotatePnt3d, aCam->Eye()).Transformed (aTrsf);
1577 myCamStartOpToCenter = gp_Vec (myRotatePnt3d, aCam->Center()).Transformed (aTrsf);
1579 theView->Invalidate();
1582 if (!myGL.OrbitRotation.ToRotate)
1587 AbortViewAnimation();
1590 // amend camera to exclude roll angle (put camera Up vector to plane containing global Z and view direction)
1591 Graphic3d_Vec2i aWinXY;
1592 theView->Window()->Size (aWinXY.x(), aWinXY.y());
1593 double aYawAngleDelta = ((myGL.OrbitRotation.PointStart.x() - myGL.OrbitRotation.PointTo.x()) / double (aWinXY.x())) * (M_PI * 0.5);
1594 double aPitchAngleDelta = -((myGL.OrbitRotation.PointStart.y() - myGL.OrbitRotation.PointTo.y()) / double (aWinXY.y())) * (M_PI * 0.5);
1595 double aPitchAngleNew = 0.0, aRoll = 0.0;
1596 const double aYawAngleNew = myRotateStartYawPitchRoll[0] + aYawAngleDelta;
1597 if (!theView->View()->IsActiveXR())
1599 aPitchAngleNew = Max (Min (myRotateStartYawPitchRoll[1] + aPitchAngleDelta, M_PI * 0.5 - M_PI / 180.0), -M_PI * 0.5 + M_PI / 180.0);
1604 aRot.SetEulerAngles (gp_YawPitchRoll, aYawAngleNew, aPitchAngleNew, aRoll);
1606 aTrsfRot.SetRotation (aRot);
1608 const gp_Dir aNewUp = gp::DZ().Transformed (aTrsfRot);
1609 aCam->SetUp (aNewUp);
1610 aCam->SetEyeAndCenter (myRotatePnt3d.XYZ() + myCamStartOpToEye .Transformed (aTrsfRot).XYZ(),
1611 myRotatePnt3d.XYZ() + myCamStartOpToCenter.Transformed (aTrsfRot).XYZ());
1613 aCam->OrthogonalizeUp();
1617 // default alternatives
1618 //if (myRotationMode == AIS_RotationMode_BndBoxActive) theView->Rotation (myGL.RotateToPoint.x(), myGL.RotateToPoint.y());
1619 //theView->Rotate (aDX, aDY, aDZ, myRotatePnt3d.X(), myRotatePnt3d.Y(), myRotatePnt3d.Z(), false);
1621 // restore previous camera state
1622 aCam->SetEyeAndCenter (myCamStartOpEye, myCamStartOpCenter);
1623 aCam->SetUp (myCamStartOpUp);
1624 aCam->SetDirectionFromEye (myCamStartOpDir);
1626 Graphic3d_Vec2d aWinXY;
1627 theView->Size (aWinXY.x(), aWinXY.y());
1628 const Standard_Real rx = (Standard_Real )theView->Convert (aWinXY.x());
1629 const Standard_Real ry = (Standard_Real )theView->Convert (aWinXY.y());
1631 const double THE_2PI = M_PI * 2.0;
1632 double aDX = (myGL.OrbitRotation.PointTo.x() - myGL.OrbitRotation.PointStart.x()) * M_PI / rx;
1633 double aDY = (myGL.OrbitRotation.PointStart.y() - myGL.OrbitRotation.PointTo.y()) * M_PI / ry;
1635 if (aDX > 0.0) { while (aDX > THE_2PI) { aDX -= THE_2PI; } }
1636 else if(aDX < 0.0) { while (aDX < -THE_2PI) { aDX += THE_2PI; } }
1637 if (aDY > 0.0) { while (aDY > THE_2PI) { aDY -= THE_2PI; } }
1638 else if(aDY < 0.0) { while (aDY < -THE_2PI) { aDY += THE_2PI; } }
1640 // rotate camera around 3 initial axes
1641 gp_Dir aCamDir (aCam->Direction().Reversed());
1642 gp_Dir aCamUp (aCam->Up());
1643 gp_Dir aCamSide(aCamUp.Crossed (aCamDir));
1645 gp_Trsf aRot[2], aTrsf;
1646 aRot[0].SetRotation (gp_Ax1 (myRotatePnt3d, aCamUp), -aDX);
1647 aRot[1].SetRotation (gp_Ax1 (myRotatePnt3d, aCamSide), aDY);
1648 aTrsf.Multiply (aRot[0]);
1649 aTrsf.Multiply (aRot[1]);
1651 aCam->Transform (aTrsf);
1654 theView->Invalidate();
1655 theView->View()->SynchronizeXRBaseToPosedCamera();
1658 // =======================================================================
1659 // function : handleViewRotation
1661 // =======================================================================
1662 void AIS_ViewController::handleViewRotation (const Handle(V3d_View)& theView,
1664 double thePitchExtra,
1666 bool theToRestartOnIncrement)
1668 if (!myToAllowRotation)
1673 const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1674 const bool toRotateAnyway = Abs (theYawExtra) > gp::Resolution()
1675 || Abs (thePitchExtra) > gp::Resolution()
1676 || Abs (theRoll - myRotateStartYawPitchRoll[2]) > gp::Resolution();
1678 && theToRestartOnIncrement)
1680 myGL.ViewRotation.ToStart = true;
1681 myGL.ViewRotation.PointTo = myGL.ViewRotation.PointStart;
1683 if (myGL.ViewRotation.ToStart)
1686 aTrsf.SetTransformation (gp_Ax3 (gp::Origin(), aCam->OrthogonalizedUp(), aCam->Direction()),
1687 gp_Ax3 (gp::Origin(), gp::DZ(), gp::DX()));
1688 const gp_Quaternion aRot = aTrsf.GetRotation();
1689 double aRollDummy = 0.0;
1690 aRot.GetEulerAngles (gp_YawPitchRoll, myRotateStartYawPitchRoll[0], myRotateStartYawPitchRoll[1], aRollDummy);
1694 myRotateStartYawPitchRoll[0] += theYawExtra;
1695 myRotateStartYawPitchRoll[1] += thePitchExtra;
1696 myRotateStartYawPitchRoll[2] = theRoll;
1697 myGL.ViewRotation.ToRotate = true;
1700 if (!myGL.ViewRotation.ToRotate)
1705 AbortViewAnimation();
1707 Graphic3d_Vec2i aWinXY;
1708 theView->Window()->Size (aWinXY.x(), aWinXY.y());
1709 double aYawAngleDelta = ((myGL.ViewRotation.PointStart.x() - myGL.ViewRotation.PointTo.x()) / double (aWinXY.x())) * (M_PI * 0.5);
1710 double aPitchAngleDelta = -((myGL.ViewRotation.PointStart.y() - myGL.ViewRotation.PointTo.y()) / double (aWinXY.y())) * (M_PI * 0.5);
1711 const double aPitchAngleNew = Max (Min (myRotateStartYawPitchRoll[1] + aPitchAngleDelta, M_PI * 0.5 - M_PI / 180.0), -M_PI * 0.5 + M_PI / 180.0);
1712 const double aYawAngleNew = myRotateStartYawPitchRoll[0] + aYawAngleDelta;
1714 aRot.SetEulerAngles (gp_YawPitchRoll, aYawAngleNew, aPitchAngleNew, theRoll);
1716 aTrsfRot.SetRotation (aRot);
1718 const gp_Dir aNewUp = gp::DZ().Transformed (aTrsfRot);
1719 const gp_Dir aNewDir = gp::DX().Transformed (aTrsfRot);
1720 aCam->SetUp (aNewUp);
1721 aCam->SetDirectionFromEye (aNewDir);
1722 aCam->OrthogonalizeUp();
1723 theView->Invalidate();
1726 // =======================================================================
1727 // function : PickPoint
1729 // =======================================================================
1730 bool AIS_ViewController::PickPoint (gp_Pnt& thePnt,
1731 const Handle(AIS_InteractiveContext)& theCtx,
1732 const Handle(V3d_View)& theView,
1733 const Graphic3d_Vec2i& theCursor,
1734 bool theToStickToPickRay)
1736 ResetPreviousMoveTo();
1738 const Handle(StdSelect_ViewerSelector3d)& aSelector = theCtx->MainSelector();
1739 aSelector->Pick (theCursor.x(), theCursor.y(), theView);
1740 if (aSelector->NbPicked() < 1)
1745 const SelectMgr_SortCriterion& aPicked = aSelector->PickedData (1);
1746 if (theToStickToPickRay
1747 && !Precision::IsInfinite (aPicked.Depth))
1749 thePnt = aSelector->GetManager().DetectedPoint (aPicked.Depth);
1753 thePnt = aSelector->PickedPoint (1);
1755 return !Precision::IsInfinite (thePnt.X())
1756 && !Precision::IsInfinite (thePnt.Y())
1757 && !Precision::IsInfinite (thePnt.Z());
1760 // =======================================================================
1761 // function : PickAxis
1763 // =======================================================================
1764 bool AIS_ViewController::PickAxis (gp_Pnt& theTopPnt,
1765 const Handle(AIS_InteractiveContext)& theCtx,
1766 const Handle(V3d_View)& theView,
1767 const gp_Ax1& theAxis)
1769 ResetPreviousMoveTo();
1771 const Handle(StdSelect_ViewerSelector3d)& aSelector = theCtx->MainSelector();
1772 aSelector->Pick (theAxis, theView);
1773 if (aSelector->NbPicked() < 1)
1778 const SelectMgr_SortCriterion& aPickedData = aSelector->PickedData (1);
1779 theTopPnt = aPickedData.Point;
1780 return !Precision::IsInfinite (theTopPnt.X())
1781 && !Precision::IsInfinite (theTopPnt.Y())
1782 && !Precision::IsInfinite (theTopPnt.Z());
1785 // =======================================================================
1786 // function : GravityPoint
1788 // =======================================================================
1789 gp_Pnt AIS_ViewController::GravityPoint (const Handle(AIS_InteractiveContext)& theCtx,
1790 const Handle(V3d_View)& theView)
1792 switch (myRotationMode)
1794 case AIS_RotationMode_PickLast:
1795 case AIS_RotationMode_PickCenter:
1797 Graphic3d_Vec2i aCursor ((int )myGL.OrbitRotation.PointStart.x(), (int )myGL.OrbitRotation.PointStart.y());
1798 if (myRotationMode == AIS_RotationMode_PickCenter)
1800 Graphic3d_Vec2i aViewPort;
1801 theView->Window()->Size (aViewPort.x(), aViewPort.y());
1802 aCursor = aViewPort / 2;
1806 if (PickPoint (aPnt, theCtx, theView, aCursor, myToStickToRayOnRotation))
1812 case AIS_RotationMode_CameraAt:
1814 const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1815 return aCam->Center();
1817 case AIS_RotationMode_BndBoxScene:
1819 Bnd_Box aBndBox = theView->View()->MinMaxValues (false);
1820 if (!aBndBox.IsVoid())
1822 return (aBndBox.CornerMin().XYZ() + aBndBox.CornerMax().XYZ()) * 0.5;
1826 case AIS_RotationMode_BndBoxActive:
1830 return theCtx ->GravityPoint (theView);
1833 // =======================================================================
1834 // function : FitAllAuto
1836 // =======================================================================
1837 void AIS_ViewController::FitAllAuto (const Handle(AIS_InteractiveContext)& theCtx,
1838 const Handle(V3d_View)& theView)
1840 const Bnd_Box aBoxSel = theCtx->BoundingBoxOfSelection();
1841 const double aFitMargin = 0.01;
1842 if (aBoxSel.IsVoid())
1844 theView->FitAll (aFitMargin, false);
1848 // fit all algorithm is not 100% stable - so compute some precision to compare equal camera values
1849 const double aFitTol = (aBoxSel.CornerMax().XYZ() - aBoxSel.CornerMin().XYZ()).Modulus() * 0.000001;
1850 const Bnd_Box aBoxAll = theView->View()->MinMaxValues();
1852 const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1853 Handle(Graphic3d_Camera) aCameraSel = new Graphic3d_Camera (aCam);
1854 Handle(Graphic3d_Camera) aCameraAll = new Graphic3d_Camera (aCam);
1855 theView->FitMinMax (aCameraSel, aBoxSel, aFitMargin);
1856 theView->FitMinMax (aCameraAll, aBoxAll, aFitMargin);
1857 if (aCameraSel->Center().IsEqual (aCam->Center(), aFitTol)
1858 && Abs (aCameraSel->Scale() - aCam->Scale()) < aFitTol
1859 && Abs (aCameraSel->Distance() - aCam->Distance()) < aFitTol)
1861 // fit all entire view on second FitALL request
1862 aCam->Copy (aCameraAll);
1866 aCam->Copy (aCameraSel);
1870 // =======================================================================
1871 // function : handleViewOrientationKeys
1873 // =======================================================================
1874 void AIS_ViewController::handleViewOrientationKeys (const Handle(AIS_InteractiveContext)& theCtx,
1875 const Handle(V3d_View)& theView)
1877 if (myNavigationMode == AIS_NavigationMode_FirstPersonWalk)
1882 Handle(Graphic3d_Camera) aCameraBack;
1883 struct ViewKeyAction
1886 V3d_TypeOfOrientation Orientation;
1888 static const ViewKeyAction THE_VIEW_KEYS[] =
1890 { Aspect_VKey_ViewTop, V3d_TypeOfOrientation_Zup_Top },
1891 { Aspect_VKey_ViewBottom, V3d_TypeOfOrientation_Zup_Bottom },
1892 { Aspect_VKey_ViewLeft, V3d_TypeOfOrientation_Zup_Left },
1893 { Aspect_VKey_ViewRight, V3d_TypeOfOrientation_Zup_Right },
1894 { Aspect_VKey_ViewFront, V3d_TypeOfOrientation_Zup_Front },
1895 { Aspect_VKey_ViewBack, V3d_TypeOfOrientation_Zup_Back },
1896 { Aspect_VKey_ViewAxoLeftProj, V3d_TypeOfOrientation_Zup_AxoLeft },
1897 { Aspect_VKey_ViewAxoRightProj, V3d_TypeOfOrientation_Zup_AxoRight },
1898 { Aspect_VKey_ViewRoll90CW, (V3d_TypeOfOrientation )-1},
1899 { Aspect_VKey_ViewRoll90CCW, (V3d_TypeOfOrientation )-1},
1900 { Aspect_VKey_ViewFitAll, (V3d_TypeOfOrientation )-1}
1903 Standard_Mutex::Sentry aLock (myKeys.Mutex());
1904 const size_t aNbKeys = sizeof(THE_VIEW_KEYS) / sizeof(*THE_VIEW_KEYS);
1905 const double anEventTime = EventTime();
1906 for (size_t aKeyIter = 0; aKeyIter < aNbKeys; ++aKeyIter)
1908 const ViewKeyAction& aKeyAction = THE_VIEW_KEYS[aKeyIter];
1909 if (!myKeys.IsKeyDown (aKeyAction.Key))
1914 myKeys.KeyUp (aKeyAction.Key, anEventTime);
1915 if (aCameraBack.IsNull())
1917 aCameraBack = theView->Camera();
1918 theView->SetCamera (new Graphic3d_Camera (aCameraBack));
1920 if (aKeyAction.Orientation != (V3d_TypeOfOrientation )-1)
1922 theView->SetProj (aKeyAction.Orientation);
1923 FitAllAuto (theCtx, theView);
1925 else if (aKeyAction.Key == Aspect_VKey_ViewRoll90CW)
1927 const double aTwist = theView->Twist() + M_PI / 2.0;
1928 theView->SetTwist (aTwist);
1930 else if (aKeyAction.Key == Aspect_VKey_ViewRoll90CCW)
1932 const double aTwist = theView->Twist() - M_PI / 2.0;
1933 theView->SetTwist (aTwist);
1935 else if (aKeyAction.Key == Aspect_VKey_ViewFitAll)
1937 FitAllAuto (theCtx, theView);
1942 if (aCameraBack.IsNull())
1947 Handle(Graphic3d_Camera) aCameraNew = theView->Camera();
1948 theView->SetCamera (aCameraBack);
1949 const Graphic3d_Mat4d anOrientMat1 = aCameraBack->OrientationMatrix();
1950 const Graphic3d_Mat4d anOrientMat2 = aCameraNew ->OrientationMatrix();
1951 if (anOrientMat1 != anOrientMat2)
1953 const Handle(AIS_AnimationCamera)& aCamAnim = myViewAnimation;
1954 aCamAnim->SetView (theView);
1955 aCamAnim->SetStartPts (0.0);
1956 aCamAnim->SetCameraStart (new Graphic3d_Camera (aCameraBack));
1957 aCamAnim->SetCameraEnd (new Graphic3d_Camera (aCameraNew));
1958 aCamAnim->StartTimer (0.0, 1.0, true, false);
1962 // =======================================================================
1963 // function : handleNavigationKeys
1965 // =======================================================================
1966 AIS_WalkDelta AIS_ViewController::handleNavigationKeys (const Handle(AIS_InteractiveContext)& ,
1967 const Handle(V3d_View)& theView)
1970 double aCrouchRatio = 1.0, aRunRatio = 1.0;
1971 if (myNavigationMode == AIS_NavigationMode_FirstPersonFlight)
1976 const double aRotSpeed = 0.5;
1977 const double aWalkSpeedCoef = WalkSpeedRelative();
1978 AIS_WalkDelta aWalk = FetchNavigationKeys (aCrouchRatio, aRunRatio);
1979 if (aWalk.IsJumping())
1983 theView->Invalidate();
1985 if (aWalk.IsEmpty())
1987 if (aWalk.IsDefined())
1993 else if (myGL.OrbitRotation.ToRotate
1994 || myGL.OrbitRotation.ToStart)
2000 const Bnd_Box aBndBox = theView->View()->MinMaxValues();
2001 if (!aBndBox.IsVoid())
2003 aMin = aBndBox.CornerMin().XYZ();
2004 aMax = aBndBox.CornerMax().XYZ();
2006 double aBndDiam = Max (Max (aMax.X() - aMin.X(), aMax.Y() - aMin.Y()), aMax.Z() - aMin.Z());
2007 if (aBndDiam <= gp::Resolution())
2012 const double aWalkSpeed = myNavigationMode != AIS_NavigationMode_Orbit
2013 && myNavigationMode != AIS_NavigationMode_FirstPersonFlight
2014 ? theView->View()->UnitFactor() * WalkSpeedAbsolute()
2015 : aWalkSpeedCoef * aBndDiam;
2016 const Handle(Graphic3d_Camera)& aCam = theView->View()->IsActiveXR()
2017 ? theView->View()->BaseXRCamera()
2018 : theView->Camera();
2020 // move forward in plane XY and up along Z
2021 const gp_Dir anUp = ToLockOrbitZUp() ? gp::DZ() : aCam->OrthogonalizedUp();
2023 && myToAllowPanning)
2025 const gp_Vec aSide = -aCam->SideRight();
2026 gp_XYZ aFwd = aCam->Direction().XYZ();
2027 aFwd -= anUp.XYZ() * (anUp.XYZ() * aFwd);
2030 if (!aWalk[AIS_WalkTranslation_Forward].IsEmpty())
2032 if (!aCam->IsOrthographic())
2034 aMoveVec += aFwd * aWalk[AIS_WalkTranslation_Forward].Value * aWalk[AIS_WalkTranslation_Forward].Pressure * aWalkSpeed;
2037 if (!aWalk[AIS_WalkTranslation_Side].IsEmpty())
2039 aMoveVec += aSide.XYZ() * aWalk[AIS_WalkTranslation_Side].Value * aWalk[AIS_WalkTranslation_Side].Pressure * aWalkSpeed;
2041 if (!aWalk[AIS_WalkTranslation_Up].IsEmpty())
2043 aMoveVec += anUp.XYZ() * aWalk[AIS_WalkTranslation_Up].Value * aWalk[AIS_WalkTranslation_Up].Pressure * aWalkSpeed;
2046 if (aCam->IsOrthographic())
2048 if (!aWalk[AIS_WalkTranslation_Forward].IsEmpty())
2050 const double aZoomDelta = aWalk[AIS_WalkTranslation_Forward].Value * aWalk[AIS_WalkTranslation_Forward].Pressure * aWalkSpeedCoef;
2051 handleZoom (theView, Aspect_ScrollDelta (aZoomDelta * 100.0), NULL);
2055 gp_Trsf aTrsfTranslate;
2056 aTrsfTranslate.SetTranslation (aMoveVec);
2057 aCam->Transform (aTrsfTranslate);
2061 if (myNavigationMode == AIS_NavigationMode_Orbit
2062 && myToAllowRotation)
2064 if (!aWalk[AIS_WalkRotation_Yaw].IsEmpty())
2067 aTrsfRot.SetRotation (gp_Ax1 (aCam->Eye(), anUp), aWalk[AIS_WalkRotation_Yaw].Value * aRotSpeed);
2068 aCam->Transform (aTrsfRot);
2070 if (!aWalk[AIS_WalkRotation_Pitch].IsEmpty())
2072 const gp_Vec aSide = -aCam->SideRight();
2074 aTrsfRot.SetRotation (gp_Ax1 (aCam->Eye(), aSide), -aWalk[AIS_WalkRotation_Pitch].Value * aRotSpeed);
2075 aCam->Transform (aTrsfRot);
2077 if (!aWalk[AIS_WalkRotation_Roll].IsEmpty()
2078 && !ToLockOrbitZUp())
2081 aTrsfRot.SetRotation (gp_Ax1 (aCam->Center(), aCam->Direction()), aWalk[AIS_WalkRotation_Roll].Value * aRotSpeed);
2082 aCam->Transform (aTrsfRot);
2088 theView->Invalidate();
2089 theView->View()->SynchronizeXRBaseToPosedCamera();
2093 // =======================================================================
2094 // function : handleCameraActions
2096 // =======================================================================
2097 void AIS_ViewController::handleCameraActions (const Handle(AIS_InteractiveContext)& theCtx,
2098 const Handle(V3d_View)& theView,
2099 const AIS_WalkDelta& theWalk)
2101 // apply view actions
2102 if (myGL.Orientation.ToSetViewOrient)
2104 theView->SetProj (myGL.Orientation.ViewOrient);
2105 myGL.Orientation.ToFitAll = true;
2109 if (myGL.Orientation.ToFitAll)
2111 const double aFitMargin = 0.01;
2112 theView->FitAll (aFitMargin, false);
2113 theView->Invalidate();
2114 myGL.Orientation.ToFitAll = false;
2117 if (myGL.IsNewGesture)
2119 if (myAnchorPointPrs1->HasInteractiveContext())
2121 theCtx->Remove (myAnchorPointPrs1, false);
2122 if (!theView->Viewer()->ZLayerSettings (myAnchorPointPrs1->ZLayer()).IsImmediate())
2124 theView->Invalidate();
2128 theView->InvalidateImmediate();
2131 if (myAnchorPointPrs2->HasInteractiveContext())
2133 theCtx->Remove (myAnchorPointPrs2, false);
2134 if (!theView->Viewer()->ZLayerSettings (myAnchorPointPrs2->ZLayer()).IsImmediate())
2136 theView->Invalidate();
2140 theView->InvalidateImmediate();
2144 if (myHasHlrOnBeforeRotation)
2146 myHasHlrOnBeforeRotation = false;
2147 theView->SetComputedMode (true);
2148 theView->Invalidate();
2152 if (myNavigationMode != AIS_NavigationMode_FirstPersonWalk)
2154 if (myGL.Panning.ToStart
2155 && myToAllowPanning)
2157 gp_Pnt aPanPnt (Precision::Infinite(), 0.0, 0.0);
2158 if (!theView->Camera()->IsOrthographic())
2160 bool toStickToRay = false;
2161 if (myGL.Panning.PointStart.x() >= 0
2162 && myGL.Panning.PointStart.y() >= 0)
2164 PickPoint (aPanPnt, theCtx, theView, myGL.Panning.PointStart, toStickToRay);
2166 if (Precision::IsInfinite (aPanPnt.X()))
2168 Graphic3d_Vec2i aWinSize;
2169 theView->Window()->Size (aWinSize.x(), aWinSize.y());
2170 PickPoint (aPanPnt, theCtx, theView, aWinSize / 2, toStickToRay);
2172 if (!Precision::IsInfinite (aPanPnt.X())
2173 && myToShowPanAnchorPoint)
2176 aPntTrsf.SetTranslation (gp_Vec (aPanPnt.XYZ()));
2177 theCtx->SetLocation (myAnchorPointPrs2, aPntTrsf);
2180 setPanningAnchorPoint (aPanPnt);
2183 if (myToShowPanAnchorPoint
2184 && hasPanningAnchorPoint()
2185 && myGL.Panning.ToPan
2186 && !myGL.IsNewGesture
2187 && !myAnchorPointPrs2->HasInteractiveContext())
2189 theCtx->Display (myAnchorPointPrs2, 0, -1, false, AIS_DS_Displayed);
2192 handlePanning (theView);
2193 handleZRotate (theView);
2196 if ((myNavigationMode == AIS_NavigationMode_Orbit
2197 || myGL.OrbitRotation.ToStart
2198 || myGL.OrbitRotation.ToRotate)
2199 && myToAllowRotation)
2201 if (myGL.OrbitRotation.ToStart
2202 && !myHasHlrOnBeforeRotation)
2204 myHasHlrOnBeforeRotation = theView->ComputedMode();
2205 if (myHasHlrOnBeforeRotation)
2207 theView->SetComputedMode (false);
2212 if (myGL.OrbitRotation.ToStart)
2214 aGravPnt = GravityPoint (theCtx, theView);
2215 if (myToShowRotateCenter)
2218 aPntTrsf.SetTranslation (gp_Vec (aGravPnt.XYZ()));
2219 theCtx->SetLocation (myAnchorPointPrs1, aPntTrsf);
2220 theCtx->SetLocation (myAnchorPointPrs2, aPntTrsf);
2224 if (myToShowRotateCenter
2225 && myGL.OrbitRotation.ToRotate
2226 && !myGL.IsNewGesture
2227 && !myAnchorPointPrs1->HasInteractiveContext())
2229 theCtx->Display (myAnchorPointPrs1, 0, -1, false, AIS_DS_Displayed);
2230 theCtx->Display (myAnchorPointPrs2, 0, -1, false, AIS_DS_Displayed);
2232 handleOrbitRotation (theView, aGravPnt,
2233 myToLockOrbitZUp || myNavigationMode != AIS_NavigationMode_Orbit);
2236 if ((myNavigationMode != AIS_NavigationMode_Orbit
2237 || myGL.ViewRotation.ToStart
2238 || myGL.ViewRotation.ToRotate)
2239 && myToAllowRotation)
2241 if (myGL.ViewRotation.ToStart
2242 && !myHasHlrOnBeforeRotation)
2244 myHasHlrOnBeforeRotation = theView->ComputedMode();
2245 if (myHasHlrOnBeforeRotation)
2247 theView->SetComputedMode (false);
2252 if (!theWalk[AIS_WalkRotation_Roll].IsEmpty()
2253 && !myToLockOrbitZUp)
2255 aRoll = (M_PI / 12.0) * theWalk[AIS_WalkRotation_Roll].Pressure;
2256 aRoll *= Min (1000.0 * theWalk[AIS_WalkRotation_Roll].Duration, 100.0) / 100.0;
2257 if (theWalk[AIS_WalkRotation_Roll].Value < 0.0)
2263 handleViewRotation (theView, theWalk[AIS_WalkRotation_Yaw].Value, theWalk[AIS_WalkRotation_Pitch].Value, aRoll,
2264 myNavigationMode == AIS_NavigationMode_FirstPersonFlight);
2267 if (!myGL.ZoomActions.IsEmpty())
2269 for (NCollection_Sequence<Aspect_ScrollDelta>::Iterator aZoomIter (myGL.ZoomActions); aZoomIter.More(); aZoomIter.Next())
2271 Aspect_ScrollDelta aZoomParams = aZoomIter.Value();
2273 && (aZoomParams.Flags & Aspect_VKeyFlags_CTRL) != 0
2274 && theView->Camera()->IsStereo())
2276 handleZFocusScroll (theView, aZoomParams);
2280 if (!myToAllowZooming)
2285 if (!theView->Camera()->IsOrthographic())
2288 if (aZoomParams.HasPoint()
2289 && PickPoint (aPnt, theCtx, theView, aZoomParams.Point, myToStickToRayOnZoom))
2291 handleZoom (theView, aZoomParams, &aPnt);
2295 Graphic3d_Vec2i aWinSize;
2296 theView->Window()->Size (aWinSize.x(), aWinSize.y());
2297 if (PickPoint (aPnt, theCtx, theView, aWinSize / 2, myToStickToRayOnZoom))
2299 aZoomParams.ResetPoint(); // do not pretend to zoom at 'nothing'
2300 handleZoom (theView, aZoomParams, &aPnt);
2304 handleZoom (theView, aZoomParams, NULL);
2306 myGL.ZoomActions.Clear();
2310 // =======================================================================
2311 // function : handleXRInput
2313 // =======================================================================
2314 void AIS_ViewController::handleXRInput (const Handle(AIS_InteractiveContext)& theCtx,
2315 const Handle(V3d_View)& theView,
2316 const AIS_WalkDelta& )
2318 theView->View()->ProcessXRInput();
2319 if (!theView->View()->IsActiveXR())
2323 handleXRTurnPad (theCtx, theView);
2324 handleXRTeleport(theCtx, theView);
2325 handleXRPicking (theCtx, theView);
2328 // =======================================================================
2329 // function : handleXRTurnPad
2331 // =======================================================================
2332 void AIS_ViewController::handleXRTurnPad (const Handle(AIS_InteractiveContext)& ,
2333 const Handle(V3d_View)& theView)
2335 if (myXRTurnAngle <= 0.0
2336 || !theView->View()->IsActiveXR())
2341 // turn left/right at 45 degrees on left/right trackpad clicks
2342 for (int aHand = 0; aHand < 2; ++aHand)
2344 const Aspect_XRTrackedDeviceRole aRole = aHand == 0 ? Aspect_XRTrackedDeviceRole_RightHand : Aspect_XRTrackedDeviceRole_LeftHand;
2345 const Handle(Aspect_XRAction)& aPadClickAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTrackPadClick);
2346 const Handle(Aspect_XRAction)& aPadPosAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTrackPadPosition);
2347 if (aPadClickAct.IsNull()
2348 || aPadPosAct.IsNull())
2353 const Aspect_XRDigitalActionData aPadClick = theView->View()->XRSession()->GetDigitalActionData (aPadClickAct);
2354 const Aspect_XRAnalogActionData aPadPos = theView->View()->XRSession()->GetAnalogActionData (aPadPosAct);
2355 if (aPadClick.IsActive
2356 && aPadClick.IsPressed
2357 && aPadClick.IsChanged
2359 && Abs (aPadPos.VecXYZ.y()) < 0.5f
2360 && Abs (aPadPos.VecXYZ.x()) > 0.7f)
2363 aTrsfTurn.SetRotation (gp_Ax1 (gp::Origin(), theView->View()->BaseXRCamera()->Up()), aPadPos.VecXYZ.x() < 0.0f ? myXRTurnAngle : -myXRTurnAngle);
2364 theView->View()->TurnViewXRCamera (aTrsfTurn);
2370 // =======================================================================
2371 // function : handleXRTeleport
2373 // =======================================================================
2374 void AIS_ViewController::handleXRTeleport (const Handle(AIS_InteractiveContext)& theCtx,
2375 const Handle(V3d_View)& theView)
2377 if (!theView->View()->IsActiveXR())
2382 // teleport on forward trackpad unclicks
2383 const Aspect_XRTrackedDeviceRole aTeleOld = myXRLastTeleportHand;
2384 myXRLastTeleportHand = Aspect_XRTrackedDeviceRole_Other;
2385 for (int aHand = 0; aHand < 2; ++aHand)
2387 const Aspect_XRTrackedDeviceRole aRole = aHand == 0 ? Aspect_XRTrackedDeviceRole_RightHand : Aspect_XRTrackedDeviceRole_LeftHand;
2388 const Standard_Integer aDeviceId = theView->View()->XRSession()->NamedTrackedDevice (aRole);
2389 if (aDeviceId == -1)
2394 const Handle(Aspect_XRAction)& aPadClickAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTrackPadClick);
2395 const Handle(Aspect_XRAction)& aPadPosAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTrackPadPosition);
2396 if (aPadClickAct.IsNull()
2397 || aPadPosAct.IsNull())
2402 const Aspect_XRDigitalActionData aPadClick = theView->View()->XRSession()->GetDigitalActionData (aPadClickAct);
2403 const Aspect_XRAnalogActionData aPadPos = theView->View()->XRSession()->GetAnalogActionData (aPadPosAct);
2404 const bool isPressed = aPadClick.IsPressed;
2405 const bool isClicked = !aPadClick.IsPressed
2406 && aPadClick.IsChanged;
2407 if (aPadClick.IsActive
2408 && (isPressed || isClicked)
2410 && aPadPos.VecXYZ.y() > 0.6f
2411 && Abs (aPadPos.VecXYZ.x()) < 0.5f)
2413 const Aspect_TrackedDevicePose& aPose = theView->View()->XRSession()->TrackedPoses()[aDeviceId];
2414 if (!aPose.IsValidPose)
2419 myXRLastTeleportHand = aRole;
2420 Standard_Real& aPickDepth = aRole == Aspect_XRTrackedDeviceRole_LeftHand ? myXRLastPickDepthLeft : myXRLastPickDepthRight;
2421 aPickDepth = Precision::Infinite();
2422 Graphic3d_Vec3 aPickNorm;
2423 const gp_Trsf aHandBase = theView->View()->PoseXRToWorld (aPose.Orientation);
2424 const Standard_Real aHeadHeight = theView->View()->XRSession()->HeadPose().TranslationPart().Y();
2426 const Standard_Integer aPickedId = handleXRMoveTo (theCtx, theView, aPose.Orientation, false);
2429 const SelectMgr_SortCriterion& aPickedData = theCtx->MainSelector()->PickedData (aPickedId);
2430 aPickNorm = aPickedData.Normal;
2431 if (aPickNorm.SquareModulus() > ShortRealEpsilon())
2433 aPickDepth = aPickedData.Point.Distance (aHandBase.TranslationPart());
2439 myXRLastTeleportHand = Aspect_XRTrackedDeviceRole_Other;
2440 if (!Precision::IsInfinite (aPickDepth))
2442 const gp_Dir aTeleDir = -gp::DZ().Transformed (aHandBase);
2443 const gp_Dir anUpDir = theView->View()->BaseXRCamera()->Up();
2445 bool isHorizontal = false;
2446 gp_Dir aPickNormDir (aPickNorm.x(), aPickNorm.y(), aPickNorm.z());
2447 if (anUpDir.IsEqual ( aPickNormDir, M_PI_4)
2448 || anUpDir.IsEqual (-aPickNormDir, M_PI_4))
2450 isHorizontal = true;
2453 gp_Pnt aNewEye = aHandBase.TranslationPart();
2456 aNewEye = aHandBase.TranslationPart()
2457 + aTeleDir.XYZ() * aPickDepth
2458 + anUpDir.XYZ() * aHeadHeight;
2462 if (aPickNormDir.Dot (aTeleDir) < 0.0)
2464 aPickNormDir.Reverse();
2466 aNewEye = aHandBase.TranslationPart()
2467 + aTeleDir.XYZ() * aPickDepth
2468 - aPickNormDir.XYZ() * aHeadHeight / 4;
2471 theView->View()->PosedXRCamera()->MoveEyeTo (aNewEye);
2472 theView->View()->ComputeXRBaseCameraFromPosed (theView->View()->PosedXRCamera(), theView->View()->XRSession()->HeadPose());
2479 if (myXRLastTeleportHand != aTeleOld)
2481 if (aTeleOld != Aspect_XRTrackedDeviceRole_Other)
2483 if (const Handle(Aspect_XRAction)& aHaptic = theView->View()->XRSession()->GenericAction (aTeleOld, Aspect_XRGenericAction_OutputHaptic))
2485 theView->View()->XRSession()->AbortHapticVibrationAction (aHaptic);
2488 if (myXRLastTeleportHand != Aspect_XRTrackedDeviceRole_Other)
2490 if (const Handle(Aspect_XRAction)& aHaptic = theView->View()->XRSession()->GenericAction (myXRLastTeleportHand, Aspect_XRGenericAction_OutputHaptic))
2492 theView->View()->XRSession()->TriggerHapticVibrationAction (aHaptic, myXRTeleportHaptic);
2498 // =======================================================================
2499 // function : handleXRPicking
2501 // =======================================================================
2502 void AIS_ViewController::handleXRPicking (const Handle(AIS_InteractiveContext)& theCtx,
2503 const Handle(V3d_View)& theView)
2505 if (!theView->View()->IsActiveXR())
2510 // handle selection on trigger clicks
2511 Aspect_XRTrackedDeviceRole aPickDevOld = myXRLastPickingHand;
2512 myXRLastPickingHand = Aspect_XRTrackedDeviceRole_Other;
2513 for (int aHand = 0; aHand < 2; ++aHand)
2515 const Aspect_XRTrackedDeviceRole aRole = aHand == 0 ? Aspect_XRTrackedDeviceRole_RightHand : Aspect_XRTrackedDeviceRole_LeftHand;
2516 const Handle(Aspect_XRAction)& aTrigClickAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTriggerClick);
2517 const Handle(Aspect_XRAction)& aTrigPullAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTriggerPull);
2518 if (aTrigClickAct.IsNull()
2519 || aTrigPullAct.IsNull())
2524 const Aspect_XRDigitalActionData aTrigClick = theView->View()->XRSession()->GetDigitalActionData (aTrigClickAct);
2525 const Aspect_XRAnalogActionData aTrigPos = theView->View()->XRSession()->GetAnalogActionData (aTrigPullAct);
2526 if (aTrigPos.IsActive
2527 && Abs (aTrigPos.VecXYZ.x()) > 0.1f)
2529 myXRLastPickingHand = aRole;
2530 handleXRHighlight (theCtx, theView);
2531 if (aTrigClick.IsActive
2532 && aTrigClick.IsPressed
2533 && aTrigClick.IsChanged)
2535 theCtx->SelectDetected();
2536 OnSelectionChanged (theCtx, theView);
2537 if (const Handle(Aspect_XRAction)& aHaptic = theView->View()->XRSession()->GenericAction (myXRLastPickingHand, Aspect_XRGenericAction_OutputHaptic))
2539 theView->View()->XRSession()->TriggerHapticVibrationAction (aHaptic, myXRSelectHaptic);
2545 if (myXRLastPickingHand != aPickDevOld)
2547 theCtx->ClearDetected();
2551 // =======================================================================
2552 // function : OnSelectionChanged
2554 // =======================================================================
2555 void AIS_ViewController::OnSelectionChanged (const Handle(AIS_InteractiveContext)& ,
2556 const Handle(V3d_View)& )
2561 // =======================================================================
2562 // function : OnObjectDragged
2564 // =======================================================================
2565 void AIS_ViewController::OnObjectDragged (const Handle(AIS_InteractiveContext)& theCtx,
2566 const Handle(V3d_View)& theView,
2567 AIS_DragAction theAction)
2571 case AIS_DragAction_Start:
2573 myDragObject.Nullify();
2574 myDragOwner.Nullify();
2575 if (!theCtx->HasDetected())
2580 const Handle(SelectMgr_EntityOwner)& aDetectedOwner = theCtx->DetectedOwner();
2581 Handle(AIS_InteractiveObject) aDetectedPrs = Handle(AIS_InteractiveObject)::DownCast (aDetectedOwner->Selectable());
2583 if (aDetectedPrs->ProcessDragging (theCtx, theView, aDetectedOwner, myGL.Dragging.PointStart,
2584 myGL.Dragging.PointTo, theAction))
2586 myDragObject = aDetectedPrs;
2587 myDragOwner = aDetectedOwner;
2591 case AIS_DragAction_Update:
2593 if (myDragObject.IsNull())
2598 if (Handle(SelectMgr_EntityOwner) aGlobOwner = myDragObject->GlobalSelOwner())
2600 theCtx->SetSelectedState (aGlobOwner, true);
2603 myDragObject->ProcessDragging (theCtx, theView, myDragOwner, myGL.Dragging.PointStart,
2604 myGL.Dragging.PointTo, theAction);
2605 theView->Invalidate();
2608 case AIS_DragAction_Abort:
2610 if (myDragObject.IsNull())
2615 myGL.Dragging.PointTo = myGL.Dragging.PointStart;
2616 OnObjectDragged (theCtx, theView, AIS_DragAction_Update);
2618 myDragObject->ProcessDragging (theCtx, theView, myDragOwner, myGL.Dragging.PointStart,
2619 myGL.Dragging.PointTo, theAction);
2620 Standard_FALLTHROUGH
2622 case AIS_DragAction_Stop:
2624 if (myDragObject.IsNull())
2629 if (Handle(SelectMgr_EntityOwner) aGlobOwner = myDragObject->GlobalSelOwner())
2631 theCtx->SetSelectedState (aGlobOwner, false);
2634 myDragObject->ProcessDragging (theCtx, theView, myDragOwner, myGL.Dragging.PointStart,
2635 myGL.Dragging.PointTo, theAction);
2636 theView->Invalidate();
2637 myDragObject.Nullify();
2638 myDragOwner.Nullify();
2644 // =======================================================================
2645 // function : contextLazyMoveTo
2647 // =======================================================================
2648 void AIS_ViewController::contextLazyMoveTo (const Handle(AIS_InteractiveContext)& theCtx,
2649 const Handle(V3d_View)& theView,
2650 const Graphic3d_Vec2i& thePnt)
2652 if (myPrevMoveTo == thePnt
2653 || myHasHlrOnBeforeRotation) // ignore highlighting in-between rotation of HLR view
2658 myPrevMoveTo = thePnt;
2660 Handle(SelectMgr_EntityOwner) aLastPicked = theCtx->DetectedOwner();
2662 // Picking relies on the camera frustum (including Z-range) - so make temporary AutoZFit()
2663 // and then restore previous frustum to avoid immediate layer rendering issues if View has not been invalidated.
2664 const Standard_Real aZNear = theView->Camera()->ZNear(), aZFar = theView->Camera()->ZFar();
2665 theView->AutoZFit();
2666 theCtx->MoveTo (thePnt.x(), thePnt.y(), theView, false);
2667 theView->Camera()->SetZRange (aZNear, aZFar);
2669 Handle(SelectMgr_EntityOwner) aNewPicked = theCtx->DetectedOwner();
2671 if (theView->Viewer()->IsGridActive()
2672 && theView->Viewer()->GridEcho())
2674 if (aNewPicked.IsNull())
2676 Graphic3d_Vec3d aPnt3d;
2677 theView->ConvertToGrid (thePnt.x(), thePnt.y(), aPnt3d[0], aPnt3d[1], aPnt3d[2]);
2678 theView->Viewer()->ShowGridEcho (theView, Graphic3d_Vertex (aPnt3d[0], aPnt3d[1], aPnt3d[2]));
2679 theView->InvalidateImmediate();
2683 theView->Viewer()->HideGridEcho (theView);
2684 theView->InvalidateImmediate();
2688 if (aLastPicked != aNewPicked
2689 || (!aNewPicked.IsNull() && aNewPicked->IsForcedHilight()))
2691 // dynamic highlight affects all Views
2692 for (V3d_ListOfViewIterator aViewIter (theView->Viewer()->ActiveViewIterator()); aViewIter.More(); aViewIter.Next())
2694 const Handle(V3d_View)& aView = aViewIter.Value();
2695 aView->InvalidateImmediate();
2700 // =======================================================================
2701 // function : handleSelectionPick
2703 // =======================================================================
2704 void AIS_ViewController::handleSelectionPick (const Handle(AIS_InteractiveContext)& theCtx,
2705 const Handle(V3d_View)& theView)
2707 if (myGL.Selection.Tool == AIS_ViewSelectionTool_Picking
2708 && !myGL.Selection.Points.IsEmpty())
2710 for (NCollection_Sequence<Graphic3d_Vec2i>::Iterator aPntIter (myGL.Selection.Points); aPntIter.More(); aPntIter.Next())
2712 const bool hadPrevMoveTo = HasPreviousMoveTo();
2713 contextLazyMoveTo (theCtx, theView, aPntIter.Value());
2716 ResetPreviousMoveTo();
2719 theCtx->SelectDetected (myGL.Selection.Scheme);
2721 // selection affects all Views
2722 theView->Viewer()->Invalidate();
2724 OnSelectionChanged (theCtx, theView);
2727 myGL.Selection.Points.Clear();
2731 // =======================================================================
2732 // function : handleSelectionPoly
2734 // =======================================================================
2735 void AIS_ViewController::handleSelectionPoly (const Handle(AIS_InteractiveContext)& theCtx,
2736 const Handle(V3d_View)& theView)
2738 // rubber-band & window polygon selection
2739 if (myGL.Selection.Tool == AIS_ViewSelectionTool_RubberBand
2740 || myGL.Selection.Tool == AIS_ViewSelectionTool_Polygon
2741 || myGL.Selection.Tool == AIS_ViewSelectionTool_ZoomWindow)
2743 if (!myGL.Selection.Points.IsEmpty())
2745 myRubberBand->ClearPoints();
2746 myRubberBand->SetToUpdate();
2748 const bool anIsRubber = myGL.Selection.Tool == AIS_ViewSelectionTool_RubberBand
2749 || myGL.Selection.Tool == AIS_ViewSelectionTool_ZoomWindow;
2752 myRubberBand->SetRectangle (myGL.Selection.Points.First().x(), -myGL.Selection.Points.First().y(),
2753 myGL.Selection.Points.Last().x(), -myGL.Selection.Points.Last().y());
2757 Graphic3d_Vec2i aPrev (IntegerLast(), IntegerLast());
2758 for (NCollection_Sequence<Graphic3d_Vec2i>::Iterator aSelIter (myGL.Selection.Points); aSelIter.More(); aSelIter.Next())
2760 Graphic3d_Vec2i aPntNew = Graphic3d_Vec2i (aSelIter.Value().x(), -aSelIter.Value().y());
2761 if (aPntNew != aPrev)
2764 myRubberBand->AddPoint (Graphic3d_Vec2i (aSelIter.Value().x(), -aSelIter.Value().y()));
2769 myRubberBand->SetPolygonClosed (anIsRubber);
2772 theCtx->Display (myRubberBand, 0, -1, false, AIS_DS_Displayed);
2774 catch (const Standard_Failure& theEx)
2776 Message::SendWarning (TCollection_AsciiString ("Internal error while displaying rubber-band: ")
2777 + theEx.DynamicType()->Name() + ", " + theEx.GetMessageString());
2778 myRubberBand->ClearPoints();
2780 if (!theView->Viewer()->ZLayerSettings (myRubberBand->ZLayer()).IsImmediate())
2782 theView->Invalidate();
2786 theView->InvalidateImmediate();
2789 else if (!myRubberBand.IsNull()
2790 && myRubberBand->HasInteractiveContext())
2792 theCtx->Remove (myRubberBand, false);
2793 myRubberBand->ClearPoints();
2797 if (myGL.Selection.ToApplyTool)
2799 myGL.Selection.ToApplyTool = false;
2800 if (theCtx->IsDisplayed (myRubberBand))
2802 theCtx->Remove (myRubberBand, false);
2804 const NCollection_Sequence<Graphic3d_Vec2i>& aPoints = myRubberBand->Points();
2805 if (aPoints.Size() == 4
2806 && aPoints.Value (1).x() == aPoints.Value (2).x()
2807 && aPoints.Value (3).x() == aPoints.Value (4).x()
2808 && aPoints.Value (1).y() == aPoints.Value (4).y()
2809 && aPoints.Value (2).y() == aPoints.Value (3).y())
2811 const Graphic3d_Vec2i aPnt1 (aPoints.Value (1).x(), -aPoints.Value (1).y());
2812 const Graphic3d_Vec2i aPnt2 (aPoints.Value (3).x(), -aPoints.Value (3).y());
2813 if (myGL.Selection.Tool == AIS_ViewSelectionTool_ZoomWindow)
2815 theView->WindowFitAll (aPnt1.x(), aPnt1.y(), aPnt2.x(), aPnt2.y());
2816 theView->Invalidate();
2820 theCtx->MainSelector()->AllowOverlapDetection (aPnt1.y() != Min (aPnt1.y(), aPnt2.y()));
2821 theCtx->SelectRectangle (Graphic3d_Vec2i (Min (aPnt1.x(), aPnt2.x()), Min (aPnt1.y(), aPnt2.y())),
2822 Graphic3d_Vec2i (Max (aPnt1.x(), aPnt2.x()), Max (aPnt1.y(), aPnt2.y())),
2824 myGL.Selection.Scheme);
2825 theCtx->MainSelector()->AllowOverlapDetection (false);
2828 else if (aPoints.Length() >= 3)
2830 TColgp_Array1OfPnt2d aPolyline (1, aPoints.Length());
2831 TColgp_Array1OfPnt2d::Iterator aPolyIter (aPolyline);
2832 for (NCollection_Sequence<Graphic3d_Vec2i>::Iterator aSelIter (aPoints);
2833 aSelIter.More(); aSelIter.Next(), aPolyIter.Next())
2835 const Graphic3d_Vec2i& aNewPnt = aSelIter.Value();
2836 aPolyIter.ChangeValue() = gp_Pnt2d (aNewPnt.x(), -aNewPnt.y());
2839 theCtx->SelectPolygon (aPolyline, theView, myGL.Selection.Scheme);
2840 theCtx->MainSelector()->AllowOverlapDetection (false);
2844 myRubberBand->ClearPoints();
2845 if (myGL.Selection.Tool != AIS_ViewSelectionTool_ZoomWindow)
2847 // selection affects all Views
2848 theView->Viewer()->Invalidate();
2849 OnSelectionChanged (theCtx, theView);
2855 // =======================================================================
2856 // function : handleDynamicHighlight
2858 // =======================================================================
2859 void AIS_ViewController::handleDynamicHighlight (const Handle(AIS_InteractiveContext)& theCtx,
2860 const Handle(V3d_View)& theView)
2862 if ((myGL.MoveTo.ToHilight || myGL.Dragging.ToStart)
2863 && myNavigationMode != AIS_NavigationMode_FirstPersonWalk)
2865 const Graphic3d_Vec2i& aMoveToPnt = myGL.MoveTo.ToHilight ? myGL.MoveTo.Point : myGL.Dragging.PointStart;
2866 if (myGL.Dragging.ToStart && (!myGL.MoveTo.ToHilight || !myToAllowHighlight)
2867 && !HasPreviousMoveTo())
2869 contextLazyMoveTo (theCtx, theView, aMoveToPnt);
2870 ResetPreviousMoveTo();
2871 OnObjectDragged (theCtx, theView, AIS_DragAction_Start);
2872 theCtx->ClearDetected();
2874 else if (myToAllowHighlight)
2876 if (myPrevMoveTo != aMoveToPnt
2877 || (!theView->View()->IsActiveXR()
2878 && (myGL.OrbitRotation.ToRotate
2879 || myGL.ViewRotation.ToRotate
2880 || theView->IsInvalidated())))
2882 ResetPreviousMoveTo();
2883 contextLazyMoveTo (theCtx, theView, aMoveToPnt);
2885 if (myGL.Dragging.ToStart)
2887 OnObjectDragged (theCtx, theView, AIS_DragAction_Start);
2891 myGL.MoveTo.ToHilight = false;
2894 if (!myDragObject.IsNull())
2896 if (myGL.Dragging.ToAbort)
2898 OnObjectDragged (theCtx, theView, AIS_DragAction_Abort);
2899 myGL.OrbitRotation.ToRotate = false;
2900 myGL.ViewRotation .ToRotate = false;
2902 else if (myGL.Dragging.ToStop)
2904 OnObjectDragged (theCtx, theView, AIS_DragAction_Stop);
2905 myGL.OrbitRotation.ToRotate = false;
2906 myGL.ViewRotation .ToRotate = false;
2908 else if (myGL.OrbitRotation.ToRotate
2909 || myGL.ViewRotation.ToRotate)
2911 OnObjectDragged (theCtx, theView, AIS_DragAction_Update);
2912 myGL.OrbitRotation.ToRotate = false;
2913 myGL.ViewRotation .ToRotate = false;
2918 // =======================================================================
2919 // function : handleMoveTo
2921 // =======================================================================
2922 void AIS_ViewController::handleMoveTo (const Handle(AIS_InteractiveContext)& theCtx,
2923 const Handle(V3d_View)& theView)
2925 handleSelectionPick (theCtx, theView);
2926 handleDynamicHighlight(theCtx, theView);
2927 handleSelectionPoly (theCtx, theView);
2930 // =======================================================================
2931 // function : handleViewRedraw
2933 // =======================================================================
2934 void AIS_ViewController::handleViewRedraw (const Handle(AIS_InteractiveContext)& ,
2935 const Handle(V3d_View)& theView)
2937 // manage animation state
2938 if (!myViewAnimation.IsNull()
2939 && !myViewAnimation->IsStopped())
2941 myViewAnimation->UpdateTimer();
2942 ResetPreviousMoveTo();
2946 if (theView->View()->IsActiveXR())
2948 // VR requires continuous rendering
2949 myToAskNextFrame = true;
2952 for (V3d_ListOfViewIterator aViewIter (theView->Viewer()->ActiveViewIterator()); aViewIter.More(); aViewIter.Next())
2954 const Handle(V3d_View)& aView = aViewIter.Value();
2955 if (aView->IsInvalidated()
2956 || (myToAskNextFrame && aView == theView))
2958 if (aView->ComputedMode())
2967 else if (aView->IsInvalidatedImmediate())
2969 aView->RedrawImmediate();
2973 if (myToAskNextFrame)
2976 theView->Window()->InvalidateContent (Handle(Aspect_DisplayConnection)());
2980 // =======================================================================
2981 // function : handleXRMoveTo
2983 // =======================================================================
2984 Standard_Integer AIS_ViewController::handleXRMoveTo (const Handle(AIS_InteractiveContext)& theCtx,
2985 const Handle(V3d_View)& theView,
2986 const gp_Trsf& thePose,
2987 const Standard_Boolean theToHighlight)
2989 //ResetPreviousMoveTo();
2990 const gp_Ax1 aViewAxis = theView->View()->ViewAxisInWorld (thePose);
2991 Standard_Integer aPickResult = 0;
2994 theCtx->MoveTo (aViewAxis, theView, false);
2995 if (!theCtx->DetectedOwner().IsNull())
3002 theCtx->MainSelector()->Pick (aViewAxis, theView);
3003 if (theCtx->MainSelector()->NbPicked() >= 1)
3012 // =======================================================================
3013 // function : handleXRHighlight
3015 // =======================================================================
3016 void AIS_ViewController::handleXRHighlight (const Handle(AIS_InteractiveContext)& theCtx,
3017 const Handle(V3d_View)& theView)
3019 if (myXRLastPickingHand != Aspect_XRTrackedDeviceRole_LeftHand
3020 && myXRLastPickingHand != Aspect_XRTrackedDeviceRole_RightHand)
3025 const Standard_Integer aDeviceId = theView->View()->XRSession()->NamedTrackedDevice (myXRLastPickingHand);
3026 if (aDeviceId == -1)
3031 const Aspect_TrackedDevicePose& aPose = theView->View()->XRSession()->TrackedPoses()[aDeviceId];
3032 if (!aPose.IsValidPose)
3037 Handle(SelectMgr_EntityOwner) aDetOld = theCtx->DetectedOwner();
3038 handleXRMoveTo (theCtx, theView, aPose.Orientation, true);
3039 if (!theCtx->DetectedOwner().IsNull()
3040 && theCtx->DetectedOwner() != aDetOld)
3042 if (const Handle(Aspect_XRAction)& aHaptic = theView->View()->XRSession()->GenericAction (myXRLastPickingHand, Aspect_XRGenericAction_OutputHaptic))
3044 theView->View()->XRSession()->TriggerHapticVibrationAction (aHaptic, myXRPickingHaptic);
3048 Standard_Real& aPickDepth = myXRLastPickingHand == Aspect_XRTrackedDeviceRole_LeftHand ? myXRLastPickDepthLeft : myXRLastPickDepthRight;
3049 aPickDepth = Precision::Infinite();
3050 if (theCtx->MainSelector()->NbPicked() > 0)
3052 const gp_Trsf aHandBase = theView->View()->PoseXRToWorld (aPose.Orientation);
3053 const SelectMgr_SortCriterion& aPicked = theCtx->MainSelector()->PickedData (1);
3054 aPickDepth = aPicked.Point.Distance (aHandBase.TranslationPart());
3058 // =======================================================================
3059 // function : handleXRPresentations
3061 // =======================================================================
3062 void AIS_ViewController::handleXRPresentations (const Handle(AIS_InteractiveContext)& theCtx,
3063 const Handle(V3d_View)& theView)
3065 if (!theView->View()->IsActiveXR()
3066 || (!myToDisplayXRAuxDevices
3067 && !myToDisplayXRHands))
3069 for (NCollection_Array1<Handle(AIS_XRTrackedDevice)>::Iterator aPrsIter (myXRPrsDevices); aPrsIter.More(); aPrsIter.Next())
3071 if (!aPrsIter.Value().IsNull()
3072 && aPrsIter.Value()->HasInteractiveContext())
3074 theCtx->Remove (aPrsIter.Value(), false);
3076 aPrsIter.ChangeValue().Nullify();
3081 if (myXRPrsDevices.Length() != theView->View()->XRSession()->TrackedPoses().Length())
3083 for (NCollection_Array1<Handle(AIS_XRTrackedDevice)>::Iterator aPrsIter (myXRPrsDevices); aPrsIter.More(); aPrsIter.Next())
3085 if (!aPrsIter.Value().IsNull())
3087 theCtx->Remove (aPrsIter.Value(), false);
3090 myXRPrsDevices.Resize (theView->View()->XRSession()->TrackedPoses().Lower(), theView->View()->XRSession()->TrackedPoses().Upper(), false);
3093 const Standard_Integer aHeadDevice = theView->View()->XRSession()->NamedTrackedDevice (Aspect_XRTrackedDeviceRole_Head);
3094 const Standard_Integer aLeftDevice = theView->View()->XRSession()->NamedTrackedDevice (Aspect_XRTrackedDeviceRole_LeftHand);
3095 const Standard_Integer aRightDevice = theView->View()->XRSession()->NamedTrackedDevice (Aspect_XRTrackedDeviceRole_RightHand);
3096 for (Standard_Integer aDeviceIter = theView->View()->XRSession()->TrackedPoses().Lower(); aDeviceIter <= theView->View()->XRSession()->TrackedPoses().Upper(); ++aDeviceIter)
3098 const Aspect_TrackedDevicePose& aPose = theView->View()->XRSession()->TrackedPoses()[aDeviceIter];
3099 Handle(AIS_XRTrackedDevice)& aPosePrs = myXRPrsDevices[aDeviceIter];
3100 if (!aPose.IsValidPose)
3105 const bool isHand = aDeviceIter == aLeftDevice
3106 || aDeviceIter == aRightDevice;
3107 if ((!myToDisplayXRHands && isHand)
3108 || (!myToDisplayXRAuxDevices && !isHand))
3110 if (!aPosePrs.IsNull()
3111 && aPosePrs->HasInteractiveContext())
3113 theCtx->Remove (aPosePrs, false);
3118 Aspect_XRTrackedDeviceRole aRole = Aspect_XRTrackedDeviceRole_Other;
3119 if (aDeviceIter == aLeftDevice)
3121 aRole = Aspect_XRTrackedDeviceRole_LeftHand;
3123 else if (aDeviceIter == aRightDevice)
3125 aRole = Aspect_XRTrackedDeviceRole_RightHand;
3128 if (!aPosePrs.IsNull()
3129 && aPosePrs->UnitFactor() != (float )theView->View()->UnitFactor())
3131 theCtx->Remove (aPosePrs, false);
3135 if (aPosePrs.IsNull())
3137 Handle(Image_Texture) aTexture;
3138 Handle(Graphic3d_ArrayOfTriangles) aTris;
3139 if (aDeviceIter != aHeadDevice)
3141 aTris = theView->View()->XRSession()->LoadRenderModel (aDeviceIter, aTexture);
3143 if (!aTris.IsNull())
3145 aPosePrs = new AIS_XRTrackedDevice (aTris, aTexture);
3149 aPosePrs = new AIS_XRTrackedDevice();
3151 aPosePrs->SetUnitFactor ((float )theView->View()->UnitFactor());
3152 aPosePrs->SetMutable (true);
3153 aPosePrs->SetInfiniteState (true);
3155 aPosePrs->SetRole (aRole);
3157 if (!aPosePrs->HasInteractiveContext())
3159 theCtx->Display (aPosePrs, 0, -1, false);
3162 gp_Trsf aPoseLocal = aPose.Orientation;
3163 if (aDeviceIter == aHeadDevice)
3165 // show headset position on floor level
3166 aPoseLocal.SetTranslationPart (gp_Vec (aPoseLocal.TranslationPart().X(), 0.0, aPoseLocal.TranslationPart().Z()));
3168 const gp_Trsf aPoseWorld = theView->View()->PoseXRToWorld (aPoseLocal);
3169 theCtx->SetLocation (aPosePrs, aPoseWorld);
3171 Standard_Real aLaserLen = 0.0;
3173 && aPosePrs->Role() == myXRLastPickingHand)
3175 aLaserLen = myXRLastPickingHand == Aspect_XRTrackedDeviceRole_LeftHand ? myXRLastPickDepthLeft : myXRLastPickDepthRight;
3176 if (Precision::IsInfinite (aLaserLen))
3178 const Bnd_Box aViewBox = theView->View()->MinMaxValues (true);
3179 if (!aViewBox.IsVoid())
3181 aLaserLen = Sqrt (aViewBox.SquareExtent());
3188 aPosePrs->SetLaserColor (myXRLaserPickColor);
3191 && aPosePrs->Role() == myXRLastTeleportHand)
3193 aLaserLen = myXRLastTeleportHand == Aspect_XRTrackedDeviceRole_LeftHand ? myXRLastPickDepthLeft : myXRLastPickDepthRight;
3194 if (Precision::IsInfinite (aLaserLen))
3196 const Bnd_Box aViewBox = theView->View()->MinMaxValues (true);
3197 if (!aViewBox.IsVoid())
3199 aLaserLen = Sqrt (aViewBox.SquareExtent());
3206 aPosePrs->SetLaserColor (myXRLaserTeleColor);
3208 aPosePrs->SetLaserLength ((float )aLaserLen);
3212 // =======================================================================
3213 // function : HandleViewEvents
3215 // =======================================================================
3216 void AIS_ViewController::HandleViewEvents (const Handle(AIS_InteractiveContext)& theCtx,
3217 const Handle(V3d_View)& theView)
3219 const bool wasImmediateUpdate = theView->SetImmediateUpdate (false);
3221 handleViewOrientationKeys (theCtx, theView);
3222 const AIS_WalkDelta aWalk = handleNavigationKeys (theCtx, theView);
3223 handleXRInput (theCtx, theView, aWalk);
3224 if (theView->View()->IsActiveXR())
3226 theView->View()->SetupXRPosedCamera();
3228 handleMoveTo (theCtx, theView);
3229 handleCameraActions (theCtx, theView, aWalk);
3230 theView->View()->SynchronizeXRPosedToBaseCamera(); // handleCameraActions() may modify posed camera position - copy this modifications also to the base camera
3231 handleXRPresentations (theCtx, theView);
3233 handleViewRedraw (theCtx, theView);
3234 theView->View()->UnsetXRPosedCamera();
3236 theView->SetImmediateUpdate (wasImmediateUpdate);
3238 // make sure to not process the same events twice
3240 myToAskNextFrame = false;