0030507: Visualization - introduce AIS_ViewController
[occt.git] / src / AIS / AIS_ViewController.cxx
CommitLineData
49582f9d 1// Copyright (c) 2016-2019 OPEN CASCADE SAS
2//
3// This file is part of Open CASCADE Technology software library.
4//
5// This library is free software; you can redistribute it and/or modify it under
6// the terms of the GNU Lesser General Public License version 2.1 as published
7// by the Free Software Foundation, with special exception defined in the file
8// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9// distribution for complete text of the license and disclaimer of any warranty.
10//
11// Alternatively, this file may be used under the terms of Open CASCADE
12// commercial license or contractual agreement.
13
14#include "AIS_ViewController.hxx"
15
16#include <AIS_InteractiveContext.hxx>
17#include <AIS_Manipulator.hxx>
18#include <AIS_Point.hxx>
19#include <AIS_RubberBand.hxx>
20#include <Aspect_Grid.hxx>
21#include <Geom_CartesianPoint.hxx>
22#include <Message.hxx>
23#include <Message_Messenger.hxx>
24#include <gp_Quaternion.hxx>
25#include <V3d_View.hxx>
26
27// =======================================================================
28// function : AIS_ViewController
29// purpose :
30// =======================================================================
31AIS_ViewController::AIS_ViewController()
32: myLastEventsTime (0.0),
33 myToAskNextFrame (false),
34 myMinCamDistance (1.0),
35 myRotationMode (AIS_RotationMode_BndBoxActive),
36 myNavigationMode (AIS_NavigationMode_Orbit),
37 myMouseAccel (1.0f),
38 myOrbitAccel (1.0f),
39 myToShowPanAnchorPoint (true),
40 myToShowRotateCenter (true),
41 myToLockOrbitZUp (false),
42 myToInvertPitch (false),
43 myToAllowTouchZRotation(false),
44 myToAllowRotation (true),
45 myToAllowPanning (true),
46 myToAllowZooming (true),
47 myToAllowZFocus (true),
48 myToAllowHighlight (true),
49 myToAllowDragging (true),
50 //
51 myWalkSpeedAbsolute (1.5f),
52 myWalkSpeedRelative (0.1f),
53 myThrustSpeed (0.0f),
54 myHasThrust (false),
55 //
56 myPrevMoveTo (-1, -1),
57 myHasHlrOnBeforeRotation (false),
58 //
59 myMouseClickThreshold (3.0),
60 myMouseDoubleClickInt (0.4),
61 myScrollZoomRatio (15.0f),
62 myMouseActiveGesture (AIS_MouseGesture_NONE),
63 myMouseActiveIdleRotation (false),
64 myMouseClickCounter (0),
65 myMousePressed (Aspect_VKeyMouse_NONE),
66 myMouseModifiers (Aspect_VKeyFlags_NONE),
67 myMouseSingleButton (-1),
68 //
69 myTouchToleranceScale (1.0f),
70 myTouchRotationThresholdPx (6.0f),
71 myTouchZRotationThreshold (float(2.0 * M_PI / 180.0)),
72 myTouchPanThresholdPx (4.0f),
73 myTouchZoomThresholdPx (6.0f),
74 myTouchZoomRatio (0.13f),
75 //
76 myNbTouchesLast (0),
77 myUpdateStartPointPan (true),
78 myUpdateStartPointRot (true),
79 myUpdateStartPointZRot (true),
80 //
81 myPanPnt3d (Precision::Infinite(), 0.0, 0.0)
82{
83 myEventTimer.Start();
84
85 myAnchorPointPrs1 = new AIS_Point (new Geom_CartesianPoint (0.0, 0.0, 0.0));
86 myAnchorPointPrs1->SetZLayer (Graphic3d_ZLayerId_Top);
87 myAnchorPointPrs1->SetMutable (true);
88
89 myAnchorPointPrs2 = new AIS_Point (new Geom_CartesianPoint (0.0, 0.0, 0.0));
90 myAnchorPointPrs2->SetZLayer (Graphic3d_ZLayerId_Topmost);
91 myAnchorPointPrs2->SetMutable (true);
92
93 myRubberBand = new AIS_RubberBand (Quantity_NOC_LIGHTBLUE, Aspect_TOL_SOLID, Quantity_NOC_LIGHTBLUE, 0.4, 1.0);
94 myRubberBand->SetZLayer (Graphic3d_ZLayerId_TopOSD);
95 myRubberBand->SetTransformPersistence (new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_UPPER));
96 myRubberBand->SetDisplayMode (0);
97 myRubberBand->SetMutable (true);
98
99 myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton, AIS_MouseGesture_RotateOrbit);
100 myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_CTRL, AIS_MouseGesture_Zoom);
101 myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_SHIFT, AIS_MouseGesture_Pan);
102 myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_ALT, AIS_MouseGesture_SelectRectangle);
103
104 myMouseGestureMap.Bind (Aspect_VKeyMouse_RightButton, AIS_MouseGesture_Zoom);
105 myMouseGestureMap.Bind (Aspect_VKeyMouse_RightButton | Aspect_VKeyFlags_CTRL, AIS_MouseGesture_RotateOrbit);
106
107 myMouseGestureMap.Bind (Aspect_VKeyMouse_MiddleButton, AIS_MouseGesture_Pan);
108 myMouseGestureMap.Bind (Aspect_VKeyMouse_MiddleButton | Aspect_VKeyFlags_CTRL, AIS_MouseGesture_Pan);
109}
110
111// =======================================================================
112// function : ResetViewInput
113// purpose :
114// =======================================================================
115void AIS_ViewController::ResetViewInput()
116{
117 myKeys.Reset();
118 myMousePressed = Aspect_VKeyMouse_NONE;
119 myMouseModifiers = Aspect_VKeyFlags_NONE;
120 myMouseSingleButton = -1;
121 myUI.Dragging.ToAbort = true;
122 myMouseActiveGesture = AIS_MouseGesture_NONE;
123 myMouseClickTimer.Stop();
124 myMouseClickCounter = 0;
125}
126
127// =======================================================================
128// function : FlushViewEvents
129// purpose :
130// =======================================================================
131void AIS_ViewController::FlushViewEvents (const Handle(AIS_InteractiveContext)& theCtx,
132 const Handle(V3d_View)& theView,
133 Standard_Boolean theToHandle)
134{
135 flushBuffers (theCtx, theView);
136 flushGestures(theCtx, theView);
137 if (theToHandle)
138 {
139 HandleViewEvents (theCtx, theView);
140 }
141}
142
143// =======================================================================
144// function : flushBuffers
145// purpose :
146// =======================================================================
147void AIS_ViewController::flushBuffers (const Handle(AIS_InteractiveContext)& ,
148 const Handle(V3d_View)& )
149{
150 myToAskNextFrame = false;
151
152 myGL.IsNewGesture = myUI.IsNewGesture;
153 myUI.IsNewGesture = false;
154
155 myGL.ZoomActions.Clear();
156 myGL.ZoomActions.Append (myUI.ZoomActions);
157 myUI.ZoomActions.Clear();
158
159 myGL.Orientation.ToFitAll = myUI.Orientation.ToFitAll;
160 myUI.Orientation.ToFitAll = false;
161 if (myUI.Orientation.ToSetViewOrient)
162 {
163 myUI.Orientation.ToSetViewOrient = false;
164 myGL.Orientation.ToSetViewOrient = true;
165 myGL.Orientation.ViewOrient = myUI.Orientation.ViewOrient;
166 }
167
168 if (myUI.MoveTo.ToHilight)
169 {
170 myUI.MoveTo.ToHilight = false;
171 myGL.MoveTo.ToHilight = true;
172 myGL.MoveTo.Point = myUI.MoveTo.Point;
173 }
174
175 {
176 myGL.Selection.Tool = myUI.Selection.Tool;
177 myGL.Selection.IsXOR = myUI.Selection.IsXOR;
178 myGL.Selection.Points = myUI.Selection.Points;
179 myUI.Selection.IsXOR = false;
180 if (myUI.Selection.Tool == AIS_ViewSelectionTool_Picking)
181 {
182 myUI.Selection.Points.Clear();
183 }
184 }
185
186 if (myUI.Selection.ToApplyTool)
187 {
188 myGL.Selection.ToApplyTool = true;
189 myUI.Selection.ToApplyTool = false;
190 myUI.Selection.Points.Clear();
191 }
192
193 if (myUI.Panning.ToStart)
194 {
195 myUI.Panning.ToStart = false;
196 myGL.Panning.ToStart = true;
197 myGL.Panning.PointStart = myUI.Panning.PointStart;
198 }
199
200 if (myUI.Panning.ToPan)
201 {
202 myUI.Panning.ToPan = false;
203 myGL.Panning.ToPan = true;
204 myGL.Panning.Delta = myUI.Panning.Delta;
205 }
206
207 if (myUI.Dragging.ToAbort)
208 {
209 myUI.Dragging.ToAbort = false;
210 myGL.Dragging.ToAbort = true;
211 }
212 else if (myUI.Dragging.ToStop)
213 {
214 myUI.Dragging.ToStop = false;
215 myGL.Dragging.ToStop = true;
216 }
217 else if (myUI.Dragging.ToStart)
218 {
219 myUI.Dragging.ToStart = false;
220 myGL.Dragging.ToStart = true;
221 myGL.Dragging.PointStart = myUI.Dragging.PointStart;
222 }
223 myGL.Dragging.PointTo = myUI.Dragging.PointTo;
224
225 if (myUI.OrbitRotation.ToStart)
226 {
227 myUI.OrbitRotation.ToStart = false;
228 myGL.OrbitRotation.ToStart = true;
229 myGL.OrbitRotation.PointStart = myUI.OrbitRotation.PointStart;
230 }
231
232 if (myUI.OrbitRotation.ToRotate)
233 {
234 myUI.OrbitRotation.ToRotate = false;
235 myGL.OrbitRotation.ToRotate = true;
236 myGL.OrbitRotation.PointTo = myUI.OrbitRotation.PointTo;
237 }
238
239 if (myUI.ViewRotation.ToStart)
240 {
241 myUI.ViewRotation.ToStart = false;
242 myGL.ViewRotation.ToStart = true;
243 myGL.ViewRotation.PointStart = myUI.ViewRotation.PointStart;
244 }
245
246 if (myUI.ViewRotation.ToRotate)
247 {
248 myUI.ViewRotation.ToRotate = false;
249 myGL.ViewRotation.ToRotate = true;
250 myGL.ViewRotation.PointTo = myUI.ViewRotation.PointTo;
251 }
252
253 if (myUI.ZRotate.ToRotate)
254 {
255 myGL.ZRotate = myUI.ZRotate;
256 myUI.ZRotate.ToRotate = false;
257 }
258}
259
260// =======================================================================
261// function : flushGestures
262// purpose :
263// =======================================================================
264void AIS_ViewController::flushGestures (const Handle(AIS_InteractiveContext)& ,
265 const Handle(V3d_View)& theView)
266{
267 const Standard_Real aTolScale = myTouchToleranceScale;
268 const Standard_Integer aTouchNb = myTouchPoints.Extent();
269 if (myNbTouchesLast != aTouchNb)
270 {
271 myNbTouchesLast = aTouchNb;
272 myGL.IsNewGesture = true;
273 }
274 if (aTouchNb == 1) // touch
275 {
276 Aspect_Touch& aTouch = myTouchPoints.ChangeFromIndex (1);
277 if (myUpdateStartPointRot)
278 {
279 // skip rotation if have active dragged object
280 if (myNavigationMode == AIS_NavigationMode_Orbit)
281 {
282 myGL.OrbitRotation.ToStart = true;
283 myGL.OrbitRotation.PointStart = myStartRotCoord;
284 }
285 else
286 {
287 myGL.ViewRotation.ToStart = true;
288 myGL.ViewRotation.PointStart = myStartRotCoord;
289 }
290
291 myUpdateStartPointRot = false;
292 theView->Invalidate();
293 }
294
295 // rotation
296 const Standard_Real aRotTouchTol = !aTouch.IsPreciseDevice
297 ? aTolScale * myTouchRotationThresholdPx
298 : gp::Resolution();
299 if (Abs (aTouch.Delta().x()) + Abs(aTouch.Delta().y()) > aRotTouchTol)
300 {
301 const Standard_Real aRotAccel = myNavigationMode == AIS_NavigationMode_FirstPersonWalk ? myMouseAccel : myOrbitAccel;
302 if (myNavigationMode == AIS_NavigationMode_Orbit)
303 {
304 const Graphic3d_Vec2d aRotDelta = aTouch.To - myGL.OrbitRotation.PointStart;
305 myGL.OrbitRotation.ToRotate = true;
306 myGL.OrbitRotation.PointTo = myGL.OrbitRotation.PointStart + aRotDelta * aRotAccel;
307 myGL.Dragging.PointTo.SetValues ((int )aTouch.To.x(), (int )aTouch.To.y());
308 }
309 else
310 {
311 const Graphic3d_Vec2d aRotDelta = aTouch.To - myGL.ViewRotation.PointStart;
312 myGL.ViewRotation.ToRotate = true;
313 myGL.ViewRotation.PointTo = myGL.ViewRotation.PointStart + aRotDelta * aRotAccel;
314 myGL.Dragging.PointTo.SetValues ((int )aTouch.To.x(), (int )aTouch.To.y());
315 }
316
317 aTouch.From = aTouch.To;
318 }
319 }
320 else if (aTouchNb == 2) // pinch
321 {
322 Aspect_Touch& aFirstTouch = myTouchPoints.ChangeFromIndex (1);
323 Aspect_Touch& aLastTouch = myTouchPoints.ChangeFromIndex (2);
324 const Graphic3d_Vec2d aFrom[2] = { aFirstTouch.From, aLastTouch.From };
325 const Graphic3d_Vec2d aTo[2] = { aFirstTouch.To, aLastTouch.To };
326
327 Graphic3d_Vec2d aPinchCenterStart ((aFrom[0].x() + aFrom[1].x()) / 2.0,
328 (aFrom[0].y() + aFrom[1].y()) / 2.0);
329
330 Standard_Real aPinchCenterXEnd = (aTo[0].x() + aTo[1].x()) / 2.0;
331 Standard_Real aPinchCenterYEnd = (aTo[0].y() + aTo[1].y()) / 2.0;
332
333 Standard_Real aPinchCenterXDev = aPinchCenterXEnd - aPinchCenterStart.x();
334 Standard_Real aPinchCenterYDev = aPinchCenterYEnd - aPinchCenterStart.y();
335
336 Standard_Real aStartSize = (aFrom[0] - aFrom[1]).Modulus();
337 Standard_Real anEndSize = ( aTo[0] - aTo[1]).Modulus();
338
339 Standard_Real aDeltaSize = anEndSize - aStartSize;
340
341 bool anIsClearDev = false;
342
343 if (myToAllowTouchZRotation)
344 {
345 Standard_Real A1 = aFrom[0].y() - aFrom[1].y();
346 Standard_Real B1 = aFrom[1].x() - aFrom[0].x();
347
348 Standard_Real A2 = aTo[0].y() - aTo[1].y();
349 Standard_Real B2 = aTo[1].x() - aTo[0].x();
350
351 Standard_Real aRotAngle = 0.0;
352
353 Standard_Real aDenomenator = A1*A2 + B1*B2;
354 if (aDenomenator <= Precision::Confusion())
355 {
356 aRotAngle = 0.0;
357 }
358 else
359 {
360 Standard_Real aNumerator = A1*B2 - A2*B1;
361 aRotAngle = ATan (aNumerator / aDenomenator);
362 }
363
364 if (Abs(aRotAngle) > Standard_Real(myTouchZRotationThreshold))
365 {
366 myGL.ZRotate.ToRotate = true;
367 myGL.ZRotate.Angle = aRotAngle;
368 anIsClearDev = true;
369 }
370 }
371
372 if (Abs(aDeltaSize) > aTolScale * myTouchZoomThresholdPx)
373 {
374 // zoom
375 aDeltaSize *= Standard_Real(myTouchZoomRatio);
376 Aspect_ScrollDelta aParams (Graphic3d_Vec2i (aPinchCenterStart), aDeltaSize);
377 myGL.ZoomActions.Append (aParams);
378 anIsClearDev = true;
379 }
380
381 const Standard_Real aPanTouchTol = !aFirstTouch.IsPreciseDevice
382 ? aTolScale * myTouchPanThresholdPx
383 : gp::Resolution();
384 if (Abs(aPinchCenterXDev) + Abs(aPinchCenterYDev) > aPanTouchTol)
385 {
386 // pan
387 if (myUpdateStartPointPan)
388 {
389 myGL.Panning.ToStart = true;
390 myGL.Panning.PointStart = Graphic3d_Vec2i (myStartPanCoord);
391 myUpdateStartPointPan = false;
392 theView->Invalidate();
393 }
394
395 myGL.Panning.ToPan = true;
396 myGL.Panning.Delta.x() = int( aPinchCenterXDev);
397 myGL.Panning.Delta.y() = int(-aPinchCenterYDev);
398 anIsClearDev = true;
399 }
400
401 if (anIsClearDev)
402 {
403 aFirstTouch.From = aFirstTouch.To;
404 aLastTouch .From = aLastTouch.To;
405 }
406 }
407}
408
409// =======================================================================
410// function : UpdateViewOrientation
411// purpose :
412// =======================================================================
413void AIS_ViewController::UpdateViewOrientation (V3d_TypeOfOrientation theOrientation,
414 bool theToFitAll)
415{
416 myUI.Orientation.ToFitAll = theToFitAll;
417 myUI.Orientation.ToSetViewOrient = true;
418 myUI.Orientation.ViewOrient = theOrientation;
419}
420
421// =======================================================================
422// function : SelectInViewer
423// purpose :
424// =======================================================================
425void AIS_ViewController::SelectInViewer (const Graphic3d_Vec2i& thePnt,
426 const bool theIsXOR)
427{
428 if (myUI.Selection.Tool != AIS_ViewSelectionTool_Picking)
429 {
430 myUI.Selection.Tool = AIS_ViewSelectionTool_Picking;
431 myUI.Selection.Points.Clear();
432 }
433
434 myUI.Selection.IsXOR = theIsXOR;
435 myUI.Selection.Points.Append (thePnt);
436}
437
438// =======================================================================
439// function : SelectInViewer
440// purpose :
441// =======================================================================
442void AIS_ViewController::SelectInViewer (const NCollection_Sequence<Graphic3d_Vec2i>& thePnts,
443 const bool theIsXOR)
444{
445 myUI.Selection.IsXOR = theIsXOR;
446 myUI.Selection.Points = thePnts;
447 myUI.Selection.ToApplyTool = true;
448 if (thePnts.Length() == 1)
449 {
450 myUI.Selection.Tool = AIS_ViewSelectionTool_Picking;
451 }
452 else if (thePnts.Length() == 2)
453 {
454 myUI.Selection.Tool = AIS_ViewSelectionTool_RubberBand;
455 }
456 else
457 {
458 myUI.Selection.Tool = AIS_ViewSelectionTool_Polygon;
459 }
460}
461
462// =======================================================================
463// function : UpdateRubberBand
464// purpose :
465// =======================================================================
466void AIS_ViewController::UpdateRubberBand (const Graphic3d_Vec2i& thePntFrom,
467 const Graphic3d_Vec2i& thePntTo,
468 const bool theIsXOR)
469{
470 myUI.Selection.Tool = AIS_ViewSelectionTool_RubberBand;
471 myUI.Selection.IsXOR = theIsXOR;
472 myUI.Selection.Points.Clear();
473 myUI.Selection.Points.Append (thePntFrom);
474 myUI.Selection.Points.Append (thePntTo);
475}
476
477// =======================================================================
478// function : UpdatePolySelection
479// purpose :
480// =======================================================================
481void AIS_ViewController::UpdatePolySelection (const Graphic3d_Vec2i& thePnt,
482 bool theToAppend)
483{
484 if (myUI.Selection.Tool != AIS_ViewSelectionTool_Polygon)
485 {
486 myUI.Selection.Tool = AIS_ViewSelectionTool_Polygon;
487 myUI.Selection.Points.Clear();
488 }
489
490 if (myUI.Selection.Points.IsEmpty())
491 {
492 myUI.Selection.Points.Append (thePnt);
493 }
494 else if (theToAppend
495 && myUI.Selection.Points.Last() != thePnt)
496 {
497 myUI.Selection.Points.Append (thePnt);
498 }
499 else
500 {
501 myUI.Selection.Points.ChangeLast() = thePnt;
502 }
503}
504
505// =======================================================================
506// function : UpdateZoom
507// purpose :
508// =======================================================================
509bool AIS_ViewController::UpdateZoom (const Aspect_ScrollDelta& theDelta)
510{
511 if (!myUI.ZoomActions.IsEmpty())
512 {
513 if (myUI.ZoomActions.ChangeLast().Point == theDelta.Point)
514 {
515 myUI.ZoomActions.ChangeLast().Delta += theDelta.Delta;
516 return false;
517 }
518 }
519
520 myUI.ZoomActions.Append (theDelta);
521 return true;
522}
523
524// =======================================================================
525// function : UpdateZRotation
526// purpose :
527// =======================================================================
528bool AIS_ViewController::UpdateZRotation (double theAngle)
529{
530 if (!ToAllowTouchZRotation())
531 {
532 return false;
533 }
534
535 myUI.ZRotate.Angle = myUI.ZRotate.ToRotate
536 ? myUI.ZRotate.Angle + theAngle
537 : theAngle;
538 if (myUI.ZRotate.ToRotate)
539 {
540 return false;
541 }
542 myUI.ZRotate.ToRotate = true;
543 return true;
544}
545
546// =======================================================================
547// function : UpdateMouseScroll
548// purpose :
549// =======================================================================
550bool AIS_ViewController::UpdateMouseScroll (const Aspect_ScrollDelta& theDelta)
551{
552 Aspect_ScrollDelta aDelta = theDelta;
553 aDelta.Delta *= myScrollZoomRatio;
554 return UpdateZoom (aDelta);
555}
556
557// =======================================================================
558// function : UpdateMouseClick
559// purpose :
560// =======================================================================
561bool AIS_ViewController::UpdateMouseClick (const Graphic3d_Vec2i& thePoint,
562 Aspect_VKeyMouse theButton,
563 Aspect_VKeyFlags theModifiers,
564 bool theIsDoubleClick)
565{
566 (void )theIsDoubleClick;
567 if (theButton == Aspect_VKeyMouse_LeftButton)
568 {
569 SelectInViewer (thePoint, (theModifiers & Aspect_VKeyFlags_SHIFT) != 0);
570 return true;
571 }
572 return false;
573}
574
575// =======================================================================
576// function : UpdateMouseButtons
577// purpose :
578// =======================================================================
579bool AIS_ViewController::UpdateMouseButtons (const Graphic3d_Vec2i& thePoint,
580 Aspect_VKeyMouse theButtons,
581 Aspect_VKeyFlags theModifiers,
582 bool theIsEmulated)
583{
584 bool toUpdateView = false;
585 const double aTolClick = (theIsEmulated ? myTouchToleranceScale : 1.0) * myMouseClickThreshold;
586 if (theButtons == Aspect_VKeyMouse_NONE
587 && myMouseSingleButton > 0)
588 {
589 const Graphic3d_Vec2i aDelta = thePoint - myMousePressPoint;
590 if (double(aDelta.cwiseAbs().maxComp()) < aTolClick)
591 {
592 ++myMouseClickCounter;
593 const bool isDoubleClick = myMouseClickCounter == 2
594 && myMouseClickTimer.IsStarted()
595 && myMouseClickTimer.ElapsedTime() <= myMouseDoubleClickInt;
596
597 myMouseClickTimer.Stop();
598 myMouseClickTimer.Reset();
599 myMouseClickTimer.Start();
600 if (isDoubleClick)
601 {
602 myMouseClickCounter = 0;
603 }
604 toUpdateView = UpdateMouseClick (thePoint, (Aspect_VKeyMouse )myMouseSingleButton, theModifiers, isDoubleClick) || toUpdateView;
605 }
606 else
607 {
608 myMouseClickTimer.Stop();
609 myMouseClickCounter = 0;
610 myUI.Dragging.ToStop = true;
611 toUpdateView = true;
612 }
613 myMouseSingleButton = -1;
614 }
615 else if (theButtons == Aspect_VKeyMouse_NONE)
616 {
617 myMouseSingleButton = -1;
618 }
619 else if (myMouseSingleButton == -1)
620 {
621 if ((theButtons & Aspect_VKeyMouse_LeftButton) == Aspect_VKeyMouse_LeftButton)
622 {
623 myMouseSingleButton = Aspect_VKeyMouse_LeftButton;
624 }
625 else if ((theButtons & Aspect_VKeyMouse_RightButton) == Aspect_VKeyMouse_RightButton)
626 {
627 myMouseSingleButton = Aspect_VKeyMouse_RightButton;
628 }
629 else if ((theButtons & Aspect_VKeyMouse_MiddleButton) == Aspect_VKeyMouse_MiddleButton)
630 {
631 myMouseSingleButton = Aspect_VKeyMouse_MiddleButton;
632 }
633 else
634 {
635 myMouseSingleButton = 0;
636 }
637 if (myMouseSingleButton != 0)
638 {
639 if (myMouseClickCounter == 1)
640 {
641 const Graphic3d_Vec2i aDelta = thePoint - myMousePressPoint;
642 if (double(aDelta.cwiseAbs().maxComp()) >= aTolClick)
643 {
644 myMouseClickTimer.Stop();
645 myMouseClickCounter = 0;
646 }
647 }
648 myMousePressPoint = thePoint;
649 }
650 }
651 else
652 {
653 myMouseSingleButton = 0;
654
655 myUI.Dragging.ToAbort = true;
656 toUpdateView = true;
657 }
658
659 const AIS_MouseGesture aPrevGesture = myMouseActiveGesture;
660 myMouseModifiers = theModifiers;
661 myMousePressed = theButtons;
662 if (theIsEmulated
663 || myNavigationMode != AIS_NavigationMode_FirstPersonWalk)
664 {
665 myMouseActiveIdleRotation = false;
666 myMouseActiveGesture = AIS_MouseGesture_NONE;
667 if (theButtons != 0)
668 {
669 myMousePressPoint = thePoint;
670 myMouseProgressPoint = myMousePressPoint;
671 }
672
673 if (myMouseGestureMap.Find (theButtons | theModifiers, myMouseActiveGesture))
674 {
675 switch (myMouseActiveGesture)
676 {
677 case AIS_MouseGesture_RotateView:
678 case AIS_MouseGesture_RotateOrbit:
679 {
680 if (myToAllowRotation)
681 {
682 myUpdateStartPointRot = true;
683 }
684 else
685 {
686 myMouseActiveGesture = AIS_MouseGesture_NONE;
687 }
688 break;
689 }
690 case AIS_MouseGesture_Pan:
691 {
692 if (myToAllowPanning)
693 {
694 myUpdateStartPointPan = true;
695 }
696 else
697 {
698 myMouseActiveGesture = AIS_MouseGesture_NONE;
699 }
700 break;
701 }
702 case AIS_MouseGesture_Zoom:
703 {
704 if (!myToAllowZooming)
705 {
706 myMouseActiveGesture = AIS_MouseGesture_NONE;
707 }
708 break;
709 }
710 case AIS_MouseGesture_SelectRectangle:
711 {
712 break;
713 }
714 case AIS_MouseGesture_SelectLasso:
715 {
716 UpdatePolySelection (thePoint, true);
717 break;
718 }
719 case AIS_MouseGesture_NONE:
720 {
721 break;
722 }
723 }
724 }
725
726 if (theButtons == Aspect_VKeyMouse_LeftButton
727 && theModifiers == Aspect_VKeyFlags_NONE
728 && myToAllowDragging)
729 {
730 myUI.Dragging.ToStart = true;
731 myUI.Dragging.PointStart = thePoint;
732 }
733 }
734
735 if (aPrevGesture != myMouseActiveGesture)
736 {
737 if (aPrevGesture == AIS_MouseGesture_SelectRectangle
738 || aPrevGesture == AIS_MouseGesture_SelectLasso)
739 {
740 myUI.Selection.ToApplyTool = true;
741 }
742
743 myUI.IsNewGesture = true;
744 toUpdateView = true;
745 }
746 return toUpdateView;
747}
748
749// =======================================================================
750// function : UpdateMousePosition
751// purpose :
752// =======================================================================
753bool AIS_ViewController::UpdateMousePosition (const Graphic3d_Vec2i& thePoint,
754 Aspect_VKeyMouse theButtons,
755 Aspect_VKeyFlags theModifiers,
756 bool theIsEmulated)
757{
758 myMousePositionLast = thePoint;
759 if (myMouseSingleButton > 0)
760 {
761 const double aTolClick = (theIsEmulated ? myTouchToleranceScale : 1.0) * myMouseClickThreshold;
762 const Graphic3d_Vec2i aPressDelta = thePoint - myMousePressPoint;
763 if (double(aPressDelta.cwiseAbs().maxComp()) >= aTolClick)
764 {
765 myMouseClickTimer.Stop();
766 myMouseClickCounter = 0;
767 myMouseSingleButton = -1;
768 }
769 }
770
771 bool toUpdateView = false;
772 Graphic3d_Vec2i aDelta = thePoint - myMouseProgressPoint;
773 if (!theIsEmulated
774 && myNavigationMode == AIS_NavigationMode_FirstPersonWalk)
775 {
776 if (!myMouseActiveIdleRotation
777 || myMouseActiveGesture != AIS_MouseGesture_RotateView)
778 {
779 myMouseActiveIdleRotation = true;
780 myMouseActiveGesture = AIS_MouseGesture_RotateView;
781 myMousePressPoint = thePoint;
782 myMouseProgressPoint = thePoint;
783 myUpdateStartPointRot = false;
784 myUI.ViewRotation.ToStart = true;
785 myUI.ViewRotation.PointStart.SetValues (thePoint.x(), thePoint.y());
786 myUI.ViewRotation.ToRotate = false;
787 aDelta.SetValues (0, 0);
788 }
789 }
790 else
791 {
792 if (myMouseActiveIdleRotation
793 && myMouseActiveGesture == AIS_MouseGesture_RotateView)
794 {
795 myMouseActiveGesture = AIS_MouseGesture_NONE;
796 }
797 myMouseActiveIdleRotation = false;
798 }
799
800 if (myMouseModifiers != theModifiers
801 && UpdateMouseButtons (thePoint, theButtons, theModifiers, theIsEmulated))
802 {
803 toUpdateView = true;
804 }
805
806 switch (myMouseActiveGesture)
807 {
808 case AIS_MouseGesture_SelectRectangle:
809 {
810 UpdateRubberBand (myMousePressPoint, thePoint);
811 toUpdateView = true;
812 break;
813 }
814 case AIS_MouseGesture_SelectLasso:
815 {
816 UpdatePolySelection (thePoint, true);
817 toUpdateView = true;
818 break;
819 }
820 case AIS_MouseGesture_RotateOrbit:
821 case AIS_MouseGesture_RotateView:
822 {
823 if (!myToAllowRotation)
824 {
825 break;
826 }
827 if (myUpdateStartPointRot)
828 {
829 if (myMouseActiveGesture == AIS_MouseGesture_RotateOrbit)
830 {
831 myUI.OrbitRotation.ToStart = true;
832 myUI.OrbitRotation.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y());
833 }
834 else
835 {
836 myUI.ViewRotation.ToStart = true;
837 myUI.ViewRotation.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y());
838 }
839 myUpdateStartPointRot = false;
840 }
841
842 const double aRotTol = theIsEmulated
843 ? double(myTouchToleranceScale) * myTouchRotationThresholdPx
844 : 0.0;
845 if (double (Abs (aDelta.x()) + Abs (aDelta.y())) > aRotTol)
846 {
847 const double aRotAccel = myNavigationMode == AIS_NavigationMode_FirstPersonWalk ? myMouseAccel : myOrbitAccel;
848 const Graphic3d_Vec2i aRotDelta = thePoint - myMousePressPoint;
849 if (myMouseActiveGesture == AIS_MouseGesture_RotateOrbit)
850 {
851 myUI.OrbitRotation.ToRotate = true;
852 myUI.OrbitRotation.PointTo = Graphic3d_Vec2d (myMousePressPoint.x(), myMousePressPoint.y())
853 + Graphic3d_Vec2d (aRotDelta.x(), aRotDelta.y()) * aRotAccel;
854 }
855 else
856 {
857 myUI.ViewRotation.ToRotate = true;
858 myUI.ViewRotation.PointTo = Graphic3d_Vec2d (myMousePressPoint.x(), myMousePressPoint.y())
859 + Graphic3d_Vec2d (aRotDelta.x(), aRotDelta.y()) * aRotAccel;
860 }
861 myUI.Dragging.PointTo = thePoint;
862
863 myMouseProgressPoint = thePoint;
864 toUpdateView = true;
865 }
866 break;
867 }
868 case AIS_MouseGesture_Zoom:
869 {
870 if (!myToAllowZooming)
871 {
872 break;
873 }
874 const double aZoomTol = theIsEmulated
875 ? double(myTouchToleranceScale) * myTouchZoomThresholdPx
876 : 0.0;
877 if (double (Abs (aDelta.x())) > aZoomTol)
878 {
879 if (UpdateZoom (Aspect_ScrollDelta (aDelta.x())))
880 {
881 toUpdateView = true;
882 }
883 myMouseProgressPoint = thePoint;
884 }
885 break;
886 }
887 case AIS_MouseGesture_Pan:
888 {
889 if (!myToAllowPanning)
890 {
891 break;
892 }
893 const double aPanTol = theIsEmulated
894 ? double(myTouchToleranceScale) * myTouchPanThresholdPx
895 : 0.0;
896 if (double (Abs (aDelta.x()) + Abs (aDelta.y())) > aPanTol)
897 {
898 if (myUpdateStartPointPan)
899 {
900 myUI.Panning.ToStart = true;
901 myUI.Panning.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y());
902 myUpdateStartPointPan = false;
903 }
904
905 aDelta.y() = -aDelta.y();
906 myMouseProgressPoint = thePoint;
907 if (myUI.Panning.ToPan)
908 {
909 myUI.Panning.Delta += aDelta;
910 }
911 else
912 {
913 myUI.Panning.ToPan = true;
914 myUI.Panning.Delta = aDelta;
915 }
916 toUpdateView = true;
917 }
918 break;
919 }
920 default:
921 {
922 break;
923 }
924 }
925
926 if (theButtons == Aspect_VKeyMouse_NONE
927 && myNavigationMode != AIS_NavigationMode_FirstPersonWalk
928 && !theIsEmulated
929 && !HasTouchPoints()
930 && myToAllowHighlight)
931 {
932 myUI.MoveTo.ToHilight = true;
933 myUI.MoveTo.Point = thePoint;
934 toUpdateView = true;
935 }
936 return toUpdateView;
937}
938
939// =======================================================================
940// function : AddTouchPoint
941// purpose :
942// =======================================================================
943void AIS_ViewController::AddTouchPoint (Standard_Size theId,
944 const Graphic3d_Vec2d& thePnt,
945 Standard_Boolean theClearBefore)
946{
947 myUI.MoveTo.ToHilight = false;
948 if (theClearBefore)
949 {
950 RemoveTouchPoint ((Standard_Size )-1);
951 }
952
953 myTouchPoints.Add (theId, Aspect_Touch (thePnt, false));
954 if (myTouchPoints.Extent() == 1)
955 {
956 myUpdateStartPointRot = true;
957 myStartRotCoord = thePnt;
958 if (myToAllowDragging)
959 {
960 myUI.Dragging.ToStart = true;
961 myUI.Dragging.PointStart.SetValues ((int )thePnt.x(), (int )thePnt.y());
962 }
963 }
964 else if (myTouchPoints.Extent() == 2)
965 {
966 myUI.Dragging.ToAbort = true;
967
968 myUpdateStartPointPan = true;
969 myStartPanCoord = thePnt;
970 }
971 myUI.IsNewGesture = true;
972}
973
974// =======================================================================
975// function : RemoveTouchPoint
976// purpose :
977// =======================================================================
978bool AIS_ViewController::RemoveTouchPoint (Standard_Size theId,
979 Standard_Boolean theClearSelectPnts)
980{
981 if (theId == (Standard_Size )-1)
982 {
983 myTouchPoints.Clear (false);
984 }
985 else
986 {
987 const Standard_Integer anOldExtent = myTouchPoints.Extent();
988 myTouchPoints.RemoveKey (theId);
989 if (myTouchPoints.Extent() == anOldExtent)
990 {
991 return false;
992 }
993 }
994
995 if (myTouchPoints.Extent() == 1)
996 {
997 // avoid incorrect transition from pinch to one finger
998 Aspect_Touch& aFirstTouch = myTouchPoints.ChangeFromIndex (1);
999 aFirstTouch.To = aFirstTouch.From;
1000
1001 myStartRotCoord = aFirstTouch.To;
1002 myUpdateStartPointRot = true;
1003 }
1004 else if (myTouchPoints.Extent() == 2)
1005 {
1006 myStartPanCoord = myTouchPoints.FindFromIndex (1).To;
1007 myUpdateStartPointPan = true;
1008 }
1009 else if (myTouchPoints.IsEmpty())
1010 {
1011 if (theClearSelectPnts)
1012 {
1013 myUI.Selection.ToApplyTool = true;
1014 }
1015
1016 myUI.Dragging.ToStop = true;
1017 }
1018 myUI.IsNewGesture = true;
1019 return true;
1020}
1021
1022// =======================================================================
1023// function : UpdateTouchPoint
1024// purpose :
1025// =======================================================================
1026void AIS_ViewController::UpdateTouchPoint (Standard_Size theId,
1027 const Graphic3d_Vec2d& thePnt)
1028{
1029 if (Aspect_Touch* aTouch = myTouchPoints.ChangeSeek (theId))
1030 {
1031 aTouch->To = thePnt;
1032 }
1033 else
1034 {
1035 AddTouchPoint (theId, thePnt);
1036 }
1037}
1038
1039// =======================================================================
1040// function : SetNavigationMode
1041// purpose :
1042// =======================================================================
1043void AIS_ViewController::SetNavigationMode (AIS_NavigationMode theMode)
1044{
1045 myNavigationMode = theMode;
1046
1047 // abort rotation
1048 myUI.OrbitRotation.ToStart = false;
1049 myUI.OrbitRotation.ToRotate = false;
1050 myUI.ViewRotation.ToStart = false;
1051 myUI.ViewRotation.ToRotate = false;
1052}
1053
1054// =======================================================================
1055// function : KeyDown
1056// purpose :
1057// =======================================================================
1058void AIS_ViewController::KeyDown (Aspect_VKey theKey,
1059 double theTime,
1060 double thePressure)
1061{
1062 myKeys.KeyDown (theKey, theTime, thePressure);
1063}
1064
1065// =======================================================================
1066// function : KeyUp
1067// purpose :
1068// =======================================================================
1069void AIS_ViewController::KeyUp (Aspect_VKey theKey,
1070 double theTime)
1071{
1072 myKeys.KeyUp (theKey, theTime);
1073}
1074
1075// =======================================================================
1076// function : KeyFromAxis
1077// purpose :
1078// =======================================================================
1079void AIS_ViewController::KeyFromAxis (Aspect_VKey theNegative,
1080 Aspect_VKey thePositive,
1081 double theTime,
1082 double thePressure)
1083{
1084 myKeys.KeyFromAxis (theNegative, thePositive, theTime, thePressure);
1085}
1086
1087// =======================================================================
1088// function : FetchNavigationKeys
1089// purpose :
1090// =======================================================================
1091AIS_WalkDelta AIS_ViewController::FetchNavigationKeys (Standard_Real theCrouchRatio,
1092 Standard_Real theRunRatio)
1093{
1094 AIS_WalkDelta aWalk;
1095
1096 // navigation keys
1097 double aPrevEventTime = 0.0, aNewEventTime = 0.0;
1098 updateEventsTime (aPrevEventTime, aNewEventTime);
1099
1100 double aDuration = 0.0, aPressure = 1.0;
1101 if (Abs (myThrustSpeed) > gp::Resolution())
1102 {
1103 if (myHasThrust)
1104 {
1105 aWalk[AIS_WalkTranslation_Forward].Value = myThrustSpeed * (aNewEventTime - aPrevEventTime);
1106 }
1107 myHasThrust = true;
1108 myToAskNextFrame = true;
1109 }
1110 else
1111 {
1112 myHasThrust = false;
1113 }
1114
1115 aWalk.SetRunning (theRunRatio > 1.0
1116 && myKeys.IsKeyDown (Aspect_VKey_Shift));
1117 if (myKeys.HoldDuration (Aspect_VKey_NavJump, aNewEventTime, aDuration))
1118 {
1119 myKeys.KeyUp (Aspect_VKey_NavJump, aNewEventTime);
1120 aWalk.SetJumping (true);
1121 }
1122 if (!aWalk.IsJumping()
1123 && theCrouchRatio < 1.0
1124 && myKeys.HoldDuration (Aspect_VKey_NavCrouch, aNewEventTime, aDuration))
1125 {
1126 aWalk.SetRunning (false);
1127 aWalk.SetCrouching (true);
1128 }
1129
1130 const double aMaxDuration = aNewEventTime - aPrevEventTime;
1131 const double aRunRatio = aWalk.IsRunning()
1132 ? theRunRatio
1133 : aWalk.IsCrouching()
1134 ? theCrouchRatio
1135 : 1.0;
1136 if (myKeys.HoldDuration (Aspect_VKey_NavForward, aNewEventTime, aDuration, aPressure))
1137 {
1138 double aProgress = Abs (Min (aMaxDuration, aDuration));
1139 aProgress *= aRunRatio;
1140 aWalk[AIS_WalkTranslation_Forward].Value += aProgress;
1141 aWalk[AIS_WalkTranslation_Forward].Pressure = aPressure;
1142 aWalk[AIS_WalkTranslation_Forward].Duration = aDuration;
1143 }
1144 if (myKeys.HoldDuration (Aspect_VKey_NavBackward, aNewEventTime, aDuration, aPressure))
1145 {
1146 double aProgress = Abs (Min (aMaxDuration, aDuration));
1147 aProgress *= aRunRatio;
1148 aWalk[AIS_WalkTranslation_Forward].Value += -aProgress;
1149 aWalk[AIS_WalkTranslation_Forward].Pressure = aPressure;
1150 aWalk[AIS_WalkTranslation_Forward].Duration = aDuration;
1151 }
1152 if (myKeys.HoldDuration (Aspect_VKey_NavSlideLeft, aNewEventTime, aDuration, aPressure))
1153 {
1154 double aProgress = Abs (Min (aMaxDuration, aDuration));
1155 aProgress *= aRunRatio;
1156 aWalk[AIS_WalkTranslation_Side].Value = -aProgress;
1157 aWalk[AIS_WalkTranslation_Side].Pressure = aPressure;
1158 aWalk[AIS_WalkTranslation_Side].Duration = aDuration;
1159 }
1160 if (myKeys.HoldDuration (Aspect_VKey_NavSlideRight, aNewEventTime, aDuration, aPressure))
1161 {
1162 double aProgress = Abs (Min (aMaxDuration, aDuration));
1163 aProgress *= aRunRatio;
1164 aWalk[AIS_WalkTranslation_Side].Value = aProgress;
1165 aWalk[AIS_WalkTranslation_Side].Pressure = aPressure;
1166 aWalk[AIS_WalkTranslation_Side].Duration = aDuration;
1167 }
1168 if (myKeys.HoldDuration (Aspect_VKey_NavLookLeft, aNewEventTime, aDuration, aPressure))
1169 {
1170 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1171 aWalk[AIS_WalkRotation_Yaw].Value = aProgress;
1172 aWalk[AIS_WalkRotation_Yaw].Pressure = aPressure;
1173 aWalk[AIS_WalkRotation_Yaw].Duration = aDuration;
1174 }
1175 if (myKeys.HoldDuration (Aspect_VKey_NavLookRight, aNewEventTime, aDuration, aPressure))
1176 {
1177 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1178 aWalk[AIS_WalkRotation_Yaw].Value = -aProgress;
1179 aWalk[AIS_WalkRotation_Yaw].Pressure = aPressure;
1180 aWalk[AIS_WalkRotation_Yaw].Duration = aDuration;
1181 }
1182 if (myKeys.HoldDuration (Aspect_VKey_NavLookUp, aNewEventTime, aDuration, aPressure))
1183 {
1184 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1185 aWalk[AIS_WalkRotation_Pitch].Value = !myToInvertPitch ? -aProgress : aProgress;
1186 aWalk[AIS_WalkRotation_Pitch].Pressure = aPressure;
1187 aWalk[AIS_WalkRotation_Pitch].Duration = aDuration;
1188 }
1189 if (myKeys.HoldDuration (Aspect_VKey_NavLookDown, aNewEventTime, aDuration, aPressure))
1190 {
1191 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1192 aWalk[AIS_WalkRotation_Pitch].Value = !myToInvertPitch ? aProgress : -aProgress;
1193 aWalk[AIS_WalkRotation_Pitch].Pressure = aPressure;
1194 aWalk[AIS_WalkRotation_Pitch].Duration = aDuration;
1195 }
1196 if (myKeys.HoldDuration (Aspect_VKey_NavRollCCW, aNewEventTime, aDuration, aPressure))
1197 {
1198 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1199 aWalk[AIS_WalkRotation_Roll].Value = -aProgress;
1200 aWalk[AIS_WalkRotation_Roll].Pressure = aPressure;
1201 aWalk[AIS_WalkRotation_Roll].Duration = aDuration;
1202 }
1203 if (myKeys.HoldDuration (Aspect_VKey_NavRollCW, aNewEventTime, aDuration, aPressure))
1204 {
1205 double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1206 aWalk[AIS_WalkRotation_Roll].Value = aProgress;
1207 aWalk[AIS_WalkRotation_Roll].Pressure = aPressure;
1208 aWalk[AIS_WalkRotation_Roll].Duration = aDuration;
1209 }
1210 if (myKeys.HoldDuration (Aspect_VKey_NavSlideUp, aNewEventTime, aDuration, aPressure))
1211 {
1212 double aProgress = Abs (Min (aMaxDuration, aDuration));
1213 aWalk[AIS_WalkTranslation_Up].Value = aProgress;
1214 aWalk[AIS_WalkTranslation_Up].Pressure = aPressure;
1215 aWalk[AIS_WalkTranslation_Up].Duration = aDuration;
1216 }
1217 if (myKeys.HoldDuration (Aspect_VKey_NavSlideDown, aNewEventTime, aDuration, aPressure))
1218 {
1219 double aProgress = Abs (Min (aMaxDuration, aDuration));
1220 aWalk[AIS_WalkTranslation_Up].Value = -aProgress;
1221 aWalk[AIS_WalkTranslation_Up].Pressure = aPressure;
1222 aWalk[AIS_WalkTranslation_Up].Duration = aDuration;
1223 }
1224 return aWalk;
1225}
1226
1227// =======================================================================
1228// function : handlePanning
1229// purpose :
1230// =======================================================================
1231void AIS_ViewController::handlePanning (const Handle(V3d_View)& theView)
1232{
1233 if (!myGL.Panning.ToPan
1234 || !myToAllowPanning)
1235 {
1236 return;
1237 }
1238
1239 const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1240 if (aCam->IsOrthographic()
1241 || !hasPanningAnchorPoint())
1242 {
1243 theView->Pan (myGL.Panning.Delta.x(), myGL.Panning.Delta.y());
1244 theView->Invalidate();
1245 return;
1246 }
1247
1248 Graphic3d_Vec2i aWinSize;
1249 theView->Window()->Size (aWinSize.x(), aWinSize.y());
1250
1251 const gp_Dir& aDir = aCam->Direction();
1252 const gp_Ax3 aCameraCS (aCam->Center(), aDir.Reversed(), aDir ^ aCam->Up());
1253 const gp_XYZ anEyeToPnt = myPanPnt3d.XYZ() - aCam->Eye().XYZ();
1254 const gp_Pnt aViewDims = aCam->ViewDimensions (anEyeToPnt.Dot (aCam->Direction().XYZ())); // view dimensions at 3D point
1255 const Graphic3d_Vec2d aDxy (-aViewDims.X() * myGL.Panning.Delta.x() / double(aWinSize.x()),
1256 -aViewDims.X() * myGL.Panning.Delta.y() / double(aWinSize.x()));
1257
1258 //theView->Translate (aCam, aDxy.x(), aDxy.y());
1259 gp_Trsf aPanTrsf;
1260 const gp_Vec aCameraPan = gp_Vec (aCameraCS.XDirection()) * aDxy.x()
1261 + gp_Vec (aCameraCS.YDirection()) * aDxy.y();
1262 aPanTrsf.SetTranslation (aCameraPan);
1263 aCam->Transform (aPanTrsf);
1264 theView->Invalidate();
1265}
1266
1267// =======================================================================
1268// function : handleZRotate
1269// purpose :
1270// =======================================================================
1271void AIS_ViewController::handleZRotate (const Handle(V3d_View)& theView)
1272{
1273 if (!myGL.ZRotate.ToRotate
1274 || !myToAllowRotation)
1275 {
1276 return;
1277 }
1278
1279 Graphic3d_Vec2i aViewPort;
1280 theView->Window()->Size (aViewPort.x(), aViewPort.y());
1281 Graphic3d_Vec2d aRotPnt (0.99 * aViewPort.x(),
1282 0.5 * aViewPort.y());
1283 theView->StartRotation (int(aRotPnt.x()), int(aRotPnt.y()), 0.4);
1284 aRotPnt.y() += myGL.ZRotate.Angle * aViewPort.y();
1285 theView->Rotation (int(aRotPnt.x()), int(aRotPnt.y()));
1286 theView->Invalidate();
1287}
1288
1289// =======================================================================
1290// function : handleZoom
1291// purpose :
1292// =======================================================================
1293void AIS_ViewController::handleZoom (const Handle(V3d_View)& theView,
1294 const Aspect_ScrollDelta& theParams,
1295 const gp_Pnt* thePnt)
1296{
1297 if (!myToAllowZooming)
1298 {
1299 return;
1300 }
1301
1302 const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1303 if (thePnt != NULL)
1304 {
1305 const double aViewDist = Max (myMinCamDistance, (thePnt->XYZ() - aCam->Eye().XYZ()).Modulus());
1306 aCam->SetCenter (aCam->Eye().XYZ() + aCam->Direction().XYZ() * aViewDist);
1307 }
1308
1309 if (!theParams.HasPoint())
1310 {
1311 Standard_Real aCoeff = Abs(theParams.Delta) / 100.0 + 1.0;
1312 aCoeff = theParams.Delta > 0.0 ? aCoeff : 1.0 / aCoeff;
1313 theView->SetZoom (aCoeff, true);
1314 theView->Invalidate();
1315 return;
1316 }
1317
1318 // integer delta is too rough for small smooth increments
1319 //theView->StartZoomAtPoint (theParams.Point.x(), theParams.Point.y());
1320 //theView->ZoomAtPoint (0, 0, (int )theParams.Delta, (int )theParams.Delta);
1321
1322 double aDZoom = Abs (theParams.Delta) / 100.0 + 1.0;
1323 aDZoom = (theParams.Delta > 0.0) ? aDZoom : 1.0 / aDZoom;
1324 if (aDZoom <= 0.0)
1325 {
1326 return;
1327 }
1328
1329 const Graphic3d_Vec2d aViewDims (aCam->ViewDimensions().X(), aCam->ViewDimensions().Y());
1330
1331 // ensure that zoom will not be too small or too big
1332 double aCoef = aDZoom;
1333 if (aViewDims.x() < aCoef * Precision::Confusion())
1334 {
1335 aCoef = aViewDims.x() / Precision::Confusion();
1336 }
1337 else if (aViewDims.x() > aCoef * 1e12)
1338 {
1339 aCoef = aViewDims.x() / 1e12;
1340 }
1341 if (aViewDims.y() < aCoef * Precision::Confusion())
1342 {
1343 aCoef = aViewDims.y() / Precision::Confusion();
1344 }
1345 else if (aViewDims.y() > aCoef * 1e12)
1346 {
1347 aCoef = aViewDims.y() / 1e12;
1348 }
1349
1350 Graphic3d_Vec2d aZoomAtPointXYv (0.0, 0.0);
1351 theView->Convert (theParams.Point.x(), theParams.Point.y(),
1352 aZoomAtPointXYv.x(), aZoomAtPointXYv.y());
1353 Graphic3d_Vec2d aDxy = aZoomAtPointXYv / aCoef;
1354 aCam->SetScale (aCam->Scale() / aCoef);
1355
1356 const gp_Dir& aDir = aCam->Direction();
1357 const gp_Ax3 aCameraCS (aCam->Center(), aDir.Reversed(), aDir ^ aCam->Up());
1358
1359 // pan back to the point
1360 aDxy = aZoomAtPointXYv - aDxy;
1361 if (thePnt != NULL)
1362 {
1363 // zoom at 3D point with perspective projection
1364 const gp_XYZ anEyeToPnt = thePnt->XYZ() - aCam->Eye().XYZ();
1365 aDxy.SetValues (anEyeToPnt.Dot (aCameraCS.XDirection().XYZ()),
1366 anEyeToPnt.Dot (aCameraCS.YDirection().XYZ()));
1367
1368 // view dimensions at 3D point
1369 const gp_Pnt aViewDims1 = aCam->ViewDimensions (anEyeToPnt.Dot (aCam->Direction().XYZ()));
1370
1371 Graphic3d_Vec2i aWinSize;
1372 theView->Window()->Size (aWinSize.x(), aWinSize.y());
1373 const Graphic3d_Vec2d aPanFromCenterPx (double(theParams.Point.x()) - 0.5 * double(aWinSize.x()),
1374 double(theParams.Point.y()) - 0.5 * double(aWinSize.y()));
1375 aDxy.x() += -aViewDims1.X() * aPanFromCenterPx.x() / double(aWinSize.x());
1376 aDxy.y() += aViewDims1.X() * aPanFromCenterPx.y() / double(aWinSize.x());
1377 }
1378
1379 //theView->Translate (aCam, aDxy.x(), aDxy.y());
1380 gp_Trsf aPanTrsf;
1381 const gp_Vec aCameraPan = gp_Vec (aCameraCS.XDirection()) * aDxy.x()
1382 + gp_Vec (aCameraCS.YDirection()) * aDxy.y();
1383 aPanTrsf.SetTranslation (aCameraPan);
1384 aCam->Transform (aPanTrsf);
1385 theView->Invalidate();
1386}
1387
1388// =======================================================================
1389// function : handleZFocusScroll
1390// purpose :
1391// =======================================================================
1392void AIS_ViewController::handleZFocusScroll (const Handle(V3d_View)& theView,
1393 const Aspect_ScrollDelta& theParams)
1394{
1395 if (!myToAllowZFocus
1396 || !theView->Camera()->IsStereo())
1397 {
1398 return;
1399 }
1400
1401 Standard_Real aFocus = theView->Camera()->ZFocus() + (theParams.Delta > 0.0 ? 0.05 : -0.05);
1402 if (aFocus > 0.2
1403 && aFocus < 2.0)
1404 {
1405 theView->Camera()->SetZFocus (theView->Camera()->ZFocusType(), aFocus);
1406 theView->Redraw();
1407 }
1408}
1409
1410// =======================================================================
1411// function : handleOrbitRotation
1412// purpose :
1413// =======================================================================
1414void AIS_ViewController::handleOrbitRotation (const Handle(V3d_View)& theView,
1415 const gp_Pnt& thePnt,
1416 bool theToLockZUp)
1417{
1418 if (!myToAllowRotation)
1419 {
1420 return;
1421 }
1422
1423 const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1424 if (myGL.OrbitRotation.ToStart)
1425 {
1426 // default alternatives
1427 //if (myRotationMode == AIS_RotationMode_BndBoxActive) theView->StartRotation (myGL.RotateAtPoint.x(), myGL.RotateAtPoint.y());
1428 //theView->Rotate (0.0, 0.0, 0.0, thePnt.X(), thePnt.Y(), thePnt.Z(), true);
1429
1430 myRotatePnt3d = thePnt;
1431 myCamStartOpUp = aCam->Up();
1432 myCamStartOpEye = aCam->Eye();
1433 myCamStartOpCenter = aCam->Center();
1434
1435 gp_Trsf aTrsf;
1436 aTrsf.SetTransformation (gp_Ax3 (myRotatePnt3d, aCam->OrthogonalizedUp(), aCam->Direction()),
1437 gp_Ax3 (myRotatePnt3d, gp::DZ(), gp::DX()));
1438 const gp_Quaternion aRot = aTrsf.GetRotation();
1439 aRot.GetEulerAngles (gp_YawPitchRoll, myRotateStartYawPitchRoll[0], myRotateStartYawPitchRoll[1], myRotateStartYawPitchRoll[2]);
1440
1441 aTrsf.Invert();
1442 myCamStartOpToEye = gp_Vec (myRotatePnt3d, aCam->Eye()).Transformed (aTrsf);
1443 myCamStartOpToCenter = gp_Vec (myRotatePnt3d, aCam->Center()).Transformed (aTrsf);
1444
1445 theView->Invalidate();
1446 }
1447
1448 if (!myGL.OrbitRotation.ToRotate)
1449 {
1450 return;
1451 }
1452
1453 if (theToLockZUp)
1454 {
1455 // amend camera to exclude roll angle (put camera Up vector to plane containing global Z and view direction)
1456 Graphic3d_Vec2i aWinXY;
1457 theView->Window()->Size (aWinXY.x(), aWinXY.y());
1458 double aYawAngleDelta = ((myGL.OrbitRotation.PointStart.x() - myGL.OrbitRotation.PointTo.x()) / double (aWinXY.x())) * (M_PI * 0.5);
1459 double aPitchAngleDelta = -((myGL.OrbitRotation.PointStart.y() - myGL.OrbitRotation.PointTo.y()) / double (aWinXY.y())) * (M_PI * 0.5);
1460 const double aPitchAngleNew = Max (Min (myRotateStartYawPitchRoll[1] + aPitchAngleDelta, M_PI * 0.5 - M_PI / 180.0), -M_PI * 0.5 + M_PI / 180.0);
1461 const double aYawAngleNew = myRotateStartYawPitchRoll[0] + aYawAngleDelta;
1462 const double aRoll = 0.0;
1463
1464 gp_Quaternion aRot;
1465 aRot.SetEulerAngles (gp_YawPitchRoll, aYawAngleNew, aPitchAngleNew, aRoll);
1466 gp_Trsf aTrsfRot;
1467 aTrsfRot.SetRotation (aRot);
1468
1469 const gp_Dir aNewUp = gp::DZ().Transformed (aTrsfRot);
1470 aCam->SetUp (aNewUp);
1471 aCam->SetCenter(myRotatePnt3d.XYZ() + myCamStartOpToCenter.Transformed (aTrsfRot).XYZ());
1472 aCam->SetEye (myRotatePnt3d.XYZ() + myCamStartOpToEye .Transformed (aTrsfRot).XYZ());
1473 aCam->OrthogonalizeUp();
1474 }
1475 else
1476 {
1477 // default alternatives
1478 //if (myRotationMode == AIS_RotationMode_BndBoxActive) theView->Rotation (myGL.RotateToPoint.x(), myGL.RotateToPoint.y());
1479 //theView->Rotate (aDX, aDY, aDZ, myRotatePnt3d.X(), myRotatePnt3d.Y(), myRotatePnt3d.Z(), false);
1480
1481 // restore previous camera state
1482 aCam->SetUp (myCamStartOpUp);
1483 aCam->SetEye (myCamStartOpEye);
1484 aCam->SetCenter (myCamStartOpCenter);
1485
1486 Graphic3d_Vec2d aWinXY;
1487 theView->Size (aWinXY.x(), aWinXY.y());
1488 const Standard_Real rx = (Standard_Real )theView->Convert (aWinXY.x());
1489 const Standard_Real ry = (Standard_Real )theView->Convert (aWinXY.y());
1490
1491 const double THE_2PI = M_PI * 2.0;
1492 double aDX = (myGL.OrbitRotation.PointTo.x() - myGL.OrbitRotation.PointStart.x()) * M_PI / rx;
1493 double aDY = (myGL.OrbitRotation.PointStart.y() - myGL.OrbitRotation.PointTo.y()) * M_PI / ry;
1494
1495 if (aDX > 0.0) { while (aDX > THE_2PI) { aDX -= THE_2PI; } }
1496 else if(aDX < 0.0) { while (aDX < -THE_2PI) { aDX += THE_2PI; } }
1497 if (aDY > 0.0) { while (aDY > THE_2PI) { aDY -= THE_2PI; } }
1498 else if(aDY < 0.0) { while (aDY < -THE_2PI) { aDY += THE_2PI; } }
1499
1500 // rotate camera around 3 initial axes
1501 gp_Dir aCamDir (aCam->Direction().Reversed());
1502 gp_Dir aCamUp (aCam->Up());
1503 gp_Dir aCamSide(aCamUp.Crossed (aCamDir));
1504
1505 gp_Trsf aRot[2], aTrsf;
1506 aRot[0].SetRotation (gp_Ax1 (myRotatePnt3d, aCamUp), -aDX);
1507 aRot[1].SetRotation (gp_Ax1 (myRotatePnt3d, aCamSide), aDY);
1508 aTrsf.Multiply (aRot[0]);
1509 aTrsf.Multiply (aRot[1]);
1510
1511 aCam->Transform (aTrsf);
1512 }
1513
1514 theView->Invalidate();
1515}
1516
1517// =======================================================================
1518// function : handleViewRotation
1519// purpose :
1520// =======================================================================
1521void AIS_ViewController::handleViewRotation (const Handle(V3d_View)& theView,
1522 double theYawExtra,
1523 double thePitchExtra,
1524 double theRoll,
1525 bool theToRestartOnIncrement)
1526{
1527 if (!myToAllowRotation)
1528 {
1529 return;
1530 }
1531
1532 const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1533 const bool toRotateAnyway = Abs (theYawExtra) > gp::Resolution()
1534 || Abs (thePitchExtra) > gp::Resolution()
1535 || Abs (theRoll - myRotateStartYawPitchRoll[2]) > gp::Resolution();
1536 if (toRotateAnyway
1537 && theToRestartOnIncrement)
1538 {
1539 myGL.ViewRotation.ToStart = true;
1540 myGL.ViewRotation.PointTo = myGL.ViewRotation.PointStart;
1541 }
1542 if (myGL.ViewRotation.ToStart)
1543 {
1544 gp_Trsf aTrsf;
1545 aTrsf.SetTransformation (gp_Ax3 (gp::Origin(), aCam->OrthogonalizedUp(), aCam->Direction()),
1546 gp_Ax3 (gp::Origin(), gp::DZ(), gp::DX()));
1547 const gp_Quaternion aRot = aTrsf.GetRotation();
1548 double aRollDummy = 0.0;
1549 aRot.GetEulerAngles (gp_YawPitchRoll, myRotateStartYawPitchRoll[0], myRotateStartYawPitchRoll[1], aRollDummy);
1550 }
1551 if (toRotateAnyway)
1552 {
1553 myRotateStartYawPitchRoll[0] += theYawExtra;
1554 myRotateStartYawPitchRoll[1] += thePitchExtra;
1555 myRotateStartYawPitchRoll[2] = theRoll;
1556 myGL.ViewRotation.ToRotate = true;
1557 }
1558
1559 if (!myGL.ViewRotation.ToRotate)
1560 {
1561 return;
1562 }
1563
1564 Graphic3d_Vec2i aWinXY;
1565 theView->Window()->Size (aWinXY.x(), aWinXY.y());
1566 double aYawAngleDelta = ((myGL.ViewRotation.PointStart.x() - myGL.ViewRotation.PointTo.x()) / double (aWinXY.x())) * (M_PI * 0.5);
1567 double aPitchAngleDelta = -((myGL.ViewRotation.PointStart.y() - myGL.ViewRotation.PointTo.y()) / double (aWinXY.y())) * (M_PI * 0.5);
1568 const double aPitchAngleNew = Max (Min (myRotateStartYawPitchRoll[1] + aPitchAngleDelta, M_PI * 0.5 - M_PI / 180.0), -M_PI * 0.5 + M_PI / 180.0);
1569 const double aYawAngleNew = myRotateStartYawPitchRoll[0] + aYawAngleDelta;
1570 gp_Quaternion aRot;
1571 aRot.SetEulerAngles (gp_YawPitchRoll, aYawAngleNew, aPitchAngleNew, theRoll);
1572 gp_Trsf aTrsfRot;
1573 aTrsfRot.SetRotation (aRot);
1574
1575 const double aDist = aCam->Distance();
1576 const gp_Dir aNewUp = gp::DZ().Transformed (aTrsfRot);
1577 const gp_Dir aNewDir = gp::DX().Transformed (aTrsfRot);
1578 aCam->SetUp (aNewUp);
1579 aCam->SetCenter (aCam->Eye().Translated (gp_Vec (aNewDir) * aDist));
1580 aCam->OrthogonalizeUp();
1581 theView->Invalidate();
1582}
1583
1584// =======================================================================
1585// function : PickPoint
1586// purpose :
1587// =======================================================================
1588bool AIS_ViewController::PickPoint (gp_Pnt& thePnt,
1589 const Handle(AIS_InteractiveContext)& theCtx,
1590 const Handle(V3d_View)& theView,
1591 const Graphic3d_Vec2i& theCursor,
1592 bool theToStickToPickRay)
1593{
1594 ResetPreviousMoveTo();
1595
1596 const Handle(StdSelect_ViewerSelector3d)& aSelector = theCtx->MainSelector();
1597 aSelector->Pick (theCursor.x(), theCursor.y(), theView);
1598 if (aSelector->NbPicked() < 1)
1599 {
1600 return false;
1601 }
1602
1603 const SelectMgr_SortCriterion& aPicked = aSelector->PickedData (1);
1604 if (theToStickToPickRay
1605 && !Precision::IsInfinite (aPicked.Depth))
1606 {
1607 thePnt = aSelector->GetManager().DetectedPoint (aPicked.Depth);
1608 }
1609 else
1610 {
1611 thePnt = aSelector->PickedPoint (1);
1612 }
1613 return !Precision::IsInfinite (thePnt.X())
1614 && !Precision::IsInfinite (thePnt.Y())
1615 && !Precision::IsInfinite (thePnt.Z());
1616}
1617
1618// =======================================================================
1619// function : GravityPoint
1620// purpose :
1621// =======================================================================
1622gp_Pnt AIS_ViewController::GravityPoint (const Handle(AIS_InteractiveContext)& theCtx,
1623 const Handle(V3d_View)& theView)
1624{
1625 switch (myRotationMode)
1626 {
1627 case AIS_RotationMode_PickLast:
1628 case AIS_RotationMode_PickCenter:
1629 {
1630 Graphic3d_Vec2i aCursor ((int )myGL.OrbitRotation.PointStart.x(), (int )myGL.OrbitRotation.PointStart.y());
1631 if (myRotationMode == AIS_RotationMode_PickCenter)
1632 {
1633 Graphic3d_Vec2i aViewPort;
1634 theView->Window()->Size (aViewPort.x(), aViewPort.y());
1635 aCursor = aViewPort / 2;
1636 }
1637
1638 gp_Pnt aPnt;
1639 if (PickPoint (aPnt, theCtx, theView, aCursor, false))
1640 {
1641 return aPnt;
1642 }
1643 break;
1644 }
1645 case AIS_RotationMode_CameraAt:
1646 {
1647 const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1648 return aCam->Center();
1649 }
1650 case AIS_RotationMode_BndBoxScene:
1651 {
1652 Bnd_Box aBndBox = theView->View()->MinMaxValues (false);
1653 if (!aBndBox.IsVoid())
1654 {
1655 return (aBndBox.CornerMin().XYZ() + aBndBox.CornerMax().XYZ()) * 0.5;
1656 }
1657 break;
1658 }
1659 case AIS_RotationMode_BndBoxActive:
1660 break;
1661 }
1662
1663 return theCtx ->GravityPoint (theView);
1664}
1665
1666// =======================================================================
1667// function : handleCameraActions
1668// purpose :
1669// =======================================================================
1670void AIS_ViewController::handleCameraActions (const Handle(AIS_InteractiveContext)& theCtx,
1671 const Handle(V3d_View)& theView,
1672 const AIS_WalkDelta& theWalk)
1673{
1674 // apply view actions
1675 if (myGL.Orientation.ToSetViewOrient)
1676 {
1677 theView->SetProj (myGL.Orientation.ViewOrient);
1678 myGL.Orientation.ToFitAll = true;
1679 }
1680
1681 // apply fit all
1682 if (myGL.Orientation.ToFitAll)
1683 {
1684 const double aFitMargin = 0.01;
1685 theView->FitAll (aFitMargin, false);
1686 theView->Invalidate();
1687 myGL.Orientation.ToFitAll = false;
1688 }
1689
1690 if (myGL.IsNewGesture)
1691 {
1692 if (myAnchorPointPrs1->HasInteractiveContext())
1693 {
1694 theCtx->Remove (myAnchorPointPrs1, false);
1695 if (!theView->Viewer()->ZLayerSettings (myAnchorPointPrs1->ZLayer()).IsImmediate())
1696 {
1697 theView->Invalidate();
1698 }
1699 else
1700 {
1701 theView->InvalidateImmediate();
1702 }
1703 }
1704 if (myAnchorPointPrs2->HasInteractiveContext())
1705 {
1706 theCtx->Remove (myAnchorPointPrs2, false);
1707 if (!theView->Viewer()->ZLayerSettings (myAnchorPointPrs2->ZLayer()).IsImmediate())
1708 {
1709 theView->Invalidate();
1710 }
1711 else
1712 {
1713 theView->InvalidateImmediate();
1714 }
1715 }
1716
1717 if (myHasHlrOnBeforeRotation)
1718 {
1719 myHasHlrOnBeforeRotation = false;
1720 theView->SetComputedMode (true);
1721 theView->Invalidate();
1722 }
1723 }
1724
1725 if (myNavigationMode != AIS_NavigationMode_FirstPersonWalk)
1726 {
1727 if (myGL.Panning.ToStart
1728 && myToAllowPanning)
1729 {
1730 gp_Pnt aPanPnt (Precision::Infinite(), 0.0, 0.0);
1731 if (!theView->Camera()->IsOrthographic())
1732 {
1733 bool toStickToRay = false;
1734 if (myGL.Panning.PointStart.x() >= 0
1735 && myGL.Panning.PointStart.y() >= 0)
1736 {
1737 PickPoint (aPanPnt, theCtx, theView, myGL.Panning.PointStart, toStickToRay);
1738 }
1739 if (Precision::IsInfinite (aPanPnt.X()))
1740 {
1741 Graphic3d_Vec2i aWinSize;
1742 theView->Window()->Size (aWinSize.x(), aWinSize.y());
1743 PickPoint (aPanPnt, theCtx, theView, aWinSize / 2, toStickToRay);
1744 }
1745 if (!Precision::IsInfinite (aPanPnt.X())
1746 && myToShowPanAnchorPoint)
1747 {
1748 gp_Trsf aPntTrsf;
1749 aPntTrsf.SetTranslation (gp_Vec (aPanPnt.XYZ()));
1750 theCtx->SetLocation (myAnchorPointPrs2, aPntTrsf);
1751 }
1752 }
1753 setPanningAnchorPoint (aPanPnt);
1754 }
1755
1756 if (myToShowPanAnchorPoint
1757 && hasPanningAnchorPoint()
1758 && myGL.Panning.ToPan
1759 && !myGL.IsNewGesture
1760 && !myAnchorPointPrs2->HasInteractiveContext())
1761 {
1762 theCtx->Display (myAnchorPointPrs2, 0, -1, false, AIS_DS_Displayed);
1763 }
1764
1765 handlePanning (theView);
1766 handleZRotate (theView);
1767 }
1768
1769 if ((myNavigationMode == AIS_NavigationMode_Orbit
1770 || myGL.OrbitRotation.ToStart
1771 || myGL.OrbitRotation.ToRotate)
1772 && myToAllowRotation)
1773 {
1774 if (myGL.OrbitRotation.ToStart
1775 && !myHasHlrOnBeforeRotation)
1776 {
1777 myHasHlrOnBeforeRotation = theView->ComputedMode();
1778 if (myHasHlrOnBeforeRotation)
1779 {
1780 theView->SetComputedMode (false);
1781 }
1782 }
1783
1784 gp_Pnt aGravPnt;
1785 if (myGL.OrbitRotation.ToStart)
1786 {
1787 aGravPnt = GravityPoint (theCtx, theView);
1788 if (myToShowRotateCenter)
1789 {
1790 gp_Trsf aPntTrsf;
1791 aPntTrsf.SetTranslation (gp_Vec (aGravPnt.XYZ()));
1792 theCtx->SetLocation (myAnchorPointPrs1, aPntTrsf);
1793 theCtx->SetLocation (myAnchorPointPrs2, aPntTrsf);
1794 }
1795 }
1796
1797 if (myToShowRotateCenter
1798 && myGL.OrbitRotation.ToRotate
1799 && !myGL.IsNewGesture
1800 && !myAnchorPointPrs1->HasInteractiveContext())
1801 {
1802 theCtx->Display (myAnchorPointPrs1, 0, -1, false, AIS_DS_Displayed);
1803 theCtx->Display (myAnchorPointPrs2, 0, -1, false, AIS_DS_Displayed);
1804 }
1805 handleOrbitRotation (theView, aGravPnt,
1806 myToLockOrbitZUp || myNavigationMode != AIS_NavigationMode_Orbit);
1807 }
1808
1809 if ((myNavigationMode != AIS_NavigationMode_Orbit
1810 || myGL.ViewRotation.ToStart
1811 || myGL.ViewRotation.ToRotate)
1812 && myToAllowRotation)
1813 {
1814 if (myGL.ViewRotation.ToStart
1815 && !myHasHlrOnBeforeRotation)
1816 {
1817 myHasHlrOnBeforeRotation = theView->ComputedMode();
1818 if (myHasHlrOnBeforeRotation)
1819 {
1820 theView->SetComputedMode (false);
1821 }
1822 }
1823
1824 double aRoll = 0.0;
1825 if (!theWalk[AIS_WalkRotation_Roll].IsEmpty()
1826 && !myToLockOrbitZUp)
1827 {
1828 aRoll = (M_PI / 12.0) * theWalk[AIS_WalkRotation_Roll].Pressure;
1829 aRoll *= Min (1000.0 * theWalk[AIS_WalkRotation_Roll].Duration, 100.0) / 100.0;
1830 if (theWalk[AIS_WalkRotation_Roll].Value < 0.0)
1831 {
1832 aRoll = -aRoll;
1833 }
1834 }
1835
1836 handleViewRotation (theView, theWalk[AIS_WalkRotation_Yaw].Value, theWalk[AIS_WalkRotation_Pitch].Value, aRoll,
1837 myNavigationMode == AIS_NavigationMode_FirstPersonFlight);
1838 }
1839
1840 if (!myGL.ZoomActions.IsEmpty())
1841 {
1842 for (NCollection_Sequence<Aspect_ScrollDelta>::Iterator aZoomIter (myGL.ZoomActions); aZoomIter.More(); aZoomIter.Next())
1843 {
1844 Aspect_ScrollDelta aZoomParams = aZoomIter.Value();
1845 if (myToAllowZFocus
1846 && (aZoomParams.Flags & Aspect_VKeyFlags_CTRL) != 0
1847 && theView->Camera()->IsStereo())
1848 {
1849 handleZFocusScroll (theView, aZoomParams);
1850 continue;
1851 }
1852
1853 if (!myToAllowZooming)
1854 {
1855 continue;
1856 }
1857
1858 if (!theView->Camera()->IsOrthographic())
1859 {
1860 // what is more natural to user - point on ray or point exactly on geometry in corner cases?
1861 const bool toStickToRay = false; // true;
1862
1863 gp_Pnt aPnt;
1864 if (aZoomParams.HasPoint()
1865 && PickPoint (aPnt, theCtx, theView, aZoomParams.Point, toStickToRay))
1866 {
1867 handleZoom (theView, aZoomParams, &aPnt);
1868 continue;
1869 }
1870
1871 Graphic3d_Vec2i aWinSize;
1872 theView->Window()->Size (aWinSize.x(), aWinSize.y());
1873 if (PickPoint (aPnt, theCtx, theView, aWinSize / 2, toStickToRay))
1874 {
1875 aZoomParams.ResetPoint(); // do not pretend to zoom at 'nothing'
1876 handleZoom (theView, aZoomParams, &aPnt);
1877 continue;
1878 }
1879 }
1880 handleZoom (theView, aZoomParams, NULL);
1881 }
1882 myGL.ZoomActions.Clear();
1883 }
1884}
1885
1886// =======================================================================
1887// function : OnSelectionChanged
1888// purpose :
1889// =======================================================================
1890void AIS_ViewController::OnSelectionChanged (const Handle(AIS_InteractiveContext)& ,
1891 const Handle(V3d_View)& )
1892{
1893 //
1894}
1895
1896// =======================================================================
1897// function : OnObjectDragged
1898// purpose :
1899// =======================================================================
1900void AIS_ViewController::OnObjectDragged (const Handle(AIS_InteractiveContext)& theCtx,
1901 const Handle(V3d_View)& theView,
1902 AIS_DragAction theAction)
1903{
1904 switch (theAction)
1905 {
1906 case AIS_DragAction_Start:
1907 {
1908 myDragObject.Nullify();
1909 if (!theCtx->HasDetected())
1910 {
1911 return;
1912 }
1913
1914 Handle(AIS_InteractiveObject) aPrs = theCtx->DetectedInteractive();
1915 if (Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (aPrs))
1916 {
1917 if (aManip->HasActiveMode())
1918 {
1919 myDragObject = aManip;
1920 aManip->StartTransform (myGL.Dragging.PointStart.x(), myGL.Dragging.PointStart.y(), theView);
1921 }
1922 }
1923 return;
1924 }
1925 case AIS_DragAction_Update:
1926 {
1927 if (myDragObject.IsNull())
1928 {
1929 return;
1930 }
1931
1932 if (Handle(SelectMgr_EntityOwner) aGlobOwner = myDragObject->GlobalSelOwner())
1933 {
1934 theCtx->SetSelectedState (aGlobOwner, true);
1935 }
1936 if (Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (myDragObject))
1937 {
1938 aManip->Transform (myGL.Dragging.PointTo.x(), myGL.Dragging.PointTo.y(), theView);
1939 }
1940 theView->Invalidate();
1941 return;
1942 }
1943 case AIS_DragAction_Abort:
1944 {
1945 if (myDragObject.IsNull())
1946 {
1947 return;
1948 }
1949
1950 myGL.Dragging.PointTo = myGL.Dragging.PointStart;
1951 OnObjectDragged (theCtx, theView, AIS_DragAction_Update);
1952
1953 if (Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (myDragObject))
1954 {
1955 aManip->StopTransform (false);
1956 }
1957 Standard_FALLTHROUGH
1958 }
1959 case AIS_DragAction_Stop:
1960 {
1961 if (myDragObject.IsNull())
1962 {
1963 return;
1964 }
1965
1966 if (Handle(SelectMgr_EntityOwner) aGlobOwner = myDragObject->GlobalSelOwner())
1967 {
1968 theCtx->SetSelectedState (aGlobOwner, false);
1969 }
1970
1971 theView->Invalidate();
1972 myDragObject.Nullify();
1973 return;
1974 }
1975 }
1976}
1977
1978// =======================================================================
1979// function : contextLazyMoveTo
1980// purpose :
1981// =======================================================================
1982void AIS_ViewController::contextLazyMoveTo (const Handle(AIS_InteractiveContext)& theCtx,
1983 const Handle(V3d_View)& theView,
1984 const Graphic3d_Vec2i& thePnt)
1985{
1986 if (myPrevMoveTo == thePnt)
1987 {
1988 return;
1989 }
1990
1991 myPrevMoveTo = thePnt;
1992
1993 Handle(SelectMgr_EntityOwner) aLastPicked = theCtx->DetectedOwner();
1994 theCtx->MoveTo (thePnt.x(), thePnt.y(), theView, false);
1995 Handle(SelectMgr_EntityOwner) aNewPicked = theCtx->DetectedOwner();
1996
1997 if (theView->Viewer()->Grid()->IsActive()
1998 && theView->Viewer()->GridEcho())
1999 {
2000 if (aNewPicked.IsNull())
2001 {
2002 Graphic3d_Vec3d aPnt3d;
2003 theView->ConvertToGrid (thePnt.x(), thePnt.y(), aPnt3d[0], aPnt3d[1], aPnt3d[2]);
2004 theView->Viewer()->ShowGridEcho (theView, Graphic3d_Vertex (aPnt3d[0], aPnt3d[1], aPnt3d[2]));
2005 theView->InvalidateImmediate();
2006 }
2007 else
2008 {
2009 theView->Viewer()->HideGridEcho (theView);
2010 theView->InvalidateImmediate();
2011 }
2012 }
2013
2014 if (aLastPicked != aNewPicked
2015 || (!aNewPicked.IsNull() && aNewPicked->IsForcedHilight()))
2016 {
2017 // dynamic highlight affects all Views
2018 for (V3d_ListOfViewIterator aViewIter (theView->Viewer()->ActiveViewIterator()); aViewIter.More(); aViewIter.Next())
2019 {
2020 const Handle(V3d_View)& aView = aViewIter.Value();
2021 aView->InvalidateImmediate();
2022 }
2023 }
2024}
2025
2026// =======================================================================
2027// function : handleSelectionPick
2028// purpose :
2029// =======================================================================
2030void AIS_ViewController::handleSelectionPick (const Handle(AIS_InteractiveContext)& theCtx,
2031 const Handle(V3d_View)& theView)
2032{
2033 if (myGL.Selection.Tool == AIS_ViewSelectionTool_Picking
2034 && !myGL.Selection.Points.IsEmpty())
2035 {
2036 for (NCollection_Sequence<Graphic3d_Vec2i>::Iterator aPntIter (myGL.Selection.Points); aPntIter.More(); aPntIter.Next())
2037 {
2038 if (!myGL.Selection.IsXOR)
2039 {
2040 theCtx->ClearSelected (false);
2041 }
2042
2043 const bool hadPrevMoveTo = HasPreviousMoveTo();
2044 contextLazyMoveTo (theCtx, theView, aPntIter.Value());
2045 if (!hadPrevMoveTo)
2046 {
2047 ResetPreviousMoveTo();
2048 }
2049
2050 if (myGL.Selection.IsXOR)
2051 {
2052 theCtx->ShiftSelect (false);
2053 }
2054 else
2055 {
2056 theCtx->Select (false);
2057 }
2058
2059 // selection affects all Views
2060 theView->Viewer()->Invalidate();
2061
2062 OnSelectionChanged (theCtx, theView);
2063 }
2064
2065 myGL.Selection.Points.Clear();
2066 }
2067}
2068
2069// =======================================================================
2070// function : handleSelectionPoly
2071// purpose :
2072// =======================================================================
2073void AIS_ViewController::handleSelectionPoly (const Handle(AIS_InteractiveContext)& theCtx,
2074 const Handle(V3d_View)& theView)
2075{
2076 // rubber-band & window polygon selection
2077 if (myGL.Selection.Tool == AIS_ViewSelectionTool_RubberBand
2078 || myGL.Selection.Tool == AIS_ViewSelectionTool_Polygon)
2079 {
2080 if (!myGL.Selection.Points.IsEmpty())
2081 {
2082 myRubberBand->ClearPoints();
2083 myRubberBand->SetToUpdate();
2084
2085 const bool anIsRubber = myGL.Selection.Tool == AIS_ViewSelectionTool_RubberBand;
2086 if (anIsRubber)
2087 {
2088 myRubberBand->SetRectangle (myGL.Selection.Points.First().x(), -myGL.Selection.Points.First().y(),
2089 myGL.Selection.Points.Last().x(), -myGL.Selection.Points.Last().y());
2090 }
2091 else
2092 {
2093 Graphic3d_Vec2i aPrev (IntegerLast(), IntegerLast());
2094 for (NCollection_Sequence<Graphic3d_Vec2i>::Iterator aSelIter (myGL.Selection.Points); aSelIter.More(); aSelIter.Next())
2095 {
2096 Graphic3d_Vec2i aPntNew = Graphic3d_Vec2i (aSelIter.Value().x(), -aSelIter.Value().y());
2097 if (aPntNew != aPrev)
2098 {
2099 aPrev = aPntNew;
2100 myRubberBand->AddPoint (Graphic3d_Vec2i (aSelIter.Value().x(), -aSelIter.Value().y()));
2101 }
2102 }
2103 }
2104
2105 myRubberBand->SetPolygonClosed (anIsRubber);
2106 try
2107 {
2108 theCtx->Display (myRubberBand, 0, -1, false, AIS_DS_Displayed);
2109 }
2110 catch (const Standard_Failure& theEx)
2111 {
2112 Message::DefaultMessenger()->Send (TCollection_AsciiString ("Internal error while displaying rubber-band: ")
2113 + theEx.DynamicType()->Name() + ", " + theEx.GetMessageString(), Message_Warning);
2114 myRubberBand->ClearPoints();
2115 }
2116 if (!theView->Viewer()->ZLayerSettings (myRubberBand->ZLayer()).IsImmediate())
2117 {
2118 theView->Invalidate();
2119 }
2120 else
2121 {
2122 theView->InvalidateImmediate();
2123 }
2124 }
2125 else if (!myRubberBand.IsNull()
2126 && myRubberBand->HasInteractiveContext())
2127 {
2128 theCtx->Remove (myRubberBand, false);
2129 myRubberBand->ClearPoints();
2130 }
2131 }
2132
2133 if (myGL.Selection.ToApplyTool)
2134 {
2135 myGL.Selection.ToApplyTool = false;
2136 if (theCtx->IsDisplayed (myRubberBand))
2137 {
2138 theCtx->Remove (myRubberBand, false);
2139 {
2140 const NCollection_Sequence<Graphic3d_Vec2i>& aPoints = myRubberBand->Points();
2141 if (aPoints.Size() == 4
2142 && aPoints.Value (1).x() == aPoints.Value (2).x()
2143 && aPoints.Value (3).x() == aPoints.Value (4).x()
2144 && aPoints.Value (1).y() == aPoints.Value (4).y()
2145 && aPoints.Value (2).y() == aPoints.Value (3).y())
2146 {
2147 const Graphic3d_Vec2i aPnt1 (aPoints.Value (1).x(), -aPoints.Value (1).y());
2148 const Graphic3d_Vec2i aPnt2 (aPoints.Value (3).x(), -aPoints.Value (3).y());
2149 theCtx->MainSelector()->AllowOverlapDetection (aPnt1.y() != Min (aPnt1.y(), aPnt2.y()));
2150 if (myGL.Selection.IsXOR)
2151 {
2152 theCtx->ShiftSelect (Min (aPnt1.x(), aPnt2.x()), Min (aPnt1.y(), aPnt2.y()),
2153 Max (aPnt1.x(), aPnt2.x()), Max (aPnt1.y(), aPnt2.y()),
2154 theView, false);
2155 }
2156 else
2157 {
2158 theCtx->Select (Min (aPnt1.x(), aPnt2.x()), Min (aPnt1.y(), aPnt2.y()),
2159 Max (aPnt1.x(), aPnt2.x()), Max (aPnt1.y(), aPnt2.y()),
2160 theView, false);
2161 }
2162 theCtx->MainSelector()->AllowOverlapDetection (false);
2163 }
2164 else if (aPoints.Length() >= 3)
2165 {
2166 TColgp_Array1OfPnt2d aPolyline (1, aPoints.Length());
2167 TColgp_Array1OfPnt2d::Iterator aPolyIter (aPolyline);
2168 for (NCollection_Sequence<Graphic3d_Vec2i>::Iterator aSelIter (aPoints);
2169 aSelIter.More(); aSelIter.Next(), aPolyIter.Next())
2170 {
2171 const Graphic3d_Vec2i& aNewPnt = aSelIter.Value();
2172 aPolyIter.ChangeValue() = gp_Pnt2d (aNewPnt.x(), -aNewPnt.y());
2173 }
2174
2175 theCtx->MainSelector()->AllowOverlapDetection (false);
2176 if (myGL.Selection.IsXOR)
2177 {
2178 theCtx->ShiftSelect (aPolyline, theView, false);
2179 }
2180 else
2181 {
2182 theCtx->Select (aPolyline, theView, false);
2183 }
2184 }
2185 }
2186
2187 // selection affects all Views
2188 theView->Viewer()->Invalidate();
2189
2190 myRubberBand->ClearPoints();
2191 OnSelectionChanged (theCtx, theView);
2192 }
2193 }
2194}
2195
2196// =======================================================================
2197// function : handleDynamicHighlight
2198// purpose :
2199// =======================================================================
2200void AIS_ViewController::handleDynamicHighlight (const Handle(AIS_InteractiveContext)& theCtx,
2201 const Handle(V3d_View)& theView)
2202{
2203 if ((myGL.MoveTo.ToHilight || myGL.Dragging.ToStart)
2204 && myNavigationMode != AIS_NavigationMode_FirstPersonWalk)
2205 {
2206 const Graphic3d_Vec2i& aMoveToPnt = myGL.MoveTo.ToHilight ? myGL.MoveTo.Point : myGL.Dragging.PointStart;
2207 if (myGL.Dragging.ToStart && (!myGL.MoveTo.ToHilight || !myToAllowHighlight)
2208 && !HasPreviousMoveTo())
2209 {
2210 contextLazyMoveTo (theCtx, theView, aMoveToPnt);
2211 ResetPreviousMoveTo();
2212 OnObjectDragged (theCtx, theView, AIS_DragAction_Start);
2213 theCtx->ClearDetected();
2214 }
2215 else if (myToAllowHighlight)
2216 {
2217 if (myPrevMoveTo != aMoveToPnt
2218 || myGL.OrbitRotation.ToRotate
2219 || myGL.ViewRotation.ToRotate
2220 || theView->IsInvalidated())
2221 {
2222 ResetPreviousMoveTo();
2223 contextLazyMoveTo (theCtx, theView, aMoveToPnt);
2224 }
2225 if (myGL.Dragging.ToStart)
2226 {
2227 OnObjectDragged (theCtx, theView, AIS_DragAction_Start);
2228 }
2229 }
2230
2231 myGL.MoveTo.ToHilight = false;
2232 }
2233
2234 if (!myDragObject.IsNull())
2235 {
2236 if (myGL.Dragging.ToAbort)
2237 {
2238 OnObjectDragged (theCtx, theView, AIS_DragAction_Abort);
2239 myGL.OrbitRotation.ToRotate = false;
2240 myGL.ViewRotation .ToRotate = false;
2241 }
2242 else if (myGL.Dragging.ToStop)
2243 {
2244 OnObjectDragged (theCtx, theView, AIS_DragAction_Stop);
2245 myGL.OrbitRotation.ToRotate = false;
2246 myGL.ViewRotation .ToRotate = false;
2247 }
2248 else if (myGL.OrbitRotation.ToRotate
2249 || myGL.ViewRotation.ToRotate)
2250 {
2251 OnObjectDragged (theCtx, theView, AIS_DragAction_Update);
2252 myGL.OrbitRotation.ToRotate = false;
2253 myGL.ViewRotation .ToRotate = false;
2254 }
2255 }
2256}
2257
2258// =======================================================================
2259// function : handleMoveTo
2260// purpose :
2261// =======================================================================
2262void AIS_ViewController::handleMoveTo (const Handle(AIS_InteractiveContext)& theCtx,
2263 const Handle(V3d_View)& theView)
2264{
2265 handleSelectionPick (theCtx, theView);
2266 handleDynamicHighlight(theCtx, theView);
2267 handleSelectionPoly (theCtx, theView);
2268}
2269
2270// =======================================================================
2271// function : handleViewRedraw
2272// purpose :
2273// =======================================================================
2274void AIS_ViewController::handleViewRedraw (const Handle(AIS_InteractiveContext)& ,
2275 const Handle(V3d_View)& theView)
2276{
2277 for (V3d_ListOfViewIterator aViewIter (theView->Viewer()->ActiveViewIterator()); aViewIter.More(); aViewIter.Next())
2278 {
2279 const Handle(V3d_View)& aView = aViewIter.Value();
2280 if (aView->IsInvalidated()
2281 || myToAskNextFrame)
2282 {
2283 if (aView->ComputedMode())
2284 {
2285 aView->Update();
2286 }
2287 else
2288 {
2289 aView->Redraw();
2290 }
2291 }
2292 else if (aView->IsInvalidatedImmediate())
2293 {
2294 aView->RedrawImmediate();
2295 }
2296 }
2297
2298 if (myToAskNextFrame)
2299 {
2300 // ask more frames
2301 theView->Window()->InvalidateContent (Handle(Aspect_DisplayConnection)());
2302 }
2303}
2304
2305// =======================================================================
2306// function : HandleViewEvents
2307// purpose :
2308// =======================================================================
2309void AIS_ViewController::HandleViewEvents (const Handle(AIS_InteractiveContext)& theCtx,
2310 const Handle(V3d_View)& theView)
2311{
2312 handleMoveTo (theCtx, theView);
2313
2314 const AIS_WalkDelta aWalk = FetchNavigationKeys (1.0, 1.0);
2315 handleCameraActions (theCtx, theView, aWalk);
2316 handleViewRedraw (theCtx, theView);
2317
2318 // make sure to not process the same events twice
2319 myGL.Reset();
2320 myToAskNextFrame = false;
2321}