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