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