1 // Copyright (c) 2016-2019 OPEN CASCADE SAS
3 // This file is part of Open CASCADE Technology software library.
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
14 #include "AIS_ViewController.hxx"
16 #include <AIS_AnimationCamera.hxx>
17 #include <AIS_InteractiveContext.hxx>
18 #include <AIS_Manipulator.hxx>
19 #include <AIS_Point.hxx>
20 #include <AIS_RubberBand.hxx>
21 #include <AIS_XRTrackedDevice.hxx>
22 #include <Aspect_XRSession.hxx>
23 #include <Aspect_Grid.hxx>
24 #include <Geom_CartesianPoint.hxx>
25 #include <Graphic3d_ArrayOfSegments.hxx>
26 #include <Graphic3d_Texture2Dmanual.hxx>
27 #include <Message.hxx>
28 #include <Message_Messenger.hxx>
29 #include <gp_Quaternion.hxx>
30 #include <V3d_View.hxx>
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 myMousePressed (Aspect_VKeyMouse_NONE),
86 myMouseModifiers (Aspect_VKeyFlags_NONE),
87 myMouseSingleButton (-1),
88 myMouseStopDragOnUnclick (false),
90 myTouchToleranceScale (1.0f),
91 myTouchRotationThresholdPx (6.0f),
92 myTouchZRotationThreshold (float(2.0 * M_PI / 180.0)),
93 myTouchPanThresholdPx (4.0f),
94 myTouchZoomThresholdPx (6.0f),
95 myTouchZoomRatio (0.13f),
98 myUpdateStartPointPan (true),
99 myUpdateStartPointRot (true),
100 myUpdateStartPointZRot (true),
102 my3dMouseNoRotate (false, false, false),
103 my3dMouseToReverse (true, false, false),
104 my3dMouseAccelTrans (2.0f),
105 my3dMouseAccelRotate (4.0f),
106 my3dMouseIsQuadric (true),
108 myPanPnt3d (Precision::Infinite(), 0.0, 0.0)
110 memset(my3dMouseButtonState, 0, sizeof(my3dMouseButtonState));
111 myEventTimer.Start();
112 myViewAnimation->SetOwnDuration (0.5);
114 myAnchorPointPrs1 = new AIS_Point (new Geom_CartesianPoint (0.0, 0.0, 0.0));
115 myAnchorPointPrs1->SetZLayer (Graphic3d_ZLayerId_Top);
116 myAnchorPointPrs1->SetMutable (true);
118 myAnchorPointPrs2 = new AIS_Point (new Geom_CartesianPoint (0.0, 0.0, 0.0));
119 myAnchorPointPrs2->SetZLayer (Graphic3d_ZLayerId_Topmost);
120 myAnchorPointPrs2->SetMutable (true);
122 myRubberBand = new AIS_RubberBand (Quantity_NOC_LIGHTBLUE, Aspect_TOL_SOLID, Quantity_NOC_LIGHTBLUE4, 0.5, 1.0);
123 myRubberBand->SetZLayer (Graphic3d_ZLayerId_TopOSD);
124 myRubberBand->SetTransformPersistence (new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_UPPER));
125 myRubberBand->SetDisplayMode (0);
126 myRubberBand->SetMutable (true);
128 myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton, AIS_MouseGesture_RotateOrbit);
129 myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_CTRL, AIS_MouseGesture_Zoom);
130 myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_SHIFT, AIS_MouseGesture_Pan);
131 myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_ALT, AIS_MouseGesture_SelectRectangle);
133 myMouseGestureMap.Bind (Aspect_VKeyMouse_RightButton, AIS_MouseGesture_Zoom);
134 myMouseGestureMap.Bind (Aspect_VKeyMouse_RightButton | Aspect_VKeyFlags_CTRL, AIS_MouseGesture_RotateOrbit);
136 myMouseGestureMap.Bind (Aspect_VKeyMouse_MiddleButton, AIS_MouseGesture_Pan);
137 myMouseGestureMap.Bind (Aspect_VKeyMouse_MiddleButton | Aspect_VKeyFlags_CTRL, AIS_MouseGesture_Pan);
139 myXRTeleportHaptic.Duration = 3600.0f;
140 myXRTeleportHaptic.Frequency = 0.1f;
141 myXRTeleportHaptic.Amplitude = 0.2f;
143 myXRPickingHaptic.Duration = 0.1f;
144 myXRPickingHaptic.Frequency = 4.0f;
145 myXRPickingHaptic.Amplitude = 0.1f;
147 myXRSelectHaptic.Duration = 0.2f;
148 myXRSelectHaptic.Frequency = 4.0f;
149 myXRSelectHaptic.Amplitude = 0.5f;
152 // =======================================================================
153 // function : ~AIS_ViewController
155 // =======================================================================
156 AIS_ViewController::~AIS_ViewController()
161 // =======================================================================
162 // function : ResetViewInput
164 // =======================================================================
165 void AIS_ViewController::ResetViewInput()
168 myMousePressed = Aspect_VKeyMouse_NONE;
169 myMouseModifiers = Aspect_VKeyFlags_NONE;
170 myMouseSingleButton = -1;
171 myUI.Dragging.ToAbort = true;
172 myMouseActiveGesture = AIS_MouseGesture_NONE;
173 myMouseClickTimer.Stop();
174 myMouseClickCounter = 0;
177 // =======================================================================
178 // function : FlushViewEvents
180 // =======================================================================
181 void AIS_ViewController::FlushViewEvents (const Handle(AIS_InteractiveContext)& theCtx,
182 const Handle(V3d_View)& theView,
183 Standard_Boolean theToHandle)
185 flushBuffers (theCtx, theView);
186 flushGestures(theCtx, theView);
189 HandleViewEvents (theCtx, theView);
193 // =======================================================================
194 // function : flushBuffers
196 // =======================================================================
197 void AIS_ViewController::flushBuffers (const Handle(AIS_InteractiveContext)& ,
198 const Handle(V3d_View)& )
200 myToAskNextFrame = false;
202 myGL.IsNewGesture = myUI.IsNewGesture;
203 myUI.IsNewGesture = false;
205 myGL.ZoomActions.Clear();
206 myGL.ZoomActions.Append (myUI.ZoomActions);
207 myUI.ZoomActions.Clear();
209 myGL.Orientation.ToFitAll = myUI.Orientation.ToFitAll;
210 myUI.Orientation.ToFitAll = false;
211 if (myUI.Orientation.ToSetViewOrient)
213 myUI.Orientation.ToSetViewOrient = false;
214 myGL.Orientation.ToSetViewOrient = true;
215 myGL.Orientation.ViewOrient = myUI.Orientation.ViewOrient;
218 if (myUI.MoveTo.ToHilight)
220 myUI.MoveTo.ToHilight = false;
221 myGL.MoveTo.ToHilight = true;
222 myGL.MoveTo.Point = myUI.MoveTo.Point;
226 myGL.Selection.Tool = myUI.Selection.Tool;
227 myGL.Selection.IsXOR = myUI.Selection.IsXOR;
228 myGL.Selection.Points = myUI.Selection.Points;
229 myUI.Selection.IsXOR = false;
230 if (myUI.Selection.Tool == AIS_ViewSelectionTool_Picking)
232 myUI.Selection.Points.Clear();
236 if (myUI.Selection.ToApplyTool)
238 myGL.Selection.ToApplyTool = true;
239 myUI.Selection.ToApplyTool = false;
240 myUI.Selection.Points.Clear();
243 if (myUI.Panning.ToStart)
245 myUI.Panning.ToStart = false;
246 myGL.Panning.ToStart = true;
247 myGL.Panning.PointStart = myUI.Panning.PointStart;
250 if (myUI.Panning.ToPan)
252 myUI.Panning.ToPan = false;
253 myGL.Panning.ToPan = true;
254 myGL.Panning.Delta = myUI.Panning.Delta;
257 if (myUI.Dragging.ToAbort)
259 myUI.Dragging.ToAbort = false;
260 myGL.Dragging.ToAbort = true;
262 else if (myUI.Dragging.ToStop)
264 myUI.Dragging.ToStop = false;
265 myGL.Dragging.ToStop = true;
267 else if (myUI.Dragging.ToStart)
269 myUI.Dragging.ToStart = false;
270 myGL.Dragging.ToStart = true;
271 myGL.Dragging.PointStart = myUI.Dragging.PointStart;
273 myGL.Dragging.PointTo = myUI.Dragging.PointTo;
275 if (myUI.OrbitRotation.ToStart)
277 myUI.OrbitRotation.ToStart = false;
278 myGL.OrbitRotation.ToStart = true;
279 myGL.OrbitRotation.PointStart = myUI.OrbitRotation.PointStart;
282 if (myUI.OrbitRotation.ToRotate)
284 myUI.OrbitRotation.ToRotate = false;
285 myGL.OrbitRotation.ToRotate = true;
286 myGL.OrbitRotation.PointTo = myUI.OrbitRotation.PointTo;
289 if (myUI.ViewRotation.ToStart)
291 myUI.ViewRotation.ToStart = false;
292 myGL.ViewRotation.ToStart = true;
293 myGL.ViewRotation.PointStart = myUI.ViewRotation.PointStart;
296 if (myUI.ViewRotation.ToRotate)
298 myUI.ViewRotation.ToRotate = false;
299 myGL.ViewRotation.ToRotate = true;
300 myGL.ViewRotation.PointTo = myUI.ViewRotation.PointTo;
303 if (myUI.ZRotate.ToRotate)
305 myGL.ZRotate = myUI.ZRotate;
306 myUI.ZRotate.ToRotate = false;
310 // =======================================================================
311 // function : flushGestures
313 // =======================================================================
314 void AIS_ViewController::flushGestures (const Handle(AIS_InteractiveContext)& ,
315 const Handle(V3d_View)& theView)
317 const Standard_Real aTolScale = myTouchToleranceScale;
318 const Standard_Integer aTouchNb = myTouchPoints.Extent();
319 if (myNbTouchesLast != aTouchNb)
321 myNbTouchesLast = aTouchNb;
322 myGL.IsNewGesture = true;
324 if (aTouchNb == 1) // touch
326 Aspect_Touch& aTouch = myTouchPoints.ChangeFromIndex (1);
327 if (myUpdateStartPointRot)
329 // skip rotation if have active dragged object
330 if (myNavigationMode == AIS_NavigationMode_Orbit)
332 myGL.OrbitRotation.ToStart = true;
333 myGL.OrbitRotation.PointStart = myStartRotCoord;
337 myGL.ViewRotation.ToStart = true;
338 myGL.ViewRotation.PointStart = myStartRotCoord;
341 myUpdateStartPointRot = false;
342 theView->Invalidate();
346 const Standard_Real aRotTouchTol = !aTouch.IsPreciseDevice
347 ? aTolScale * myTouchRotationThresholdPx
349 if (Abs (aTouch.Delta().x()) + Abs(aTouch.Delta().y()) > aRotTouchTol)
351 const Standard_Real aRotAccel = myNavigationMode == AIS_NavigationMode_FirstPersonWalk ? myMouseAccel : myOrbitAccel;
352 if (myNavigationMode == AIS_NavigationMode_Orbit)
354 const Graphic3d_Vec2d aRotDelta = aTouch.To - myGL.OrbitRotation.PointStart;
355 myGL.OrbitRotation.ToRotate = true;
356 myGL.OrbitRotation.PointTo = myGL.OrbitRotation.PointStart + aRotDelta * aRotAccel;
357 myGL.Dragging.PointTo.SetValues ((int )aTouch.To.x(), (int )aTouch.To.y());
361 const Graphic3d_Vec2d aRotDelta = aTouch.To - myGL.ViewRotation.PointStart;
362 myGL.ViewRotation.ToRotate = true;
363 myGL.ViewRotation.PointTo = myGL.ViewRotation.PointStart + aRotDelta * aRotAccel;
364 myGL.Dragging.PointTo.SetValues ((int )aTouch.To.x(), (int )aTouch.To.y());
367 aTouch.From = aTouch.To;
370 else if (aTouchNb == 2) // pinch
372 Aspect_Touch& aFirstTouch = myTouchPoints.ChangeFromIndex (1);
373 Aspect_Touch& aLastTouch = myTouchPoints.ChangeFromIndex (2);
374 const Graphic3d_Vec2d aFrom[2] = { aFirstTouch.From, aLastTouch.From };
375 const Graphic3d_Vec2d aTo[2] = { aFirstTouch.To, aLastTouch.To };
377 Graphic3d_Vec2d aPinchCenterStart ((aFrom[0].x() + aFrom[1].x()) / 2.0,
378 (aFrom[0].y() + aFrom[1].y()) / 2.0);
380 Standard_Real aPinchCenterXEnd = (aTo[0].x() + aTo[1].x()) / 2.0;
381 Standard_Real aPinchCenterYEnd = (aTo[0].y() + aTo[1].y()) / 2.0;
383 Standard_Real aPinchCenterXDev = aPinchCenterXEnd - aPinchCenterStart.x();
384 Standard_Real aPinchCenterYDev = aPinchCenterYEnd - aPinchCenterStart.y();
386 Standard_Real aStartSize = (aFrom[0] - aFrom[1]).Modulus();
387 Standard_Real anEndSize = ( aTo[0] - aTo[1]).Modulus();
389 Standard_Real aDeltaSize = anEndSize - aStartSize;
391 bool anIsClearDev = false;
393 if (myToAllowTouchZRotation)
395 Standard_Real A1 = aFrom[0].y() - aFrom[1].y();
396 Standard_Real B1 = aFrom[1].x() - aFrom[0].x();
398 Standard_Real A2 = aTo[0].y() - aTo[1].y();
399 Standard_Real B2 = aTo[1].x() - aTo[0].x();
401 Standard_Real aRotAngle = 0.0;
403 Standard_Real aDenomenator = A1*A2 + B1*B2;
404 if (aDenomenator <= Precision::Confusion())
410 Standard_Real aNumerator = A1*B2 - A2*B1;
411 aRotAngle = ATan (aNumerator / aDenomenator);
414 if (Abs(aRotAngle) > Standard_Real(myTouchZRotationThreshold))
416 myGL.ZRotate.ToRotate = true;
417 myGL.ZRotate.Angle = aRotAngle;
422 if (Abs(aDeltaSize) > aTolScale * myTouchZoomThresholdPx)
425 aDeltaSize *= Standard_Real(myTouchZoomRatio);
426 Aspect_ScrollDelta aParams (Graphic3d_Vec2i (aPinchCenterStart), aDeltaSize);
427 myGL.ZoomActions.Append (aParams);
431 const Standard_Real aPanTouchTol = !aFirstTouch.IsPreciseDevice
432 ? aTolScale * myTouchPanThresholdPx
434 if (Abs(aPinchCenterXDev) + Abs(aPinchCenterYDev) > aPanTouchTol)
437 if (myUpdateStartPointPan)
439 myGL.Panning.ToStart = true;
440 myGL.Panning.PointStart = Graphic3d_Vec2i (myStartPanCoord);
441 myUpdateStartPointPan = false;
442 theView->Invalidate();
445 myGL.Panning.ToPan = true;
446 myGL.Panning.Delta.x() = int( aPinchCenterXDev);
447 myGL.Panning.Delta.y() = int(-aPinchCenterYDev);
453 aFirstTouch.From = aFirstTouch.To;
454 aLastTouch .From = aLastTouch.To;
459 // =======================================================================
460 // function : UpdateViewOrientation
462 // =======================================================================
463 void AIS_ViewController::UpdateViewOrientation (V3d_TypeOfOrientation theOrientation,
466 myUI.Orientation.ToFitAll = theToFitAll;
467 myUI.Orientation.ToSetViewOrient = true;
468 myUI.Orientation.ViewOrient = theOrientation;
471 // =======================================================================
472 // function : SelectInViewer
474 // =======================================================================
475 void AIS_ViewController::SelectInViewer (const Graphic3d_Vec2i& thePnt,
478 if (myUI.Selection.Tool != AIS_ViewSelectionTool_Picking)
480 myUI.Selection.Tool = AIS_ViewSelectionTool_Picking;
481 myUI.Selection.Points.Clear();
484 myUI.Selection.IsXOR = theIsXOR;
485 myUI.Selection.Points.Append (thePnt);
488 // =======================================================================
489 // function : SelectInViewer
491 // =======================================================================
492 void AIS_ViewController::SelectInViewer (const NCollection_Sequence<Graphic3d_Vec2i>& thePnts,
495 myUI.Selection.IsXOR = theIsXOR;
496 myUI.Selection.Points = thePnts;
497 myUI.Selection.ToApplyTool = true;
498 if (thePnts.Length() == 1)
500 myUI.Selection.Tool = AIS_ViewSelectionTool_Picking;
502 else if (thePnts.Length() == 2)
504 myUI.Selection.Tool = AIS_ViewSelectionTool_RubberBand;
508 myUI.Selection.Tool = AIS_ViewSelectionTool_Polygon;
512 // =======================================================================
513 // function : UpdateRubberBand
515 // =======================================================================
516 void AIS_ViewController::UpdateRubberBand (const Graphic3d_Vec2i& thePntFrom,
517 const Graphic3d_Vec2i& thePntTo,
520 myUI.Selection.Tool = AIS_ViewSelectionTool_RubberBand;
521 myUI.Selection.IsXOR = theIsXOR;
522 myUI.Selection.Points.Clear();
523 myUI.Selection.Points.Append (thePntFrom);
524 myUI.Selection.Points.Append (thePntTo);
527 // =======================================================================
528 // function : UpdatePolySelection
530 // =======================================================================
531 void AIS_ViewController::UpdatePolySelection (const Graphic3d_Vec2i& thePnt,
534 if (myUI.Selection.Tool != AIS_ViewSelectionTool_Polygon)
536 myUI.Selection.Tool = AIS_ViewSelectionTool_Polygon;
537 myUI.Selection.Points.Clear();
540 if (myUI.Selection.Points.IsEmpty())
542 myUI.Selection.Points.Append (thePnt);
545 && myUI.Selection.Points.Last() != thePnt)
547 myUI.Selection.Points.Append (thePnt);
551 myUI.Selection.Points.ChangeLast() = thePnt;
555 // =======================================================================
556 // function : UpdateZoom
558 // =======================================================================
559 bool AIS_ViewController::UpdateZoom (const Aspect_ScrollDelta& theDelta)
561 if (!myUI.ZoomActions.IsEmpty())
563 if (myUI.ZoomActions.ChangeLast().Point == theDelta.Point)
565 myUI.ZoomActions.ChangeLast().Delta += theDelta.Delta;
570 myUI.ZoomActions.Append (theDelta);
574 // =======================================================================
575 // function : UpdateZRotation
577 // =======================================================================
578 bool AIS_ViewController::UpdateZRotation (double theAngle)
580 if (!ToAllowTouchZRotation())
585 myUI.ZRotate.Angle = myUI.ZRotate.ToRotate
586 ? myUI.ZRotate.Angle + theAngle
588 if (myUI.ZRotate.ToRotate)
592 myUI.ZRotate.ToRotate = true;
596 // =======================================================================
597 // function : UpdateMouseScroll
599 // =======================================================================
600 bool AIS_ViewController::UpdateMouseScroll (const Aspect_ScrollDelta& theDelta)
602 Aspect_ScrollDelta aDelta = theDelta;
603 aDelta.Delta *= myScrollZoomRatio;
604 return UpdateZoom (aDelta);
607 // =======================================================================
608 // function : UpdateMouseClick
610 // =======================================================================
611 bool AIS_ViewController::UpdateMouseClick (const Graphic3d_Vec2i& thePoint,
612 Aspect_VKeyMouse theButton,
613 Aspect_VKeyFlags theModifiers,
614 bool theIsDoubleClick)
616 (void )theIsDoubleClick;
617 if (theButton == Aspect_VKeyMouse_LeftButton)
619 SelectInViewer (thePoint, (theModifiers & Aspect_VKeyFlags_SHIFT) != 0);
625 // =======================================================================
626 // function : UpdateMouseButtons
628 // =======================================================================
629 bool AIS_ViewController::UpdateMouseButtons (const Graphic3d_Vec2i& thePoint,
630 Aspect_VKeyMouse theButtons,
631 Aspect_VKeyFlags theModifiers,
634 bool toUpdateView = false;
635 const double aTolClick = (theIsEmulated ? myTouchToleranceScale : 1.0) * myMouseClickThreshold;
636 if (theButtons == Aspect_VKeyMouse_NONE
637 && myMouseSingleButton > 0)
639 const Graphic3d_Vec2i aDelta = thePoint - myMousePressPoint;
640 if (double(aDelta.cwiseAbs().maxComp()) < aTolClick)
642 ++myMouseClickCounter;
643 const bool isDoubleClick = myMouseClickCounter == 2
644 && myMouseClickTimer.IsStarted()
645 && myMouseClickTimer.ElapsedTime() <= myMouseDoubleClickInt;
647 myMouseClickTimer.Stop();
648 myMouseClickTimer.Reset();
649 myMouseClickTimer.Start();
652 myMouseClickCounter = 0;
654 toUpdateView = UpdateMouseClick (thePoint, (Aspect_VKeyMouse )myMouseSingleButton, theModifiers, isDoubleClick) || toUpdateView;
658 myMouseClickTimer.Stop();
659 myMouseClickCounter = 0;
660 myMouseStopDragOnUnclick = false;
661 myUI.Dragging.ToStop = true;
664 myMouseSingleButton = -1;
666 else if (theButtons == Aspect_VKeyMouse_NONE)
668 myMouseSingleButton = -1;
669 if (myMouseStopDragOnUnclick)
671 myMouseStopDragOnUnclick = false;
672 myUI.Dragging.ToStop = true;
676 else if (myMouseSingleButton == -1)
678 if ((theButtons & Aspect_VKeyMouse_LeftButton) == Aspect_VKeyMouse_LeftButton)
680 myMouseSingleButton = Aspect_VKeyMouse_LeftButton;
682 else if ((theButtons & Aspect_VKeyMouse_RightButton) == Aspect_VKeyMouse_RightButton)
684 myMouseSingleButton = Aspect_VKeyMouse_RightButton;
686 else if ((theButtons & Aspect_VKeyMouse_MiddleButton) == Aspect_VKeyMouse_MiddleButton)
688 myMouseSingleButton = Aspect_VKeyMouse_MiddleButton;
692 myMouseSingleButton = 0;
694 if (myMouseSingleButton != 0)
696 if (myMouseClickCounter == 1)
698 const Graphic3d_Vec2i aDelta = thePoint - myMousePressPoint;
699 if (double(aDelta.cwiseAbs().maxComp()) >= aTolClick)
701 myMouseClickTimer.Stop();
702 myMouseClickCounter = 0;
705 myMousePressPoint = thePoint;
710 myMouseSingleButton = 0;
712 myUI.Dragging.ToAbort = true;
716 const AIS_MouseGesture aPrevGesture = myMouseActiveGesture;
717 myMouseModifiers = theModifiers;
718 myMousePressed = theButtons;
720 || myNavigationMode != AIS_NavigationMode_FirstPersonWalk)
722 myMouseActiveIdleRotation = false;
723 myMouseActiveGesture = AIS_MouseGesture_NONE;
726 myMousePressPoint = thePoint;
727 myMouseProgressPoint = myMousePressPoint;
730 if (myMouseGestureMap.Find (theButtons | theModifiers, myMouseActiveGesture))
732 switch (myMouseActiveGesture)
734 case AIS_MouseGesture_RotateView:
735 case AIS_MouseGesture_RotateOrbit:
737 if (myToAllowRotation)
739 myUpdateStartPointRot = true;
743 myMouseActiveGesture = AIS_MouseGesture_NONE;
747 case AIS_MouseGesture_Pan:
749 if (myToAllowPanning)
751 myUpdateStartPointPan = true;
755 myMouseActiveGesture = AIS_MouseGesture_NONE;
759 case AIS_MouseGesture_Zoom:
760 case AIS_MouseGesture_ZoomWindow:
762 if (!myToAllowZooming)
764 myMouseActiveGesture = AIS_MouseGesture_NONE;
768 case AIS_MouseGesture_SelectRectangle:
772 case AIS_MouseGesture_SelectLasso:
774 UpdatePolySelection (thePoint, true);
777 case AIS_MouseGesture_NONE:
784 if (theButtons == Aspect_VKeyMouse_LeftButton
785 && theModifiers == Aspect_VKeyFlags_NONE
786 && myToAllowDragging)
788 myUI.Dragging.ToStart = true;
789 myUI.Dragging.PointStart = thePoint;
793 if (aPrevGesture != myMouseActiveGesture)
795 if (aPrevGesture == AIS_MouseGesture_SelectRectangle
796 || aPrevGesture == AIS_MouseGesture_SelectLasso
797 || aPrevGesture == AIS_MouseGesture_ZoomWindow)
799 myUI.Selection.ToApplyTool = true;
802 myUI.IsNewGesture = true;
808 // =======================================================================
809 // function : UpdateMousePosition
811 // =======================================================================
812 bool AIS_ViewController::UpdateMousePosition (const Graphic3d_Vec2i& thePoint,
813 Aspect_VKeyMouse theButtons,
814 Aspect_VKeyFlags theModifiers,
817 myMousePositionLast = thePoint;
818 if (myMouseSingleButton > 0)
820 const double aTolClick = (theIsEmulated ? myTouchToleranceScale : 1.0) * myMouseClickThreshold;
821 const Graphic3d_Vec2i aPressDelta = thePoint - myMousePressPoint;
822 if (double(aPressDelta.cwiseAbs().maxComp()) >= aTolClick)
824 myMouseClickTimer.Stop();
825 myMouseClickCounter = 0;
826 myMouseSingleButton = -1;
827 myMouseStopDragOnUnclick = true;
831 bool toUpdateView = false;
832 Graphic3d_Vec2i aDelta = thePoint - myMouseProgressPoint;
834 && myNavigationMode == AIS_NavigationMode_FirstPersonWalk)
836 if (!myMouseActiveIdleRotation
837 || myMouseActiveGesture != AIS_MouseGesture_RotateView)
839 myMouseActiveIdleRotation = true;
840 myMouseActiveGesture = AIS_MouseGesture_RotateView;
841 myMousePressPoint = thePoint;
842 myMouseProgressPoint = thePoint;
843 myUpdateStartPointRot = false;
844 myUI.ViewRotation.ToStart = true;
845 myUI.ViewRotation.PointStart.SetValues (thePoint.x(), thePoint.y());
846 myUI.ViewRotation.ToRotate = false;
847 aDelta.SetValues (0, 0);
852 if (myMouseActiveIdleRotation
853 && myMouseActiveGesture == AIS_MouseGesture_RotateView)
855 myMouseActiveGesture = AIS_MouseGesture_NONE;
857 myMouseActiveIdleRotation = false;
860 if (myMouseModifiers != theModifiers
861 && UpdateMouseButtons (thePoint, theButtons, theModifiers, theIsEmulated))
866 switch (myMouseActiveGesture)
868 case AIS_MouseGesture_SelectRectangle:
869 case AIS_MouseGesture_ZoomWindow:
871 UpdateRubberBand (myMousePressPoint, thePoint);
872 if (myMouseActiveGesture == AIS_MouseGesture_ZoomWindow)
874 myUI.Selection.Tool = AIS_ViewSelectionTool_ZoomWindow;
879 case AIS_MouseGesture_SelectLasso:
881 UpdatePolySelection (thePoint, true);
885 case AIS_MouseGesture_RotateOrbit:
886 case AIS_MouseGesture_RotateView:
888 if (!myToAllowRotation)
892 if (myUpdateStartPointRot)
894 if (myMouseActiveGesture == AIS_MouseGesture_RotateOrbit)
896 myUI.OrbitRotation.ToStart = true;
897 myUI.OrbitRotation.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y());
901 myUI.ViewRotation.ToStart = true;
902 myUI.ViewRotation.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y());
904 myUpdateStartPointRot = false;
907 const double aRotTol = theIsEmulated
908 ? double(myTouchToleranceScale) * myTouchRotationThresholdPx
910 if (double (Abs (aDelta.x()) + Abs (aDelta.y())) > aRotTol)
912 const double aRotAccel = myNavigationMode == AIS_NavigationMode_FirstPersonWalk ? myMouseAccel : myOrbitAccel;
913 const Graphic3d_Vec2i aRotDelta = thePoint - myMousePressPoint;
914 if (myMouseActiveGesture == AIS_MouseGesture_RotateOrbit)
916 myUI.OrbitRotation.ToRotate = true;
917 myUI.OrbitRotation.PointTo = Graphic3d_Vec2d (myMousePressPoint.x(), myMousePressPoint.y())
918 + Graphic3d_Vec2d (aRotDelta.x(), aRotDelta.y()) * aRotAccel;
922 myUI.ViewRotation.ToRotate = true;
923 myUI.ViewRotation.PointTo = Graphic3d_Vec2d (myMousePressPoint.x(), myMousePressPoint.y())
924 + Graphic3d_Vec2d (aRotDelta.x(), aRotDelta.y()) * aRotAccel;
926 myUI.Dragging.PointTo = thePoint;
928 myMouseProgressPoint = thePoint;
933 case AIS_MouseGesture_Zoom:
935 if (!myToAllowZooming)
939 const double aZoomTol = theIsEmulated
940 ? double(myTouchToleranceScale) * myTouchZoomThresholdPx
942 if (double (Abs (aDelta.x())) > aZoomTol)
944 if (UpdateZoom (Aspect_ScrollDelta (aDelta.x())))
948 myMouseProgressPoint = thePoint;
952 case AIS_MouseGesture_Pan:
954 if (!myToAllowPanning)
958 const double aPanTol = theIsEmulated
959 ? double(myTouchToleranceScale) * myTouchPanThresholdPx
961 if (double (Abs (aDelta.x()) + Abs (aDelta.y())) > aPanTol)
963 if (myUpdateStartPointPan)
965 myUI.Panning.ToStart = true;
966 myUI.Panning.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y());
967 myUpdateStartPointPan = false;
970 aDelta.y() = -aDelta.y();
971 myMouseProgressPoint = thePoint;
972 if (myUI.Panning.ToPan)
974 myUI.Panning.Delta += aDelta;
978 myUI.Panning.ToPan = true;
979 myUI.Panning.Delta = aDelta;
991 if (theButtons == Aspect_VKeyMouse_NONE
992 && myNavigationMode != AIS_NavigationMode_FirstPersonWalk
995 && myToAllowHighlight)
997 myUI.MoveTo.ToHilight = true;
998 myUI.MoveTo.Point = thePoint;
1001 return toUpdateView;
1004 // =======================================================================
1005 // function : AddTouchPoint
1007 // =======================================================================
1008 void AIS_ViewController::AddTouchPoint (Standard_Size theId,
1009 const Graphic3d_Vec2d& thePnt,
1010 Standard_Boolean theClearBefore)
1012 myUI.MoveTo.ToHilight = false;
1015 RemoveTouchPoint ((Standard_Size )-1);
1018 myTouchPoints.Add (theId, Aspect_Touch (thePnt, false));
1019 if (myTouchPoints.Extent() == 1)
1021 myUpdateStartPointRot = true;
1022 myStartRotCoord = thePnt;
1023 if (myToAllowDragging)
1025 myUI.Dragging.ToStart = true;
1026 myUI.Dragging.PointStart.SetValues ((int )thePnt.x(), (int )thePnt.y());
1029 else if (myTouchPoints.Extent() == 2)
1031 myUI.Dragging.ToAbort = true;
1033 myUpdateStartPointPan = true;
1034 myStartPanCoord = thePnt;
1036 myUI.IsNewGesture = true;
1039 // =======================================================================
1040 // function : RemoveTouchPoint
1042 // =======================================================================
1043 bool AIS_ViewController::RemoveTouchPoint (Standard_Size theId,
1044 Standard_Boolean theClearSelectPnts)
1046 if (theId == (Standard_Size )-1)
1048 myTouchPoints.Clear (false);
1052 const Standard_Integer anOldExtent = myTouchPoints.Extent();
1053 myTouchPoints.RemoveKey (theId);
1054 if (myTouchPoints.Extent() == anOldExtent)
1060 if (myTouchPoints.Extent() == 1)
1062 // avoid incorrect transition from pinch to one finger
1063 Aspect_Touch& aFirstTouch = myTouchPoints.ChangeFromIndex (1);
1064 aFirstTouch.To = aFirstTouch.From;
1066 myStartRotCoord = aFirstTouch.To;
1067 myUpdateStartPointRot = true;
1069 else if (myTouchPoints.Extent() == 2)
1071 myStartPanCoord = myTouchPoints.FindFromIndex (1).To;
1072 myUpdateStartPointPan = true;
1074 else if (myTouchPoints.IsEmpty())
1076 if (theClearSelectPnts)
1078 myUI.Selection.ToApplyTool = true;
1081 myUI.Dragging.ToStop = true;
1083 myUI.IsNewGesture = true;
1087 // =======================================================================
1088 // function : UpdateTouchPoint
1090 // =======================================================================
1091 void AIS_ViewController::UpdateTouchPoint (Standard_Size theId,
1092 const Graphic3d_Vec2d& thePnt)
1094 if (Aspect_Touch* aTouch = myTouchPoints.ChangeSeek (theId))
1096 aTouch->To = thePnt;
1100 AddTouchPoint (theId, thePnt);
1104 // =======================================================================
1105 // function : Update3dMouse
1107 // =======================================================================
1108 bool AIS_ViewController::Update3dMouse (const WNT_HIDSpaceMouse& theEvent)
1110 bool toUpdate = false;
1111 toUpdate = update3dMouseTranslation (theEvent) || toUpdate;
1112 toUpdate = update3dMouseRotation (theEvent) || toUpdate;
1113 toUpdate = update3dMouseKeys (theEvent) || toUpdate;
1117 // =======================================================================
1118 // function : update3dMouseTranslation
1120 // =======================================================================
1121 bool AIS_ViewController::update3dMouseTranslation (const WNT_HIDSpaceMouse& theEvent)
1123 if (!theEvent.IsTranslation())
1129 const double aTimeStamp = EventTime();
1130 const Graphic3d_Vec3d aTrans = theEvent.Translation (isIdle, my3dMouseIsQuadric) * my3dMouseAccelTrans;
1131 myKeys.KeyFromAxis (Aspect_VKey_NavSlideLeft, Aspect_VKey_NavSlideRight, aTimeStamp, aTrans.x());
1132 myKeys.KeyFromAxis (Aspect_VKey_NavForward, Aspect_VKey_NavBackward, aTimeStamp, aTrans.y());
1133 myKeys.KeyFromAxis (Aspect_VKey_NavSlideUp, Aspect_VKey_NavSlideDown, aTimeStamp, aTrans.z());
1137 // =======================================================================
1138 // function : update3dMouseRotation
1140 // =======================================================================
1141 bool AIS_ViewController::update3dMouseRotation (const WNT_HIDSpaceMouse& theEvent)
1143 if (!theEvent.IsRotation()
1144 || !myToAllowRotation)
1149 bool isIdle = true, toUpdate = false;
1150 const double aTimeStamp = EventTime();
1151 const Graphic3d_Vec3d aRot3 = theEvent.Rotation (isIdle, my3dMouseIsQuadric) * my3dMouseAccelRotate;
1152 if (!my3dMouseNoRotate.x())
1154 KeyFromAxis (Aspect_VKey_NavLookUp, Aspect_VKey_NavLookDown, aTimeStamp, !my3dMouseToReverse.x() ? aRot3.x() : -aRot3.x());
1157 if (!my3dMouseNoRotate.y())
1159 KeyFromAxis (Aspect_VKey_NavRollCW, Aspect_VKey_NavRollCCW, aTimeStamp, !my3dMouseToReverse.y() ? aRot3.y() : -aRot3.y());
1162 if (!my3dMouseNoRotate.z())
1164 KeyFromAxis (Aspect_VKey_NavLookLeft, Aspect_VKey_NavLookRight, aTimeStamp, !my3dMouseToReverse.z() ? aRot3.z() : -aRot3.z());
1170 // =======================================================================
1171 // function : update3dMouseKeys
1173 // =======================================================================
1174 bool AIS_ViewController::update3dMouseKeys (const WNT_HIDSpaceMouse& theEvent)
1176 bool toUpdate = false;
1177 const double aTimeStamp = EventTime();
1178 if (theEvent.IsKeyState())
1180 const uint32_t aKeyState = theEvent.KeyState();
1181 for (unsigned short aKeyBit = 0; aKeyBit < 32; ++aKeyBit)
1183 const bool isPressed = (aKeyState & (1 << aKeyBit)) != 0;
1184 const bool isReleased = my3dMouseButtonState[aKeyBit] && !isPressed;
1185 //const bool isRepeated = my3dMouseButtonState[aKeyBit] && isPressed;
1186 my3dMouseButtonState[aKeyBit] = isPressed;
1187 if (!isReleased && !isPressed)
1192 const Aspect_VKey aVKey = theEvent.HidToSpaceKey (aKeyBit);
1193 if (aVKey != Aspect_VKey_UNKNOWN)
1198 KeyDown (aVKey, aTimeStamp);
1202 KeyUp (aVKey, aTimeStamp);
1210 // =======================================================================
1211 // function : SetNavigationMode
1213 // =======================================================================
1214 void AIS_ViewController::SetNavigationMode (AIS_NavigationMode theMode)
1216 myNavigationMode = theMode;
1219 myUI.OrbitRotation.ToStart = false;
1220 myUI.OrbitRotation.ToRotate = false;
1221 myUI.ViewRotation.ToStart = false;
1222 myUI.ViewRotation.ToRotate = false;
1225 // =======================================================================
1226 // function : KeyDown
1228 // =======================================================================
1229 void AIS_ViewController::KeyDown (Aspect_VKey theKey,
1233 myKeys.KeyDown (theKey, theTime, thePressure);
1236 // =======================================================================
1239 // =======================================================================
1240 void AIS_ViewController::KeyUp (Aspect_VKey theKey,
1243 myKeys.KeyUp (theKey, theTime);
1246 // =======================================================================
1247 // function : KeyFromAxis
1249 // =======================================================================
1250 void AIS_ViewController::KeyFromAxis (Aspect_VKey theNegative,
1251 Aspect_VKey thePositive,
1255 myKeys.KeyFromAxis (theNegative, thePositive, theTime, thePressure);
1258 // =======================================================================
1259 // function : FetchNavigationKeys
1261 // =======================================================================
1262 AIS_WalkDelta AIS_ViewController::FetchNavigationKeys (Standard_Real theCrouchRatio,
1263 Standard_Real theRunRatio)
1265 AIS_WalkDelta aWalk;
1268 double aPrevEventTime = 0.0, aNewEventTime = 0.0;
1269 updateEventsTime (aPrevEventTime, aNewEventTime);
1271 double aDuration = 0.0, aPressure = 1.0;
1272 if (Abs (myThrustSpeed) > gp::Resolution())
1276 aWalk[AIS_WalkTranslation_Forward].Value = myThrustSpeed * (aNewEventTime - aPrevEventTime);
1279 myToAskNextFrame = true;
1283 myHasThrust = false;
1286 aWalk.SetRunning (theRunRatio > 1.0
1287 && myKeys.IsKeyDown (Aspect_VKey_Shift));
1288 if (myKeys.HoldDuration (Aspect_VKey_NavJump, aNewEventTime, aDuration))
1290 myKeys.KeyUp (Aspect_VKey_NavJump, aNewEventTime);
1291 aWalk.SetJumping (true);
1293 if (!aWalk.IsJumping()
1294 && theCrouchRatio < 1.0
1295 && myKeys.HoldDuration (Aspect_VKey_NavCrouch, aNewEventTime, aDuration))
1297 aWalk.SetRunning (false);
1298 aWalk.SetCrouching (true);
1301 const double aMaxDuration = aNewEventTime - aPrevEventTime;
1302 const double aRunRatio = aWalk.IsRunning()
1304 : aWalk.IsCrouching()
1307 if (myKeys.HoldDuration (Aspect_VKey_NavForward, aNewEventTime, aDuration, aPressure))
1309 double aProgress = Abs (Min (aMaxDuration, aDuration));
1310 aProgress *= aRunRatio;
1311 aWalk[AIS_WalkTranslation_Forward].Value += aProgress;
1312 aWalk[AIS_WalkTranslation_Forward].Pressure = aPressure;
1313 aWalk[AIS_WalkTranslation_Forward].Duration = aDuration;
1315 if (myKeys.HoldDuration (Aspect_VKey_NavBackward, aNewEventTime, aDuration, aPressure))
1317 double aProgress = Abs (Min (aMaxDuration, aDuration));
1318 aProgress *= aRunRatio;
1319 aWalk[AIS_WalkTranslation_Forward].Value += -aProgress;
1320 aWalk[AIS_WalkTranslation_Forward].Pressure = aPressure;
1321 aWalk[AIS_WalkTranslation_Forward].Duration = aDuration;
1323 if (myKeys.HoldDuration (Aspect_VKey_NavSlideLeft, aNewEventTime, aDuration, aPressure))
1325 double aProgress = Abs (Min (aMaxDuration, aDuration));
1326 aProgress *= aRunRatio;
1327 aWalk[AIS_WalkTranslation_Side].Value = -aProgress;
1328 aWalk[AIS_WalkTranslation_Side].Pressure = aPressure;
1329 aWalk[AIS_WalkTranslation_Side].Duration = aDuration;
1331 if (myKeys.HoldDuration (Aspect_VKey_NavSlideRight, aNewEventTime, aDuration, aPressure))
1333 double aProgress = Abs (Min (aMaxDuration, aDuration));
1334 aProgress *= aRunRatio;
1335 aWalk[AIS_WalkTranslation_Side].Value = aProgress;
1336 aWalk[AIS_WalkTranslation_Side].Pressure = aPressure;
1337 aWalk[AIS_WalkTranslation_Side].Duration = aDuration;
1339 if (myKeys.HoldDuration (Aspect_VKey_NavLookLeft, aNewEventTime, aDuration, aPressure))
1341 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1342 aWalk[AIS_WalkRotation_Yaw].Value = aProgress;
1343 aWalk[AIS_WalkRotation_Yaw].Pressure = aPressure;
1344 aWalk[AIS_WalkRotation_Yaw].Duration = aDuration;
1346 if (myKeys.HoldDuration (Aspect_VKey_NavLookRight, aNewEventTime, aDuration, aPressure))
1348 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1349 aWalk[AIS_WalkRotation_Yaw].Value = -aProgress;
1350 aWalk[AIS_WalkRotation_Yaw].Pressure = aPressure;
1351 aWalk[AIS_WalkRotation_Yaw].Duration = aDuration;
1353 if (myKeys.HoldDuration (Aspect_VKey_NavLookUp, aNewEventTime, aDuration, aPressure))
1355 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1356 aWalk[AIS_WalkRotation_Pitch].Value = !myToInvertPitch ? -aProgress : aProgress;
1357 aWalk[AIS_WalkRotation_Pitch].Pressure = aPressure;
1358 aWalk[AIS_WalkRotation_Pitch].Duration = aDuration;
1360 if (myKeys.HoldDuration (Aspect_VKey_NavLookDown, aNewEventTime, aDuration, aPressure))
1362 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1363 aWalk[AIS_WalkRotation_Pitch].Value = !myToInvertPitch ? aProgress : -aProgress;
1364 aWalk[AIS_WalkRotation_Pitch].Pressure = aPressure;
1365 aWalk[AIS_WalkRotation_Pitch].Duration = aDuration;
1367 if (myKeys.HoldDuration (Aspect_VKey_NavRollCCW, aNewEventTime, aDuration, aPressure))
1369 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1370 aWalk[AIS_WalkRotation_Roll].Value = -aProgress;
1371 aWalk[AIS_WalkRotation_Roll].Pressure = aPressure;
1372 aWalk[AIS_WalkRotation_Roll].Duration = aDuration;
1374 if (myKeys.HoldDuration (Aspect_VKey_NavRollCW, aNewEventTime, aDuration, aPressure))
1376 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1377 aWalk[AIS_WalkRotation_Roll].Value = aProgress;
1378 aWalk[AIS_WalkRotation_Roll].Pressure = aPressure;
1379 aWalk[AIS_WalkRotation_Roll].Duration = aDuration;
1381 if (myKeys.HoldDuration (Aspect_VKey_NavSlideUp, aNewEventTime, aDuration, aPressure))
1383 double aProgress = Abs (Min (aMaxDuration, aDuration));
1384 aWalk[AIS_WalkTranslation_Up].Value = aProgress;
1385 aWalk[AIS_WalkTranslation_Up].Pressure = aPressure;
1386 aWalk[AIS_WalkTranslation_Up].Duration = aDuration;
1388 if (myKeys.HoldDuration (Aspect_VKey_NavSlideDown, aNewEventTime, aDuration, aPressure))
1390 double aProgress = Abs (Min (aMaxDuration, aDuration));
1391 aWalk[AIS_WalkTranslation_Up].Value = -aProgress;
1392 aWalk[AIS_WalkTranslation_Up].Pressure = aPressure;
1393 aWalk[AIS_WalkTranslation_Up].Duration = aDuration;
1398 // =======================================================================
1399 // function : AbortViewAnimation
1401 // =======================================================================
1402 void AIS_ViewController::AbortViewAnimation()
1404 if (!myViewAnimation.IsNull()
1405 && !myViewAnimation->IsStopped())
1407 myViewAnimation->Stop();
1408 myViewAnimation->SetView (Handle(V3d_View)());
1412 // =======================================================================
1413 // function : handlePanning
1415 // =======================================================================
1416 void AIS_ViewController::handlePanning (const Handle(V3d_View)& theView)
1418 if (!myGL.Panning.ToPan
1419 || !myToAllowPanning)
1424 AbortViewAnimation();
1426 const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1427 if (aCam->IsOrthographic()
1428 || !hasPanningAnchorPoint())
1430 theView->Pan (myGL.Panning.Delta.x(), myGL.Panning.Delta.y());
1431 theView->Invalidate();
1432 theView->View()->SynchronizeXRPosedToBaseCamera();
1436 Graphic3d_Vec2i aWinSize;
1437 theView->Window()->Size (aWinSize.x(), aWinSize.y());
1439 const gp_Dir& aDir = aCam->Direction();
1440 const gp_Ax3 aCameraCS (aCam->Center(), aDir.Reversed(), aDir ^ aCam->Up());
1441 const gp_XYZ anEyeToPnt = myPanPnt3d.XYZ() - aCam->Eye().XYZ();
1442 const gp_Pnt aViewDims = aCam->ViewDimensions (anEyeToPnt.Dot (aCam->Direction().XYZ())); // view dimensions at 3D point
1443 const Graphic3d_Vec2d aDxy (-aViewDims.X() * myGL.Panning.Delta.x() / double(aWinSize.x()),
1444 -aViewDims.X() * myGL.Panning.Delta.y() / double(aWinSize.x()));
1446 //theView->Translate (aCam, aDxy.x(), aDxy.y());
1448 const gp_Vec aCameraPan = gp_Vec (aCameraCS.XDirection()) * aDxy.x()
1449 + gp_Vec (aCameraCS.YDirection()) * aDxy.y();
1450 aPanTrsf.SetTranslation (aCameraPan);
1451 aCam->Transform (aPanTrsf);
1452 theView->Invalidate();
1453 theView->View()->SynchronizeXRPosedToBaseCamera();
1456 // =======================================================================
1457 // function : handleZRotate
1459 // =======================================================================
1460 void AIS_ViewController::handleZRotate (const Handle(V3d_View)& theView)
1462 if (!myGL.ZRotate.ToRotate
1463 || !myToAllowRotation)
1468 AbortViewAnimation();
1470 Graphic3d_Vec2i aViewPort;
1471 theView->Window()->Size (aViewPort.x(), aViewPort.y());
1472 Graphic3d_Vec2d aRotPnt (0.99 * aViewPort.x(),
1473 0.5 * aViewPort.y());
1474 theView->StartRotation (int(aRotPnt.x()), int(aRotPnt.y()), 0.4);
1475 aRotPnt.y() += myGL.ZRotate.Angle * aViewPort.y();
1476 theView->Rotation (int(aRotPnt.x()), int(aRotPnt.y()));
1477 theView->Invalidate();
1478 theView->View()->SynchronizeXRPosedToBaseCamera();
1481 // =======================================================================
1482 // function : handleZoom
1484 // =======================================================================
1485 void AIS_ViewController::handleZoom (const Handle(V3d_View)& theView,
1486 const Aspect_ScrollDelta& theParams,
1487 const gp_Pnt* thePnt)
1489 if (!myToAllowZooming)
1494 AbortViewAnimation();
1496 const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1499 const double aViewDist = Max (myMinCamDistance, (thePnt->XYZ() - aCam->Eye().XYZ()).Modulus());
1500 aCam->SetCenter (aCam->Eye().XYZ() + aCam->Direction().XYZ() * aViewDist);
1503 if (!theParams.HasPoint())
1505 Standard_Real aCoeff = Abs(theParams.Delta) / 100.0 + 1.0;
1506 aCoeff = theParams.Delta > 0.0 ? aCoeff : 1.0 / aCoeff;
1507 theView->SetZoom (aCoeff, true);
1508 theView->Invalidate();
1509 theView->View()->SynchronizeXRPosedToBaseCamera();
1513 // integer delta is too rough for small smooth increments
1514 //theView->StartZoomAtPoint (theParams.Point.x(), theParams.Point.y());
1515 //theView->ZoomAtPoint (0, 0, (int )theParams.Delta, (int )theParams.Delta);
1517 double aDZoom = Abs (theParams.Delta) / 100.0 + 1.0;
1518 aDZoom = (theParams.Delta > 0.0) ? aDZoom : 1.0 / aDZoom;
1524 const Graphic3d_Vec2d aViewDims (aCam->ViewDimensions().X(), aCam->ViewDimensions().Y());
1526 // ensure that zoom will not be too small or too big
1527 double aCoef = aDZoom;
1528 if (aViewDims.x() < aCoef * Precision::Confusion())
1530 aCoef = aViewDims.x() / Precision::Confusion();
1532 else if (aViewDims.x() > aCoef * 1e12)
1534 aCoef = aViewDims.x() / 1e12;
1536 if (aViewDims.y() < aCoef * Precision::Confusion())
1538 aCoef = aViewDims.y() / Precision::Confusion();
1540 else if (aViewDims.y() > aCoef * 1e12)
1542 aCoef = aViewDims.y() / 1e12;
1545 Graphic3d_Vec2d aZoomAtPointXYv (0.0, 0.0);
1546 theView->Convert (theParams.Point.x(), theParams.Point.y(),
1547 aZoomAtPointXYv.x(), aZoomAtPointXYv.y());
1548 Graphic3d_Vec2d aDxy = aZoomAtPointXYv / aCoef;
1549 aCam->SetScale (aCam->Scale() / aCoef);
1551 const gp_Dir& aDir = aCam->Direction();
1552 const gp_Ax3 aCameraCS (aCam->Center(), aDir.Reversed(), aDir ^ aCam->Up());
1554 // pan back to the point
1555 aDxy = aZoomAtPointXYv - aDxy;
1558 // zoom at 3D point with perspective projection
1559 const gp_XYZ anEyeToPnt = thePnt->XYZ() - aCam->Eye().XYZ();
1560 aDxy.SetValues (anEyeToPnt.Dot (aCameraCS.XDirection().XYZ()),
1561 anEyeToPnt.Dot (aCameraCS.YDirection().XYZ()));
1563 // view dimensions at 3D point
1564 const gp_Pnt aViewDims1 = aCam->ViewDimensions (anEyeToPnt.Dot (aCam->Direction().XYZ()));
1566 Graphic3d_Vec2i aWinSize;
1567 theView->Window()->Size (aWinSize.x(), aWinSize.y());
1568 const Graphic3d_Vec2d aPanFromCenterPx (double(theParams.Point.x()) - 0.5 * double(aWinSize.x()),
1569 double(aWinSize.y() - theParams.Point.y() - 1) - 0.5 * double(aWinSize.y()));
1570 aDxy.x() += -aViewDims1.X() * aPanFromCenterPx.x() / double(aWinSize.x());
1571 aDxy.y() += -aViewDims1.Y() * aPanFromCenterPx.y() / double(aWinSize.y());
1574 //theView->Translate (aCam, aDxy.x(), aDxy.y());
1576 const gp_Vec aCameraPan = gp_Vec (aCameraCS.XDirection()) * aDxy.x()
1577 + gp_Vec (aCameraCS.YDirection()) * aDxy.y();
1578 aPanTrsf.SetTranslation (aCameraPan);
1579 aCam->Transform (aPanTrsf);
1580 theView->Invalidate();
1581 theView->View()->SynchronizeXRPosedToBaseCamera();
1584 // =======================================================================
1585 // function : handleZFocusScroll
1587 // =======================================================================
1588 void AIS_ViewController::handleZFocusScroll (const Handle(V3d_View)& theView,
1589 const Aspect_ScrollDelta& theParams)
1591 if (!myToAllowZFocus
1592 || !theView->Camera()->IsStereo())
1597 Standard_Real aFocus = theView->Camera()->ZFocus() + (theParams.Delta > 0.0 ? 0.05 : -0.05);
1601 theView->Camera()->SetZFocus (theView->Camera()->ZFocusType(), aFocus);
1602 theView->Invalidate();
1606 // =======================================================================
1607 // function : handleOrbitRotation
1609 // =======================================================================
1610 void AIS_ViewController::handleOrbitRotation (const Handle(V3d_View)& theView,
1611 const gp_Pnt& thePnt,
1614 if (!myToAllowRotation)
1619 const Handle(Graphic3d_Camera)& aCam = theView->View()->IsActiveXR()
1620 ? theView->View()->BaseXRCamera()
1621 : theView->Camera();
1622 if (myGL.OrbitRotation.ToStart)
1624 // default alternatives
1625 //if (myRotationMode == AIS_RotationMode_BndBoxActive) theView->StartRotation (myGL.RotateAtPoint.x(), myGL.RotateAtPoint.y());
1626 //theView->Rotate (0.0, 0.0, 0.0, thePnt.X(), thePnt.Y(), thePnt.Z(), true);
1628 myRotatePnt3d = thePnt;
1629 myCamStartOpUp = aCam->Up();
1630 myCamStartOpDir = aCam->Direction();
1631 myCamStartOpEye = aCam->Eye();
1632 myCamStartOpCenter = aCam->Center();
1635 aTrsf.SetTransformation (gp_Ax3 (myRotatePnt3d, aCam->OrthogonalizedUp(), aCam->Direction()),
1636 gp_Ax3 (myRotatePnt3d, gp::DZ(), gp::DX()));
1637 const gp_Quaternion aRot = aTrsf.GetRotation();
1638 aRot.GetEulerAngles (gp_YawPitchRoll, myRotateStartYawPitchRoll[0], myRotateStartYawPitchRoll[1], myRotateStartYawPitchRoll[2]);
1641 myCamStartOpToEye = gp_Vec (myRotatePnt3d, aCam->Eye()).Transformed (aTrsf);
1642 myCamStartOpToCenter = gp_Vec (myRotatePnt3d, aCam->Center()).Transformed (aTrsf);
1644 theView->Invalidate();
1647 if (!myGL.OrbitRotation.ToRotate)
1652 AbortViewAnimation();
1655 // amend camera to exclude roll angle (put camera Up vector to plane containing global Z and view direction)
1656 Graphic3d_Vec2i aWinXY;
1657 theView->Window()->Size (aWinXY.x(), aWinXY.y());
1658 double aYawAngleDelta = ((myGL.OrbitRotation.PointStart.x() - myGL.OrbitRotation.PointTo.x()) / double (aWinXY.x())) * (M_PI * 0.5);
1659 double aPitchAngleDelta = -((myGL.OrbitRotation.PointStart.y() - myGL.OrbitRotation.PointTo.y()) / double (aWinXY.y())) * (M_PI * 0.5);
1660 double aPitchAngleNew = 0.0, aRoll = 0.0;
1661 const double aYawAngleNew = myRotateStartYawPitchRoll[0] + aYawAngleDelta;
1662 if (!theView->View()->IsActiveXR())
1664 aPitchAngleNew = Max (Min (myRotateStartYawPitchRoll[1] + aPitchAngleDelta, M_PI * 0.5 - M_PI / 180.0), -M_PI * 0.5 + M_PI / 180.0);
1669 aRot.SetEulerAngles (gp_YawPitchRoll, aYawAngleNew, aPitchAngleNew, aRoll);
1671 aTrsfRot.SetRotation (aRot);
1673 const gp_Dir aNewUp = gp::DZ().Transformed (aTrsfRot);
1674 aCam->SetUp (aNewUp);
1675 aCam->SetEyeAndCenter (myRotatePnt3d.XYZ() + myCamStartOpToEye .Transformed (aTrsfRot).XYZ(),
1676 myRotatePnt3d.XYZ() + myCamStartOpToCenter.Transformed (aTrsfRot).XYZ());
1678 aCam->OrthogonalizeUp();
1682 // default alternatives
1683 //if (myRotationMode == AIS_RotationMode_BndBoxActive) theView->Rotation (myGL.RotateToPoint.x(), myGL.RotateToPoint.y());
1684 //theView->Rotate (aDX, aDY, aDZ, myRotatePnt3d.X(), myRotatePnt3d.Y(), myRotatePnt3d.Z(), false);
1686 // restore previous camera state
1687 aCam->SetEyeAndCenter (myCamStartOpEye, myCamStartOpCenter);
1688 aCam->SetUp (myCamStartOpUp);
1689 aCam->SetDirectionFromEye (myCamStartOpDir);
1691 Graphic3d_Vec2d aWinXY;
1692 theView->Size (aWinXY.x(), aWinXY.y());
1693 const Standard_Real rx = (Standard_Real )theView->Convert (aWinXY.x());
1694 const Standard_Real ry = (Standard_Real )theView->Convert (aWinXY.y());
1696 const double THE_2PI = M_PI * 2.0;
1697 double aDX = (myGL.OrbitRotation.PointTo.x() - myGL.OrbitRotation.PointStart.x()) * M_PI / rx;
1698 double aDY = (myGL.OrbitRotation.PointStart.y() - myGL.OrbitRotation.PointTo.y()) * M_PI / ry;
1700 if (aDX > 0.0) { while (aDX > THE_2PI) { aDX -= THE_2PI; } }
1701 else if(aDX < 0.0) { while (aDX < -THE_2PI) { aDX += THE_2PI; } }
1702 if (aDY > 0.0) { while (aDY > THE_2PI) { aDY -= THE_2PI; } }
1703 else if(aDY < 0.0) { while (aDY < -THE_2PI) { aDY += THE_2PI; } }
1705 // rotate camera around 3 initial axes
1706 gp_Dir aCamDir (aCam->Direction().Reversed());
1707 gp_Dir aCamUp (aCam->Up());
1708 gp_Dir aCamSide(aCamUp.Crossed (aCamDir));
1710 gp_Trsf aRot[2], aTrsf;
1711 aRot[0].SetRotation (gp_Ax1 (myRotatePnt3d, aCamUp), -aDX);
1712 aRot[1].SetRotation (gp_Ax1 (myRotatePnt3d, aCamSide), aDY);
1713 aTrsf.Multiply (aRot[0]);
1714 aTrsf.Multiply (aRot[1]);
1716 aCam->Transform (aTrsf);
1719 theView->Invalidate();
1720 theView->View()->SynchronizeXRBaseToPosedCamera();
1723 // =======================================================================
1724 // function : handleViewRotation
1726 // =======================================================================
1727 void AIS_ViewController::handleViewRotation (const Handle(V3d_View)& theView,
1729 double thePitchExtra,
1731 bool theToRestartOnIncrement)
1733 if (!myToAllowRotation)
1738 const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1739 const bool toRotateAnyway = Abs (theYawExtra) > gp::Resolution()
1740 || Abs (thePitchExtra) > gp::Resolution()
1741 || Abs (theRoll - myRotateStartYawPitchRoll[2]) > gp::Resolution();
1743 && theToRestartOnIncrement)
1745 myGL.ViewRotation.ToStart = true;
1746 myGL.ViewRotation.PointTo = myGL.ViewRotation.PointStart;
1748 if (myGL.ViewRotation.ToStart)
1751 aTrsf.SetTransformation (gp_Ax3 (gp::Origin(), aCam->OrthogonalizedUp(), aCam->Direction()),
1752 gp_Ax3 (gp::Origin(), gp::DZ(), gp::DX()));
1753 const gp_Quaternion aRot = aTrsf.GetRotation();
1754 double aRollDummy = 0.0;
1755 aRot.GetEulerAngles (gp_YawPitchRoll, myRotateStartYawPitchRoll[0], myRotateStartYawPitchRoll[1], aRollDummy);
1759 myRotateStartYawPitchRoll[0] += theYawExtra;
1760 myRotateStartYawPitchRoll[1] += thePitchExtra;
1761 myRotateStartYawPitchRoll[2] = theRoll;
1762 myGL.ViewRotation.ToRotate = true;
1765 if (!myGL.ViewRotation.ToRotate)
1770 AbortViewAnimation();
1772 Graphic3d_Vec2i aWinXY;
1773 theView->Window()->Size (aWinXY.x(), aWinXY.y());
1774 double aYawAngleDelta = ((myGL.ViewRotation.PointStart.x() - myGL.ViewRotation.PointTo.x()) / double (aWinXY.x())) * (M_PI * 0.5);
1775 double aPitchAngleDelta = -((myGL.ViewRotation.PointStart.y() - myGL.ViewRotation.PointTo.y()) / double (aWinXY.y())) * (M_PI * 0.5);
1776 const double aPitchAngleNew = Max (Min (myRotateStartYawPitchRoll[1] + aPitchAngleDelta, M_PI * 0.5 - M_PI / 180.0), -M_PI * 0.5 + M_PI / 180.0);
1777 const double aYawAngleNew = myRotateStartYawPitchRoll[0] + aYawAngleDelta;
1779 aRot.SetEulerAngles (gp_YawPitchRoll, aYawAngleNew, aPitchAngleNew, theRoll);
1781 aTrsfRot.SetRotation (aRot);
1783 const gp_Dir aNewUp = gp::DZ().Transformed (aTrsfRot);
1784 const gp_Dir aNewDir = gp::DX().Transformed (aTrsfRot);
1785 aCam->SetUp (aNewUp);
1786 aCam->SetDirectionFromEye (aNewDir);
1787 aCam->OrthogonalizeUp();
1788 theView->Invalidate();
1791 // =======================================================================
1792 // function : PickPoint
1794 // =======================================================================
1795 bool AIS_ViewController::PickPoint (gp_Pnt& thePnt,
1796 const Handle(AIS_InteractiveContext)& theCtx,
1797 const Handle(V3d_View)& theView,
1798 const Graphic3d_Vec2i& theCursor,
1799 bool theToStickToPickRay)
1801 ResetPreviousMoveTo();
1803 const Handle(StdSelect_ViewerSelector3d)& aSelector = theCtx->MainSelector();
1804 aSelector->Pick (theCursor.x(), theCursor.y(), theView);
1805 if (aSelector->NbPicked() < 1)
1810 const SelectMgr_SortCriterion& aPicked = aSelector->PickedData (1);
1811 if (theToStickToPickRay
1812 && !Precision::IsInfinite (aPicked.Depth))
1814 thePnt = aSelector->GetManager().DetectedPoint (aPicked.Depth);
1818 thePnt = aSelector->PickedPoint (1);
1820 return !Precision::IsInfinite (thePnt.X())
1821 && !Precision::IsInfinite (thePnt.Y())
1822 && !Precision::IsInfinite (thePnt.Z());
1825 // =======================================================================
1826 // function : GravityPoint
1828 // =======================================================================
1829 gp_Pnt AIS_ViewController::GravityPoint (const Handle(AIS_InteractiveContext)& theCtx,
1830 const Handle(V3d_View)& theView)
1832 switch (myRotationMode)
1834 case AIS_RotationMode_PickLast:
1835 case AIS_RotationMode_PickCenter:
1837 Graphic3d_Vec2i aCursor ((int )myGL.OrbitRotation.PointStart.x(), (int )myGL.OrbitRotation.PointStart.y());
1838 if (myRotationMode == AIS_RotationMode_PickCenter)
1840 Graphic3d_Vec2i aViewPort;
1841 theView->Window()->Size (aViewPort.x(), aViewPort.y());
1842 aCursor = aViewPort / 2;
1846 if (PickPoint (aPnt, theCtx, theView, aCursor, myToStickToRayOnRotation))
1852 case AIS_RotationMode_CameraAt:
1854 const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1855 return aCam->Center();
1857 case AIS_RotationMode_BndBoxScene:
1859 Bnd_Box aBndBox = theView->View()->MinMaxValues (false);
1860 if (!aBndBox.IsVoid())
1862 return (aBndBox.CornerMin().XYZ() + aBndBox.CornerMax().XYZ()) * 0.5;
1866 case AIS_RotationMode_BndBoxActive:
1870 return theCtx ->GravityPoint (theView);
1873 // =======================================================================
1874 // function : FitAllAuto
1876 // =======================================================================
1877 void AIS_ViewController::FitAllAuto (const Handle(AIS_InteractiveContext)& theCtx,
1878 const Handle(V3d_View)& theView)
1880 const Bnd_Box aBoxSel = theCtx->BoundingBoxOfSelection();
1881 const double aFitMargin = 0.01;
1882 if (aBoxSel.IsVoid())
1884 theView->FitAll (aFitMargin, false);
1888 // fit all algorithm is not 100% stable - so compute some precision to compare equal camera values
1889 const double aFitTol = (aBoxSel.CornerMax().XYZ() - aBoxSel.CornerMin().XYZ()).Modulus() * 0.000001;
1890 const Bnd_Box aBoxAll = theView->View()->MinMaxValues();
1892 const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1893 Handle(Graphic3d_Camera) aCameraSel = new Graphic3d_Camera (aCam);
1894 Handle(Graphic3d_Camera) aCameraAll = new Graphic3d_Camera (aCam);
1895 theView->FitMinMax (aCameraSel, aBoxSel, aFitMargin);
1896 theView->FitMinMax (aCameraAll, aBoxAll, aFitMargin);
1897 if (aCameraSel->Center().IsEqual (aCam->Center(), aFitTol)
1898 && Abs (aCameraSel->Scale() - aCam->Scale()) < aFitTol
1899 && Abs (aCameraSel->Distance() - aCam->Distance()) < aFitTol)
1901 // fit all entire view on second FitALL request
1902 aCam->Copy (aCameraAll);
1906 aCam->Copy (aCameraSel);
1910 // =======================================================================
1911 // function : handleViewOrientationKeys
1913 // =======================================================================
1914 void AIS_ViewController::handleViewOrientationKeys (const Handle(AIS_InteractiveContext)& theCtx,
1915 const Handle(V3d_View)& theView)
1917 if (myNavigationMode == AIS_NavigationMode_FirstPersonWalk)
1922 Handle(Graphic3d_Camera) aCameraBack;
1923 struct ViewKeyAction
1926 V3d_TypeOfOrientation Orientation;
1928 static const ViewKeyAction THE_VIEW_KEYS[] =
1930 { Aspect_VKey_ViewTop, V3d_TypeOfOrientation_Zup_Top },
1931 { Aspect_VKey_ViewBottom, V3d_TypeOfOrientation_Zup_Bottom },
1932 { Aspect_VKey_ViewLeft, V3d_TypeOfOrientation_Zup_Left },
1933 { Aspect_VKey_ViewRight, V3d_TypeOfOrientation_Zup_Right },
1934 { Aspect_VKey_ViewFront, V3d_TypeOfOrientation_Zup_Front },
1935 { Aspect_VKey_ViewBack, V3d_TypeOfOrientation_Zup_Back },
1936 { Aspect_VKey_ViewAxoLeftProj, V3d_TypeOfOrientation_Zup_AxoLeft },
1937 { Aspect_VKey_ViewAxoRightProj, V3d_TypeOfOrientation_Zup_AxoRight },
1938 { Aspect_VKey_ViewRoll90CW, (V3d_TypeOfOrientation )-1},
1939 { Aspect_VKey_ViewRoll90CCW, (V3d_TypeOfOrientation )-1},
1940 { Aspect_VKey_ViewFitAll, (V3d_TypeOfOrientation )-1}
1943 Standard_Mutex::Sentry aLock (myKeys.Mutex());
1944 const size_t aNbKeys = sizeof(THE_VIEW_KEYS) / sizeof(*THE_VIEW_KEYS);
1945 const double anEventTime = EventTime();
1946 for (size_t aKeyIter = 0; aKeyIter < aNbKeys; ++aKeyIter)
1948 const ViewKeyAction& aKeyAction = THE_VIEW_KEYS[aKeyIter];
1949 if (!myKeys.IsKeyDown (aKeyAction.Key))
1954 myKeys.KeyUp (aKeyAction.Key, anEventTime);
1955 if (aCameraBack.IsNull())
1957 aCameraBack = theView->Camera();
1958 theView->SetCamera (new Graphic3d_Camera (aCameraBack));
1960 if (aKeyAction.Orientation != (V3d_TypeOfOrientation )-1)
1962 theView->SetProj (aKeyAction.Orientation);
1963 FitAllAuto (theCtx, theView);
1965 else if (aKeyAction.Key == Aspect_VKey_ViewRoll90CW)
1967 const double aTwist = theView->Twist() + M_PI / 2.0;
1968 theView->SetTwist (aTwist);
1970 else if (aKeyAction.Key == Aspect_VKey_ViewRoll90CCW)
1972 const double aTwist = theView->Twist() - M_PI / 2.0;
1973 theView->SetTwist (aTwist);
1975 else if (aKeyAction.Key == Aspect_VKey_ViewFitAll)
1977 FitAllAuto (theCtx, theView);
1982 if (aCameraBack.IsNull())
1987 Handle(Graphic3d_Camera) aCameraNew = theView->Camera();
1988 theView->SetCamera (aCameraBack);
1989 const Graphic3d_Mat4d anOrientMat1 = aCameraBack->OrientationMatrix();
1990 const Graphic3d_Mat4d anOrientMat2 = aCameraNew ->OrientationMatrix();
1991 if (anOrientMat1 != anOrientMat2)
1993 const Handle(AIS_AnimationCamera)& aCamAnim = myViewAnimation;
1994 aCamAnim->SetView (theView);
1995 aCamAnim->SetStartPts (0.0);
1996 aCamAnim->SetCameraStart (new Graphic3d_Camera (aCameraBack));
1997 aCamAnim->SetCameraEnd (new Graphic3d_Camera (aCameraNew));
1998 aCamAnim->StartTimer (0.0, 1.0, true, false);
2002 // =======================================================================
2003 // function : handleNavigationKeys
2005 // =======================================================================
2006 AIS_WalkDelta AIS_ViewController::handleNavigationKeys (const Handle(AIS_InteractiveContext)& ,
2007 const Handle(V3d_View)& theView)
2010 double aCrouchRatio = 1.0, aRunRatio = 1.0;
2011 if (myNavigationMode == AIS_NavigationMode_FirstPersonFlight)
2016 const double aRotSpeed = 0.5;
2017 const double aWalkSpeedCoef = WalkSpeedRelative();
2018 AIS_WalkDelta aWalk = FetchNavigationKeys (aCrouchRatio, aRunRatio);
2019 if (aWalk.IsJumping())
2023 theView->Invalidate();
2025 if (aWalk.IsEmpty())
2029 else if (myGL.OrbitRotation.ToRotate
2030 || myGL.OrbitRotation.ToStart)
2036 const Bnd_Box aBndBox = theView->View()->MinMaxValues();
2037 if (!aBndBox.IsVoid())
2039 aMin = aBndBox.CornerMin().XYZ();
2040 aMax = aBndBox.CornerMax().XYZ();
2042 double aBndDiam = Max (Max (aMax.X() - aMin.X(), aMax.Y() - aMin.Y()), aMax.Z() - aMin.Z());
2043 if (aBndDiam <= gp::Resolution())
2048 const double aWalkSpeed = myNavigationMode != AIS_NavigationMode_Orbit
2049 && myNavigationMode != AIS_NavigationMode_FirstPersonFlight
2050 ? theView->View()->UnitFactor() * WalkSpeedAbsolute()
2051 : aWalkSpeedCoef * aBndDiam;
2052 const Handle(Graphic3d_Camera)& aCam = theView->View()->IsActiveXR()
2053 ? theView->View()->BaseXRCamera()
2054 : theView->Camera();
2056 // move forward in plane XY and up along Z
2057 const gp_Dir anUp = ToLockOrbitZUp() ? gp::DZ() : aCam->OrthogonalizedUp();
2059 && myToAllowPanning)
2061 const gp_Vec aSide = -aCam->SideRight();
2062 gp_XYZ aFwd = aCam->Direction().XYZ();
2063 aFwd -= anUp.XYZ() * (anUp.XYZ() * aFwd);
2066 if (!aWalk[AIS_WalkTranslation_Forward].IsEmpty())
2068 if (!aCam->IsOrthographic())
2070 aMoveVec += aFwd * aWalk[AIS_WalkTranslation_Forward].Value * aWalk[AIS_WalkTranslation_Forward].Pressure * aWalkSpeed;
2073 if (!aWalk[AIS_WalkTranslation_Side].IsEmpty())
2075 aMoveVec += aSide.XYZ() * aWalk[AIS_WalkTranslation_Side].Value * aWalk[AIS_WalkTranslation_Side].Pressure * aWalkSpeed;
2077 if (!aWalk[AIS_WalkTranslation_Up].IsEmpty())
2079 aMoveVec += anUp.XYZ() * aWalk[AIS_WalkTranslation_Up].Value * aWalk[AIS_WalkTranslation_Up].Pressure * aWalkSpeed;
2082 if (aCam->IsOrthographic())
2084 if (!aWalk[AIS_WalkTranslation_Forward].IsEmpty())
2086 const double aZoomDelta = aWalk[AIS_WalkTranslation_Forward].Value * aWalk[AIS_WalkTranslation_Forward].Pressure * aWalkSpeedCoef;
2087 handleZoom (theView, Aspect_ScrollDelta (aZoomDelta * 100.0), NULL);
2091 gp_Trsf aTrsfTranslate;
2092 aTrsfTranslate.SetTranslation (aMoveVec);
2093 aCam->Transform (aTrsfTranslate);
2097 if (myNavigationMode == AIS_NavigationMode_Orbit
2098 && myToAllowRotation)
2100 if (!aWalk[AIS_WalkRotation_Yaw].IsEmpty())
2103 aTrsfRot.SetRotation (gp_Ax1 (aCam->Eye(), anUp), aWalk[AIS_WalkRotation_Yaw].Value * aRotSpeed);
2104 aCam->Transform (aTrsfRot);
2106 if (!aWalk[AIS_WalkRotation_Pitch].IsEmpty())
2108 const gp_Vec aSide = -aCam->SideRight();
2110 aTrsfRot.SetRotation (gp_Ax1 (aCam->Eye(), aSide), -aWalk[AIS_WalkRotation_Pitch].Value * aRotSpeed);
2111 aCam->Transform (aTrsfRot);
2113 if (!aWalk[AIS_WalkRotation_Roll].IsEmpty()
2114 && !ToLockOrbitZUp())
2117 aTrsfRot.SetRotation (gp_Ax1 (aCam->Center(), aCam->Direction()), aWalk[AIS_WalkRotation_Roll].Value * aRotSpeed);
2118 aCam->Transform (aTrsfRot);
2124 theView->Invalidate();
2125 theView->View()->SynchronizeXRBaseToPosedCamera();
2129 // =======================================================================
2130 // function : handleCameraActions
2132 // =======================================================================
2133 void AIS_ViewController::handleCameraActions (const Handle(AIS_InteractiveContext)& theCtx,
2134 const Handle(V3d_View)& theView,
2135 const AIS_WalkDelta& theWalk)
2137 // apply view actions
2138 if (myGL.Orientation.ToSetViewOrient)
2140 theView->SetProj (myGL.Orientation.ViewOrient);
2141 myGL.Orientation.ToFitAll = true;
2145 if (myGL.Orientation.ToFitAll)
2147 const double aFitMargin = 0.01;
2148 theView->FitAll (aFitMargin, false);
2149 theView->Invalidate();
2150 myGL.Orientation.ToFitAll = false;
2153 if (myGL.IsNewGesture)
2155 if (myAnchorPointPrs1->HasInteractiveContext())
2157 theCtx->Remove (myAnchorPointPrs1, false);
2158 if (!theView->Viewer()->ZLayerSettings (myAnchorPointPrs1->ZLayer()).IsImmediate())
2160 theView->Invalidate();
2164 theView->InvalidateImmediate();
2167 if (myAnchorPointPrs2->HasInteractiveContext())
2169 theCtx->Remove (myAnchorPointPrs2, false);
2170 if (!theView->Viewer()->ZLayerSettings (myAnchorPointPrs2->ZLayer()).IsImmediate())
2172 theView->Invalidate();
2176 theView->InvalidateImmediate();
2180 if (myHasHlrOnBeforeRotation)
2182 myHasHlrOnBeforeRotation = false;
2183 theView->SetComputedMode (true);
2184 theView->Invalidate();
2188 if (myNavigationMode != AIS_NavigationMode_FirstPersonWalk)
2190 if (myGL.Panning.ToStart
2191 && myToAllowPanning)
2193 gp_Pnt aPanPnt (Precision::Infinite(), 0.0, 0.0);
2194 if (!theView->Camera()->IsOrthographic())
2196 bool toStickToRay = false;
2197 if (myGL.Panning.PointStart.x() >= 0
2198 && myGL.Panning.PointStart.y() >= 0)
2200 PickPoint (aPanPnt, theCtx, theView, myGL.Panning.PointStart, toStickToRay);
2202 if (Precision::IsInfinite (aPanPnt.X()))
2204 Graphic3d_Vec2i aWinSize;
2205 theView->Window()->Size (aWinSize.x(), aWinSize.y());
2206 PickPoint (aPanPnt, theCtx, theView, aWinSize / 2, toStickToRay);
2208 if (!Precision::IsInfinite (aPanPnt.X())
2209 && myToShowPanAnchorPoint)
2212 aPntTrsf.SetTranslation (gp_Vec (aPanPnt.XYZ()));
2213 theCtx->SetLocation (myAnchorPointPrs2, aPntTrsf);
2216 setPanningAnchorPoint (aPanPnt);
2219 if (myToShowPanAnchorPoint
2220 && hasPanningAnchorPoint()
2221 && myGL.Panning.ToPan
2222 && !myGL.IsNewGesture
2223 && !myAnchorPointPrs2->HasInteractiveContext())
2225 theCtx->Display (myAnchorPointPrs2, 0, -1, false, AIS_DS_Displayed);
2228 handlePanning (theView);
2229 handleZRotate (theView);
2232 if ((myNavigationMode == AIS_NavigationMode_Orbit
2233 || myGL.OrbitRotation.ToStart
2234 || myGL.OrbitRotation.ToRotate)
2235 && myToAllowRotation)
2237 if (myGL.OrbitRotation.ToStart
2238 && !myHasHlrOnBeforeRotation)
2240 myHasHlrOnBeforeRotation = theView->ComputedMode();
2241 if (myHasHlrOnBeforeRotation)
2243 theView->SetComputedMode (false);
2248 if (myGL.OrbitRotation.ToStart)
2250 aGravPnt = GravityPoint (theCtx, theView);
2251 if (myToShowRotateCenter)
2254 aPntTrsf.SetTranslation (gp_Vec (aGravPnt.XYZ()));
2255 theCtx->SetLocation (myAnchorPointPrs1, aPntTrsf);
2256 theCtx->SetLocation (myAnchorPointPrs2, aPntTrsf);
2260 if (myToShowRotateCenter
2261 && myGL.OrbitRotation.ToRotate
2262 && !myGL.IsNewGesture
2263 && !myAnchorPointPrs1->HasInteractiveContext())
2265 theCtx->Display (myAnchorPointPrs1, 0, -1, false, AIS_DS_Displayed);
2266 theCtx->Display (myAnchorPointPrs2, 0, -1, false, AIS_DS_Displayed);
2268 handleOrbitRotation (theView, aGravPnt,
2269 myToLockOrbitZUp || myNavigationMode != AIS_NavigationMode_Orbit);
2272 if ((myNavigationMode != AIS_NavigationMode_Orbit
2273 || myGL.ViewRotation.ToStart
2274 || myGL.ViewRotation.ToRotate)
2275 && myToAllowRotation)
2277 if (myGL.ViewRotation.ToStart
2278 && !myHasHlrOnBeforeRotation)
2280 myHasHlrOnBeforeRotation = theView->ComputedMode();
2281 if (myHasHlrOnBeforeRotation)
2283 theView->SetComputedMode (false);
2288 if (!theWalk[AIS_WalkRotation_Roll].IsEmpty()
2289 && !myToLockOrbitZUp)
2291 aRoll = (M_PI / 12.0) * theWalk[AIS_WalkRotation_Roll].Pressure;
2292 aRoll *= Min (1000.0 * theWalk[AIS_WalkRotation_Roll].Duration, 100.0) / 100.0;
2293 if (theWalk[AIS_WalkRotation_Roll].Value < 0.0)
2299 handleViewRotation (theView, theWalk[AIS_WalkRotation_Yaw].Value, theWalk[AIS_WalkRotation_Pitch].Value, aRoll,
2300 myNavigationMode == AIS_NavigationMode_FirstPersonFlight);
2303 if (!myGL.ZoomActions.IsEmpty())
2305 for (NCollection_Sequence<Aspect_ScrollDelta>::Iterator aZoomIter (myGL.ZoomActions); aZoomIter.More(); aZoomIter.Next())
2307 Aspect_ScrollDelta aZoomParams = aZoomIter.Value();
2309 && (aZoomParams.Flags & Aspect_VKeyFlags_CTRL) != 0
2310 && theView->Camera()->IsStereo())
2312 handleZFocusScroll (theView, aZoomParams);
2316 if (!myToAllowZooming)
2321 if (!theView->Camera()->IsOrthographic())
2324 if (aZoomParams.HasPoint()
2325 && PickPoint (aPnt, theCtx, theView, aZoomParams.Point, myToStickToRayOnZoom))
2327 handleZoom (theView, aZoomParams, &aPnt);
2331 Graphic3d_Vec2i aWinSize;
2332 theView->Window()->Size (aWinSize.x(), aWinSize.y());
2333 if (PickPoint (aPnt, theCtx, theView, aWinSize / 2, myToStickToRayOnZoom))
2335 aZoomParams.ResetPoint(); // do not pretend to zoom at 'nothing'
2336 handleZoom (theView, aZoomParams, &aPnt);
2340 handleZoom (theView, aZoomParams, NULL);
2342 myGL.ZoomActions.Clear();
2346 // =======================================================================
2347 // function : handleXRInput
2349 // =======================================================================
2350 void AIS_ViewController::handleXRInput (const Handle(AIS_InteractiveContext)& theCtx,
2351 const Handle(V3d_View)& theView,
2352 const AIS_WalkDelta& )
2354 theView->View()->ProcessXRInput();
2355 if (!theView->View()->IsActiveXR())
2359 if (myXRCameraTmp.IsNull())
2361 myXRCameraTmp = new Graphic3d_Camera();
2363 handleXRTurnPad (theCtx, theView);
2364 handleXRTeleport(theCtx, theView);
2365 handleXRPicking (theCtx, theView);
2368 // =======================================================================
2369 // function : handleXRTurnPad
2371 // =======================================================================
2372 void AIS_ViewController::handleXRTurnPad (const Handle(AIS_InteractiveContext)& ,
2373 const Handle(V3d_View)& theView)
2375 if (myXRTurnAngle <= 0.0
2376 || !theView->View()->IsActiveXR())
2381 // turn left/right at 45 degrees on left/right trackpad clicks
2382 for (int aHand = 0; aHand < 2; ++aHand)
2384 const Aspect_XRTrackedDeviceRole aRole = aHand == 0 ? Aspect_XRTrackedDeviceRole_RightHand : Aspect_XRTrackedDeviceRole_LeftHand;
2385 const Handle(Aspect_XRAction)& aPadClickAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTrackPadClick);
2386 const Handle(Aspect_XRAction)& aPadPosAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTrackPadPosition);
2387 if (aPadClickAct.IsNull()
2388 || aPadPosAct.IsNull())
2393 const Aspect_XRDigitalActionData aPadClick = theView->View()->XRSession()->GetDigitalActionData (aPadClickAct);
2394 const Aspect_XRAnalogActionData aPadPos = theView->View()->XRSession()->GetAnalogActionData (aPadPosAct);
2395 if (aPadClick.IsActive
2396 && aPadClick.IsPressed
2397 && aPadClick.IsChanged
2399 && Abs (aPadPos.VecXYZ.y()) < 0.5f
2400 && Abs (aPadPos.VecXYZ.x()) > 0.7f)
2403 aTrsfTurn.SetRotation (gp_Ax1 (gp::Origin(), theView->View()->BaseXRCamera()->Up()), aPadPos.VecXYZ.x() < 0.0f ? myXRTurnAngle : -myXRTurnAngle);
2404 theView->View()->TurnViewXRCamera (aTrsfTurn);
2410 // =======================================================================
2411 // function : handleXRTeleport
2413 // =======================================================================
2414 void AIS_ViewController::handleXRTeleport (const Handle(AIS_InteractiveContext)& theCtx,
2415 const Handle(V3d_View)& theView)
2417 if (!theView->View()->IsActiveXR())
2422 // teleport on forward trackpad unclicks
2423 const Aspect_XRTrackedDeviceRole aTeleOld = myXRLastTeleportHand;
2424 myXRLastTeleportHand = Aspect_XRTrackedDeviceRole_Other;
2425 for (int aHand = 0; aHand < 2; ++aHand)
2427 const Aspect_XRTrackedDeviceRole aRole = aHand == 0 ? Aspect_XRTrackedDeviceRole_RightHand : Aspect_XRTrackedDeviceRole_LeftHand;
2428 const Standard_Integer aDeviceId = theView->View()->XRSession()->NamedTrackedDevice (aRole);
2429 if (aDeviceId == -1)
2434 const Handle(Aspect_XRAction)& aPadClickAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTrackPadClick);
2435 const Handle(Aspect_XRAction)& aPadPosAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTrackPadPosition);
2436 if (aPadClickAct.IsNull()
2437 || aPadPosAct.IsNull())
2442 const Aspect_XRDigitalActionData aPadClick = theView->View()->XRSession()->GetDigitalActionData (aPadClickAct);
2443 const Aspect_XRAnalogActionData aPadPos = theView->View()->XRSession()->GetAnalogActionData (aPadPosAct);
2444 const bool isPressed = aPadClick.IsPressed;
2445 const bool isClicked = !aPadClick.IsPressed
2446 && aPadClick.IsChanged;
2447 if (aPadClick.IsActive
2448 && (isPressed || isClicked)
2450 && aPadPos.VecXYZ.y() > 0.6f
2451 && Abs (aPadPos.VecXYZ.x()) < 0.5f)
2453 const Aspect_TrackedDevicePose& aPose = theView->View()->XRSession()->TrackedPoses()[aDeviceId];
2454 if (!aPose.IsValidPose)
2459 myXRLastTeleportHand = aRole;
2460 Standard_Real& aPickDepth = aRole == Aspect_XRTrackedDeviceRole_LeftHand ? myXRLastPickDepthLeft : myXRLastPickDepthRight;
2461 aPickDepth = Precision::Infinite();
2462 Graphic3d_Vec3 aPickNorm;
2463 const gp_Trsf aHandBase = theView->View()->PoseXRToWorld (aPose.Orientation);
2464 const Standard_Real aHeadHeight = theView->View()->XRSession()->HeadPose().TranslationPart().Y();
2466 const Standard_Integer aPickedId = handleXRMoveTo (theCtx, theView, aPose.Orientation, false);
2469 const SelectMgr_SortCriterion& aPickedData = theCtx->MainSelector()->PickedData (aPickedId);
2470 aPickNorm = aPickedData.Normal;
2471 if (aPickNorm.SquareModulus() > ShortRealEpsilon())
2473 aPickDepth = aPickedData.Point.Distance (aHandBase.TranslationPart());
2479 myXRLastTeleportHand = Aspect_XRTrackedDeviceRole_Other;
2480 if (!Precision::IsInfinite (aPickDepth))
2482 const gp_Dir aTeleDir = -gp::DZ().Transformed (aHandBase);
2483 const gp_Dir anUpDir = theView->View()->BaseXRCamera()->Up();
2485 bool isHorizontal = false;
2486 gp_Dir aPickNormDir (aPickNorm.x(), aPickNorm.y(), aPickNorm.z());
2487 if (anUpDir.IsEqual ( aPickNormDir, M_PI_4)
2488 || anUpDir.IsEqual (-aPickNormDir, M_PI_4))
2490 isHorizontal = true;
2493 gp_Pnt aNewEye = aHandBase.TranslationPart();
2496 aNewEye = aHandBase.TranslationPart()
2497 + aTeleDir.XYZ() * aPickDepth
2498 + anUpDir.XYZ() * aHeadHeight;
2502 if (aPickNormDir.Dot (aTeleDir) < 0.0)
2504 aPickNormDir.Reverse();
2506 aNewEye = aHandBase.TranslationPart()
2507 + aTeleDir.XYZ() * aPickDepth
2508 - aPickNormDir.XYZ() * aHeadHeight / 4;
2511 theView->View()->PosedXRCamera()->MoveEyeTo (aNewEye);
2512 theView->View()->ComputeXRBaseCameraFromPosed (theView->View()->PosedXRCamera(), theView->View()->XRSession()->HeadPose());
2519 if (myXRLastTeleportHand != aTeleOld)
2521 if (aTeleOld != Aspect_XRTrackedDeviceRole_Other)
2523 if (const Handle(Aspect_XRAction)& aHaptic = theView->View()->XRSession()->GenericAction (aTeleOld, Aspect_XRGenericAction_OutputHaptic))
2525 theView->View()->XRSession()->AbortHapticVibrationAction (aHaptic);
2528 if (myXRLastTeleportHand != Aspect_XRTrackedDeviceRole_Other)
2530 if (const Handle(Aspect_XRAction)& aHaptic = theView->View()->XRSession()->GenericAction (myXRLastTeleportHand, Aspect_XRGenericAction_OutputHaptic))
2532 theView->View()->XRSession()->TriggerHapticVibrationAction (aHaptic, myXRTeleportHaptic);
2538 // =======================================================================
2539 // function : handleXRPicking
2541 // =======================================================================
2542 void AIS_ViewController::handleXRPicking (const Handle(AIS_InteractiveContext)& theCtx,
2543 const Handle(V3d_View)& theView)
2545 if (!theView->View()->IsActiveXR())
2550 // handle selection on trigger clicks
2551 Aspect_XRTrackedDeviceRole aPickDevOld = myXRLastPickingHand;
2552 myXRLastPickingHand = Aspect_XRTrackedDeviceRole_Other;
2553 for (int aHand = 0; aHand < 2; ++aHand)
2555 const Aspect_XRTrackedDeviceRole aRole = aHand == 0 ? Aspect_XRTrackedDeviceRole_RightHand : Aspect_XRTrackedDeviceRole_LeftHand;
2556 const Handle(Aspect_XRAction)& aTrigClickAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTriggerClick);
2557 const Handle(Aspect_XRAction)& aTrigPullAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTriggerPull);
2558 if (aTrigClickAct.IsNull()
2559 || aTrigPullAct.IsNull())
2564 const Aspect_XRDigitalActionData aTrigClick = theView->View()->XRSession()->GetDigitalActionData (aTrigClickAct);
2565 const Aspect_XRAnalogActionData aTrigPos = theView->View()->XRSession()->GetAnalogActionData (aTrigPullAct);
2566 if (aTrigPos.IsActive
2567 && Abs (aTrigPos.VecXYZ.x()) > 0.1f)
2569 myXRLastPickingHand = aRole;
2570 handleXRHighlight (theCtx, theView);
2571 if (aTrigClick.IsActive
2572 && aTrigClick.IsPressed
2573 && aTrigClick.IsChanged)
2575 theCtx->Select (false);
2576 OnSelectionChanged (theCtx, theView);
2577 if (const Handle(Aspect_XRAction)& aHaptic = theView->View()->XRSession()->GenericAction (myXRLastPickingHand, Aspect_XRGenericAction_OutputHaptic))
2579 theView->View()->XRSession()->TriggerHapticVibrationAction (aHaptic, myXRSelectHaptic);
2585 if (myXRLastPickingHand != aPickDevOld)
2587 theCtx->ClearDetected();
2591 // =======================================================================
2592 // function : OnSelectionChanged
2594 // =======================================================================
2595 void AIS_ViewController::OnSelectionChanged (const Handle(AIS_InteractiveContext)& ,
2596 const Handle(V3d_View)& )
2601 // =======================================================================
2602 // function : OnObjectDragged
2604 // =======================================================================
2605 void AIS_ViewController::OnObjectDragged (const Handle(AIS_InteractiveContext)& theCtx,
2606 const Handle(V3d_View)& theView,
2607 AIS_DragAction theAction)
2611 case AIS_DragAction_Start:
2613 myDragObject.Nullify();
2614 if (!theCtx->HasDetected())
2619 Handle(AIS_InteractiveObject) aPrs = theCtx->DetectedInteractive();
2620 if (Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (aPrs))
2622 if (aManip->HasActiveMode())
2624 myDragObject = aManip;
2625 aManip->StartTransform (myGL.Dragging.PointStart.x(), myGL.Dragging.PointStart.y(), theView);
2630 case AIS_DragAction_Update:
2632 if (myDragObject.IsNull())
2637 if (Handle(SelectMgr_EntityOwner) aGlobOwner = myDragObject->GlobalSelOwner())
2639 theCtx->SetSelectedState (aGlobOwner, true);
2641 if (Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (myDragObject))
2643 aManip->Transform (myGL.Dragging.PointTo.x(), myGL.Dragging.PointTo.y(), theView);
2645 theView->Invalidate();
2648 case AIS_DragAction_Abort:
2650 if (myDragObject.IsNull())
2655 myGL.Dragging.PointTo = myGL.Dragging.PointStart;
2656 OnObjectDragged (theCtx, theView, AIS_DragAction_Update);
2658 if (Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (myDragObject))
2660 aManip->StopTransform (false);
2662 Standard_FALLTHROUGH
2664 case AIS_DragAction_Stop:
2666 if (myDragObject.IsNull())
2671 if (Handle(SelectMgr_EntityOwner) aGlobOwner = myDragObject->GlobalSelOwner())
2673 theCtx->SetSelectedState (aGlobOwner, false);
2676 theView->Invalidate();
2677 myDragObject.Nullify();
2683 // =======================================================================
2684 // function : contextLazyMoveTo
2686 // =======================================================================
2687 void AIS_ViewController::contextLazyMoveTo (const Handle(AIS_InteractiveContext)& theCtx,
2688 const Handle(V3d_View)& theView,
2689 const Graphic3d_Vec2i& thePnt)
2691 if (myPrevMoveTo == thePnt
2692 || myHasHlrOnBeforeRotation) // ignore highlighting in-between rotation of HLR view
2697 myPrevMoveTo = thePnt;
2699 Handle(SelectMgr_EntityOwner) aLastPicked = theCtx->DetectedOwner();
2700 theView->AutoZFit();
2701 theCtx->MoveTo (thePnt.x(), thePnt.y(), theView, false);
2702 Handle(SelectMgr_EntityOwner) aNewPicked = theCtx->DetectedOwner();
2704 if (theView->Viewer()->Grid()->IsActive()
2705 && theView->Viewer()->GridEcho())
2707 if (aNewPicked.IsNull())
2709 Graphic3d_Vec3d aPnt3d;
2710 theView->ConvertToGrid (thePnt.x(), thePnt.y(), aPnt3d[0], aPnt3d[1], aPnt3d[2]);
2711 theView->Viewer()->ShowGridEcho (theView, Graphic3d_Vertex (aPnt3d[0], aPnt3d[1], aPnt3d[2]));
2712 theView->InvalidateImmediate();
2716 theView->Viewer()->HideGridEcho (theView);
2717 theView->InvalidateImmediate();
2721 if (aLastPicked != aNewPicked
2722 || (!aNewPicked.IsNull() && aNewPicked->IsForcedHilight()))
2724 // dynamic highlight affects all Views
2725 for (V3d_ListOfViewIterator aViewIter (theView->Viewer()->ActiveViewIterator()); aViewIter.More(); aViewIter.Next())
2727 const Handle(V3d_View)& aView = aViewIter.Value();
2728 aView->InvalidateImmediate();
2733 // =======================================================================
2734 // function : handleSelectionPick
2736 // =======================================================================
2737 void AIS_ViewController::handleSelectionPick (const Handle(AIS_InteractiveContext)& theCtx,
2738 const Handle(V3d_View)& theView)
2740 if (myGL.Selection.Tool == AIS_ViewSelectionTool_Picking
2741 && !myGL.Selection.Points.IsEmpty())
2743 for (NCollection_Sequence<Graphic3d_Vec2i>::Iterator aPntIter (myGL.Selection.Points); aPntIter.More(); aPntIter.Next())
2745 const bool hadPrevMoveTo = HasPreviousMoveTo();
2746 contextLazyMoveTo (theCtx, theView, aPntIter.Value());
2749 ResetPreviousMoveTo();
2752 if (myGL.Selection.IsXOR)
2754 theCtx->ShiftSelect (false);
2758 theCtx->Select (false);
2761 // selection affects all Views
2762 theView->Viewer()->Invalidate();
2764 OnSelectionChanged (theCtx, theView);
2767 myGL.Selection.Points.Clear();
2771 // =======================================================================
2772 // function : handleSelectionPoly
2774 // =======================================================================
2775 void AIS_ViewController::handleSelectionPoly (const Handle(AIS_InteractiveContext)& theCtx,
2776 const Handle(V3d_View)& theView)
2778 // rubber-band & window polygon selection
2779 if (myGL.Selection.Tool == AIS_ViewSelectionTool_RubberBand
2780 || myGL.Selection.Tool == AIS_ViewSelectionTool_Polygon
2781 || myGL.Selection.Tool == AIS_ViewSelectionTool_ZoomWindow)
2783 if (!myGL.Selection.Points.IsEmpty())
2785 myRubberBand->ClearPoints();
2786 myRubberBand->SetToUpdate();
2788 const bool anIsRubber = myGL.Selection.Tool == AIS_ViewSelectionTool_RubberBand
2789 || myGL.Selection.Tool == AIS_ViewSelectionTool_ZoomWindow;
2792 myRubberBand->SetRectangle (myGL.Selection.Points.First().x(), -myGL.Selection.Points.First().y(),
2793 myGL.Selection.Points.Last().x(), -myGL.Selection.Points.Last().y());
2797 Graphic3d_Vec2i aPrev (IntegerLast(), IntegerLast());
2798 for (NCollection_Sequence<Graphic3d_Vec2i>::Iterator aSelIter (myGL.Selection.Points); aSelIter.More(); aSelIter.Next())
2800 Graphic3d_Vec2i aPntNew = Graphic3d_Vec2i (aSelIter.Value().x(), -aSelIter.Value().y());
2801 if (aPntNew != aPrev)
2804 myRubberBand->AddPoint (Graphic3d_Vec2i (aSelIter.Value().x(), -aSelIter.Value().y()));
2809 myRubberBand->SetPolygonClosed (anIsRubber);
2812 theCtx->Display (myRubberBand, 0, -1, false, AIS_DS_Displayed);
2814 catch (const Standard_Failure& theEx)
2816 Message::SendWarning (TCollection_AsciiString ("Internal error while displaying rubber-band: ")
2817 + theEx.DynamicType()->Name() + ", " + theEx.GetMessageString());
2818 myRubberBand->ClearPoints();
2820 if (!theView->Viewer()->ZLayerSettings (myRubberBand->ZLayer()).IsImmediate())
2822 theView->Invalidate();
2826 theView->InvalidateImmediate();
2829 else if (!myRubberBand.IsNull()
2830 && myRubberBand->HasInteractiveContext())
2832 theCtx->Remove (myRubberBand, false);
2833 myRubberBand->ClearPoints();
2837 if (myGL.Selection.ToApplyTool)
2839 myGL.Selection.ToApplyTool = false;
2840 if (theCtx->IsDisplayed (myRubberBand))
2842 theCtx->Remove (myRubberBand, false);
2844 const NCollection_Sequence<Graphic3d_Vec2i>& aPoints = myRubberBand->Points();
2845 if (aPoints.Size() == 4
2846 && aPoints.Value (1).x() == aPoints.Value (2).x()
2847 && aPoints.Value (3).x() == aPoints.Value (4).x()
2848 && aPoints.Value (1).y() == aPoints.Value (4).y()
2849 && aPoints.Value (2).y() == aPoints.Value (3).y())
2851 const Graphic3d_Vec2i aPnt1 (aPoints.Value (1).x(), -aPoints.Value (1).y());
2852 const Graphic3d_Vec2i aPnt2 (aPoints.Value (3).x(), -aPoints.Value (3).y());
2853 if (myGL.Selection.Tool == AIS_ViewSelectionTool_ZoomWindow)
2855 theView->WindowFitAll (aPnt1.x(), aPnt1.y(), aPnt2.x(), aPnt2.y());
2856 theView->Invalidate();
2860 theCtx->MainSelector()->AllowOverlapDetection (aPnt1.y() != Min (aPnt1.y(), aPnt2.y()));
2861 if (myGL.Selection.IsXOR)
2863 theCtx->ShiftSelect (Min (aPnt1.x(), aPnt2.x()), Min (aPnt1.y(), aPnt2.y()),
2864 Max (aPnt1.x(), aPnt2.x()), Max (aPnt1.y(), aPnt2.y()),
2869 theCtx->Select (Min (aPnt1.x(), aPnt2.x()), Min (aPnt1.y(), aPnt2.y()),
2870 Max (aPnt1.x(), aPnt2.x()), Max (aPnt1.y(), aPnt2.y()),
2873 theCtx->MainSelector()->AllowOverlapDetection (false);
2876 else if (aPoints.Length() >= 3)
2878 TColgp_Array1OfPnt2d aPolyline (1, aPoints.Length());
2879 TColgp_Array1OfPnt2d::Iterator aPolyIter (aPolyline);
2880 for (NCollection_Sequence<Graphic3d_Vec2i>::Iterator aSelIter (aPoints);
2881 aSelIter.More(); aSelIter.Next(), aPolyIter.Next())
2883 const Graphic3d_Vec2i& aNewPnt = aSelIter.Value();
2884 aPolyIter.ChangeValue() = gp_Pnt2d (aNewPnt.x(), -aNewPnt.y());
2887 if (myGL.Selection.IsXOR)
2889 theCtx->ShiftSelect (aPolyline, theView, false);
2893 theCtx->Select (aPolyline, theView, false);
2895 theCtx->MainSelector()->AllowOverlapDetection (false);
2899 myRubberBand->ClearPoints();
2900 if (myGL.Selection.Tool != AIS_ViewSelectionTool_ZoomWindow)
2902 // selection affects all Views
2903 theView->Viewer()->Invalidate();
2904 OnSelectionChanged (theCtx, theView);
2910 // =======================================================================
2911 // function : handleDynamicHighlight
2913 // =======================================================================
2914 void AIS_ViewController::handleDynamicHighlight (const Handle(AIS_InteractiveContext)& theCtx,
2915 const Handle(V3d_View)& theView)
2917 if ((myGL.MoveTo.ToHilight || myGL.Dragging.ToStart)
2918 && myNavigationMode != AIS_NavigationMode_FirstPersonWalk)
2920 const Graphic3d_Vec2i& aMoveToPnt = myGL.MoveTo.ToHilight ? myGL.MoveTo.Point : myGL.Dragging.PointStart;
2921 if (myGL.Dragging.ToStart && (!myGL.MoveTo.ToHilight || !myToAllowHighlight)
2922 && !HasPreviousMoveTo())
2924 contextLazyMoveTo (theCtx, theView, aMoveToPnt);
2925 ResetPreviousMoveTo();
2926 OnObjectDragged (theCtx, theView, AIS_DragAction_Start);
2927 theCtx->ClearDetected();
2929 else if (myToAllowHighlight)
2931 if (myPrevMoveTo != aMoveToPnt
2932 || (!theView->View()->IsActiveXR()
2933 && (myGL.OrbitRotation.ToRotate
2934 || myGL.ViewRotation.ToRotate
2935 || theView->IsInvalidated())))
2937 ResetPreviousMoveTo();
2938 contextLazyMoveTo (theCtx, theView, aMoveToPnt);
2940 if (myGL.Dragging.ToStart)
2942 OnObjectDragged (theCtx, theView, AIS_DragAction_Start);
2946 myGL.MoveTo.ToHilight = false;
2949 if (!myDragObject.IsNull())
2951 if (myGL.Dragging.ToAbort)
2953 OnObjectDragged (theCtx, theView, AIS_DragAction_Abort);
2954 myGL.OrbitRotation.ToRotate = false;
2955 myGL.ViewRotation .ToRotate = false;
2957 else if (myGL.Dragging.ToStop)
2959 OnObjectDragged (theCtx, theView, AIS_DragAction_Stop);
2960 myGL.OrbitRotation.ToRotate = false;
2961 myGL.ViewRotation .ToRotate = false;
2963 else if (myGL.OrbitRotation.ToRotate
2964 || myGL.ViewRotation.ToRotate)
2966 OnObjectDragged (theCtx, theView, AIS_DragAction_Update);
2967 myGL.OrbitRotation.ToRotate = false;
2968 myGL.ViewRotation .ToRotate = false;
2973 // =======================================================================
2974 // function : handleMoveTo
2976 // =======================================================================
2977 void AIS_ViewController::handleMoveTo (const Handle(AIS_InteractiveContext)& theCtx,
2978 const Handle(V3d_View)& theView)
2980 handleSelectionPick (theCtx, theView);
2981 handleDynamicHighlight(theCtx, theView);
2982 handleSelectionPoly (theCtx, theView);
2985 // =======================================================================
2986 // function : handleViewRedraw
2988 // =======================================================================
2989 void AIS_ViewController::handleViewRedraw (const Handle(AIS_InteractiveContext)& ,
2990 const Handle(V3d_View)& theView)
2992 // manage animation state
2993 if (!myViewAnimation.IsNull()
2994 && !myViewAnimation->IsStopped())
2996 myViewAnimation->UpdateTimer();
2997 ResetPreviousMoveTo();
3001 if (theView->View()->IsActiveXR())
3003 // VR requires continuous rendering
3004 myToAskNextFrame = true;
3007 for (V3d_ListOfViewIterator aViewIter (theView->Viewer()->ActiveViewIterator()); aViewIter.More(); aViewIter.Next())
3009 const Handle(V3d_View)& aView = aViewIter.Value();
3010 if (aView->IsInvalidated()
3011 || (myToAskNextFrame && aView == theView))
3013 if (aView->ComputedMode())
3022 else if (aView->IsInvalidatedImmediate())
3024 aView->RedrawImmediate();
3028 if (myToAskNextFrame)
3031 theView->Window()->InvalidateContent (Handle(Aspect_DisplayConnection)());
3035 // =======================================================================
3036 // function : handleXRMoveTo
3038 // =======================================================================
3039 Standard_Integer AIS_ViewController::handleXRMoveTo (const Handle(AIS_InteractiveContext)& theCtx,
3040 const Handle(V3d_View)& theView,
3041 const gp_Trsf& thePose,
3042 const Standard_Boolean theToHighlight)
3044 //ResetPreviousMoveTo();
3045 Standard_Integer aPickResult = 0;
3047 Handle(Graphic3d_Camera) aCamBack = theView->Camera();
3048 myXRCameraTmp->Copy (aCamBack);
3049 theView->View()->ComputeXRPosedCameraFromBase (*myXRCameraTmp, thePose);
3050 theView->SetCamera (myXRCameraTmp);
3051 Graphic3d_Vec2i aPickPixel;
3052 theView->Window()->Size (aPickPixel.x(), aPickPixel.y());
3054 const Standard_Integer aSelTolerBack = theCtx->MainSelector()->CustomPixelTolerance();
3055 theCtx->MainSelector()->SetPixelTolerance (1);
3056 theView->AutoZFit();
3059 theCtx->MoveTo (aPickPixel.x(), aPickPixel.y(), theView, false);
3060 if (!theCtx->DetectedOwner().IsNull())
3062 // ignore 2D objects
3063 for (aPickResult = 1; !theCtx->DetectedOwner()->Selectable()->TransformPersistence().IsNull(); ++aPickResult)
3065 if (theCtx->HilightNextDetected (theView, false) <= 1)
3067 theCtx->ClearDetected();
3076 theCtx->MainSelector()->Pick (aPickPixel.x(), aPickPixel.y(), theView);
3077 for (Standard_Integer aPickIter = 1; aPickIter <= theCtx->MainSelector()->NbPicked(); ++aPickIter)
3079 const SelectMgr_SortCriterion& aPickedData = theCtx->MainSelector()->PickedData (aPickIter);
3080 if (!aPickedData.Entity->OwnerId()->Selectable()->TransformPersistence().IsNull())
3086 aPickResult = aPickIter;
3090 theCtx->MainSelector()->SetPixelTolerance (aSelTolerBack);
3091 theView->SetCamera (aCamBack);
3095 // =======================================================================
3096 // function : handleXRHighlight
3098 // =======================================================================
3099 void AIS_ViewController::handleXRHighlight (const Handle(AIS_InteractiveContext)& theCtx,
3100 const Handle(V3d_View)& theView)
3102 if (myXRLastPickingHand != Aspect_XRTrackedDeviceRole_LeftHand
3103 && myXRLastPickingHand != Aspect_XRTrackedDeviceRole_RightHand)
3108 const Standard_Integer aDeviceId = theView->View()->XRSession()->NamedTrackedDevice (myXRLastPickingHand);
3109 if (aDeviceId == -1)
3114 const Aspect_TrackedDevicePose& aPose = theView->View()->XRSession()->TrackedPoses()[aDeviceId];
3115 if (!aPose.IsValidPose)
3120 Handle(SelectMgr_EntityOwner) aDetOld = theCtx->DetectedOwner();
3121 handleXRMoveTo (theCtx, theView, aPose.Orientation, true);
3122 if (!theCtx->DetectedOwner().IsNull()
3123 && theCtx->DetectedOwner() != aDetOld)
3125 if (const Handle(Aspect_XRAction)& aHaptic = theView->View()->XRSession()->GenericAction (myXRLastPickingHand, Aspect_XRGenericAction_OutputHaptic))
3127 theView->View()->XRSession()->TriggerHapticVibrationAction (aHaptic, myXRPickingHaptic);
3131 Standard_Real& aPickDepth = myXRLastPickingHand == Aspect_XRTrackedDeviceRole_LeftHand ? myXRLastPickDepthLeft : myXRLastPickDepthRight;
3132 aPickDepth = Precision::Infinite();
3133 if (theCtx->MainSelector()->NbPicked() > 0)
3135 const gp_Trsf aHandBase = theView->View()->PoseXRToWorld (aPose.Orientation);
3136 const SelectMgr_SortCriterion& aPicked = theCtx->MainSelector()->PickedData (1);
3137 aPickDepth = aPicked.Point.Distance (aHandBase.TranslationPart());
3141 // =======================================================================
3142 // function : handleXRPresentations
3144 // =======================================================================
3145 void AIS_ViewController::handleXRPresentations (const Handle(AIS_InteractiveContext)& theCtx,
3146 const Handle(V3d_View)& theView)
3148 if (!theView->View()->IsActiveXR()
3149 || (!myToDisplayXRAuxDevices
3150 && !myToDisplayXRHands))
3152 for (NCollection_Array1<Handle(AIS_XRTrackedDevice)>::Iterator aPrsIter (myXRPrsDevices); aPrsIter.More(); aPrsIter.Next())
3154 if (!aPrsIter.Value().IsNull()
3155 && aPrsIter.Value()->HasInteractiveContext())
3157 theCtx->Remove (aPrsIter.Value(), false);
3159 aPrsIter.ChangeValue().Nullify();
3164 if (myXRPrsDevices.Length() != theView->View()->XRSession()->TrackedPoses().Length())
3166 for (NCollection_Array1<Handle(AIS_XRTrackedDevice)>::Iterator aPrsIter (myXRPrsDevices); aPrsIter.More(); aPrsIter.Next())
3168 if (!aPrsIter.Value().IsNull())
3170 theCtx->Remove (aPrsIter.Value(), false);
3173 myXRPrsDevices.Resize (theView->View()->XRSession()->TrackedPoses().Lower(), theView->View()->XRSession()->TrackedPoses().Upper(), false);
3176 const Standard_Integer aHeadDevice = theView->View()->XRSession()->NamedTrackedDevice (Aspect_XRTrackedDeviceRole_Head);
3177 const Standard_Integer aLeftDevice = theView->View()->XRSession()->NamedTrackedDevice (Aspect_XRTrackedDeviceRole_LeftHand);
3178 const Standard_Integer aRightDevice = theView->View()->XRSession()->NamedTrackedDevice (Aspect_XRTrackedDeviceRole_RightHand);
3179 for (Standard_Integer aDeviceIter = theView->View()->XRSession()->TrackedPoses().Lower(); aDeviceIter <= theView->View()->XRSession()->TrackedPoses().Upper(); ++aDeviceIter)
3181 const Aspect_TrackedDevicePose& aPose = theView->View()->XRSession()->TrackedPoses()[aDeviceIter];
3182 Handle(AIS_XRTrackedDevice)& aPosePrs = myXRPrsDevices[aDeviceIter];
3183 if (!aPose.IsValidPose)
3188 const bool isHand = aDeviceIter == aLeftDevice
3189 || aDeviceIter == aRightDevice;
3190 if ((!myToDisplayXRHands && isHand)
3191 || (!myToDisplayXRAuxDevices && !isHand))
3193 if (!aPosePrs.IsNull()
3194 && aPosePrs->HasInteractiveContext())
3196 theCtx->Remove (aPosePrs, false);
3201 Aspect_XRTrackedDeviceRole aRole = Aspect_XRTrackedDeviceRole_Other;
3202 if (aDeviceIter == aLeftDevice)
3204 aRole = Aspect_XRTrackedDeviceRole_LeftHand;
3206 else if (aDeviceIter == aRightDevice)
3208 aRole = Aspect_XRTrackedDeviceRole_RightHand;
3211 if (!aPosePrs.IsNull()
3212 && aPosePrs->UnitFactor() != (float )theView->View()->UnitFactor())
3214 theCtx->Remove (aPosePrs, false);
3218 if (aPosePrs.IsNull())
3220 Handle(Image_Texture) aTexture;
3221 Handle(Graphic3d_ArrayOfTriangles) aTris;
3222 if (aDeviceIter != aHeadDevice)
3224 aTris = theView->View()->XRSession()->LoadRenderModel (aDeviceIter, aTexture);
3226 if (!aTris.IsNull())
3228 aPosePrs = new AIS_XRTrackedDevice (aTris, aTexture);
3232 aPosePrs = new AIS_XRTrackedDevice();
3234 aPosePrs->SetUnitFactor ((float )theView->View()->UnitFactor());
3235 aPosePrs->SetMutable (true);
3236 aPosePrs->SetInfiniteState (true);
3238 aPosePrs->SetRole (aRole);
3240 if (!aPosePrs->HasInteractiveContext())
3242 theCtx->Display (aPosePrs, 0, -1, false);
3245 gp_Trsf aPoseLocal = aPose.Orientation;
3246 if (aDeviceIter == aHeadDevice)
3248 // show headset position on floor level
3249 aPoseLocal.SetTranslationPart (gp_Vec (aPoseLocal.TranslationPart().X(), 0.0, aPoseLocal.TranslationPart().Z()));
3251 const gp_Trsf aPoseWorld = theView->View()->PoseXRToWorld (aPoseLocal);
3252 theCtx->SetLocation (aPosePrs, aPoseWorld);
3254 Standard_Real aLaserLen = 0.0;
3256 && aPosePrs->Role() == myXRLastPickingHand)
3258 aLaserLen = myXRLastPickingHand == Aspect_XRTrackedDeviceRole_LeftHand ? myXRLastPickDepthLeft : myXRLastPickDepthRight;
3259 if (Precision::IsInfinite (aLaserLen))
3261 const Bnd_Box aViewBox = theView->View()->MinMaxValues (true);
3262 if (!aViewBox.IsVoid())
3264 aLaserLen = Sqrt (aViewBox.SquareExtent());
3271 aPosePrs->SetLaserColor (myXRLaserPickColor);
3274 && aPosePrs->Role() == myXRLastTeleportHand)
3276 aLaserLen = myXRLastTeleportHand == Aspect_XRTrackedDeviceRole_LeftHand ? myXRLastPickDepthLeft : myXRLastPickDepthRight;
3277 if (Precision::IsInfinite (aLaserLen))
3279 const Bnd_Box aViewBox = theView->View()->MinMaxValues (true);
3280 if (!aViewBox.IsVoid())
3282 aLaserLen = Sqrt (aViewBox.SquareExtent());
3289 aPosePrs->SetLaserColor (myXRLaserTeleColor);
3291 aPosePrs->SetLaserLength ((float )aLaserLen);
3295 // =======================================================================
3296 // function : HandleViewEvents
3298 // =======================================================================
3299 void AIS_ViewController::HandleViewEvents (const Handle(AIS_InteractiveContext)& theCtx,
3300 const Handle(V3d_View)& theView)
3302 const bool wasImmediateUpdate = theView->SetImmediateUpdate (false);
3304 handleViewOrientationKeys (theCtx, theView);
3305 const AIS_WalkDelta aWalk = handleNavigationKeys (theCtx, theView);
3306 handleXRInput (theCtx, theView, aWalk);
3307 if (theView->View()->IsActiveXR())
3309 theView->View()->SetupXRPosedCamera();
3311 handleMoveTo (theCtx, theView);
3312 handleCameraActions (theCtx, theView, aWalk);
3313 theView->View()->SynchronizeXRPosedToBaseCamera(); // handleCameraActions() may modify posed camera position - copy this modifications also to the base camera
3314 handleXRPresentations (theCtx, theView);
3316 handleViewRedraw (theCtx, theView);
3317 theView->View()->UnsetXRPosedCamera();
3319 theView->SetImmediateUpdate (wasImmediateUpdate);
3321 // make sure to not process the same events twice
3323 myToAskNextFrame = false;