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