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