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