1 // Copyright (c) 2016-2019 OPEN CASCADE SAS
3 // This file is part of Open CASCADE Technology software library.
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
14 #include "AIS_ViewController.hxx"
16 #include <AIS_AnimationCamera.hxx>
17 #include <AIS_InteractiveContext.hxx>
18 #include <AIS_Point.hxx>
19 #include <AIS_RubberBand.hxx>
20 #include <AIS_XRTrackedDevice.hxx>
21 #include <Aspect_XRSession.hxx>
22 #include <Aspect_Grid.hxx>
23 #include <Geom_CartesianPoint.hxx>
24 #include <Graphic3d_ArrayOfSegments.hxx>
25 #include <Graphic3d_Texture2Dmanual.hxx>
26 #include <Message.hxx>
27 #include <Message_Messenger.hxx>
28 #include <gp_Quaternion.hxx>
29 #include <V3d_View.hxx>
30 #include <WNT_HIDSpaceMouse.hxx>
32 // =======================================================================
33 // function : AIS_ViewController
35 // =======================================================================
36 AIS_ViewController::AIS_ViewController()
37 : myLastEventsTime (0.0),
38 myToAskNextFrame (false),
39 myMinCamDistance (1.0),
40 myRotationMode (AIS_RotationMode_BndBoxActive),
41 myNavigationMode (AIS_NavigationMode_Orbit),
44 myToShowPanAnchorPoint (true),
45 myToShowRotateCenter (true),
46 myToLockOrbitZUp (false),
47 myToInvertPitch (false),
48 myToAllowTouchZRotation(false),
49 myToAllowRotation (true),
50 myToAllowPanning (true),
51 myToAllowZooming (true),
52 myToAllowZFocus (true),
53 myToAllowHighlight (true),
54 myToAllowDragging (true),
55 myToStickToRayOnZoom (true),
56 myToStickToRayOnRotation (true),
58 myWalkSpeedAbsolute (1.5f),
59 myWalkSpeedRelative (0.1f),
63 myViewAnimation (new AIS_AnimationCamera ("AIS_ViewController_ViewAnimation", Handle(V3d_View)())),
64 myPrevMoveTo (-1, -1),
65 myHasHlrOnBeforeRotation (false),
67 myXRPrsDevices (0, 0),
68 myXRLaserTeleColor (Quantity_NOC_GREEN),
69 myXRLaserPickColor (Quantity_NOC_BLUE),
70 myXRLastTeleportHand(Aspect_XRTrackedDeviceRole_Other),
71 myXRLastPickingHand (Aspect_XRTrackedDeviceRole_Other),
72 myXRLastPickDepthLeft (Precision::Infinite()),
73 myXRLastPickDepthRight(Precision::Infinite()),
74 myXRTurnAngle (M_PI_4),
75 myToDisplayXRAuxDevices (false),
76 myToDisplayXRHands (true),
78 myMouseClickThreshold (3.0),
79 myMouseDoubleClickInt (0.4),
80 myScrollZoomRatio (15.0f),
81 myMouseActiveGesture (AIS_MouseGesture_NONE),
82 myMouseActiveIdleRotation (false),
83 myMouseClickCounter (0),
84 myMousePressed (Aspect_VKeyMouse_NONE),
85 myMouseModifiers (Aspect_VKeyFlags_NONE),
86 myMouseSingleButton (-1),
87 myMouseStopDragOnUnclick (false),
89 myTouchToleranceScale (1.0f),
90 myTouchRotationThresholdPx (6.0f),
91 myTouchZRotationThreshold (float(2.0 * M_PI / 180.0)),
92 myTouchPanThresholdPx (4.0f),
93 myTouchZoomThresholdPx (6.0f),
94 myTouchZoomRatio (0.13f),
97 myUpdateStartPointPan (true),
98 myUpdateStartPointRot (true),
99 myUpdateStartPointZRot (true),
101 my3dMouseNoRotate (false, false, false),
102 my3dMouseToReverse (true, false, false),
103 my3dMouseAccelTrans (2.0f),
104 my3dMouseAccelRotate (4.0f),
105 my3dMouseIsQuadric (true),
107 myPanPnt3d (Precision::Infinite(), 0.0, 0.0)
109 memset(my3dMouseButtonState, 0, sizeof(my3dMouseButtonState));
110 myEventTimer.Start();
111 myViewAnimation->SetOwnDuration (0.5);
113 myAnchorPointPrs1 = new AIS_Point (new Geom_CartesianPoint (0.0, 0.0, 0.0));
114 myAnchorPointPrs1->SetZLayer (Graphic3d_ZLayerId_Top);
115 myAnchorPointPrs1->SetMutable (true);
117 myAnchorPointPrs2 = new AIS_Point (new Geom_CartesianPoint (0.0, 0.0, 0.0));
118 myAnchorPointPrs2->SetZLayer (Graphic3d_ZLayerId_Topmost);
119 myAnchorPointPrs2->SetMutable (true);
121 myRubberBand = new AIS_RubberBand (Quantity_NOC_LIGHTBLUE, Aspect_TOL_SOLID, Quantity_NOC_LIGHTBLUE4, 0.5, 1.0);
122 myRubberBand->SetZLayer (Graphic3d_ZLayerId_TopOSD);
123 myRubberBand->SetTransformPersistence (new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_UPPER));
124 myRubberBand->SetDisplayMode (0);
125 myRubberBand->SetMutable (true);
127 myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton, AIS_MouseGesture_RotateOrbit);
128 myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_CTRL, AIS_MouseGesture_Zoom);
129 myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_SHIFT, AIS_MouseGesture_Pan);
130 myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_ALT, AIS_MouseGesture_SelectRectangle);
132 myMouseGestureMap.Bind (Aspect_VKeyMouse_RightButton, AIS_MouseGesture_Zoom);
133 myMouseGestureMap.Bind (Aspect_VKeyMouse_RightButton | Aspect_VKeyFlags_CTRL, AIS_MouseGesture_RotateOrbit);
135 myMouseGestureMap.Bind (Aspect_VKeyMouse_MiddleButton, AIS_MouseGesture_Pan);
136 myMouseGestureMap.Bind (Aspect_VKeyMouse_MiddleButton | Aspect_VKeyFlags_CTRL, AIS_MouseGesture_Pan);
138 myXRTeleportHaptic.Duration = 3600.0f;
139 myXRTeleportHaptic.Frequency = 0.1f;
140 myXRTeleportHaptic.Amplitude = 0.2f;
142 myXRPickingHaptic.Duration = 0.1f;
143 myXRPickingHaptic.Frequency = 4.0f;
144 myXRPickingHaptic.Amplitude = 0.1f;
146 myXRSelectHaptic.Duration = 0.2f;
147 myXRSelectHaptic.Frequency = 4.0f;
148 myXRSelectHaptic.Amplitude = 0.5f;
151 // =======================================================================
152 // function : ~AIS_ViewController
154 // =======================================================================
155 AIS_ViewController::~AIS_ViewController()
160 // =======================================================================
161 // function : ResetViewInput
163 // =======================================================================
164 void AIS_ViewController::ResetViewInput()
167 myMousePressed = Aspect_VKeyMouse_NONE;
168 myMouseModifiers = Aspect_VKeyFlags_NONE;
169 myMouseSingleButton = -1;
170 myUI.Dragging.ToAbort = true;
171 myMouseActiveGesture = AIS_MouseGesture_NONE;
172 myMouseClickTimer.Stop();
173 myMouseClickCounter = 0;
176 // =======================================================================
177 // function : FlushViewEvents
179 // =======================================================================
180 void AIS_ViewController::FlushViewEvents (const Handle(AIS_InteractiveContext)& theCtx,
181 const Handle(V3d_View)& theView,
182 Standard_Boolean theToHandle)
184 flushBuffers (theCtx, theView);
185 flushGestures(theCtx, theView);
188 HandleViewEvents (theCtx, theView);
192 // =======================================================================
193 // function : flushBuffers
195 // =======================================================================
196 void AIS_ViewController::flushBuffers (const Handle(AIS_InteractiveContext)& ,
197 const Handle(V3d_View)& )
199 myToAskNextFrame = false;
201 myGL.IsNewGesture = myUI.IsNewGesture;
202 myUI.IsNewGesture = false;
204 myGL.ZoomActions.Clear();
205 myGL.ZoomActions.Append (myUI.ZoomActions);
206 myUI.ZoomActions.Clear();
208 myGL.Orientation.ToFitAll = myUI.Orientation.ToFitAll;
209 myUI.Orientation.ToFitAll = false;
210 if (myUI.Orientation.ToSetViewOrient)
212 myUI.Orientation.ToSetViewOrient = false;
213 myGL.Orientation.ToSetViewOrient = true;
214 myGL.Orientation.ViewOrient = myUI.Orientation.ViewOrient;
217 if (myUI.MoveTo.ToHilight)
219 myUI.MoveTo.ToHilight = false;
220 myGL.MoveTo.ToHilight = true;
221 myGL.MoveTo.Point = myUI.MoveTo.Point;
225 myGL.Selection.Tool = myUI.Selection.Tool;
226 myGL.Selection.IsXOR = myUI.Selection.IsXOR;
227 myGL.Selection.Points = myUI.Selection.Points;
228 myUI.Selection.IsXOR = false;
229 if (myUI.Selection.Tool == AIS_ViewSelectionTool_Picking)
231 myUI.Selection.Points.Clear();
235 if (myUI.Selection.ToApplyTool)
237 myGL.Selection.ToApplyTool = true;
238 myUI.Selection.ToApplyTool = false;
239 myUI.Selection.Points.Clear();
242 if (myUI.Panning.ToStart)
244 myUI.Panning.ToStart = false;
245 myGL.Panning.ToStart = true;
246 myGL.Panning.PointStart = myUI.Panning.PointStart;
249 if (myUI.Panning.ToPan)
251 myUI.Panning.ToPan = false;
252 myGL.Panning.ToPan = true;
253 myGL.Panning.Delta = myUI.Panning.Delta;
256 if (myUI.Dragging.ToAbort)
258 myUI.Dragging.ToAbort = false;
259 myGL.Dragging.ToAbort = true;
261 else if (myUI.Dragging.ToStop)
263 myUI.Dragging.ToStop = false;
264 myGL.Dragging.ToStop = true;
266 else if (myUI.Dragging.ToStart)
268 myUI.Dragging.ToStart = false;
269 myGL.Dragging.ToStart = true;
270 myGL.Dragging.PointStart = myUI.Dragging.PointStart;
272 myGL.Dragging.PointTo = myUI.Dragging.PointTo;
274 if (myUI.OrbitRotation.ToStart)
276 myUI.OrbitRotation.ToStart = false;
277 myGL.OrbitRotation.ToStart = true;
278 myGL.OrbitRotation.PointStart = myUI.OrbitRotation.PointStart;
281 if (myUI.OrbitRotation.ToRotate)
283 myUI.OrbitRotation.ToRotate = false;
284 myGL.OrbitRotation.ToRotate = true;
285 myGL.OrbitRotation.PointTo = myUI.OrbitRotation.PointTo;
288 if (myUI.ViewRotation.ToStart)
290 myUI.ViewRotation.ToStart = false;
291 myGL.ViewRotation.ToStart = true;
292 myGL.ViewRotation.PointStart = myUI.ViewRotation.PointStart;
295 if (myUI.ViewRotation.ToRotate)
297 myUI.ViewRotation.ToRotate = false;
298 myGL.ViewRotation.ToRotate = true;
299 myGL.ViewRotation.PointTo = myUI.ViewRotation.PointTo;
302 if (myUI.ZRotate.ToRotate)
304 myGL.ZRotate = myUI.ZRotate;
305 myUI.ZRotate.ToRotate = false;
309 // =======================================================================
310 // function : flushGestures
312 // =======================================================================
313 void AIS_ViewController::flushGestures (const Handle(AIS_InteractiveContext)& ,
314 const Handle(V3d_View)& theView)
316 const Standard_Real aTolScale = myTouchToleranceScale;
317 const Standard_Integer aTouchNb = myTouchPoints.Extent();
318 if (myNbTouchesLast != aTouchNb)
320 myNbTouchesLast = aTouchNb;
321 myGL.IsNewGesture = true;
323 if (aTouchNb == 1) // touch
325 Aspect_Touch& aTouch = myTouchPoints.ChangeFromIndex (1);
326 if (myUpdateStartPointRot)
328 // skip rotation if have active dragged object
329 if (myNavigationMode == AIS_NavigationMode_Orbit)
331 myGL.OrbitRotation.ToStart = true;
332 myGL.OrbitRotation.PointStart = myStartRotCoord;
336 myGL.ViewRotation.ToStart = true;
337 myGL.ViewRotation.PointStart = myStartRotCoord;
340 myUpdateStartPointRot = false;
341 theView->Invalidate();
345 const Standard_Real aRotTouchTol = !aTouch.IsPreciseDevice
346 ? aTolScale * myTouchRotationThresholdPx
348 if (Abs (aTouch.Delta().x()) + Abs(aTouch.Delta().y()) > aRotTouchTol)
350 const Standard_Real aRotAccel = myNavigationMode == AIS_NavigationMode_FirstPersonWalk ? myMouseAccel : myOrbitAccel;
351 if (myNavigationMode == AIS_NavigationMode_Orbit)
353 const Graphic3d_Vec2d aRotDelta = aTouch.To - myGL.OrbitRotation.PointStart;
354 myGL.OrbitRotation.ToRotate = true;
355 myGL.OrbitRotation.PointTo = myGL.OrbitRotation.PointStart + aRotDelta * aRotAccel;
356 myGL.Dragging.PointTo.SetValues ((int )aTouch.To.x(), (int )aTouch.To.y());
360 const Graphic3d_Vec2d aRotDelta = aTouch.To - myGL.ViewRotation.PointStart;
361 myGL.ViewRotation.ToRotate = true;
362 myGL.ViewRotation.PointTo = myGL.ViewRotation.PointStart + aRotDelta * aRotAccel;
363 myGL.Dragging.PointTo.SetValues ((int )aTouch.To.x(), (int )aTouch.To.y());
366 aTouch.From = aTouch.To;
369 else if (aTouchNb == 2) // pinch
371 Aspect_Touch& aFirstTouch = myTouchPoints.ChangeFromIndex (1);
372 Aspect_Touch& aLastTouch = myTouchPoints.ChangeFromIndex (2);
373 const Graphic3d_Vec2d aFrom[2] = { aFirstTouch.From, aLastTouch.From };
374 const Graphic3d_Vec2d aTo[2] = { aFirstTouch.To, aLastTouch.To };
376 Graphic3d_Vec2d aPinchCenterStart ((aFrom[0].x() + aFrom[1].x()) / 2.0,
377 (aFrom[0].y() + aFrom[1].y()) / 2.0);
379 Standard_Real aPinchCenterXEnd = (aTo[0].x() + aTo[1].x()) / 2.0;
380 Standard_Real aPinchCenterYEnd = (aTo[0].y() + aTo[1].y()) / 2.0;
382 Standard_Real aPinchCenterXDev = aPinchCenterXEnd - aPinchCenterStart.x();
383 Standard_Real aPinchCenterYDev = aPinchCenterYEnd - aPinchCenterStart.y();
385 Standard_Real aStartSize = (aFrom[0] - aFrom[1]).Modulus();
386 Standard_Real anEndSize = ( aTo[0] - aTo[1]).Modulus();
388 Standard_Real aDeltaSize = anEndSize - aStartSize;
390 bool anIsClearDev = false;
392 if (myToAllowTouchZRotation)
394 Standard_Real A1 = aFrom[0].y() - aFrom[1].y();
395 Standard_Real B1 = aFrom[1].x() - aFrom[0].x();
397 Standard_Real A2 = aTo[0].y() - aTo[1].y();
398 Standard_Real B2 = aTo[1].x() - aTo[0].x();
400 Standard_Real aRotAngle = 0.0;
402 Standard_Real aDenomenator = A1*A2 + B1*B2;
403 if (aDenomenator <= Precision::Confusion())
409 Standard_Real aNumerator = A1*B2 - A2*B1;
410 aRotAngle = ATan (aNumerator / aDenomenator);
413 if (Abs(aRotAngle) > Standard_Real(myTouchZRotationThreshold))
415 myGL.ZRotate.ToRotate = true;
416 myGL.ZRotate.Angle = aRotAngle;
421 if (Abs(aDeltaSize) > aTolScale * myTouchZoomThresholdPx)
424 aDeltaSize *= Standard_Real(myTouchZoomRatio);
425 Aspect_ScrollDelta aParams (Graphic3d_Vec2i (aPinchCenterStart), aDeltaSize);
426 myGL.ZoomActions.Append (aParams);
430 const Standard_Real aPanTouchTol = !aFirstTouch.IsPreciseDevice
431 ? aTolScale * myTouchPanThresholdPx
433 if (Abs(aPinchCenterXDev) + Abs(aPinchCenterYDev) > aPanTouchTol)
436 if (myUpdateStartPointPan)
438 myGL.Panning.ToStart = true;
439 myGL.Panning.PointStart = Graphic3d_Vec2i (myStartPanCoord);
440 myUpdateStartPointPan = false;
441 theView->Invalidate();
444 myGL.Panning.ToPan = true;
445 myGL.Panning.Delta.x() = int( aPinchCenterXDev);
446 myGL.Panning.Delta.y() = int(-aPinchCenterYDev);
452 aFirstTouch.From = aFirstTouch.To;
453 aLastTouch .From = aLastTouch.To;
458 // =======================================================================
459 // function : UpdateViewOrientation
461 // =======================================================================
462 void AIS_ViewController::UpdateViewOrientation (V3d_TypeOfOrientation theOrientation,
465 myUI.Orientation.ToFitAll = theToFitAll;
466 myUI.Orientation.ToSetViewOrient = true;
467 myUI.Orientation.ViewOrient = theOrientation;
470 // =======================================================================
471 // function : SelectInViewer
473 // =======================================================================
474 void AIS_ViewController::SelectInViewer (const Graphic3d_Vec2i& thePnt,
477 if (myUI.Selection.Tool != AIS_ViewSelectionTool_Picking)
479 myUI.Selection.Tool = AIS_ViewSelectionTool_Picking;
480 myUI.Selection.Points.Clear();
483 myUI.Selection.IsXOR = theIsXOR;
484 myUI.Selection.Points.Append (thePnt);
487 // =======================================================================
488 // function : SelectInViewer
490 // =======================================================================
491 void AIS_ViewController::SelectInViewer (const NCollection_Sequence<Graphic3d_Vec2i>& thePnts,
494 myUI.Selection.IsXOR = theIsXOR;
495 myUI.Selection.Points = thePnts;
496 myUI.Selection.ToApplyTool = true;
497 if (thePnts.Length() == 1)
499 myUI.Selection.Tool = AIS_ViewSelectionTool_Picking;
501 else if (thePnts.Length() == 2)
503 myUI.Selection.Tool = AIS_ViewSelectionTool_RubberBand;
507 myUI.Selection.Tool = AIS_ViewSelectionTool_Polygon;
511 // =======================================================================
512 // function : UpdateRubberBand
514 // =======================================================================
515 void AIS_ViewController::UpdateRubberBand (const Graphic3d_Vec2i& thePntFrom,
516 const Graphic3d_Vec2i& thePntTo,
519 myUI.Selection.Tool = AIS_ViewSelectionTool_RubberBand;
520 myUI.Selection.IsXOR = theIsXOR;
521 myUI.Selection.Points.Clear();
522 myUI.Selection.Points.Append (thePntFrom);
523 myUI.Selection.Points.Append (thePntTo);
526 // =======================================================================
527 // function : UpdatePolySelection
529 // =======================================================================
530 void AIS_ViewController::UpdatePolySelection (const Graphic3d_Vec2i& thePnt,
533 if (myUI.Selection.Tool != AIS_ViewSelectionTool_Polygon)
535 myUI.Selection.Tool = AIS_ViewSelectionTool_Polygon;
536 myUI.Selection.Points.Clear();
539 if (myUI.Selection.Points.IsEmpty())
541 myUI.Selection.Points.Append (thePnt);
544 && myUI.Selection.Points.Last() != thePnt)
546 myUI.Selection.Points.Append (thePnt);
550 myUI.Selection.Points.ChangeLast() = thePnt;
554 // =======================================================================
555 // function : UpdateZoom
557 // =======================================================================
558 bool AIS_ViewController::UpdateZoom (const Aspect_ScrollDelta& theDelta)
560 if (!myUI.ZoomActions.IsEmpty())
562 if (myUI.ZoomActions.ChangeLast().Point == theDelta.Point)
564 myUI.ZoomActions.ChangeLast().Delta += theDelta.Delta;
569 myUI.ZoomActions.Append (theDelta);
573 // =======================================================================
574 // function : UpdateZRotation
576 // =======================================================================
577 bool AIS_ViewController::UpdateZRotation (double theAngle)
579 if (!ToAllowTouchZRotation())
584 myUI.ZRotate.Angle = myUI.ZRotate.ToRotate
585 ? myUI.ZRotate.Angle + theAngle
587 if (myUI.ZRotate.ToRotate)
591 myUI.ZRotate.ToRotate = true;
595 // =======================================================================
596 // function : UpdateMouseScroll
598 // =======================================================================
599 bool AIS_ViewController::UpdateMouseScroll (const Aspect_ScrollDelta& theDelta)
601 Aspect_ScrollDelta aDelta = theDelta;
602 aDelta.Delta *= myScrollZoomRatio;
603 return UpdateZoom (aDelta);
606 // =======================================================================
607 // function : UpdateMouseClick
609 // =======================================================================
610 bool AIS_ViewController::UpdateMouseClick (const Graphic3d_Vec2i& thePoint,
611 Aspect_VKeyMouse theButton,
612 Aspect_VKeyFlags theModifiers,
613 bool theIsDoubleClick)
615 (void )theIsDoubleClick;
616 if (theButton == Aspect_VKeyMouse_LeftButton)
618 SelectInViewer (thePoint, (theModifiers & Aspect_VKeyFlags_SHIFT) != 0);
624 // =======================================================================
625 // function : UpdateMouseButtons
627 // =======================================================================
628 bool AIS_ViewController::UpdateMouseButtons (const Graphic3d_Vec2i& thePoint,
629 Aspect_VKeyMouse theButtons,
630 Aspect_VKeyFlags theModifiers,
633 bool toUpdateView = false;
634 const double aTolClick = (theIsEmulated ? myTouchToleranceScale : 1.0) * myMouseClickThreshold;
635 if (theButtons == Aspect_VKeyMouse_NONE
636 && myMouseSingleButton > 0)
638 const Graphic3d_Vec2i aDelta = thePoint - myMousePressPoint;
639 if (double(aDelta.cwiseAbs().maxComp()) < aTolClick)
641 ++myMouseClickCounter;
642 const bool isDoubleClick = myMouseClickCounter == 2
643 && myMouseClickTimer.IsStarted()
644 && myMouseClickTimer.ElapsedTime() <= myMouseDoubleClickInt;
646 myMouseClickTimer.Stop();
647 myMouseClickTimer.Reset();
648 myMouseClickTimer.Start();
651 myMouseClickCounter = 0;
653 toUpdateView = UpdateMouseClick (thePoint, (Aspect_VKeyMouse )myMouseSingleButton, theModifiers, isDoubleClick) || toUpdateView;
657 myMouseClickTimer.Stop();
658 myMouseClickCounter = 0;
659 myMouseStopDragOnUnclick = false;
660 myUI.Dragging.ToStop = true;
663 myMouseSingleButton = -1;
665 else if (theButtons == Aspect_VKeyMouse_NONE)
667 myMouseSingleButton = -1;
668 if (myMouseStopDragOnUnclick)
670 myMouseStopDragOnUnclick = false;
671 myUI.Dragging.ToStop = true;
675 else if (myMouseSingleButton == -1)
677 if ((theButtons & Aspect_VKeyMouse_LeftButton) == Aspect_VKeyMouse_LeftButton)
679 myMouseSingleButton = Aspect_VKeyMouse_LeftButton;
681 else if ((theButtons & Aspect_VKeyMouse_RightButton) == Aspect_VKeyMouse_RightButton)
683 myMouseSingleButton = Aspect_VKeyMouse_RightButton;
685 else if ((theButtons & Aspect_VKeyMouse_MiddleButton) == Aspect_VKeyMouse_MiddleButton)
687 myMouseSingleButton = Aspect_VKeyMouse_MiddleButton;
691 myMouseSingleButton = 0;
693 if (myMouseSingleButton != 0)
695 if (myMouseClickCounter == 1)
697 const Graphic3d_Vec2i aDelta = thePoint - myMousePressPoint;
698 if (double(aDelta.cwiseAbs().maxComp()) >= aTolClick)
700 myMouseClickTimer.Stop();
701 myMouseClickCounter = 0;
704 myMousePressPoint = thePoint;
709 myMouseSingleButton = 0;
711 myUI.Dragging.ToAbort = true;
715 const AIS_MouseGesture aPrevGesture = myMouseActiveGesture;
716 myMouseModifiers = theModifiers;
717 myMousePressed = theButtons;
719 || myNavigationMode != AIS_NavigationMode_FirstPersonWalk)
721 myMouseActiveIdleRotation = false;
722 myMouseActiveGesture = AIS_MouseGesture_NONE;
725 myMousePressPoint = thePoint;
726 myMouseProgressPoint = myMousePressPoint;
729 if (myMouseGestureMap.Find (theButtons | theModifiers, myMouseActiveGesture))
731 switch (myMouseActiveGesture)
733 case AIS_MouseGesture_RotateView:
734 case AIS_MouseGesture_RotateOrbit:
736 if (myToAllowRotation)
738 myUpdateStartPointRot = true;
742 myMouseActiveGesture = AIS_MouseGesture_NONE;
746 case AIS_MouseGesture_Pan:
748 if (myToAllowPanning)
750 myUpdateStartPointPan = true;
754 myMouseActiveGesture = AIS_MouseGesture_NONE;
758 case AIS_MouseGesture_Zoom:
759 case AIS_MouseGesture_ZoomWindow:
761 if (!myToAllowZooming)
763 myMouseActiveGesture = AIS_MouseGesture_NONE;
767 case AIS_MouseGesture_SelectRectangle:
771 case AIS_MouseGesture_SelectLasso:
773 UpdatePolySelection (thePoint, true);
776 case AIS_MouseGesture_NONE:
783 if (theButtons == Aspect_VKeyMouse_LeftButton
784 && theModifiers == Aspect_VKeyFlags_NONE
785 && myToAllowDragging)
787 myUI.Dragging.ToStart = true;
788 myUI.Dragging.PointStart = thePoint;
792 if (aPrevGesture != myMouseActiveGesture)
794 if (aPrevGesture == AIS_MouseGesture_SelectRectangle
795 || aPrevGesture == AIS_MouseGesture_SelectLasso
796 || aPrevGesture == AIS_MouseGesture_ZoomWindow)
798 myUI.Selection.ToApplyTool = true;
801 myUI.IsNewGesture = true;
807 // =======================================================================
808 // function : UpdateMousePosition
810 // =======================================================================
811 bool AIS_ViewController::UpdateMousePosition (const Graphic3d_Vec2i& thePoint,
812 Aspect_VKeyMouse theButtons,
813 Aspect_VKeyFlags theModifiers,
816 myMousePositionLast = thePoint;
817 if (myMouseSingleButton > 0)
819 const double aTolClick = (theIsEmulated ? myTouchToleranceScale : 1.0) * myMouseClickThreshold;
820 const Graphic3d_Vec2i aPressDelta = thePoint - myMousePressPoint;
821 if (double(aPressDelta.cwiseAbs().maxComp()) >= aTolClick)
823 myMouseClickTimer.Stop();
824 myMouseClickCounter = 0;
825 myMouseSingleButton = -1;
826 myMouseStopDragOnUnclick = true;
830 bool toUpdateView = false;
831 Graphic3d_Vec2i aDelta = thePoint - myMouseProgressPoint;
833 && myNavigationMode == AIS_NavigationMode_FirstPersonWalk)
835 if (!myMouseActiveIdleRotation
836 || myMouseActiveGesture != AIS_MouseGesture_RotateView)
838 myMouseActiveIdleRotation = true;
839 myMouseActiveGesture = AIS_MouseGesture_RotateView;
840 myMousePressPoint = thePoint;
841 myMouseProgressPoint = thePoint;
842 myUpdateStartPointRot = false;
843 myUI.ViewRotation.ToStart = true;
844 myUI.ViewRotation.PointStart.SetValues (thePoint.x(), thePoint.y());
845 myUI.ViewRotation.ToRotate = false;
846 aDelta.SetValues (0, 0);
851 if (myMouseActiveIdleRotation
852 && myMouseActiveGesture == AIS_MouseGesture_RotateView)
854 myMouseActiveGesture = AIS_MouseGesture_NONE;
856 myMouseActiveIdleRotation = false;
859 if (myMouseModifiers != theModifiers
860 && UpdateMouseButtons (thePoint, theButtons, theModifiers, theIsEmulated))
865 switch (myMouseActiveGesture)
867 case AIS_MouseGesture_SelectRectangle:
868 case AIS_MouseGesture_ZoomWindow:
870 UpdateRubberBand (myMousePressPoint, thePoint);
871 if (myMouseActiveGesture == AIS_MouseGesture_ZoomWindow)
873 myUI.Selection.Tool = AIS_ViewSelectionTool_ZoomWindow;
878 case AIS_MouseGesture_SelectLasso:
880 UpdatePolySelection (thePoint, true);
884 case AIS_MouseGesture_RotateOrbit:
885 case AIS_MouseGesture_RotateView:
887 if (!myToAllowRotation)
891 if (myUpdateStartPointRot)
893 if (myMouseActiveGesture == AIS_MouseGesture_RotateOrbit)
895 myUI.OrbitRotation.ToStart = true;
896 myUI.OrbitRotation.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y());
900 myUI.ViewRotation.ToStart = true;
901 myUI.ViewRotation.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y());
903 myUpdateStartPointRot = false;
906 const double aRotTol = theIsEmulated
907 ? double(myTouchToleranceScale) * myTouchRotationThresholdPx
909 if (double (Abs (aDelta.x()) + Abs (aDelta.y())) > aRotTol)
911 const double aRotAccel = myNavigationMode == AIS_NavigationMode_FirstPersonWalk ? myMouseAccel : myOrbitAccel;
912 const Graphic3d_Vec2i aRotDelta = thePoint - myMousePressPoint;
913 if (myMouseActiveGesture == AIS_MouseGesture_RotateOrbit)
915 myUI.OrbitRotation.ToRotate = true;
916 myUI.OrbitRotation.PointTo = Graphic3d_Vec2d (myMousePressPoint.x(), myMousePressPoint.y())
917 + Graphic3d_Vec2d (aRotDelta.x(), aRotDelta.y()) * aRotAccel;
921 myUI.ViewRotation.ToRotate = true;
922 myUI.ViewRotation.PointTo = Graphic3d_Vec2d (myMousePressPoint.x(), myMousePressPoint.y())
923 + Graphic3d_Vec2d (aRotDelta.x(), aRotDelta.y()) * aRotAccel;
925 myUI.Dragging.PointTo = thePoint;
927 myMouseProgressPoint = thePoint;
932 case AIS_MouseGesture_Zoom:
934 if (!myToAllowZooming)
938 const double aZoomTol = theIsEmulated
939 ? double(myTouchToleranceScale) * myTouchZoomThresholdPx
941 if (double (Abs (aDelta.x())) > aZoomTol)
943 if (UpdateZoom (Aspect_ScrollDelta (aDelta.x())))
947 myMouseProgressPoint = thePoint;
951 case AIS_MouseGesture_Pan:
953 if (!myToAllowPanning)
957 const double aPanTol = theIsEmulated
958 ? double(myTouchToleranceScale) * myTouchPanThresholdPx
960 if (double (Abs (aDelta.x()) + Abs (aDelta.y())) > aPanTol)
962 if (myUpdateStartPointPan)
964 myUI.Panning.ToStart = true;
965 myUI.Panning.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y());
966 myUpdateStartPointPan = false;
969 aDelta.y() = -aDelta.y();
970 myMouseProgressPoint = thePoint;
971 if (myUI.Panning.ToPan)
973 myUI.Panning.Delta += aDelta;
977 myUI.Panning.ToPan = true;
978 myUI.Panning.Delta = aDelta;
990 if (theButtons == Aspect_VKeyMouse_NONE
991 && myNavigationMode != AIS_NavigationMode_FirstPersonWalk
994 && myToAllowHighlight)
996 myUI.MoveTo.ToHilight = true;
997 myUI.MoveTo.Point = thePoint;
1000 return toUpdateView;
1003 // =======================================================================
1004 // function : AddTouchPoint
1006 // =======================================================================
1007 void AIS_ViewController::AddTouchPoint (Standard_Size theId,
1008 const Graphic3d_Vec2d& thePnt,
1009 Standard_Boolean theClearBefore)
1011 myUI.MoveTo.ToHilight = false;
1014 RemoveTouchPoint ((Standard_Size )-1);
1017 myTouchPoints.Add (theId, Aspect_Touch (thePnt, false));
1018 if (myTouchPoints.Extent() == 1)
1020 myUpdateStartPointRot = true;
1021 myStartRotCoord = thePnt;
1022 if (myToAllowDragging)
1024 myUI.Dragging.ToStart = true;
1025 myUI.Dragging.PointStart.SetValues ((int )thePnt.x(), (int )thePnt.y());
1028 else if (myTouchPoints.Extent() == 2)
1030 myUI.Dragging.ToAbort = true;
1032 myUpdateStartPointPan = true;
1033 myStartPanCoord = thePnt;
1035 myUI.IsNewGesture = true;
1038 // =======================================================================
1039 // function : RemoveTouchPoint
1041 // =======================================================================
1042 bool AIS_ViewController::RemoveTouchPoint (Standard_Size theId,
1043 Standard_Boolean theClearSelectPnts)
1045 if (theId == (Standard_Size )-1)
1047 myTouchPoints.Clear (false);
1051 const Standard_Integer anOldExtent = myTouchPoints.Extent();
1052 myTouchPoints.RemoveKey (theId);
1053 if (myTouchPoints.Extent() == anOldExtent)
1059 if (myTouchPoints.Extent() == 1)
1061 // avoid incorrect transition from pinch to one finger
1062 Aspect_Touch& aFirstTouch = myTouchPoints.ChangeFromIndex (1);
1063 aFirstTouch.To = aFirstTouch.From;
1065 myStartRotCoord = aFirstTouch.To;
1066 myUpdateStartPointRot = true;
1068 else if (myTouchPoints.Extent() == 2)
1070 myStartPanCoord = myTouchPoints.FindFromIndex (1).To;
1071 myUpdateStartPointPan = true;
1073 else if (myTouchPoints.IsEmpty())
1075 if (theClearSelectPnts)
1077 myUI.Selection.ToApplyTool = true;
1080 myUI.Dragging.ToStop = true;
1082 myUI.IsNewGesture = true;
1086 // =======================================================================
1087 // function : UpdateTouchPoint
1089 // =======================================================================
1090 void AIS_ViewController::UpdateTouchPoint (Standard_Size theId,
1091 const Graphic3d_Vec2d& thePnt)
1093 if (Aspect_Touch* aTouch = myTouchPoints.ChangeSeek (theId))
1095 aTouch->To = thePnt;
1099 AddTouchPoint (theId, thePnt);
1103 // =======================================================================
1104 // function : Update3dMouse
1106 // =======================================================================
1107 bool AIS_ViewController::Update3dMouse (const WNT_HIDSpaceMouse& theEvent)
1109 bool toUpdate = false;
1110 toUpdate = update3dMouseTranslation (theEvent) || toUpdate;
1111 toUpdate = update3dMouseRotation (theEvent) || toUpdate;
1112 toUpdate = update3dMouseKeys (theEvent) || toUpdate;
1116 // =======================================================================
1117 // function : update3dMouseTranslation
1119 // =======================================================================
1120 bool AIS_ViewController::update3dMouseTranslation (const WNT_HIDSpaceMouse& theEvent)
1122 if (!theEvent.IsTranslation())
1128 const double aTimeStamp = EventTime();
1129 const Graphic3d_Vec3d aTrans = theEvent.Translation (isIdle, my3dMouseIsQuadric) * my3dMouseAccelTrans;
1130 myKeys.KeyFromAxis (Aspect_VKey_NavSlideLeft, Aspect_VKey_NavSlideRight, aTimeStamp, aTrans.x());
1131 myKeys.KeyFromAxis (Aspect_VKey_NavForward, Aspect_VKey_NavBackward, aTimeStamp, aTrans.y());
1132 myKeys.KeyFromAxis (Aspect_VKey_NavSlideUp, Aspect_VKey_NavSlideDown, aTimeStamp, aTrans.z());
1136 // =======================================================================
1137 // function : update3dMouseRotation
1139 // =======================================================================
1140 bool AIS_ViewController::update3dMouseRotation (const WNT_HIDSpaceMouse& theEvent)
1142 if (!theEvent.IsRotation()
1143 || !myToAllowRotation)
1148 bool isIdle = true, toUpdate = false;
1149 const double aTimeStamp = EventTime();
1150 const Graphic3d_Vec3d aRot3 = theEvent.Rotation (isIdle, my3dMouseIsQuadric) * my3dMouseAccelRotate;
1151 if (!my3dMouseNoRotate.x())
1153 KeyFromAxis (Aspect_VKey_NavLookUp, Aspect_VKey_NavLookDown, aTimeStamp, !my3dMouseToReverse.x() ? aRot3.x() : -aRot3.x());
1156 if (!my3dMouseNoRotate.y())
1158 KeyFromAxis (Aspect_VKey_NavRollCW, Aspect_VKey_NavRollCCW, aTimeStamp, !my3dMouseToReverse.y() ? aRot3.y() : -aRot3.y());
1161 if (!my3dMouseNoRotate.z())
1163 KeyFromAxis (Aspect_VKey_NavLookLeft, Aspect_VKey_NavLookRight, aTimeStamp, !my3dMouseToReverse.z() ? aRot3.z() : -aRot3.z());
1169 // =======================================================================
1170 // function : update3dMouseKeys
1172 // =======================================================================
1173 bool AIS_ViewController::update3dMouseKeys (const WNT_HIDSpaceMouse& theEvent)
1175 bool toUpdate = false;
1176 const double aTimeStamp = EventTime();
1177 if (theEvent.IsKeyState())
1179 const uint32_t aKeyState = theEvent.KeyState();
1180 for (unsigned short aKeyBit = 0; aKeyBit < 32; ++aKeyBit)
1182 const bool isPressed = (aKeyState & (1 << aKeyBit)) != 0;
1183 const bool isReleased = my3dMouseButtonState[aKeyBit] && !isPressed;
1184 //const bool isRepeated = my3dMouseButtonState[aKeyBit] && isPressed;
1185 my3dMouseButtonState[aKeyBit] = isPressed;
1186 if (!isReleased && !isPressed)
1191 const Aspect_VKey aVKey = theEvent.HidToSpaceKey (aKeyBit);
1192 if (aVKey != Aspect_VKey_UNKNOWN)
1197 KeyDown (aVKey, aTimeStamp);
1201 KeyUp (aVKey, aTimeStamp);
1209 // =======================================================================
1210 // function : SetNavigationMode
1212 // =======================================================================
1213 void AIS_ViewController::SetNavigationMode (AIS_NavigationMode theMode)
1215 myNavigationMode = theMode;
1218 myUI.OrbitRotation.ToStart = false;
1219 myUI.OrbitRotation.ToRotate = false;
1220 myUI.ViewRotation.ToStart = false;
1221 myUI.ViewRotation.ToRotate = false;
1224 // =======================================================================
1225 // function : KeyDown
1227 // =======================================================================
1228 void AIS_ViewController::KeyDown (Aspect_VKey theKey,
1232 myKeys.KeyDown (theKey, theTime, thePressure);
1235 // =======================================================================
1238 // =======================================================================
1239 void AIS_ViewController::KeyUp (Aspect_VKey theKey,
1242 myKeys.KeyUp (theKey, theTime);
1245 // =======================================================================
1246 // function : KeyFromAxis
1248 // =======================================================================
1249 void AIS_ViewController::KeyFromAxis (Aspect_VKey theNegative,
1250 Aspect_VKey thePositive,
1254 myKeys.KeyFromAxis (theNegative, thePositive, theTime, thePressure);
1257 // =======================================================================
1258 // function : FetchNavigationKeys
1260 // =======================================================================
1261 AIS_WalkDelta AIS_ViewController::FetchNavigationKeys (Standard_Real theCrouchRatio,
1262 Standard_Real theRunRatio)
1264 AIS_WalkDelta aWalk;
1267 double aPrevEventTime = 0.0, aNewEventTime = 0.0;
1268 updateEventsTime (aPrevEventTime, aNewEventTime);
1270 double aDuration = 0.0, aPressure = 1.0;
1271 if (Abs (myThrustSpeed) > gp::Resolution())
1275 aWalk[AIS_WalkTranslation_Forward].Value = myThrustSpeed * (aNewEventTime - aPrevEventTime);
1278 myToAskNextFrame = true;
1282 myHasThrust = false;
1285 aWalk.SetRunning (theRunRatio > 1.0
1286 && myKeys.IsKeyDown (Aspect_VKey_Shift));
1287 if (myKeys.HoldDuration (Aspect_VKey_NavJump, aNewEventTime, aDuration))
1289 myKeys.KeyUp (Aspect_VKey_NavJump, aNewEventTime);
1290 aWalk.SetJumping (true);
1292 if (!aWalk.IsJumping()
1293 && theCrouchRatio < 1.0
1294 && myKeys.HoldDuration (Aspect_VKey_NavCrouch, aNewEventTime, aDuration))
1296 aWalk.SetRunning (false);
1297 aWalk.SetCrouching (true);
1300 const double aMaxDuration = aNewEventTime - aPrevEventTime;
1301 const double aRunRatio = aWalk.IsRunning()
1303 : aWalk.IsCrouching()
1306 if (myKeys.HoldDuration (Aspect_VKey_NavForward, aNewEventTime, aDuration, aPressure))
1308 double aProgress = Abs (Min (aMaxDuration, aDuration));
1309 aProgress *= aRunRatio;
1310 aWalk[AIS_WalkTranslation_Forward].Value += aProgress;
1311 aWalk[AIS_WalkTranslation_Forward].Pressure = aPressure;
1312 aWalk[AIS_WalkTranslation_Forward].Duration = aDuration;
1314 if (myKeys.HoldDuration (Aspect_VKey_NavBackward, aNewEventTime, aDuration, aPressure))
1316 double aProgress = Abs (Min (aMaxDuration, aDuration));
1317 aProgress *= aRunRatio;
1318 aWalk[AIS_WalkTranslation_Forward].Value += -aProgress;
1319 aWalk[AIS_WalkTranslation_Forward].Pressure = aPressure;
1320 aWalk[AIS_WalkTranslation_Forward].Duration = aDuration;
1322 if (myKeys.HoldDuration (Aspect_VKey_NavSlideLeft, aNewEventTime, aDuration, aPressure))
1324 double aProgress = Abs (Min (aMaxDuration, aDuration));
1325 aProgress *= aRunRatio;
1326 aWalk[AIS_WalkTranslation_Side].Value = -aProgress;
1327 aWalk[AIS_WalkTranslation_Side].Pressure = aPressure;
1328 aWalk[AIS_WalkTranslation_Side].Duration = aDuration;
1330 if (myKeys.HoldDuration (Aspect_VKey_NavSlideRight, aNewEventTime, aDuration, aPressure))
1332 double aProgress = Abs (Min (aMaxDuration, aDuration));
1333 aProgress *= aRunRatio;
1334 aWalk[AIS_WalkTranslation_Side].Value = aProgress;
1335 aWalk[AIS_WalkTranslation_Side].Pressure = aPressure;
1336 aWalk[AIS_WalkTranslation_Side].Duration = aDuration;
1338 if (myKeys.HoldDuration (Aspect_VKey_NavLookLeft, aNewEventTime, aDuration, aPressure))
1340 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1341 aWalk[AIS_WalkRotation_Yaw].Value = aProgress;
1342 aWalk[AIS_WalkRotation_Yaw].Pressure = aPressure;
1343 aWalk[AIS_WalkRotation_Yaw].Duration = aDuration;
1345 if (myKeys.HoldDuration (Aspect_VKey_NavLookRight, aNewEventTime, aDuration, aPressure))
1347 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1348 aWalk[AIS_WalkRotation_Yaw].Value = -aProgress;
1349 aWalk[AIS_WalkRotation_Yaw].Pressure = aPressure;
1350 aWalk[AIS_WalkRotation_Yaw].Duration = aDuration;
1352 if (myKeys.HoldDuration (Aspect_VKey_NavLookUp, aNewEventTime, aDuration, aPressure))
1354 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1355 aWalk[AIS_WalkRotation_Pitch].Value = !myToInvertPitch ? -aProgress : aProgress;
1356 aWalk[AIS_WalkRotation_Pitch].Pressure = aPressure;
1357 aWalk[AIS_WalkRotation_Pitch].Duration = aDuration;
1359 if (myKeys.HoldDuration (Aspect_VKey_NavLookDown, aNewEventTime, aDuration, aPressure))
1361 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1362 aWalk[AIS_WalkRotation_Pitch].Value = !myToInvertPitch ? aProgress : -aProgress;
1363 aWalk[AIS_WalkRotation_Pitch].Pressure = aPressure;
1364 aWalk[AIS_WalkRotation_Pitch].Duration = aDuration;
1366 if (myKeys.HoldDuration (Aspect_VKey_NavRollCCW, aNewEventTime, aDuration, aPressure))
1368 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1369 aWalk[AIS_WalkRotation_Roll].Value = -aProgress;
1370 aWalk[AIS_WalkRotation_Roll].Pressure = aPressure;
1371 aWalk[AIS_WalkRotation_Roll].Duration = aDuration;
1373 if (myKeys.HoldDuration (Aspect_VKey_NavRollCW, aNewEventTime, aDuration, aPressure))
1375 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1376 aWalk[AIS_WalkRotation_Roll].Value = aProgress;
1377 aWalk[AIS_WalkRotation_Roll].Pressure = aPressure;
1378 aWalk[AIS_WalkRotation_Roll].Duration = aDuration;
1380 if (myKeys.HoldDuration (Aspect_VKey_NavSlideUp, aNewEventTime, aDuration, aPressure))
1382 double aProgress = Abs (Min (aMaxDuration, aDuration));
1383 aWalk[AIS_WalkTranslation_Up].Value = aProgress;
1384 aWalk[AIS_WalkTranslation_Up].Pressure = aPressure;
1385 aWalk[AIS_WalkTranslation_Up].Duration = aDuration;
1387 if (myKeys.HoldDuration (Aspect_VKey_NavSlideDown, aNewEventTime, aDuration, aPressure))
1389 double aProgress = Abs (Min (aMaxDuration, aDuration));
1390 aWalk[AIS_WalkTranslation_Up].Value = -aProgress;
1391 aWalk[AIS_WalkTranslation_Up].Pressure = aPressure;
1392 aWalk[AIS_WalkTranslation_Up].Duration = aDuration;
1397 // =======================================================================
1398 // function : AbortViewAnimation
1400 // =======================================================================
1401 void AIS_ViewController::AbortViewAnimation()
1403 if (!myViewAnimation.IsNull()
1404 && !myViewAnimation->IsStopped())
1406 myViewAnimation->Stop();
1407 myViewAnimation->SetView (Handle(V3d_View)());
1411 // =======================================================================
1412 // function : handlePanning
1414 // =======================================================================
1415 void AIS_ViewController::handlePanning (const Handle(V3d_View)& theView)
1417 if (!myGL.Panning.ToPan
1418 || !myToAllowPanning)
1423 AbortViewAnimation();
1425 const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1426 if (aCam->IsOrthographic()
1427 || !hasPanningAnchorPoint())
1429 theView->Pan (myGL.Panning.Delta.x(), myGL.Panning.Delta.y());
1430 theView->Invalidate();
1431 theView->View()->SynchronizeXRPosedToBaseCamera();
1435 Graphic3d_Vec2i aWinSize;
1436 theView->Window()->Size (aWinSize.x(), aWinSize.y());
1438 const gp_Dir& aDir = aCam->Direction();
1439 const gp_Ax3 aCameraCS (aCam->Center(), aDir.Reversed(), aDir ^ aCam->Up());
1440 const gp_XYZ anEyeToPnt = myPanPnt3d.XYZ() - aCam->Eye().XYZ();
1441 const gp_Pnt aViewDims = aCam->ViewDimensions (anEyeToPnt.Dot (aCam->Direction().XYZ())); // view dimensions at 3D point
1442 const Graphic3d_Vec2d aDxy (-aViewDims.X() * myGL.Panning.Delta.x() / double(aWinSize.x()),
1443 -aViewDims.X() * myGL.Panning.Delta.y() / double(aWinSize.x()));
1445 //theView->Translate (aCam, aDxy.x(), aDxy.y());
1447 const gp_Vec aCameraPan = gp_Vec (aCameraCS.XDirection()) * aDxy.x()
1448 + gp_Vec (aCameraCS.YDirection()) * aDxy.y();
1449 aPanTrsf.SetTranslation (aCameraPan);
1450 aCam->Transform (aPanTrsf);
1451 theView->Invalidate();
1452 theView->View()->SynchronizeXRPosedToBaseCamera();
1455 // =======================================================================
1456 // function : handleZRotate
1458 // =======================================================================
1459 void AIS_ViewController::handleZRotate (const Handle(V3d_View)& theView)
1461 if (!myGL.ZRotate.ToRotate
1462 || !myToAllowRotation)
1467 AbortViewAnimation();
1469 Graphic3d_Vec2i aViewPort;
1470 theView->Window()->Size (aViewPort.x(), aViewPort.y());
1471 Graphic3d_Vec2d aRotPnt (0.99 * aViewPort.x(),
1472 0.5 * aViewPort.y());
1473 theView->StartRotation (int(aRotPnt.x()), int(aRotPnt.y()), 0.4);
1474 aRotPnt.y() += myGL.ZRotate.Angle * aViewPort.y();
1475 theView->Rotation (int(aRotPnt.x()), int(aRotPnt.y()));
1476 theView->Invalidate();
1477 theView->View()->SynchronizeXRPosedToBaseCamera();
1480 // =======================================================================
1481 // function : handleZoom
1483 // =======================================================================
1484 void AIS_ViewController::handleZoom (const Handle(V3d_View)& theView,
1485 const Aspect_ScrollDelta& theParams,
1486 const gp_Pnt* thePnt)
1488 if (!myToAllowZooming)
1493 AbortViewAnimation();
1495 const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1498 const double aViewDist = Max (myMinCamDistance, (thePnt->XYZ() - aCam->Eye().XYZ()).Modulus());
1499 aCam->SetCenter (aCam->Eye().XYZ() + aCam->Direction().XYZ() * aViewDist);
1502 if (!theParams.HasPoint())
1504 Standard_Real aCoeff = Abs(theParams.Delta) / 100.0 + 1.0;
1505 aCoeff = theParams.Delta > 0.0 ? aCoeff : 1.0 / aCoeff;
1506 theView->SetZoom (aCoeff, true);
1507 theView->Invalidate();
1508 theView->View()->SynchronizeXRPosedToBaseCamera();
1512 // integer delta is too rough for small smooth increments
1513 //theView->StartZoomAtPoint (theParams.Point.x(), theParams.Point.y());
1514 //theView->ZoomAtPoint (0, 0, (int )theParams.Delta, (int )theParams.Delta);
1516 double aDZoom = Abs (theParams.Delta) / 100.0 + 1.0;
1517 aDZoom = (theParams.Delta > 0.0) ? aDZoom : 1.0 / aDZoom;
1523 const Graphic3d_Vec2d aViewDims (aCam->ViewDimensions().X(), aCam->ViewDimensions().Y());
1525 // ensure that zoom will not be too small or too big
1526 double aCoef = aDZoom;
1527 if (aViewDims.x() < aCoef * Precision::Confusion())
1529 aCoef = aViewDims.x() / Precision::Confusion();
1531 else if (aViewDims.x() > aCoef * 1e12)
1533 aCoef = aViewDims.x() / 1e12;
1535 if (aViewDims.y() < aCoef * Precision::Confusion())
1537 aCoef = aViewDims.y() / Precision::Confusion();
1539 else if (aViewDims.y() > aCoef * 1e12)
1541 aCoef = aViewDims.y() / 1e12;
1544 Graphic3d_Vec2d aZoomAtPointXYv (0.0, 0.0);
1545 theView->Convert (theParams.Point.x(), theParams.Point.y(),
1546 aZoomAtPointXYv.x(), aZoomAtPointXYv.y());
1547 Graphic3d_Vec2d aDxy = aZoomAtPointXYv / aCoef;
1548 aCam->SetScale (aCam->Scale() / aCoef);
1550 const gp_Dir& aDir = aCam->Direction();
1551 const gp_Ax3 aCameraCS (aCam->Center(), aDir.Reversed(), aDir ^ aCam->Up());
1553 // pan back to the point
1554 aDxy = aZoomAtPointXYv - aDxy;
1557 // zoom at 3D point with perspective projection
1558 const gp_XYZ anEyeToPnt = thePnt->XYZ() - aCam->Eye().XYZ();
1559 aDxy.SetValues (anEyeToPnt.Dot (aCameraCS.XDirection().XYZ()),
1560 anEyeToPnt.Dot (aCameraCS.YDirection().XYZ()));
1562 // view dimensions at 3D point
1563 const gp_Pnt aViewDims1 = aCam->ViewDimensions (anEyeToPnt.Dot (aCam->Direction().XYZ()));
1565 Graphic3d_Vec2i aWinSize;
1566 theView->Window()->Size (aWinSize.x(), aWinSize.y());
1567 const Graphic3d_Vec2d aPanFromCenterPx (double(theParams.Point.x()) - 0.5 * double(aWinSize.x()),
1568 double(aWinSize.y() - theParams.Point.y() - 1) - 0.5 * double(aWinSize.y()));
1569 aDxy.x() += -aViewDims1.X() * aPanFromCenterPx.x() / double(aWinSize.x());
1570 aDxy.y() += -aViewDims1.Y() * aPanFromCenterPx.y() / double(aWinSize.y());
1573 //theView->Translate (aCam, aDxy.x(), aDxy.y());
1575 const gp_Vec aCameraPan = gp_Vec (aCameraCS.XDirection()) * aDxy.x()
1576 + gp_Vec (aCameraCS.YDirection()) * aDxy.y();
1577 aPanTrsf.SetTranslation (aCameraPan);
1578 aCam->Transform (aPanTrsf);
1579 theView->Invalidate();
1580 theView->View()->SynchronizeXRPosedToBaseCamera();
1583 // =======================================================================
1584 // function : handleZFocusScroll
1586 // =======================================================================
1587 void AIS_ViewController::handleZFocusScroll (const Handle(V3d_View)& theView,
1588 const Aspect_ScrollDelta& theParams)
1590 if (!myToAllowZFocus
1591 || !theView->Camera()->IsStereo())
1596 Standard_Real aFocus = theView->Camera()->ZFocus() + (theParams.Delta > 0.0 ? 0.05 : -0.05);
1600 theView->Camera()->SetZFocus (theView->Camera()->ZFocusType(), aFocus);
1601 theView->Invalidate();
1605 // =======================================================================
1606 // function : handleOrbitRotation
1608 // =======================================================================
1609 void AIS_ViewController::handleOrbitRotation (const Handle(V3d_View)& theView,
1610 const gp_Pnt& thePnt,
1613 if (!myToAllowRotation)
1618 const Handle(Graphic3d_Camera)& aCam = theView->View()->IsActiveXR()
1619 ? theView->View()->BaseXRCamera()
1620 : theView->Camera();
1621 if (myGL.OrbitRotation.ToStart)
1623 // default alternatives
1624 //if (myRotationMode == AIS_RotationMode_BndBoxActive) theView->StartRotation (myGL.RotateAtPoint.x(), myGL.RotateAtPoint.y());
1625 //theView->Rotate (0.0, 0.0, 0.0, thePnt.X(), thePnt.Y(), thePnt.Z(), true);
1627 myRotatePnt3d = thePnt;
1628 myCamStartOpUp = aCam->Up();
1629 myCamStartOpDir = aCam->Direction();
1630 myCamStartOpEye = aCam->Eye();
1631 myCamStartOpCenter = aCam->Center();
1634 aTrsf.SetTransformation (gp_Ax3 (myRotatePnt3d, aCam->OrthogonalizedUp(), aCam->Direction()),
1635 gp_Ax3 (myRotatePnt3d, gp::DZ(), gp::DX()));
1636 const gp_Quaternion aRot = aTrsf.GetRotation();
1637 aRot.GetEulerAngles (gp_YawPitchRoll, myRotateStartYawPitchRoll[0], myRotateStartYawPitchRoll[1], myRotateStartYawPitchRoll[2]);
1640 myCamStartOpToEye = gp_Vec (myRotatePnt3d, aCam->Eye()).Transformed (aTrsf);
1641 myCamStartOpToCenter = gp_Vec (myRotatePnt3d, aCam->Center()).Transformed (aTrsf);
1643 theView->Invalidate();
1646 if (!myGL.OrbitRotation.ToRotate)
1651 AbortViewAnimation();
1654 // amend camera to exclude roll angle (put camera Up vector to plane containing global Z and view direction)
1655 Graphic3d_Vec2i aWinXY;
1656 theView->Window()->Size (aWinXY.x(), aWinXY.y());
1657 double aYawAngleDelta = ((myGL.OrbitRotation.PointStart.x() - myGL.OrbitRotation.PointTo.x()) / double (aWinXY.x())) * (M_PI * 0.5);
1658 double aPitchAngleDelta = -((myGL.OrbitRotation.PointStart.y() - myGL.OrbitRotation.PointTo.y()) / double (aWinXY.y())) * (M_PI * 0.5);
1659 double aPitchAngleNew = 0.0, aRoll = 0.0;
1660 const double aYawAngleNew = myRotateStartYawPitchRoll[0] + aYawAngleDelta;
1661 if (!theView->View()->IsActiveXR())
1663 aPitchAngleNew = Max (Min (myRotateStartYawPitchRoll[1] + aPitchAngleDelta, M_PI * 0.5 - M_PI / 180.0), -M_PI * 0.5 + M_PI / 180.0);
1668 aRot.SetEulerAngles (gp_YawPitchRoll, aYawAngleNew, aPitchAngleNew, aRoll);
1670 aTrsfRot.SetRotation (aRot);
1672 const gp_Dir aNewUp = gp::DZ().Transformed (aTrsfRot);
1673 aCam->SetUp (aNewUp);
1674 aCam->SetEyeAndCenter (myRotatePnt3d.XYZ() + myCamStartOpToEye .Transformed (aTrsfRot).XYZ(),
1675 myRotatePnt3d.XYZ() + myCamStartOpToCenter.Transformed (aTrsfRot).XYZ());
1677 aCam->OrthogonalizeUp();
1681 // default alternatives
1682 //if (myRotationMode == AIS_RotationMode_BndBoxActive) theView->Rotation (myGL.RotateToPoint.x(), myGL.RotateToPoint.y());
1683 //theView->Rotate (aDX, aDY, aDZ, myRotatePnt3d.X(), myRotatePnt3d.Y(), myRotatePnt3d.Z(), false);
1685 // restore previous camera state
1686 aCam->SetEyeAndCenter (myCamStartOpEye, myCamStartOpCenter);
1687 aCam->SetUp (myCamStartOpUp);
1688 aCam->SetDirectionFromEye (myCamStartOpDir);
1690 Graphic3d_Vec2d aWinXY;
1691 theView->Size (aWinXY.x(), aWinXY.y());
1692 const Standard_Real rx = (Standard_Real )theView->Convert (aWinXY.x());
1693 const Standard_Real ry = (Standard_Real )theView->Convert (aWinXY.y());
1695 const double THE_2PI = M_PI * 2.0;
1696 double aDX = (myGL.OrbitRotation.PointTo.x() - myGL.OrbitRotation.PointStart.x()) * M_PI / rx;
1697 double aDY = (myGL.OrbitRotation.PointStart.y() - myGL.OrbitRotation.PointTo.y()) * M_PI / ry;
1699 if (aDX > 0.0) { while (aDX > THE_2PI) { aDX -= THE_2PI; } }
1700 else if(aDX < 0.0) { while (aDX < -THE_2PI) { aDX += THE_2PI; } }
1701 if (aDY > 0.0) { while (aDY > THE_2PI) { aDY -= THE_2PI; } }
1702 else if(aDY < 0.0) { while (aDY < -THE_2PI) { aDY += THE_2PI; } }
1704 // rotate camera around 3 initial axes
1705 gp_Dir aCamDir (aCam->Direction().Reversed());
1706 gp_Dir aCamUp (aCam->Up());
1707 gp_Dir aCamSide(aCamUp.Crossed (aCamDir));
1709 gp_Trsf aRot[2], aTrsf;
1710 aRot[0].SetRotation (gp_Ax1 (myRotatePnt3d, aCamUp), -aDX);
1711 aRot[1].SetRotation (gp_Ax1 (myRotatePnt3d, aCamSide), aDY);
1712 aTrsf.Multiply (aRot[0]);
1713 aTrsf.Multiply (aRot[1]);
1715 aCam->Transform (aTrsf);
1718 theView->Invalidate();
1719 theView->View()->SynchronizeXRBaseToPosedCamera();
1722 // =======================================================================
1723 // function : handleViewRotation
1725 // =======================================================================
1726 void AIS_ViewController::handleViewRotation (const Handle(V3d_View)& theView,
1728 double thePitchExtra,
1730 bool theToRestartOnIncrement)
1732 if (!myToAllowRotation)
1737 const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1738 const bool toRotateAnyway = Abs (theYawExtra) > gp::Resolution()
1739 || Abs (thePitchExtra) > gp::Resolution()
1740 || Abs (theRoll - myRotateStartYawPitchRoll[2]) > gp::Resolution();
1742 && theToRestartOnIncrement)
1744 myGL.ViewRotation.ToStart = true;
1745 myGL.ViewRotation.PointTo = myGL.ViewRotation.PointStart;
1747 if (myGL.ViewRotation.ToStart)
1750 aTrsf.SetTransformation (gp_Ax3 (gp::Origin(), aCam->OrthogonalizedUp(), aCam->Direction()),
1751 gp_Ax3 (gp::Origin(), gp::DZ(), gp::DX()));
1752 const gp_Quaternion aRot = aTrsf.GetRotation();
1753 double aRollDummy = 0.0;
1754 aRot.GetEulerAngles (gp_YawPitchRoll, myRotateStartYawPitchRoll[0], myRotateStartYawPitchRoll[1], aRollDummy);
1758 myRotateStartYawPitchRoll[0] += theYawExtra;
1759 myRotateStartYawPitchRoll[1] += thePitchExtra;
1760 myRotateStartYawPitchRoll[2] = theRoll;
1761 myGL.ViewRotation.ToRotate = true;
1764 if (!myGL.ViewRotation.ToRotate)
1769 AbortViewAnimation();
1771 Graphic3d_Vec2i aWinXY;
1772 theView->Window()->Size (aWinXY.x(), aWinXY.y());
1773 double aYawAngleDelta = ((myGL.ViewRotation.PointStart.x() - myGL.ViewRotation.PointTo.x()) / double (aWinXY.x())) * (M_PI * 0.5);
1774 double aPitchAngleDelta = -((myGL.ViewRotation.PointStart.y() - myGL.ViewRotation.PointTo.y()) / double (aWinXY.y())) * (M_PI * 0.5);
1775 const double aPitchAngleNew = Max (Min (myRotateStartYawPitchRoll[1] + aPitchAngleDelta, M_PI * 0.5 - M_PI / 180.0), -M_PI * 0.5 + M_PI / 180.0);
1776 const double aYawAngleNew = myRotateStartYawPitchRoll[0] + aYawAngleDelta;
1778 aRot.SetEulerAngles (gp_YawPitchRoll, aYawAngleNew, aPitchAngleNew, theRoll);
1780 aTrsfRot.SetRotation (aRot);
1782 const gp_Dir aNewUp = gp::DZ().Transformed (aTrsfRot);
1783 const gp_Dir aNewDir = gp::DX().Transformed (aTrsfRot);
1784 aCam->SetUp (aNewUp);
1785 aCam->SetDirectionFromEye (aNewDir);
1786 aCam->OrthogonalizeUp();
1787 theView->Invalidate();
1790 // =======================================================================
1791 // function : PickPoint
1793 // =======================================================================
1794 bool AIS_ViewController::PickPoint (gp_Pnt& thePnt,
1795 const Handle(AIS_InteractiveContext)& theCtx,
1796 const Handle(V3d_View)& theView,
1797 const Graphic3d_Vec2i& theCursor,
1798 bool theToStickToPickRay)
1800 ResetPreviousMoveTo();
1802 const Handle(StdSelect_ViewerSelector3d)& aSelector = theCtx->MainSelector();
1803 aSelector->Pick (theCursor.x(), theCursor.y(), theView);
1804 if (aSelector->NbPicked() < 1)
1809 const SelectMgr_SortCriterion& aPicked = aSelector->PickedData (1);
1810 if (theToStickToPickRay
1811 && !Precision::IsInfinite (aPicked.Depth))
1813 thePnt = aSelector->GetManager().DetectedPoint (aPicked.Depth);
1817 thePnt = aSelector->PickedPoint (1);
1819 return !Precision::IsInfinite (thePnt.X())
1820 && !Precision::IsInfinite (thePnt.Y())
1821 && !Precision::IsInfinite (thePnt.Z());
1824 // =======================================================================
1825 // function : GravityPoint
1827 // =======================================================================
1828 gp_Pnt AIS_ViewController::GravityPoint (const Handle(AIS_InteractiveContext)& theCtx,
1829 const Handle(V3d_View)& theView)
1831 switch (myRotationMode)
1833 case AIS_RotationMode_PickLast:
1834 case AIS_RotationMode_PickCenter:
1836 Graphic3d_Vec2i aCursor ((int )myGL.OrbitRotation.PointStart.x(), (int )myGL.OrbitRotation.PointStart.y());
1837 if (myRotationMode == AIS_RotationMode_PickCenter)
1839 Graphic3d_Vec2i aViewPort;
1840 theView->Window()->Size (aViewPort.x(), aViewPort.y());
1841 aCursor = aViewPort / 2;
1845 if (PickPoint (aPnt, theCtx, theView, aCursor, myToStickToRayOnRotation))
1851 case AIS_RotationMode_CameraAt:
1853 const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1854 return aCam->Center();
1856 case AIS_RotationMode_BndBoxScene:
1858 Bnd_Box aBndBox = theView->View()->MinMaxValues (false);
1859 if (!aBndBox.IsVoid())
1861 return (aBndBox.CornerMin().XYZ() + aBndBox.CornerMax().XYZ()) * 0.5;
1865 case AIS_RotationMode_BndBoxActive:
1869 return theCtx ->GravityPoint (theView);
1872 // =======================================================================
1873 // function : FitAllAuto
1875 // =======================================================================
1876 void AIS_ViewController::FitAllAuto (const Handle(AIS_InteractiveContext)& theCtx,
1877 const Handle(V3d_View)& theView)
1879 const Bnd_Box aBoxSel = theCtx->BoundingBoxOfSelection();
1880 const double aFitMargin = 0.01;
1881 if (aBoxSel.IsVoid())
1883 theView->FitAll (aFitMargin, false);
1887 // fit all algorithm is not 100% stable - so compute some precision to compare equal camera values
1888 const double aFitTol = (aBoxSel.CornerMax().XYZ() - aBoxSel.CornerMin().XYZ()).Modulus() * 0.000001;
1889 const Bnd_Box aBoxAll = theView->View()->MinMaxValues();
1891 const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1892 Handle(Graphic3d_Camera) aCameraSel = new Graphic3d_Camera (aCam);
1893 Handle(Graphic3d_Camera) aCameraAll = new Graphic3d_Camera (aCam);
1894 theView->FitMinMax (aCameraSel, aBoxSel, aFitMargin);
1895 theView->FitMinMax (aCameraAll, aBoxAll, aFitMargin);
1896 if (aCameraSel->Center().IsEqual (aCam->Center(), aFitTol)
1897 && Abs (aCameraSel->Scale() - aCam->Scale()) < aFitTol
1898 && Abs (aCameraSel->Distance() - aCam->Distance()) < aFitTol)
1900 // fit all entire view on second FitALL request
1901 aCam->Copy (aCameraAll);
1905 aCam->Copy (aCameraSel);
1909 // =======================================================================
1910 // function : handleViewOrientationKeys
1912 // =======================================================================
1913 void AIS_ViewController::handleViewOrientationKeys (const Handle(AIS_InteractiveContext)& theCtx,
1914 const Handle(V3d_View)& theView)
1916 if (myNavigationMode == AIS_NavigationMode_FirstPersonWalk)
1921 Handle(Graphic3d_Camera) aCameraBack;
1922 struct ViewKeyAction
1925 V3d_TypeOfOrientation Orientation;
1927 static const ViewKeyAction THE_VIEW_KEYS[] =
1929 { Aspect_VKey_ViewTop, V3d_TypeOfOrientation_Zup_Top },
1930 { Aspect_VKey_ViewBottom, V3d_TypeOfOrientation_Zup_Bottom },
1931 { Aspect_VKey_ViewLeft, V3d_TypeOfOrientation_Zup_Left },
1932 { Aspect_VKey_ViewRight, V3d_TypeOfOrientation_Zup_Right },
1933 { Aspect_VKey_ViewFront, V3d_TypeOfOrientation_Zup_Front },
1934 { Aspect_VKey_ViewBack, V3d_TypeOfOrientation_Zup_Back },
1935 { Aspect_VKey_ViewAxoLeftProj, V3d_TypeOfOrientation_Zup_AxoLeft },
1936 { Aspect_VKey_ViewAxoRightProj, V3d_TypeOfOrientation_Zup_AxoRight },
1937 { Aspect_VKey_ViewRoll90CW, (V3d_TypeOfOrientation )-1},
1938 { Aspect_VKey_ViewRoll90CCW, (V3d_TypeOfOrientation )-1},
1939 { Aspect_VKey_ViewFitAll, (V3d_TypeOfOrientation )-1}
1942 Standard_Mutex::Sentry aLock (myKeys.Mutex());
1943 const size_t aNbKeys = sizeof(THE_VIEW_KEYS) / sizeof(*THE_VIEW_KEYS);
1944 const double anEventTime = EventTime();
1945 for (size_t aKeyIter = 0; aKeyIter < aNbKeys; ++aKeyIter)
1947 const ViewKeyAction& aKeyAction = THE_VIEW_KEYS[aKeyIter];
1948 if (!myKeys.IsKeyDown (aKeyAction.Key))
1953 myKeys.KeyUp (aKeyAction.Key, anEventTime);
1954 if (aCameraBack.IsNull())
1956 aCameraBack = theView->Camera();
1957 theView->SetCamera (new Graphic3d_Camera (aCameraBack));
1959 if (aKeyAction.Orientation != (V3d_TypeOfOrientation )-1)
1961 theView->SetProj (aKeyAction.Orientation);
1962 FitAllAuto (theCtx, theView);
1964 else if (aKeyAction.Key == Aspect_VKey_ViewRoll90CW)
1966 const double aTwist = theView->Twist() + M_PI / 2.0;
1967 theView->SetTwist (aTwist);
1969 else if (aKeyAction.Key == Aspect_VKey_ViewRoll90CCW)
1971 const double aTwist = theView->Twist() - M_PI / 2.0;
1972 theView->SetTwist (aTwist);
1974 else if (aKeyAction.Key == Aspect_VKey_ViewFitAll)
1976 FitAllAuto (theCtx, theView);
1981 if (aCameraBack.IsNull())
1986 Handle(Graphic3d_Camera) aCameraNew = theView->Camera();
1987 theView->SetCamera (aCameraBack);
1988 const Graphic3d_Mat4d anOrientMat1 = aCameraBack->OrientationMatrix();
1989 const Graphic3d_Mat4d anOrientMat2 = aCameraNew ->OrientationMatrix();
1990 if (anOrientMat1 != anOrientMat2)
1992 const Handle(AIS_AnimationCamera)& aCamAnim = myViewAnimation;
1993 aCamAnim->SetView (theView);
1994 aCamAnim->SetStartPts (0.0);
1995 aCamAnim->SetCameraStart (new Graphic3d_Camera (aCameraBack));
1996 aCamAnim->SetCameraEnd (new Graphic3d_Camera (aCameraNew));
1997 aCamAnim->StartTimer (0.0, 1.0, true, false);
2001 // =======================================================================
2002 // function : handleNavigationKeys
2004 // =======================================================================
2005 AIS_WalkDelta AIS_ViewController::handleNavigationKeys (const Handle(AIS_InteractiveContext)& ,
2006 const Handle(V3d_View)& theView)
2009 double aCrouchRatio = 1.0, aRunRatio = 1.0;
2010 if (myNavigationMode == AIS_NavigationMode_FirstPersonFlight)
2015 const double aRotSpeed = 0.5;
2016 const double aWalkSpeedCoef = WalkSpeedRelative();
2017 AIS_WalkDelta aWalk = FetchNavigationKeys (aCrouchRatio, aRunRatio);
2018 if (aWalk.IsJumping())
2022 theView->Invalidate();
2024 if (aWalk.IsEmpty())
2028 else if (myGL.OrbitRotation.ToRotate
2029 || myGL.OrbitRotation.ToStart)
2035 const Bnd_Box aBndBox = theView->View()->MinMaxValues();
2036 if (!aBndBox.IsVoid())
2038 aMin = aBndBox.CornerMin().XYZ();
2039 aMax = aBndBox.CornerMax().XYZ();
2041 double aBndDiam = Max (Max (aMax.X() - aMin.X(), aMax.Y() - aMin.Y()), aMax.Z() - aMin.Z());
2042 if (aBndDiam <= gp::Resolution())
2047 const double aWalkSpeed = myNavigationMode != AIS_NavigationMode_Orbit
2048 && myNavigationMode != AIS_NavigationMode_FirstPersonFlight
2049 ? theView->View()->UnitFactor() * WalkSpeedAbsolute()
2050 : aWalkSpeedCoef * aBndDiam;
2051 const Handle(Graphic3d_Camera)& aCam = theView->View()->IsActiveXR()
2052 ? theView->View()->BaseXRCamera()
2053 : theView->Camera();
2055 // move forward in plane XY and up along Z
2056 const gp_Dir anUp = ToLockOrbitZUp() ? gp::DZ() : aCam->OrthogonalizedUp();
2058 && myToAllowPanning)
2060 const gp_Vec aSide = -aCam->SideRight();
2061 gp_XYZ aFwd = aCam->Direction().XYZ();
2062 aFwd -= anUp.XYZ() * (anUp.XYZ() * aFwd);
2065 if (!aWalk[AIS_WalkTranslation_Forward].IsEmpty())
2067 if (!aCam->IsOrthographic())
2069 aMoveVec += aFwd * aWalk[AIS_WalkTranslation_Forward].Value * aWalk[AIS_WalkTranslation_Forward].Pressure * aWalkSpeed;
2072 if (!aWalk[AIS_WalkTranslation_Side].IsEmpty())
2074 aMoveVec += aSide.XYZ() * aWalk[AIS_WalkTranslation_Side].Value * aWalk[AIS_WalkTranslation_Side].Pressure * aWalkSpeed;
2076 if (!aWalk[AIS_WalkTranslation_Up].IsEmpty())
2078 aMoveVec += anUp.XYZ() * aWalk[AIS_WalkTranslation_Up].Value * aWalk[AIS_WalkTranslation_Up].Pressure * aWalkSpeed;
2081 if (aCam->IsOrthographic())
2083 if (!aWalk[AIS_WalkTranslation_Forward].IsEmpty())
2085 const double aZoomDelta = aWalk[AIS_WalkTranslation_Forward].Value * aWalk[AIS_WalkTranslation_Forward].Pressure * aWalkSpeedCoef;
2086 handleZoom (theView, Aspect_ScrollDelta (aZoomDelta * 100.0), NULL);
2090 gp_Trsf aTrsfTranslate;
2091 aTrsfTranslate.SetTranslation (aMoveVec);
2092 aCam->Transform (aTrsfTranslate);
2096 if (myNavigationMode == AIS_NavigationMode_Orbit
2097 && myToAllowRotation)
2099 if (!aWalk[AIS_WalkRotation_Yaw].IsEmpty())
2102 aTrsfRot.SetRotation (gp_Ax1 (aCam->Eye(), anUp), aWalk[AIS_WalkRotation_Yaw].Value * aRotSpeed);
2103 aCam->Transform (aTrsfRot);
2105 if (!aWalk[AIS_WalkRotation_Pitch].IsEmpty())
2107 const gp_Vec aSide = -aCam->SideRight();
2109 aTrsfRot.SetRotation (gp_Ax1 (aCam->Eye(), aSide), -aWalk[AIS_WalkRotation_Pitch].Value * aRotSpeed);
2110 aCam->Transform (aTrsfRot);
2112 if (!aWalk[AIS_WalkRotation_Roll].IsEmpty()
2113 && !ToLockOrbitZUp())
2116 aTrsfRot.SetRotation (gp_Ax1 (aCam->Center(), aCam->Direction()), aWalk[AIS_WalkRotation_Roll].Value * aRotSpeed);
2117 aCam->Transform (aTrsfRot);
2123 theView->Invalidate();
2124 theView->View()->SynchronizeXRBaseToPosedCamera();
2128 // =======================================================================
2129 // function : handleCameraActions
2131 // =======================================================================
2132 void AIS_ViewController::handleCameraActions (const Handle(AIS_InteractiveContext)& theCtx,
2133 const Handle(V3d_View)& theView,
2134 const AIS_WalkDelta& theWalk)
2136 // apply view actions
2137 if (myGL.Orientation.ToSetViewOrient)
2139 theView->SetProj (myGL.Orientation.ViewOrient);
2140 myGL.Orientation.ToFitAll = true;
2144 if (myGL.Orientation.ToFitAll)
2146 const double aFitMargin = 0.01;
2147 theView->FitAll (aFitMargin, false);
2148 theView->Invalidate();
2149 myGL.Orientation.ToFitAll = false;
2152 if (myGL.IsNewGesture)
2154 if (myAnchorPointPrs1->HasInteractiveContext())
2156 theCtx->Remove (myAnchorPointPrs1, false);
2157 if (!theView->Viewer()->ZLayerSettings (myAnchorPointPrs1->ZLayer()).IsImmediate())
2159 theView->Invalidate();
2163 theView->InvalidateImmediate();
2166 if (myAnchorPointPrs2->HasInteractiveContext())
2168 theCtx->Remove (myAnchorPointPrs2, false);
2169 if (!theView->Viewer()->ZLayerSettings (myAnchorPointPrs2->ZLayer()).IsImmediate())
2171 theView->Invalidate();
2175 theView->InvalidateImmediate();
2179 if (myHasHlrOnBeforeRotation)
2181 myHasHlrOnBeforeRotation = false;
2182 theView->SetComputedMode (true);
2183 theView->Invalidate();
2187 if (myNavigationMode != AIS_NavigationMode_FirstPersonWalk)
2189 if (myGL.Panning.ToStart
2190 && myToAllowPanning)
2192 gp_Pnt aPanPnt (Precision::Infinite(), 0.0, 0.0);
2193 if (!theView->Camera()->IsOrthographic())
2195 bool toStickToRay = false;
2196 if (myGL.Panning.PointStart.x() >= 0
2197 && myGL.Panning.PointStart.y() >= 0)
2199 PickPoint (aPanPnt, theCtx, theView, myGL.Panning.PointStart, toStickToRay);
2201 if (Precision::IsInfinite (aPanPnt.X()))
2203 Graphic3d_Vec2i aWinSize;
2204 theView->Window()->Size (aWinSize.x(), aWinSize.y());
2205 PickPoint (aPanPnt, theCtx, theView, aWinSize / 2, toStickToRay);
2207 if (!Precision::IsInfinite (aPanPnt.X())
2208 && myToShowPanAnchorPoint)
2211 aPntTrsf.SetTranslation (gp_Vec (aPanPnt.XYZ()));
2212 theCtx->SetLocation (myAnchorPointPrs2, aPntTrsf);
2215 setPanningAnchorPoint (aPanPnt);
2218 if (myToShowPanAnchorPoint
2219 && hasPanningAnchorPoint()
2220 && myGL.Panning.ToPan
2221 && !myGL.IsNewGesture
2222 && !myAnchorPointPrs2->HasInteractiveContext())
2224 theCtx->Display (myAnchorPointPrs2, 0, -1, false, AIS_DS_Displayed);
2227 handlePanning (theView);
2228 handleZRotate (theView);
2231 if ((myNavigationMode == AIS_NavigationMode_Orbit
2232 || myGL.OrbitRotation.ToStart
2233 || myGL.OrbitRotation.ToRotate)
2234 && myToAllowRotation)
2236 if (myGL.OrbitRotation.ToStart
2237 && !myHasHlrOnBeforeRotation)
2239 myHasHlrOnBeforeRotation = theView->ComputedMode();
2240 if (myHasHlrOnBeforeRotation)
2242 theView->SetComputedMode (false);
2247 if (myGL.OrbitRotation.ToStart)
2249 aGravPnt = GravityPoint (theCtx, theView);
2250 if (myToShowRotateCenter)
2253 aPntTrsf.SetTranslation (gp_Vec (aGravPnt.XYZ()));
2254 theCtx->SetLocation (myAnchorPointPrs1, aPntTrsf);
2255 theCtx->SetLocation (myAnchorPointPrs2, aPntTrsf);
2259 if (myToShowRotateCenter
2260 && myGL.OrbitRotation.ToRotate
2261 && !myGL.IsNewGesture
2262 && !myAnchorPointPrs1->HasInteractiveContext())
2264 theCtx->Display (myAnchorPointPrs1, 0, -1, false, AIS_DS_Displayed);
2265 theCtx->Display (myAnchorPointPrs2, 0, -1, false, AIS_DS_Displayed);
2267 handleOrbitRotation (theView, aGravPnt,
2268 myToLockOrbitZUp || myNavigationMode != AIS_NavigationMode_Orbit);
2271 if ((myNavigationMode != AIS_NavigationMode_Orbit
2272 || myGL.ViewRotation.ToStart
2273 || myGL.ViewRotation.ToRotate)
2274 && myToAllowRotation)
2276 if (myGL.ViewRotation.ToStart
2277 && !myHasHlrOnBeforeRotation)
2279 myHasHlrOnBeforeRotation = theView->ComputedMode();
2280 if (myHasHlrOnBeforeRotation)
2282 theView->SetComputedMode (false);
2287 if (!theWalk[AIS_WalkRotation_Roll].IsEmpty()
2288 && !myToLockOrbitZUp)
2290 aRoll = (M_PI / 12.0) * theWalk[AIS_WalkRotation_Roll].Pressure;
2291 aRoll *= Min (1000.0 * theWalk[AIS_WalkRotation_Roll].Duration, 100.0) / 100.0;
2292 if (theWalk[AIS_WalkRotation_Roll].Value < 0.0)
2298 handleViewRotation (theView, theWalk[AIS_WalkRotation_Yaw].Value, theWalk[AIS_WalkRotation_Pitch].Value, aRoll,
2299 myNavigationMode == AIS_NavigationMode_FirstPersonFlight);
2302 if (!myGL.ZoomActions.IsEmpty())
2304 for (NCollection_Sequence<Aspect_ScrollDelta>::Iterator aZoomIter (myGL.ZoomActions); aZoomIter.More(); aZoomIter.Next())
2306 Aspect_ScrollDelta aZoomParams = aZoomIter.Value();
2308 && (aZoomParams.Flags & Aspect_VKeyFlags_CTRL) != 0
2309 && theView->Camera()->IsStereo())
2311 handleZFocusScroll (theView, aZoomParams);
2315 if (!myToAllowZooming)
2320 if (!theView->Camera()->IsOrthographic())
2323 if (aZoomParams.HasPoint()
2324 && PickPoint (aPnt, theCtx, theView, aZoomParams.Point, myToStickToRayOnZoom))
2326 handleZoom (theView, aZoomParams, &aPnt);
2330 Graphic3d_Vec2i aWinSize;
2331 theView->Window()->Size (aWinSize.x(), aWinSize.y());
2332 if (PickPoint (aPnt, theCtx, theView, aWinSize / 2, myToStickToRayOnZoom))
2334 aZoomParams.ResetPoint(); // do not pretend to zoom at 'nothing'
2335 handleZoom (theView, aZoomParams, &aPnt);
2339 handleZoom (theView, aZoomParams, NULL);
2341 myGL.ZoomActions.Clear();
2345 // =======================================================================
2346 // function : handleXRInput
2348 // =======================================================================
2349 void AIS_ViewController::handleXRInput (const Handle(AIS_InteractiveContext)& theCtx,
2350 const Handle(V3d_View)& theView,
2351 const AIS_WalkDelta& )
2353 theView->View()->ProcessXRInput();
2354 if (!theView->View()->IsActiveXR())
2358 if (myXRCameraTmp.IsNull())
2360 myXRCameraTmp = new Graphic3d_Camera();
2362 handleXRTurnPad (theCtx, theView);
2363 handleXRTeleport(theCtx, theView);
2364 handleXRPicking (theCtx, theView);
2367 // =======================================================================
2368 // function : handleXRTurnPad
2370 // =======================================================================
2371 void AIS_ViewController::handleXRTurnPad (const Handle(AIS_InteractiveContext)& ,
2372 const Handle(V3d_View)& theView)
2374 if (myXRTurnAngle <= 0.0
2375 || !theView->View()->IsActiveXR())
2380 // turn left/right at 45 degrees on left/right trackpad clicks
2381 for (int aHand = 0; aHand < 2; ++aHand)
2383 const Aspect_XRTrackedDeviceRole aRole = aHand == 0 ? Aspect_XRTrackedDeviceRole_RightHand : Aspect_XRTrackedDeviceRole_LeftHand;
2384 const Handle(Aspect_XRAction)& aPadClickAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTrackPadClick);
2385 const Handle(Aspect_XRAction)& aPadPosAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTrackPadPosition);
2386 if (aPadClickAct.IsNull()
2387 || aPadPosAct.IsNull())
2392 const Aspect_XRDigitalActionData aPadClick = theView->View()->XRSession()->GetDigitalActionData (aPadClickAct);
2393 const Aspect_XRAnalogActionData aPadPos = theView->View()->XRSession()->GetAnalogActionData (aPadPosAct);
2394 if (aPadClick.IsActive
2395 && aPadClick.IsPressed
2396 && aPadClick.IsChanged
2398 && Abs (aPadPos.VecXYZ.y()) < 0.5f
2399 && Abs (aPadPos.VecXYZ.x()) > 0.7f)
2402 aTrsfTurn.SetRotation (gp_Ax1 (gp::Origin(), theView->View()->BaseXRCamera()->Up()), aPadPos.VecXYZ.x() < 0.0f ? myXRTurnAngle : -myXRTurnAngle);
2403 theView->View()->TurnViewXRCamera (aTrsfTurn);
2409 // =======================================================================
2410 // function : handleXRTeleport
2412 // =======================================================================
2413 void AIS_ViewController::handleXRTeleport (const Handle(AIS_InteractiveContext)& theCtx,
2414 const Handle(V3d_View)& theView)
2416 if (!theView->View()->IsActiveXR())
2421 // teleport on forward trackpad unclicks
2422 const Aspect_XRTrackedDeviceRole aTeleOld = myXRLastTeleportHand;
2423 myXRLastTeleportHand = Aspect_XRTrackedDeviceRole_Other;
2424 for (int aHand = 0; aHand < 2; ++aHand)
2426 const Aspect_XRTrackedDeviceRole aRole = aHand == 0 ? Aspect_XRTrackedDeviceRole_RightHand : Aspect_XRTrackedDeviceRole_LeftHand;
2427 const Standard_Integer aDeviceId = theView->View()->XRSession()->NamedTrackedDevice (aRole);
2428 if (aDeviceId == -1)
2433 const Handle(Aspect_XRAction)& aPadClickAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTrackPadClick);
2434 const Handle(Aspect_XRAction)& aPadPosAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTrackPadPosition);
2435 if (aPadClickAct.IsNull()
2436 || aPadPosAct.IsNull())
2441 const Aspect_XRDigitalActionData aPadClick = theView->View()->XRSession()->GetDigitalActionData (aPadClickAct);
2442 const Aspect_XRAnalogActionData aPadPos = theView->View()->XRSession()->GetAnalogActionData (aPadPosAct);
2443 const bool isPressed = aPadClick.IsPressed;
2444 const bool isClicked = !aPadClick.IsPressed
2445 && aPadClick.IsChanged;
2446 if (aPadClick.IsActive
2447 && (isPressed || isClicked)
2449 && aPadPos.VecXYZ.y() > 0.6f
2450 && Abs (aPadPos.VecXYZ.x()) < 0.5f)
2452 const Aspect_TrackedDevicePose& aPose = theView->View()->XRSession()->TrackedPoses()[aDeviceId];
2453 if (!aPose.IsValidPose)
2458 myXRLastTeleportHand = aRole;
2459 Standard_Real& aPickDepth = aRole == Aspect_XRTrackedDeviceRole_LeftHand ? myXRLastPickDepthLeft : myXRLastPickDepthRight;
2460 aPickDepth = Precision::Infinite();
2461 Graphic3d_Vec3 aPickNorm;
2462 const gp_Trsf aHandBase = theView->View()->PoseXRToWorld (aPose.Orientation);
2463 const Standard_Real aHeadHeight = theView->View()->XRSession()->HeadPose().TranslationPart().Y();
2465 const Standard_Integer aPickedId = handleXRMoveTo (theCtx, theView, aPose.Orientation, false);
2468 const SelectMgr_SortCriterion& aPickedData = theCtx->MainSelector()->PickedData (aPickedId);
2469 aPickNorm = aPickedData.Normal;
2470 if (aPickNorm.SquareModulus() > ShortRealEpsilon())
2472 aPickDepth = aPickedData.Point.Distance (aHandBase.TranslationPart());
2478 myXRLastTeleportHand = Aspect_XRTrackedDeviceRole_Other;
2479 if (!Precision::IsInfinite (aPickDepth))
2481 const gp_Dir aTeleDir = -gp::DZ().Transformed (aHandBase);
2482 const gp_Dir anUpDir = theView->View()->BaseXRCamera()->Up();
2484 bool isHorizontal = false;
2485 gp_Dir aPickNormDir (aPickNorm.x(), aPickNorm.y(), aPickNorm.z());
2486 if (anUpDir.IsEqual ( aPickNormDir, M_PI_4)
2487 || anUpDir.IsEqual (-aPickNormDir, M_PI_4))
2489 isHorizontal = true;
2492 gp_Pnt aNewEye = aHandBase.TranslationPart();
2495 aNewEye = aHandBase.TranslationPart()
2496 + aTeleDir.XYZ() * aPickDepth
2497 + anUpDir.XYZ() * aHeadHeight;
2501 if (aPickNormDir.Dot (aTeleDir) < 0.0)
2503 aPickNormDir.Reverse();
2505 aNewEye = aHandBase.TranslationPart()
2506 + aTeleDir.XYZ() * aPickDepth
2507 - aPickNormDir.XYZ() * aHeadHeight / 4;
2510 theView->View()->PosedXRCamera()->MoveEyeTo (aNewEye);
2511 theView->View()->ComputeXRBaseCameraFromPosed (theView->View()->PosedXRCamera(), theView->View()->XRSession()->HeadPose());
2518 if (myXRLastTeleportHand != aTeleOld)
2520 if (aTeleOld != Aspect_XRTrackedDeviceRole_Other)
2522 if (const Handle(Aspect_XRAction)& aHaptic = theView->View()->XRSession()->GenericAction (aTeleOld, Aspect_XRGenericAction_OutputHaptic))
2524 theView->View()->XRSession()->AbortHapticVibrationAction (aHaptic);
2527 if (myXRLastTeleportHand != Aspect_XRTrackedDeviceRole_Other)
2529 if (const Handle(Aspect_XRAction)& aHaptic = theView->View()->XRSession()->GenericAction (myXRLastTeleportHand, Aspect_XRGenericAction_OutputHaptic))
2531 theView->View()->XRSession()->TriggerHapticVibrationAction (aHaptic, myXRTeleportHaptic);
2537 // =======================================================================
2538 // function : handleXRPicking
2540 // =======================================================================
2541 void AIS_ViewController::handleXRPicking (const Handle(AIS_InteractiveContext)& theCtx,
2542 const Handle(V3d_View)& theView)
2544 if (!theView->View()->IsActiveXR())
2549 // handle selection on trigger clicks
2550 Aspect_XRTrackedDeviceRole aPickDevOld = myXRLastPickingHand;
2551 myXRLastPickingHand = Aspect_XRTrackedDeviceRole_Other;
2552 for (int aHand = 0; aHand < 2; ++aHand)
2554 const Aspect_XRTrackedDeviceRole aRole = aHand == 0 ? Aspect_XRTrackedDeviceRole_RightHand : Aspect_XRTrackedDeviceRole_LeftHand;
2555 const Handle(Aspect_XRAction)& aTrigClickAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTriggerClick);
2556 const Handle(Aspect_XRAction)& aTrigPullAct = theView->View()->XRSession()->GenericAction (aRole, Aspect_XRGenericAction_InputTriggerPull);
2557 if (aTrigClickAct.IsNull()
2558 || aTrigPullAct.IsNull())
2563 const Aspect_XRDigitalActionData aTrigClick = theView->View()->XRSession()->GetDigitalActionData (aTrigClickAct);
2564 const Aspect_XRAnalogActionData aTrigPos = theView->View()->XRSession()->GetAnalogActionData (aTrigPullAct);
2565 if (aTrigPos.IsActive
2566 && Abs (aTrigPos.VecXYZ.x()) > 0.1f)
2568 myXRLastPickingHand = aRole;
2569 handleXRHighlight (theCtx, theView);
2570 if (aTrigClick.IsActive
2571 && aTrigClick.IsPressed
2572 && aTrigClick.IsChanged)
2574 theCtx->SelectDetected();
2575 OnSelectionChanged (theCtx, theView);
2576 if (const Handle(Aspect_XRAction)& aHaptic = theView->View()->XRSession()->GenericAction (myXRLastPickingHand, Aspect_XRGenericAction_OutputHaptic))
2578 theView->View()->XRSession()->TriggerHapticVibrationAction (aHaptic, myXRSelectHaptic);
2584 if (myXRLastPickingHand != aPickDevOld)
2586 theCtx->ClearDetected();
2590 // =======================================================================
2591 // function : OnSelectionChanged
2593 // =======================================================================
2594 void AIS_ViewController::OnSelectionChanged (const Handle(AIS_InteractiveContext)& ,
2595 const Handle(V3d_View)& )
2600 // =======================================================================
2601 // function : OnObjectDragged
2603 // =======================================================================
2604 void AIS_ViewController::OnObjectDragged (const Handle(AIS_InteractiveContext)& theCtx,
2605 const Handle(V3d_View)& theView,
2606 AIS_DragAction theAction)
2610 case AIS_DragAction_Start:
2612 myDragObject.Nullify();
2613 myDragOwner.Nullify();
2614 if (!theCtx->HasDetected())
2619 const Handle(SelectMgr_EntityOwner)& aDetectedOwner = theCtx->DetectedOwner();
2620 Handle(AIS_InteractiveObject) aDetectedPrs = Handle(AIS_InteractiveObject)::DownCast (aDetectedOwner->Selectable());
2622 if (aDetectedPrs->ProcessDragging (theCtx, theView, aDetectedOwner, myGL.Dragging.PointStart,
2623 myGL.Dragging.PointTo, theAction))
2625 myDragObject = aDetectedPrs;
2626 myDragOwner = aDetectedOwner;
2630 case AIS_DragAction_Update:
2632 if (myDragObject.IsNull())
2637 if (Handle(SelectMgr_EntityOwner) aGlobOwner = myDragObject->GlobalSelOwner())
2639 theCtx->SetSelectedState (aGlobOwner, true);
2642 myDragObject->ProcessDragging (theCtx, theView, myDragOwner, myGL.Dragging.PointStart,
2643 myGL.Dragging.PointTo, theAction);
2644 theView->Invalidate();
2647 case AIS_DragAction_Abort:
2649 if (myDragObject.IsNull())
2654 myGL.Dragging.PointTo = myGL.Dragging.PointStart;
2655 OnObjectDragged (theCtx, theView, AIS_DragAction_Update);
2657 myDragObject->ProcessDragging (theCtx, theView, myDragOwner, myGL.Dragging.PointStart,
2658 myGL.Dragging.PointTo, theAction);
2659 Standard_FALLTHROUGH
2661 case AIS_DragAction_Stop:
2663 if (myDragObject.IsNull())
2668 if (Handle(SelectMgr_EntityOwner) aGlobOwner = myDragObject->GlobalSelOwner())
2670 theCtx->SetSelectedState (aGlobOwner, false);
2673 myDragObject->ProcessDragging (theCtx, theView, myDragOwner, myGL.Dragging.PointStart,
2674 myGL.Dragging.PointTo, theAction);
2675 theView->Invalidate();
2676 myDragObject.Nullify();
2677 myDragOwner.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();
2701 // Picking relies on the camera frustum (including Z-range) - so make temporary AutoZFit()
2702 // and then restore previous frustum to avoid immediate layer rendering issues if View has not been invalidated.
2703 const Standard_Real aZNear = theView->Camera()->ZNear(), aZFar = theView->Camera()->ZFar();
2704 theView->AutoZFit();
2705 theCtx->MoveTo (thePnt.x(), thePnt.y(), theView, false);
2706 theView->Camera()->SetZRange (aZNear, aZFar);
2708 Handle(SelectMgr_EntityOwner) aNewPicked = theCtx->DetectedOwner();
2710 if (theView->Viewer()->Grid()->IsActive()
2711 && theView->Viewer()->GridEcho())
2713 if (aNewPicked.IsNull())
2715 Graphic3d_Vec3d aPnt3d;
2716 theView->ConvertToGrid (thePnt.x(), thePnt.y(), aPnt3d[0], aPnt3d[1], aPnt3d[2]);
2717 theView->Viewer()->ShowGridEcho (theView, Graphic3d_Vertex (aPnt3d[0], aPnt3d[1], aPnt3d[2]));
2718 theView->InvalidateImmediate();
2722 theView->Viewer()->HideGridEcho (theView);
2723 theView->InvalidateImmediate();
2727 if (aLastPicked != aNewPicked
2728 || (!aNewPicked.IsNull() && aNewPicked->IsForcedHilight()))
2730 // dynamic highlight affects all Views
2731 for (V3d_ListOfViewIterator aViewIter (theView->Viewer()->ActiveViewIterator()); aViewIter.More(); aViewIter.Next())
2733 const Handle(V3d_View)& aView = aViewIter.Value();
2734 aView->InvalidateImmediate();
2739 // =======================================================================
2740 // function : handleSelectionPick
2742 // =======================================================================
2743 void AIS_ViewController::handleSelectionPick (const Handle(AIS_InteractiveContext)& theCtx,
2744 const Handle(V3d_View)& theView)
2746 if (myGL.Selection.Tool == AIS_ViewSelectionTool_Picking
2747 && !myGL.Selection.Points.IsEmpty())
2749 for (NCollection_Sequence<Graphic3d_Vec2i>::Iterator aPntIter (myGL.Selection.Points); aPntIter.More(); aPntIter.Next())
2751 const bool hadPrevMoveTo = HasPreviousMoveTo();
2752 contextLazyMoveTo (theCtx, theView, aPntIter.Value());
2755 ResetPreviousMoveTo();
2758 theCtx->SelectDetected (myGL.Selection.IsXOR ? AIS_SelectionScheme_XOR : AIS_SelectionScheme_Replace);
2760 // selection affects all Views
2761 theView->Viewer()->Invalidate();
2763 OnSelectionChanged (theCtx, theView);
2766 myGL.Selection.Points.Clear();
2770 // =======================================================================
2771 // function : handleSelectionPoly
2773 // =======================================================================
2774 void AIS_ViewController::handleSelectionPoly (const Handle(AIS_InteractiveContext)& theCtx,
2775 const Handle(V3d_View)& theView)
2777 // rubber-band & window polygon selection
2778 if (myGL.Selection.Tool == AIS_ViewSelectionTool_RubberBand
2779 || myGL.Selection.Tool == AIS_ViewSelectionTool_Polygon
2780 || myGL.Selection.Tool == AIS_ViewSelectionTool_ZoomWindow)
2782 if (!myGL.Selection.Points.IsEmpty())
2784 myRubberBand->ClearPoints();
2785 myRubberBand->SetToUpdate();
2787 const bool anIsRubber = myGL.Selection.Tool == AIS_ViewSelectionTool_RubberBand
2788 || myGL.Selection.Tool == AIS_ViewSelectionTool_ZoomWindow;
2791 myRubberBand->SetRectangle (myGL.Selection.Points.First().x(), -myGL.Selection.Points.First().y(),
2792 myGL.Selection.Points.Last().x(), -myGL.Selection.Points.Last().y());
2796 Graphic3d_Vec2i aPrev (IntegerLast(), IntegerLast());
2797 for (NCollection_Sequence<Graphic3d_Vec2i>::Iterator aSelIter (myGL.Selection.Points); aSelIter.More(); aSelIter.Next())
2799 Graphic3d_Vec2i aPntNew = Graphic3d_Vec2i (aSelIter.Value().x(), -aSelIter.Value().y());
2800 if (aPntNew != aPrev)
2803 myRubberBand->AddPoint (Graphic3d_Vec2i (aSelIter.Value().x(), -aSelIter.Value().y()));
2808 myRubberBand->SetPolygonClosed (anIsRubber);
2811 theCtx->Display (myRubberBand, 0, -1, false, AIS_DS_Displayed);
2813 catch (const Standard_Failure& theEx)
2815 Message::SendWarning (TCollection_AsciiString ("Internal error while displaying rubber-band: ")
2816 + theEx.DynamicType()->Name() + ", " + theEx.GetMessageString());
2817 myRubberBand->ClearPoints();
2819 if (!theView->Viewer()->ZLayerSettings (myRubberBand->ZLayer()).IsImmediate())
2821 theView->Invalidate();
2825 theView->InvalidateImmediate();
2828 else if (!myRubberBand.IsNull()
2829 && myRubberBand->HasInteractiveContext())
2831 theCtx->Remove (myRubberBand, false);
2832 myRubberBand->ClearPoints();
2836 if (myGL.Selection.ToApplyTool)
2838 myGL.Selection.ToApplyTool = false;
2839 if (theCtx->IsDisplayed (myRubberBand))
2841 theCtx->Remove (myRubberBand, false);
2843 const NCollection_Sequence<Graphic3d_Vec2i>& aPoints = myRubberBand->Points();
2844 if (aPoints.Size() == 4
2845 && aPoints.Value (1).x() == aPoints.Value (2).x()
2846 && aPoints.Value (3).x() == aPoints.Value (4).x()
2847 && aPoints.Value (1).y() == aPoints.Value (4).y()
2848 && aPoints.Value (2).y() == aPoints.Value (3).y())
2850 const Graphic3d_Vec2i aPnt1 (aPoints.Value (1).x(), -aPoints.Value (1).y());
2851 const Graphic3d_Vec2i aPnt2 (aPoints.Value (3).x(), -aPoints.Value (3).y());
2852 if (myGL.Selection.Tool == AIS_ViewSelectionTool_ZoomWindow)
2854 theView->WindowFitAll (aPnt1.x(), aPnt1.y(), aPnt2.x(), aPnt2.y());
2855 theView->Invalidate();
2859 theCtx->MainSelector()->AllowOverlapDetection (aPnt1.y() != Min (aPnt1.y(), aPnt2.y()));
2860 theCtx->SelectRectangle (Graphic3d_Vec2i (Min (aPnt1.x(), aPnt2.x()), Min (aPnt1.y(), aPnt2.y())),
2861 Graphic3d_Vec2i (Max (aPnt1.x(), aPnt2.x()), Max (aPnt1.y(), aPnt2.y())),
2863 myGL.Selection.IsXOR ? AIS_SelectionScheme_XOR : AIS_SelectionScheme_Replace);
2864 theCtx->MainSelector()->AllowOverlapDetection (false);
2867 else if (aPoints.Length() >= 3)
2869 TColgp_Array1OfPnt2d aPolyline (1, aPoints.Length());
2870 TColgp_Array1OfPnt2d::Iterator aPolyIter (aPolyline);
2871 for (NCollection_Sequence<Graphic3d_Vec2i>::Iterator aSelIter (aPoints);
2872 aSelIter.More(); aSelIter.Next(), aPolyIter.Next())
2874 const Graphic3d_Vec2i& aNewPnt = aSelIter.Value();
2875 aPolyIter.ChangeValue() = gp_Pnt2d (aNewPnt.x(), -aNewPnt.y());
2878 theCtx->SelectPolygon (aPolyline, theView,
2879 myGL.Selection.IsXOR ? AIS_SelectionScheme_XOR : AIS_SelectionScheme_Replace);
2880 theCtx->MainSelector()->AllowOverlapDetection (false);
2884 myRubberBand->ClearPoints();
2885 if (myGL.Selection.Tool != AIS_ViewSelectionTool_ZoomWindow)
2887 // selection affects all Views
2888 theView->Viewer()->Invalidate();
2889 OnSelectionChanged (theCtx, theView);
2895 // =======================================================================
2896 // function : handleDynamicHighlight
2898 // =======================================================================
2899 void AIS_ViewController::handleDynamicHighlight (const Handle(AIS_InteractiveContext)& theCtx,
2900 const Handle(V3d_View)& theView)
2902 if ((myGL.MoveTo.ToHilight || myGL.Dragging.ToStart)
2903 && myNavigationMode != AIS_NavigationMode_FirstPersonWalk)
2905 const Graphic3d_Vec2i& aMoveToPnt = myGL.MoveTo.ToHilight ? myGL.MoveTo.Point : myGL.Dragging.PointStart;
2906 if (myGL.Dragging.ToStart && (!myGL.MoveTo.ToHilight || !myToAllowHighlight)
2907 && !HasPreviousMoveTo())
2909 contextLazyMoveTo (theCtx, theView, aMoveToPnt);
2910 ResetPreviousMoveTo();
2911 OnObjectDragged (theCtx, theView, AIS_DragAction_Start);
2912 theCtx->ClearDetected();
2914 else if (myToAllowHighlight)
2916 if (myPrevMoveTo != aMoveToPnt
2917 || (!theView->View()->IsActiveXR()
2918 && (myGL.OrbitRotation.ToRotate
2919 || myGL.ViewRotation.ToRotate
2920 || theView->IsInvalidated())))
2922 ResetPreviousMoveTo();
2923 contextLazyMoveTo (theCtx, theView, aMoveToPnt);
2925 if (myGL.Dragging.ToStart)
2927 OnObjectDragged (theCtx, theView, AIS_DragAction_Start);
2931 myGL.MoveTo.ToHilight = false;
2934 if (!myDragObject.IsNull())
2936 if (myGL.Dragging.ToAbort)
2938 OnObjectDragged (theCtx, theView, AIS_DragAction_Abort);
2939 myGL.OrbitRotation.ToRotate = false;
2940 myGL.ViewRotation .ToRotate = false;
2942 else if (myGL.Dragging.ToStop)
2944 OnObjectDragged (theCtx, theView, AIS_DragAction_Stop);
2945 myGL.OrbitRotation.ToRotate = false;
2946 myGL.ViewRotation .ToRotate = false;
2948 else if (myGL.OrbitRotation.ToRotate
2949 || myGL.ViewRotation.ToRotate)
2951 OnObjectDragged (theCtx, theView, AIS_DragAction_Update);
2952 myGL.OrbitRotation.ToRotate = false;
2953 myGL.ViewRotation .ToRotate = false;
2958 // =======================================================================
2959 // function : handleMoveTo
2961 // =======================================================================
2962 void AIS_ViewController::handleMoveTo (const Handle(AIS_InteractiveContext)& theCtx,
2963 const Handle(V3d_View)& theView)
2965 handleSelectionPick (theCtx, theView);
2966 handleDynamicHighlight(theCtx, theView);
2967 handleSelectionPoly (theCtx, theView);
2970 // =======================================================================
2971 // function : handleViewRedraw
2973 // =======================================================================
2974 void AIS_ViewController::handleViewRedraw (const Handle(AIS_InteractiveContext)& ,
2975 const Handle(V3d_View)& theView)
2977 // manage animation state
2978 if (!myViewAnimation.IsNull()
2979 && !myViewAnimation->IsStopped())
2981 myViewAnimation->UpdateTimer();
2982 ResetPreviousMoveTo();
2986 if (theView->View()->IsActiveXR())
2988 // VR requires continuous rendering
2989 myToAskNextFrame = true;
2992 for (V3d_ListOfViewIterator aViewIter (theView->Viewer()->ActiveViewIterator()); aViewIter.More(); aViewIter.Next())
2994 const Handle(V3d_View)& aView = aViewIter.Value();
2995 if (aView->IsInvalidated()
2996 || (myToAskNextFrame && aView == theView))
2998 if (aView->ComputedMode())
3007 else if (aView->IsInvalidatedImmediate())
3009 aView->RedrawImmediate();
3013 if (myToAskNextFrame)
3016 theView->Window()->InvalidateContent (Handle(Aspect_DisplayConnection)());
3020 // =======================================================================
3021 // function : handleXRMoveTo
3023 // =======================================================================
3024 Standard_Integer AIS_ViewController::handleXRMoveTo (const Handle(AIS_InteractiveContext)& theCtx,
3025 const Handle(V3d_View)& theView,
3026 const gp_Trsf& thePose,
3027 const Standard_Boolean theToHighlight)
3029 //ResetPreviousMoveTo();
3030 Standard_Integer aPickResult = 0;
3032 Handle(Graphic3d_Camera) aCamBack = theView->Camera();
3033 myXRCameraTmp->Copy (aCamBack);
3034 theView->View()->ComputeXRPosedCameraFromBase (*myXRCameraTmp, thePose);
3035 theView->SetCamera (myXRCameraTmp);
3036 Graphic3d_Vec2i aPickPixel;
3037 theView->Window()->Size (aPickPixel.x(), aPickPixel.y());
3039 const Standard_Integer aSelTolerBack = theCtx->MainSelector()->CustomPixelTolerance();
3040 theCtx->MainSelector()->SetPixelTolerance (1);
3041 theView->AutoZFit();
3044 theCtx->MoveTo (aPickPixel.x(), aPickPixel.y(), theView, false);
3045 if (!theCtx->DetectedOwner().IsNull())
3047 // ignore 2D objects
3048 for (aPickResult = 1; !theCtx->DetectedOwner()->Selectable()->TransformPersistence().IsNull(); ++aPickResult)
3050 if (theCtx->HilightNextDetected (theView, false) <= 1)
3052 theCtx->ClearDetected();
3061 theCtx->MainSelector()->Pick (aPickPixel.x(), aPickPixel.y(), theView);
3062 for (Standard_Integer aPickIter = 1; aPickIter <= theCtx->MainSelector()->NbPicked(); ++aPickIter)
3064 const SelectMgr_SortCriterion& aPickedData = theCtx->MainSelector()->PickedData (aPickIter);
3065 if (!aPickedData.Entity->OwnerId()->Selectable()->TransformPersistence().IsNull())
3071 aPickResult = aPickIter;
3075 theCtx->MainSelector()->SetPixelTolerance (aSelTolerBack);
3076 theView->SetCamera (aCamBack);
3080 // =======================================================================
3081 // function : handleXRHighlight
3083 // =======================================================================
3084 void AIS_ViewController::handleXRHighlight (const Handle(AIS_InteractiveContext)& theCtx,
3085 const Handle(V3d_View)& theView)
3087 if (myXRLastPickingHand != Aspect_XRTrackedDeviceRole_LeftHand
3088 && myXRLastPickingHand != Aspect_XRTrackedDeviceRole_RightHand)
3093 const Standard_Integer aDeviceId = theView->View()->XRSession()->NamedTrackedDevice (myXRLastPickingHand);
3094 if (aDeviceId == -1)
3099 const Aspect_TrackedDevicePose& aPose = theView->View()->XRSession()->TrackedPoses()[aDeviceId];
3100 if (!aPose.IsValidPose)
3105 Handle(SelectMgr_EntityOwner) aDetOld = theCtx->DetectedOwner();
3106 handleXRMoveTo (theCtx, theView, aPose.Orientation, true);
3107 if (!theCtx->DetectedOwner().IsNull()
3108 && theCtx->DetectedOwner() != aDetOld)
3110 if (const Handle(Aspect_XRAction)& aHaptic = theView->View()->XRSession()->GenericAction (myXRLastPickingHand, Aspect_XRGenericAction_OutputHaptic))
3112 theView->View()->XRSession()->TriggerHapticVibrationAction (aHaptic, myXRPickingHaptic);
3116 Standard_Real& aPickDepth = myXRLastPickingHand == Aspect_XRTrackedDeviceRole_LeftHand ? myXRLastPickDepthLeft : myXRLastPickDepthRight;
3117 aPickDepth = Precision::Infinite();
3118 if (theCtx->MainSelector()->NbPicked() > 0)
3120 const gp_Trsf aHandBase = theView->View()->PoseXRToWorld (aPose.Orientation);
3121 const SelectMgr_SortCriterion& aPicked = theCtx->MainSelector()->PickedData (1);
3122 aPickDepth = aPicked.Point.Distance (aHandBase.TranslationPart());
3126 // =======================================================================
3127 // function : handleXRPresentations
3129 // =======================================================================
3130 void AIS_ViewController::handleXRPresentations (const Handle(AIS_InteractiveContext)& theCtx,
3131 const Handle(V3d_View)& theView)
3133 if (!theView->View()->IsActiveXR()
3134 || (!myToDisplayXRAuxDevices
3135 && !myToDisplayXRHands))
3137 for (NCollection_Array1<Handle(AIS_XRTrackedDevice)>::Iterator aPrsIter (myXRPrsDevices); aPrsIter.More(); aPrsIter.Next())
3139 if (!aPrsIter.Value().IsNull()
3140 && aPrsIter.Value()->HasInteractiveContext())
3142 theCtx->Remove (aPrsIter.Value(), false);
3144 aPrsIter.ChangeValue().Nullify();
3149 if (myXRPrsDevices.Length() != theView->View()->XRSession()->TrackedPoses().Length())
3151 for (NCollection_Array1<Handle(AIS_XRTrackedDevice)>::Iterator aPrsIter (myXRPrsDevices); aPrsIter.More(); aPrsIter.Next())
3153 if (!aPrsIter.Value().IsNull())
3155 theCtx->Remove (aPrsIter.Value(), false);
3158 myXRPrsDevices.Resize (theView->View()->XRSession()->TrackedPoses().Lower(), theView->View()->XRSession()->TrackedPoses().Upper(), false);
3161 const Standard_Integer aHeadDevice = theView->View()->XRSession()->NamedTrackedDevice (Aspect_XRTrackedDeviceRole_Head);
3162 const Standard_Integer aLeftDevice = theView->View()->XRSession()->NamedTrackedDevice (Aspect_XRTrackedDeviceRole_LeftHand);
3163 const Standard_Integer aRightDevice = theView->View()->XRSession()->NamedTrackedDevice (Aspect_XRTrackedDeviceRole_RightHand);
3164 for (Standard_Integer aDeviceIter = theView->View()->XRSession()->TrackedPoses().Lower(); aDeviceIter <= theView->View()->XRSession()->TrackedPoses().Upper(); ++aDeviceIter)
3166 const Aspect_TrackedDevicePose& aPose = theView->View()->XRSession()->TrackedPoses()[aDeviceIter];
3167 Handle(AIS_XRTrackedDevice)& aPosePrs = myXRPrsDevices[aDeviceIter];
3168 if (!aPose.IsValidPose)
3173 const bool isHand = aDeviceIter == aLeftDevice
3174 || aDeviceIter == aRightDevice;
3175 if ((!myToDisplayXRHands && isHand)
3176 || (!myToDisplayXRAuxDevices && !isHand))
3178 if (!aPosePrs.IsNull()
3179 && aPosePrs->HasInteractiveContext())
3181 theCtx->Remove (aPosePrs, false);
3186 Aspect_XRTrackedDeviceRole aRole = Aspect_XRTrackedDeviceRole_Other;
3187 if (aDeviceIter == aLeftDevice)
3189 aRole = Aspect_XRTrackedDeviceRole_LeftHand;
3191 else if (aDeviceIter == aRightDevice)
3193 aRole = Aspect_XRTrackedDeviceRole_RightHand;
3196 if (!aPosePrs.IsNull()
3197 && aPosePrs->UnitFactor() != (float )theView->View()->UnitFactor())
3199 theCtx->Remove (aPosePrs, false);
3203 if (aPosePrs.IsNull())
3205 Handle(Image_Texture) aTexture;
3206 Handle(Graphic3d_ArrayOfTriangles) aTris;
3207 if (aDeviceIter != aHeadDevice)
3209 aTris = theView->View()->XRSession()->LoadRenderModel (aDeviceIter, aTexture);
3211 if (!aTris.IsNull())
3213 aPosePrs = new AIS_XRTrackedDevice (aTris, aTexture);
3217 aPosePrs = new AIS_XRTrackedDevice();
3219 aPosePrs->SetUnitFactor ((float )theView->View()->UnitFactor());
3220 aPosePrs->SetMutable (true);
3221 aPosePrs->SetInfiniteState (true);
3223 aPosePrs->SetRole (aRole);
3225 if (!aPosePrs->HasInteractiveContext())
3227 theCtx->Display (aPosePrs, 0, -1, false);
3230 gp_Trsf aPoseLocal = aPose.Orientation;
3231 if (aDeviceIter == aHeadDevice)
3233 // show headset position on floor level
3234 aPoseLocal.SetTranslationPart (gp_Vec (aPoseLocal.TranslationPart().X(), 0.0, aPoseLocal.TranslationPart().Z()));
3236 const gp_Trsf aPoseWorld = theView->View()->PoseXRToWorld (aPoseLocal);
3237 theCtx->SetLocation (aPosePrs, aPoseWorld);
3239 Standard_Real aLaserLen = 0.0;
3241 && aPosePrs->Role() == myXRLastPickingHand)
3243 aLaserLen = myXRLastPickingHand == Aspect_XRTrackedDeviceRole_LeftHand ? myXRLastPickDepthLeft : myXRLastPickDepthRight;
3244 if (Precision::IsInfinite (aLaserLen))
3246 const Bnd_Box aViewBox = theView->View()->MinMaxValues (true);
3247 if (!aViewBox.IsVoid())
3249 aLaserLen = Sqrt (aViewBox.SquareExtent());
3256 aPosePrs->SetLaserColor (myXRLaserPickColor);
3259 && aPosePrs->Role() == myXRLastTeleportHand)
3261 aLaserLen = myXRLastTeleportHand == Aspect_XRTrackedDeviceRole_LeftHand ? myXRLastPickDepthLeft : myXRLastPickDepthRight;
3262 if (Precision::IsInfinite (aLaserLen))
3264 const Bnd_Box aViewBox = theView->View()->MinMaxValues (true);
3265 if (!aViewBox.IsVoid())
3267 aLaserLen = Sqrt (aViewBox.SquareExtent());
3274 aPosePrs->SetLaserColor (myXRLaserTeleColor);
3276 aPosePrs->SetLaserLength ((float )aLaserLen);
3280 // =======================================================================
3281 // function : HandleViewEvents
3283 // =======================================================================
3284 void AIS_ViewController::HandleViewEvents (const Handle(AIS_InteractiveContext)& theCtx,
3285 const Handle(V3d_View)& theView)
3287 const bool wasImmediateUpdate = theView->SetImmediateUpdate (false);
3289 handleViewOrientationKeys (theCtx, theView);
3290 const AIS_WalkDelta aWalk = handleNavigationKeys (theCtx, theView);
3291 handleXRInput (theCtx, theView, aWalk);
3292 if (theView->View()->IsActiveXR())
3294 theView->View()->SetupXRPosedCamera();
3296 handleMoveTo (theCtx, theView);
3297 handleCameraActions (theCtx, theView, aWalk);
3298 theView->View()->SynchronizeXRPosedToBaseCamera(); // handleCameraActions() may modify posed camera position - copy this modifications also to the base camera
3299 handleXRPresentations (theCtx, theView);
3301 handleViewRedraw (theCtx, theView);
3302 theView->View()->UnsetXRPosedCamera();
3304 theView->SetImmediateUpdate (wasImmediateUpdate);
3306 // make sure to not process the same events twice
3308 myToAskNextFrame = false;