root/OpenSceneGraph/trunk/src/osgGA/StandardManipulator.cpp @ 13041

Revision 13041, 24.6 kB (checked in by robert, 3 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2010 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12 *
13 * StandardManipulator code Copyright (C) 2010 PCJohn (Jan Peciva)
14 * while some pieces of code were taken from OSG.
15 * Thanks to company Cadwork (www.cadwork.ch) and
16 * Brno University of Technology (www.fit.vutbr.cz) for open-sourcing this work.
17*/
18
19#include <osgGA/StandardManipulator>
20#include <osgViewer/View>
21
22using namespace osg;
23using namespace osgGA;
24using namespace osgUtil;
25
26int StandardManipulator::numRelativeFlagsAllocated = 0;
27
28int StandardManipulator::allocateRelativeFlag()
29{
30    return numRelativeFlagsAllocated++;
31}
32
33
34/// Constructor.
35StandardManipulator::StandardManipulator( int flags )
36    : inherited(),
37      _thrown( false ),
38      _allowThrow( true ),
39      _mouseCenterX(0.0f), _mouseCenterY(0.0f),
40      _delta_frame_time(0.01), _last_frame_time(0.0),
41      _modelSize( 0. ),
42      _verticalAxisFixed( true ),
43      _flags( flags ),
44      _relativeFlags( 0 )
45{
46}
47
48
49/// Constructor.
50StandardManipulator::StandardManipulator( const StandardManipulator& uim, const CopyOp& copyOp )
51   : inherited( uim, copyOp ),
52     _thrown( uim._thrown ),
53     _allowThrow( uim._allowThrow ),
54     _mouseCenterX(0.0f), _mouseCenterY(0.0f),
55     _ga_t1( dynamic_cast< GUIEventAdapter* >( copyOp( uim._ga_t1.get() ) ) ),
56     _ga_t0( dynamic_cast< GUIEventAdapter* >( copyOp( uim._ga_t0.get() ) ) ),
57     _delta_frame_time(0.01), _last_frame_time(0.0),
58     _modelSize( uim._modelSize ),
59     _verticalAxisFixed( uim._verticalAxisFixed ),
60     _flags( uim._flags ),
61     _relativeFlags( uim._relativeFlags )
62{
63}
64
65
66/** Attach a node to the manipulator.
67    Automatically detaches previously attached node.
68    setNode(NULL) detaches previously attached nodes.
69    Is ignored by manipulators which do not require a reference model.*/
70void StandardManipulator::setNode( Node* node )
71{
72    _node = node;
73
74    // update model size
75    if( _node.get() )
76    {
77        const BoundingSphere& boundingSphere = _node->getBound();
78        _modelSize = boundingSphere.radius();
79    }
80    else
81    {
82        _modelSize = 0.;
83    }
84
85    // compute home position
86    if( getAutoComputeHomePosition() )
87        computeHomePosition( NULL, ( _flags & COMPUTE_HOME_USING_BBOX ) != 0 );
88}
89
90
91/** Return node if attached.*/
92const Node* StandardManipulator::getNode() const
93{
94    return _node.get();
95}
96
97
98/** Return node if attached.*/
99Node* StandardManipulator::getNode()
100{
101    return _node.get();
102}
103
104
105/** Makes manipulator to keep camera's "UP" vector.
106 *
107 *  In general, fixed up vector makes camera control more user friendly.
108 *
109 *  To change up vector, use CameraManipulator::setCoordinateFrameCallback.*/
110void StandardManipulator::setVerticalAxisFixed( bool value )
111{
112    _verticalAxisFixed = value;
113}
114
115
116/// Sets manipulator animation time when centering on mouse wheel up is enabled.
117void StandardManipulator::setAnimationTime( const double t )
118{
119    if( t <= 0. )
120    {
121        finishAnimation();
122        _animationData = NULL;
123        return;
124    }
125
126    if( !_animationData )
127        allocAnimationData();
128
129    _animationData->_animationTime = t;
130}
131
132
133/// Returns manipulator animation time when centering on mouse wheel up is enabled.
134double StandardManipulator::getAnimationTime() const
135{
136    if( _animationData )
137        return _animationData->_animationTime;
138    else
139        return 0.;
140}
141
142
143/// Returns whether manipulator is performing animation at the moment.
144bool StandardManipulator::isAnimating() const
145{
146    if( _animationData )
147        return _animationData->_isAnimating;
148    else
149        return false;
150}
151
152
153/// Finishes the animation by performing a step that moves it to its final position.
154void StandardManipulator::finishAnimation()
155{
156    if( !isAnimating() )
157        return;
158
159    applyAnimationStep( 1., _animationData->_phase );
160}
161
162
163/** Move the camera to the default position.
164
165    The user should probably want to use home(GUIEventAdapter&, GUIActionAdapter&)
166    instead to set manipulator to the home position. This method does not trigger
167    any redraw processing or updates continuous update processing.
168
169    StandardManipulator implementation only updates its internal structures and
170    recomputes its home position if autoComputeHomePosition is set.
171    Descendant classes are expected to update camera position.*/
172void StandardManipulator::home( double /*currentTime*/ )
173{
174    if( getAutoComputeHomePosition() )
175        computeHomePosition( NULL, ( _flags & COMPUTE_HOME_USING_BBOX ) != 0 );
176
177    _thrown = false;
178    setTransformation( _homeEye, _homeCenter, _homeUp );
179    flushMouseEventStack();
180}
181
182
183/** Move the camera to the default position.
184
185    If autoComputeHomePosition is on, home position is computed.
186    The computation considers camera fov and model size and
187    positions camera far enough to fit the model to the screen.
188
189    StandardManipulator implementation only updates its internal data.
190    If home position is expected to be supported by the descendant manipulator,
191    it has to reimplement the method to update manipulator transformation.*/
192void StandardManipulator::home( const GUIEventAdapter& ea, GUIActionAdapter& us )
193{
194    if( getAutoComputeHomePosition() )
195    {
196        const Camera *camera = us.asView() ? us.asView()->getCamera() : NULL;
197        computeHomePosition( camera, ( _flags & COMPUTE_HOME_USING_BBOX ) != 0 );
198    }
199
200    _thrown = false;
201    setTransformation( _homeEye, _homeCenter, _homeUp );
202
203    us.requestRedraw();
204    us.requestContinuousUpdate( false );
205    flushMouseEventStack();
206}
207
208
209/** Start/restart the manipulator.*/
210void StandardManipulator::init( const GUIEventAdapter& ea, GUIActionAdapter& us )
211{
212    flushMouseEventStack();
213
214    // stop animation
215    _thrown = false;
216    us.requestContinuousUpdate(false);
217}
218
219
220/** Handles events. Returns true if handled, false otherwise.*/
221bool StandardManipulator::handle( const GUIEventAdapter& ea, GUIActionAdapter& us )
222{
223    switch( ea.getEventType() )
224    {
225
226        case GUIEventAdapter::FRAME:
227            return handleFrame( ea, us );
228
229        case GUIEventAdapter::RESIZE:
230            return handleResize( ea, us );
231
232        default:
233            break;
234   }
235
236    if( ea.getHandled() )
237        return false;
238
239    switch( ea.getEventType() )
240    {
241        case GUIEventAdapter::MOVE:
242            return handleMouseMove( ea, us );
243
244        case GUIEventAdapter::DRAG:
245            return handleMouseDrag( ea, us );
246
247        case GUIEventAdapter::PUSH:
248            return handleMousePush( ea, us );
249
250        case GUIEventAdapter::RELEASE:
251            return handleMouseRelease( ea, us );
252
253        case GUIEventAdapter::KEYDOWN:
254            return handleKeyDown( ea, us );
255
256        case GUIEventAdapter::KEYUP:
257            return handleKeyUp( ea, us );
258
259        case GUIEventAdapter::SCROLL:
260            if( _flags & PROCESS_MOUSE_WHEEL )
261            return handleMouseWheel( ea, us );
262            else
263            return false;
264
265        default:
266            return false;
267    }
268}
269
270
271/// Handles GUIEventAdapter::FRAME event.
272bool StandardManipulator::handleFrame( const GUIEventAdapter& ea, GUIActionAdapter& us )
273{
274    double current_frame_time = ea.getTime();
275
276    _delta_frame_time = current_frame_time - _last_frame_time;
277    _last_frame_time = current_frame_time;
278
279    if( _thrown && performMovement() )
280    {
281        us.requestRedraw();
282    }
283
284    if( _animationData && _animationData->_isAnimating )
285    {
286        performAnimationMovement( ea, us );
287    }
288
289   return false;
290}
291
292/// Handles GUIEventAdapter::RESIZE event.
293bool StandardManipulator::handleResize( const GUIEventAdapter& ea, GUIActionAdapter& us )
294{
295    init( ea, us );
296    us.requestRedraw();
297
298    return true;
299}
300
301
302/// Handles GUIEventAdapter::MOVE event.
303bool StandardManipulator::handleMouseMove( const GUIEventAdapter& ea, GUIActionAdapter& us )
304{
305    return false;
306}
307
308
309/// Handles GUIEventAdapter::DRAG event.
310bool StandardManipulator::handleMouseDrag( const GUIEventAdapter& ea, GUIActionAdapter& us )
311{
312    addMouseEvent( ea );
313
314    if( performMovement() )
315        us.requestRedraw();
316
317    us.requestContinuousUpdate( false );
318    _thrown = false;
319
320    return true;
321}
322
323
324/// Handles GUIEventAdapter::PUSH event.
325bool StandardManipulator::handleMousePush( const GUIEventAdapter& ea, GUIActionAdapter& us )
326{
327    flushMouseEventStack();
328    addMouseEvent( ea );
329
330    if( performMovement() )
331        us.requestRedraw();
332
333    us.requestContinuousUpdate( false );
334    _thrown = false;
335
336    return true;
337}
338
339
340/// Handles GUIEventAdapter::RELEASE event.
341bool StandardManipulator::handleMouseRelease( const GUIEventAdapter& ea, GUIActionAdapter& us )
342{
343    if( ea.getButtonMask() == 0 )
344    {
345
346        double timeSinceLastRecordEvent = _ga_t0.valid() ? (ea.getTime() - _ga_t0->getTime()) : DBL_MAX;
347        if( timeSinceLastRecordEvent > 0.02 )
348            flushMouseEventStack();
349
350        if( isMouseMoving() )
351        {
352
353            if( performMovement() && _allowThrow )
354            {
355                us.requestRedraw();
356                us.requestContinuousUpdate( true );
357                _thrown = true;
358            }
359
360            return true;
361        }
362    }
363
364    flushMouseEventStack();
365    addMouseEvent( ea );
366    if( performMovement() )
367        us.requestRedraw();
368    us.requestContinuousUpdate( false );
369    _thrown = false;
370
371    return true;
372}
373
374
375/// Handles GUIEventAdapter::KEYDOWN event.
376bool StandardManipulator::handleKeyDown( const GUIEventAdapter& ea, GUIActionAdapter& us )
377{
378    if( ea.getKey() == GUIEventAdapter::KEY_Space )
379    {
380        flushMouseEventStack();
381        _thrown = false;
382        home(ea,us);
383        return true;
384    }
385
386    return false;
387}
388
389
390/// Handles GUIEventAdapter::KEYUP event.
391bool StandardManipulator::handleKeyUp( const GUIEventAdapter& ea, GUIActionAdapter& us )
392{
393    return false;
394}
395
396
397/// Handles GUIEventAdapter::SCROLL event.
398bool StandardManipulator::handleMouseWheel( const GUIEventAdapter& ea, GUIActionAdapter& us )
399{
400    return false;
401}
402
403
404/** Get the keyboard and mouse usage of the manipulator.*/
405void StandardManipulator::getUsage( ApplicationUsage& usage ) const
406{
407    usage.addKeyboardMouseBinding( getManipulatorName() + ": Space", "Reset the viewing position to home" );
408}
409
410
411/// Make movement step of manipulator. Returns true if any movement was made.
412bool StandardManipulator::performMovement()
413{
414    // return if less then two events have been added
415    if( _ga_t0.get() == NULL || _ga_t1.get() == NULL )
416        return false;
417
418    // get delta time
419    double eventTimeDelta = _ga_t0->getTime() - _ga_t1->getTime();
420    if( eventTimeDelta < 0. )
421    {
422        OSG_WARN << "Manipulator warning: eventTimeDelta = " << eventTimeDelta << std::endl;
423        eventTimeDelta = 0.;
424    }
425
426    // get deltaX and deltaY
427    float dx = _ga_t0->getXnormalized() - _ga_t1->getXnormalized();
428    float dy = _ga_t0->getYnormalized() - _ga_t1->getYnormalized();
429
430    // return if there is no movement.
431    if( dx == 0. && dy == 0. )
432        return false;
433
434
435    // call appropriate methods
436    unsigned int buttonMask = _ga_t1->getButtonMask();
437    if( buttonMask == GUIEventAdapter::LEFT_MOUSE_BUTTON )
438    {
439        return performMovementLeftMouseButton( eventTimeDelta, dx, dy );
440    }
441    else if( buttonMask == GUIEventAdapter::MIDDLE_MOUSE_BUTTON ||
442            buttonMask == (GUIEventAdapter::LEFT_MOUSE_BUTTON | GUIEventAdapter::RIGHT_MOUSE_BUTTON) )
443    {
444        return performMovementMiddleMouseButton( eventTimeDelta, dx, dy );
445    }
446    else if( buttonMask == GUIEventAdapter::RIGHT_MOUSE_BUTTON )
447    {
448        return performMovementRightMouseButton( eventTimeDelta, dx, dy );
449    }
450
451    return false;
452}
453
454
455/** Make movement step of manipulator.
456    This method implements movement for left mouse button.*/
457bool StandardManipulator::performMovementLeftMouseButton( const double eventTimeDelta, const double dx, const double dy )
458{
459    return false;
460}
461
462
463/** Make movement step of manipulator.
464    This method implements movement for middle mouse button
465    or combination of left and right mouse button pressed together.*/
466bool StandardManipulator::performMovementMiddleMouseButton( const double eventTimeDelta, const double dx, const double dy )
467{
468    return false;
469}
470
471
472/** Make movement step of manipulator.
473    This method implements movement for right mouse button.*/
474bool StandardManipulator::performMovementRightMouseButton( const double eventTimeDelta, const double dx, const double dy )
475{
476    return false;
477}
478
479
480/// The method processes events for manipulation based on relative mouse movement (mouse delta).
481bool StandardManipulator::handleMouseDeltaMovement( const GUIEventAdapter& ea, GUIActionAdapter& us )
482{
483    float dx = ea.getX() - _mouseCenterX;
484    float dy = ea.getY() - _mouseCenterY;
485
486    if( dx == 0.f && dy == 0.f )
487        return false;
488
489    addMouseEvent( ea );
490    centerMousePointer( ea, us );
491
492    return performMouseDeltaMovement( dx, dy );
493}
494
495
496/// The method performs manipulator update based on relative mouse movement (mouse delta).
497bool StandardManipulator::performMouseDeltaMovement( const float dx, const float dy )
498{
499   return false;
500}
501
502
503/// Makes the manipulator progress in its current animation.
504bool StandardManipulator::performAnimationMovement( const GUIEventAdapter& ea, GUIActionAdapter& us )
505{
506    double f = (ea.getTime() - _animationData->_startTime) / _animationData->_animationTime;
507    if( f >= 1. )
508    {
509        f = 1.;
510        _animationData->_isAnimating = false;
511        if( !_thrown )
512            us.requestContinuousUpdate( false );
513    }
514
515    applyAnimationStep( f, _animationData->_phase );
516
517    _animationData->_phase = f;
518    us.requestRedraw();
519
520    return _animationData->_isAnimating;
521}
522
523
524/// Updates manipulator by a single animation step
525void StandardManipulator::applyAnimationStep( const double currentProgress, const double prevProgress )
526{
527}
528
529
530/// Centers mouse pointer
531void StandardManipulator::centerMousePointer( const GUIEventAdapter& ea, GUIActionAdapter& us )
532{
533    _mouseCenterX = (ea.getXmin() + ea.getXmax()) / 2.0f;
534    _mouseCenterY = (ea.getYmin() + ea.getYmax()) / 2.0f;
535    us.requestWarpPointer( _mouseCenterX, _mouseCenterY );
536}
537
538
539/** Add the current mouse GUIEvent to internal stack.*/
540void StandardManipulator::addMouseEvent( const GUIEventAdapter& ea )
541{
542    _ga_t1 = _ga_t0;
543    _ga_t0 = &ea;
544}
545
546
547/** Reset the internal GUIEvent stack.*/
548void StandardManipulator::flushMouseEventStack()
549{
550    _ga_t1 = NULL;
551    _ga_t0 = NULL;
552}
553
554
555/** Check the speed at which the mouse is moving.
556    If speed is below a threshold then return false, otherwise return true.*/
557bool StandardManipulator::isMouseMoving() const
558{
559    if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false;
560
561    static const float velocity = 0.1f;
562
563    float dx = _ga_t0->getXnormalized()-_ga_t1->getXnormalized();
564    float dy = _ga_t0->getYnormalized()-_ga_t1->getYnormalized();
565    float len = sqrtf(dx*dx+dy*dy);
566    float dt = _ga_t0->getTime()-_ga_t1->getTime();
567
568    return (len>dt*velocity);
569}
570
571
572/** Set the 'allow throw' flag. If it is set to true (default), releasing the mouse button
573    while moving the mouse results in a throw. If manipulator was thrown, it continues spinning
574    although no mouse button is down at the moment.*/
575void StandardManipulator::setAllowThrow( bool allowThrow )
576{
577    _allowThrow = allowThrow;
578}
579
580
581/** Returns the scale that should be applied on animation of "thrown" manipulator state
582    to avoid its dependency on varying frame rate.
583
584    eventTimeDelta parameter gives the time difference between last two
585    events that started the animation.*/
586float StandardManipulator::getThrowScale( const double eventTimeDelta ) const
587{
588    if( _thrown )  return float( _delta_frame_time / eventTimeDelta );
589    else  return 1.f;
590}
591
592
593/** Update rotation by yaw and pitch.
594 *
595 *  localUp parameter defines either camera's "UP" vector
596 *  that will be preserved during rotation, or it can be zero (0,0,0) to specify
597 *  that camera's "UP" vector will be not preserved and free rotation will be made.*/
598void StandardManipulator::rotateYawPitch( Quat& rotation, const double yaw, const double pitch,
599                                           const Vec3d& localUp )
600{
601    bool verticalAxisFixed = (localUp != Vec3d( 0.,0.,0. ));
602
603    // fix current rotation
604    if( verticalAxisFixed )
605        fixVerticalAxis( rotation, localUp, true );
606
607    // rotations
608    Quat rotateYaw( -yaw, verticalAxisFixed ? localUp : rotation * Vec3d( 0.,1.,0. ) );
609    Quat rotatePitch;
610    Quat newRotation;
611    Vec3d cameraRight( rotation * Vec3d( 1.,0.,0. ) );
612
613    double my_dy = pitch;
614    int i = 0;
615
616    do {
617
618        // rotations
619        rotatePitch.makeRotate( my_dy, cameraRight );
620        newRotation = rotation * rotateYaw * rotatePitch;
621
622        // update vertical axis
623        if( verticalAxisFixed )
624            fixVerticalAxis( newRotation, localUp, false );
625
626        // check for viewer's up vector to be more than 90 degrees from "up" axis
627        Vec3d newCameraUp = newRotation * Vec3d( 0.,1.,0. );
628        if( newCameraUp * localUp > 0. )
629        {
630
631            // apply new rotation
632            rotation = newRotation;
633            return;
634
635        }
636
637        my_dy /= 2.;
638        if( ++i == 20 )
639        {
640            rotation = rotation * rotateYaw;
641            return;
642        }
643
644    } while( true );
645}
646
647
648/** The method corrects the rotation to make impression of fixed up direction.
649 *  Technically said, it makes the roll component of the rotation equal to zero.
650 *
651 *  Up vector is given by CoordinateFrame and it is +z by default.
652 *  It can be changed by osgGA::CameraManipulator::setCoordinateFrameCallback().
653 *
654 *  Eye parameter is user position, rotation is the rotation to be fixed, and
655 *  disallowFlipOver, when set on true, avoids pitch rotation component to grow
656 *  over +/- 90 degrees. If this happens and disallowFlipOver is true,
657 *  manipulator is rotated by 180 degrees. More precisely, roll rotation component is changed by 180 degrees,
658 *  making pitch once again between -90..+90 degrees limits.*/
659void StandardManipulator::fixVerticalAxis( Vec3d& eye, Quat& rotation, bool disallowFlipOver )
660{
661   CoordinateFrame coordinateFrame = getCoordinateFrame( eye );
662   Vec3d localUp = getUpVector( coordinateFrame );
663
664   fixVerticalAxis( rotation, localUp, disallowFlipOver );
665}
666
667
668/** The method corrects the rotation to make impression of fixed up direction.
669 *  Technically said, it makes the roll component of the rotation equal to zero.
670 *
671 *  rotation parameter is the rotation to be fixed.
672 *  localUp is UP vector and must not be zero length.
673 *  disallowFlipOver, when set on true, avoids pitch rotation component to grow
674 *  over +/- 90 degrees. If this happens and disallowFlipOver is true,
675 *  manipulator is rotated by 180 degrees. More precisely, roll rotation component is changed by 180 degrees,
676 *  making pitch once again between -90..+90 degrees limits.*/
677void StandardManipulator::fixVerticalAxis( Quat& rotation, const Vec3d& localUp, bool disallowFlipOver )
678{
679    // camera direction vectors
680    Vec3d cameraUp = rotation * Vec3d( 0.,1.,0. );
681    Vec3d cameraRight = rotation * Vec3d( 1.,0.,0. );
682    Vec3d cameraForward = rotation * Vec3d( 0.,0.,-1. );
683
684    // computed directions
685    Vec3d newCameraRight1 = cameraForward ^ localUp;
686    Vec3d newCameraRight2 = cameraUp ^ localUp;
687    Vec3d newCameraRight = (newCameraRight1.length2() > newCameraRight2.length2()) ?
688                            newCameraRight1 : newCameraRight2;
689    if( newCameraRight * cameraRight < 0. )
690        newCameraRight = -newCameraRight;
691
692    // vertical axis correction
693    Quat rotationVerticalAxisCorrection;
694    rotationVerticalAxisCorrection.makeRotate( cameraRight, newCameraRight );
695
696    // rotate camera
697    rotation *= rotationVerticalAxisCorrection;
698
699    if( disallowFlipOver )
700    {
701
702        // make viewer's up vector to be always less than 90 degrees from "up" axis
703        Vec3d newCameraUp = newCameraRight ^ cameraForward;
704        if( newCameraUp * localUp < 0. )
705            rotation = Quat( PI, Vec3d( 0.,0.,1. ) ) * rotation;
706
707    }
708}
709
710
711/** The method corrects the rotation to make impression of fixed up direction.
712 *  Technically said, it makes the roll component of the rotation equal to zero.
713 *
714 *  forward and up parameters are the forward and up vectors of the manipulator.
715 *  newUp will receive corrected UP manipulator vector. localUp is UP vector
716 *  that is used for vertical correction.
717 *  disallowFlipOver when set on true avoids pitch rotation component to grow
718 *  over +/- 90 degrees. If this happens and disallowFlipOver is true,
719 *  right and up camera vectors are negated (changing roll by 180 degrees),
720 *  making pitch once again between -90..+90 degrees limits.*/
721void StandardManipulator::fixVerticalAxis( const osg::Vec3d& forward, const osg::Vec3d& up, osg::Vec3d& newUp,
722                                           const osg::Vec3d& localUp, bool disallowFlipOver )
723{
724    // right direction
725    osg::Vec3d right1 = forward ^ localUp;
726    osg::Vec3d right2 = up ^ localUp;
727    osg::Vec3d right = (right1.length2() > right2.length2()) ? right1 : right2;
728
729    // updatedUp
730    osg::Vec3d updatedUp = right ^ forward;
731    if( updatedUp.normalize() >= 0. )
732
733        // return updatedUp
734        newUp = updatedUp;
735
736    else {
737
738       // return original up
739       OSG_WARN << "StandardManipulator::fixVerticalAxis warning: Can not update vertical axis." << std::endl;
740       newUp = up;
741
742    }
743}
744
745
746/** The method sends a ray into the scene and the point of the closest intersection
747    is used to set a new center for the manipulator. For Orbit-style manipulators,
748    the orbiting center is set. For FirstPerson-style manipulators, view is pointed
749    towards the center.*/
750bool StandardManipulator::setCenterByMousePointerIntersection( const GUIEventAdapter& ea, GUIActionAdapter& us )
751{
752    osg::View* view = us.asView();
753    if( !view )
754        return false;
755
756    Camera *camera = view->getCamera();
757    if( !camera )
758        return false;
759
760    // prepare variables
761    float x = ( ea.getX() - ea.getXmin() ) / ( ea.getXmax() - ea.getXmin() );
762    float y = ( ea.getY() - ea.getYmin() ) / ( ea.getYmax() - ea.getYmin() );
763    LineSegmentIntersector::CoordinateFrame cf;
764    Viewport *vp = camera->getViewport();
765    if( vp ) {
766        cf = Intersector::WINDOW;
767        x *= vp->width();
768        y *= vp->height();
769    } else
770        cf = Intersector::PROJECTION;
771
772    // perform intersection computation
773    ref_ptr< LineSegmentIntersector > picker = new LineSegmentIntersector( cf, x, y );
774    IntersectionVisitor iv( picker.get() );
775    camera->accept( iv );
776
777    // return on no intersections
778    if( !picker->containsIntersections() )
779        return false;
780
781    // get all intersections
782    LineSegmentIntersector::Intersections& intersections = picker->getIntersections();
783
784    // get current transformation
785    osg::Vec3d eye, oldCenter, up;
786    getTransformation( eye, oldCenter, up );
787
788    // new center
789    osg::Vec3d newCenter = (*intersections.begin()).getWorldIntersectPoint();
790
791    // make vertical axis correction
792    if( getVerticalAxisFixed() )
793    {
794
795        CoordinateFrame coordinateFrame = getCoordinateFrame( newCenter );
796        Vec3d localUp = getUpVector( coordinateFrame );
797
798        fixVerticalAxis( newCenter - eye, up, up, localUp, true );
799
800    }
801
802    // set the new center
803    setTransformation( eye, newCenter, up );
804
805
806    // warp pointer
807    // note: this works for me on standard camera on GraphicsWindowEmbedded and Qt,
808    //       while it was necessary to implement requestWarpPointer like follows:
809    //
810    // void QOSGWidget::requestWarpPointer( float x, float y )
811    // {
812    //    osgViewer::Viewer::requestWarpPointer( x, y );
813    //    QCursor::setPos( this->mapToGlobal( QPoint( int( x+.5f ), int( y+.5f ) ) ) );
814    // }
815    //
816    // Additions of .5f are just for the purpose of rounding.
817    centerMousePointer( ea, us );
818
819    return true;
820}
821
822
823/** Makes mouse pointer intersection test with the geometry bellow the pointer
824    and starts animation to center camera to look at the closest hit bellow the mouse pointer.
825
826    If there is a hit, animation is started and true is returned.
827    Otherwise, the method returns false.*/
828bool StandardManipulator::startAnimationByMousePointerIntersection(
829      const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us )
830{
831    return false;
832}
833
834
835StandardManipulator::AnimationData::AnimationData()
836    :_isAnimating( false )
837{
838}
839
840
841void StandardManipulator::AnimationData::start( const double startTime )
842{
843    _isAnimating = true;
844    _startTime = startTime;
845    _phase = 0.;
846}
Note: See TracBrowser for help on using the browser.