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

Revision 13041, 16.2 kB (checked in by robert, 2 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 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
14/* Written by Don Burns */
15
16#include <osgGA/UFOManipulator>
17#include <osgUtil/LineSegmentIntersector>
18
19#include <osg/io_utils>
20
21#ifndef M_PI
22# define M_PI       3.14159265358979323846  /* pi */
23#endif
24
25using namespace osgGA;
26
27UFOManipulator::UFOManipulator():
28            _t0(0.0),
29            _shift(false),
30            _ctrl(false)
31{
32    _minHeightAboveGround          = 2.0;
33    _minDistanceInFront            = 5.0;
34
35    _speedAccelerationFactor       = 0.4;
36    _speedDecelerationFactor       = 0.90;
37
38    _directionRotationRate         = 0.0;
39    _directionRotationAcceleration = M_PI*0.00005;
40    _directionRotationDeceleration = 0.90;
41
42    _speedEpsilon                  = 0.02;
43    _directionRotationEpsilon      = 0.0001;
44
45    _viewOffsetDelta = M_PI * 0.0025;
46    _pitchOffsetRate = 0.0;
47    _pitchOffset = 0.0;
48
49    _yawOffsetRate = 0.0;
50    _yawOffset = 0.0;
51    _offset.makeIdentity();
52
53    _decelerateOffsetRate = true;
54    _straightenOffset = false;
55
56    _direction.set( 0,1,0);
57    _stop();
58}
59
60UFOManipulator::~UFOManipulator()
61{
62}
63
64bool UFOManipulator::intersect(const osg::Vec3d& start, const osg::Vec3d& end, osg::Vec3d& intersection) const
65{
66    osg::ref_ptr<osgUtil::LineSegmentIntersector> lsi = new osgUtil::LineSegmentIntersector(start,end);
67
68    osgUtil::IntersectionVisitor iv(lsi.get());
69    iv.setTraversalMask(_intersectTraversalMask);
70
71    _node->accept(iv);
72
73    if (lsi->containsIntersections())
74    {
75        intersection = lsi->getIntersections().begin()->getWorldIntersectPoint();
76        return true;
77    }
78    return false;
79}
80
81void UFOManipulator::setNode( osg::Node *node )
82{
83    _node = node;
84
85    if (getAutoComputeHomePosition())
86        computeHomePosition();
87
88    home(0.0);
89}
90
91const osg::Node* UFOManipulator::getNode() const
92{
93    return _node.get();
94}
95
96osg::Node* UFOManipulator::getNode()
97{
98    return _node.get();
99}
100
101
102const char* UFOManipulator::className() const
103{
104    return "UFO";
105}
106
107void UFOManipulator::setByMatrix( const osg::Matrixd &mat )
108{
109    _inverseMatrix = mat;
110    _matrix.invert( _inverseMatrix );
111
112    _position.set( _inverseMatrix(3,0), _inverseMatrix(3,1), _inverseMatrix(3,2 ));
113    osg::Matrix R(_inverseMatrix);
114    R(3,0) = R(3,1) = R(3,2) = 0.0;
115    _direction = osg::Vec3d(0,0,-1) * R; // camera up is +Z, regardless of CoordinateFrame
116
117    _stop();
118}
119
120void UFOManipulator::setByInverseMatrix( const osg::Matrixd &invmat)
121{
122    _matrix = invmat;
123    _inverseMatrix.invert( _matrix );
124
125    _position.set( _inverseMatrix(3,0), _inverseMatrix(3,1), _inverseMatrix(3,2 ));
126    osg::Matrix R(_inverseMatrix);
127    R(3,0) = R(3,1) = R(3,2) = 0.0;
128    _direction = osg::Vec3d(0,0,-1) * R; // camera up is +Z, regardless of CoordinateFrame
129
130    _stop();
131}
132
133osg::Matrixd UFOManipulator::getMatrix() const
134{
135    return (osg::Matrix::inverse(_offset) * _matrix);
136}
137
138osg::Matrixd UFOManipulator::getInverseMatrix() const
139{
140    return (_inverseMatrix * _offset);
141}
142
143void UFOManipulator::computeHomePosition()
144{
145    if( !_node.valid() )
146        return;
147
148    osg::BoundingSphere bs = _node->getBound();
149
150    /*
151       * Find the ground - Assumption: The ground is the hit of an intersection
152       * from a line segment extending from above to below the database at its
153       * horizontal center, that intersects the database closest to zero. */
154
155    osg::CoordinateFrame cf( getCoordinateFrame(bs.center()) ); // not sure what position to use here
156    osg::Vec3d upVec( getUpVector(cf) );
157
158    osg::Vec3d A = bs.center() + (upVec*(bs.radius()*2));
159    osg::Vec3d B = bs.center() + (-upVec*(bs.radius()*2));
160
161    if( (B-A).length() == 0.0)
162    {
163        return;
164    }
165
166    // start with it high
167    double ground = bs.radius() * 3;
168
169    osg::Vec3d ip;
170    if (intersect(A, B, ip))
171    {
172        double d = ip.length();
173        if( d < ground )
174            ground = d;
175    }
176    else
177    {
178        //OSG_WARN<<"UFOManipulator : I can't find the ground!"<<std::endl;
179        ground = 0.0;
180    }
181
182
183    osg::Vec3d p(bs.center() + upVec*( ground + _minHeightAboveGround*1.25 ) );
184    setHomePosition( p, p + getFrontVector(cf), upVec );
185}
186
187void UFOManipulator::init(const GUIEventAdapter&, GUIActionAdapter&)
188{
189    //home(ea.getTime());
190
191    _stop();
192}
193
194void UFOManipulator::home(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us)
195{
196    home(ea.getTime());
197    us.requestRedraw();
198    us.requestContinuousUpdate(false);
199
200}
201
202void UFOManipulator::home(double)
203{
204    if (getAutoComputeHomePosition())
205        computeHomePosition();
206
207    _position = _homeEye;
208    _direction = _homeCenter - _homeEye;
209    _direction.normalize();
210    _directionRotationRate = 0.0;
211
212    _inverseMatrix.makeLookAt( _homeEye, _homeCenter, _homeUp );
213    _matrix.invert( _inverseMatrix );
214
215    _offset.makeIdentity();
216
217    _forwardSpeed = 0.0;
218    _sideSpeed = 0.0;
219    _upSpeed = 0.0;
220}
221
222bool UFOManipulator::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter &aa)
223{
224    switch(ea.getEventType())
225    {
226        case(osgGA::GUIEventAdapter::FRAME):
227            _frame(ea,aa);
228            return false;
229        default:
230            break;
231    }
232
233    if (ea.getHandled()) return false;
234
235    switch(ea.getEventType())
236    {
237        case(osgGA::GUIEventAdapter::KEYUP):
238            _keyUp( ea, aa );
239            return false;
240            break;
241
242        case(osgGA::GUIEventAdapter::KEYDOWN):
243            _keyDown(ea, aa);
244            return false;
245            break;
246
247        case(osgGA::GUIEventAdapter::FRAME):
248            _frame(ea,aa);
249            return false;
250            break;
251
252        default:
253            return false;
254    }
255}
256
257void UFOManipulator::getUsage(osg::ApplicationUsage& usage) const
258{
259    /** Way too busy.  This needs to wait until we have a scrollable window
260    usage.addKeyboardMouseBinding("UFO Manipulator: <SpaceBar>",        "Reset the viewing angle to 0.0");
261    usage.addKeyboardMouseBinding("UFO Manipulator: <UpArrow>",         "Acceleration forward.");
262    usage.addKeyboardMouseBinding("UFO Manipulator: <DownArrow>",       "Acceleration backward (or deceleration forward");
263    usage.addKeyboardMouseBinding("UFO Manipulator: <LeftArrow>",       "Rotate view and direction of travel to the left.");
264    usage.addKeyboardMouseBinding("UFO Manipulator: <RightArrow>",      "Rotate view and direction of travel to the right.");
265    usage.addKeyboardMouseBinding("UFO Manipulator: <SpaceBar>",        "Brake.  Gradually decelerates linear and rotational movement.");
266    usage.addKeyboardMouseBinding("UFO Manipulator: <Shift/UpArrow>",   "Accelerate up.");
267    usage.addKeyboardMouseBinding("UFO Manipulator: <Shift/DownArrow>", "Accelerate down.");
268    usage.addKeyboardMouseBinding("UFO Manipulator: <Shift/LeftArrow>", "Accelerate (linearly) left.");
269    usage.addKeyboardMouseBinding("UFO Manipulator: <Shift/RightArrow>","Accelerate (linearly) right.");
270    usage.addKeyboardMouseBinding("UFO Manipulator: <Shift/SpaceBar>",  "Instant brake.  Immediately stop all linear and rotational movement.");
271    usage.addKeyboardMouseBinding("UFO Manipulator: <Ctrl/UpArrow>",    "Rotate view (but not direction of travel) up.");
272    usage.addKeyboardMouseBinding("UFO Manipulator: <Ctrl/DownArrow>",  "Rotate view (but not direction of travel) down.");
273    usage.addKeyboardMouseBinding("UFO Manipulator: <Ctrl/LeftArrow>",  "Rotate view (but not direction of travel) left.");
274    usage.addKeyboardMouseBinding("UFO Manipulator: <Ctrl/RightArrow>", "Rotate view (but not direction of travel) right.");
275    */
276    usage.addKeyboardMouseBinding("UFO: ", "Please see http://www.openscenegraph.org/html/UFOCameraManipulator.html");
277    // Keep this one as it might be confusing
278    usage.addKeyboardMouseBinding("UFO: H", "Reset the viewing position to home");
279}
280
281
282
283void UFOManipulator::_keyUp( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter & )
284{
285    switch( ea.getKey() )
286    {
287        case osgGA::GUIEventAdapter::KEY_Control_L:
288        case osgGA::GUIEventAdapter::KEY_Control_R:
289            _ctrl = false;
290            _decelerateOffsetRate = true;
291            _straightenOffset = false;
292            break;
293
294        case osgGA::GUIEventAdapter::KEY_Shift_L:
295        case osgGA::GUIEventAdapter::KEY_Shift_R:
296            _shift = false;
297            _decelerateUpSideRate = true;
298            break;
299    }
300}
301
302void UFOManipulator::_keyDown( const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter & )
303{
304    switch( ea.getKey() )
305    {
306        case osgGA::GUIEventAdapter::KEY_Control_L:
307        case osgGA::GUIEventAdapter::KEY_Control_R:
308            _ctrl = true;
309            break;
310
311        case osgGA::GUIEventAdapter::KEY_Shift_L :
312        case osgGA::GUIEventAdapter::KEY_Shift_R :
313            _shift = true;
314            break;
315
316        case osgGA::GUIEventAdapter::KEY_Up:
317            if( _ctrl )
318            {
319                _pitchOffsetRate -= _viewOffsetDelta;
320                _decelerateOffsetRate = false;
321            }
322            else
323            {
324                if( _shift )
325                {
326                    _upSpeed += _speedAccelerationFactor;
327                    _decelerateUpSideRate = false;
328                }
329                else
330                    _forwardSpeed += _speedAccelerationFactor;
331            }
332            break;
333
334        case osgGA::GUIEventAdapter::KEY_Down:
335            if( _ctrl )
336            {
337                _pitchOffsetRate += _viewOffsetDelta;
338                _decelerateOffsetRate = false;
339            }
340            else
341            {
342                if( _shift )
343                {
344                    _upSpeed -= _speedAccelerationFactor;
345                    _decelerateUpSideRate = false;
346                }
347                else
348                    _forwardSpeed -= _speedAccelerationFactor;
349            }
350            break;
351
352        case osgGA::GUIEventAdapter::KEY_Right:
353            if( _ctrl )
354            {
355                _yawOffsetRate += _viewOffsetDelta;
356                _decelerateOffsetRate = false;
357            }
358            else
359            {
360                if(_shift)
361                {
362                    _sideSpeed += _speedAccelerationFactor;
363                    _decelerateUpSideRate = false;
364                }
365                else
366                    _directionRotationRate -= _directionRotationAcceleration;
367            }
368            break;
369
370        case osgGA::GUIEventAdapter::KEY_Left:
371            if( _ctrl )
372            {
373                _yawOffsetRate -= _viewOffsetDelta;
374                _decelerateOffsetRate = false;
375            }
376            else
377            {
378                if(_shift)
379                {
380                    _sideSpeed -= _speedAccelerationFactor;
381                    _decelerateUpSideRate = false;
382                }
383                else
384                    _directionRotationRate += _directionRotationAcceleration;
385            }
386            break;
387
388        case osgGA::GUIEventAdapter::KEY_Return:
389            if( _ctrl )
390            {
391                _straightenOffset = true;
392            }
393            break;
394
395        case ' ':
396            if( _shift )
397            {
398                _stop();
399            }
400            else
401            {
402                if( fabs(_forwardSpeed) > 0.0 )
403                {
404                    _forwardSpeed *= _speedDecelerationFactor;
405
406                    if( fabs(_forwardSpeed ) < _speedEpsilon )
407                        _forwardSpeed = 0.0;
408                }
409                if( fabs(_sideSpeed) > 0.0 )
410                {
411                    _sideSpeed *= _speedDecelerationFactor;
412
413                    if( fabs( _sideSpeed ) < _speedEpsilon )
414                        _sideSpeed = 0.0;
415                }
416
417                if( fabs(_upSpeed) > 0.0 )
418                {
419                    _upSpeed *= _speedDecelerationFactor;
420
421                    if( fabs( _upSpeed ) < _speedEpsilon )
422                        _sideSpeed = 0.0;
423                }
424
425
426                if( fabs(_directionRotationRate ) > 0.0 )
427                {
428                    _directionRotationRate *= _directionRotationDeceleration;
429                    if( fabs( _directionRotationRate ) < _directionRotationEpsilon )
430                        _directionRotationRate = 0.0;
431                }
432
433            }
434            break;
435
436        case 'H':
437            home(ea.getTime());
438            break;
439    }
440
441}
442
443void UFOManipulator::_frame( const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter & )
444{
445    double t1 = ea.getTime();
446    if( _t0 == 0.0 )
447    {
448        _t0 = ea.getTime();
449        _dt = 0.0;
450    }
451    else
452    {
453        _dt = t1 - _t0;
454        _t0 = t1;
455    }
456
457    osg::CoordinateFrame cf( getCoordinateFrame(_position) );
458    osg::Vec3d upVec( getUpVector(cf) );
459    if( fabs( _directionRotationRate ) > _directionRotationEpsilon )
460    {
461      _direction = _direction * osg::Matrix::rotate( _directionRotationRate, upVec);
462    }
463
464    {
465      osg::Vec3d _sideVec = _direction * osg::Matrix::rotate( -M_PI*0.5, upVec);
466
467        _position += ((_direction       * _forwardSpeed) +
468                      (_sideVec         * _sideSpeed) +
469                      (upVec * _upSpeed))
470                       * _dt;
471
472    }
473
474    _pitchOffset += _pitchOffsetRate * _dt;
475    if( _pitchOffset >= M_PI || _pitchOffset < -M_PI )
476        _pitchOffset *= -1;
477
478    _yawOffset   += _yawOffsetRate   * _dt;
479    if( _yawOffset >= M_PI || _yawOffset < -M_PI )
480        _yawOffset *= -1;
481
482    _offset       = osg::Matrix::rotate( _yawOffset, getSideVector(cf),
483                                         _pitchOffset, getFrontVector(cf),
484                                         0.0, upVec);
485
486    _adjustPosition();
487
488    _inverseMatrix.makeLookAt( _position, _position + _direction, upVec);
489    _matrix.invert(_inverseMatrix);
490
491    if( _decelerateUpSideRate )
492    {
493        _upSpeed   *= 0.98;
494        _sideSpeed *= 0.98;
495    }
496
497    if( _decelerateOffsetRate )
498    {
499        _yawOffsetRate   *= 0.98;
500        _pitchOffsetRate *= 0.98;
501    }
502
503    if( _straightenOffset )
504    {
505        if( _shift )
506        {
507            _pitchOffset = 0.0;
508            _yawOffset = 0.0;
509            _pitchOffsetRate = 0.0;
510            _yawOffsetRate   = 0.0;
511        }
512        else
513        {
514            _pitchOffsetRate = 0.0;
515            _yawOffsetRate   = 0.0;
516            _pitchOffset *= 0.99;
517            _yawOffset *= 0.99;
518
519            if( fabs(_pitchOffset ) < 0.01 )
520                _pitchOffset = 0.0;
521            if( fabs(_yawOffset ) < 0.01 )
522                _pitchOffset = 0.0;
523
524        }
525        if( _pitchOffset == 0.0 && _yawOffset == 0.0 )
526            _straightenOffset = false;
527    }
528}
529
530void UFOManipulator::_adjustPosition()
531{
532    if( !_node.valid() )
533        return;
534
535    // Forward line segment at 3 times our intersect distance
536
537
538    typedef std::vector<osg::Vec3d> Intersections;
539    Intersections intersections;
540
541    // Check intersects infront.
542    osg::Vec3d ip;
543    if (intersect(_position,
544                  _position + (_direction * (_minDistanceInFront * 3.0)),
545                  ip ))
546    {
547        double d = (ip - _position).length();
548
549        if( d < _minDistanceInFront )
550        {
551            _position = ip + (_direction * -_minDistanceInFront);
552            _stop();
553        }
554    }
555
556    // Check intersects below.
557    osg::CoordinateFrame cf( getCoordinateFrame(_position) );
558    osg::Vec3d upVec( getUpVector(cf) );
559
560    if (intersect(_position,
561                  _position - upVec*_minHeightAboveGround*3,
562                  ip ))
563    {
564        double d = (ip - _position).length();
565
566        if( d < _minHeightAboveGround )
567          _position = ip + (upVec * _minHeightAboveGround);
568    }
569}
570
571
572void UFOManipulator::_stop()
573{
574    _forwardSpeed = 0.0;
575    _sideSpeed = 0.0;
576    _upSpeed = 0.0;
577    _directionRotationRate = 0.0;
578}
579
580void UFOManipulator::getCurrentPositionAsLookAt( osg::Vec3d& eye, osg::Vec3d& center, osg::Vec3d& up )
581{
582    eye = _position;
583    center = _position + _direction;
584    up.set(getUpVector(getCoordinateFrame(_position)));
585}
Note: See TracBrowser for help on using the browser.