~ubuntu-branches/debian/experimental/openscenegraph/experimental

« back to all changes in this revision

Viewing changes to OpenSceneGraph/src/osgGA/TerrainManipulator.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alberto Luaces
  • Date: 2011-01-29 11:36:29 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20110129113629-qisrm2kdqlurc7t3
Tags: 2.9.11-1
* Removed bug-555869-ftbfs_with_binutils_gold.dpatch since upstream has
  already taken care of the issue.
* Removed bug-528229.dpatch since the pkgconfig files are now also split
  in upstream.
* Removed explicit dependency on GLU.
* Upstream no longer includes osgIntrospection (Closes: #592420).
* Disabled zip plugin as its implementation stores an embedded copy of
  zlib.
* Enabled Qt support. Thanks James Goppert.
* Enabled SVG and PDF plugins. Thanks James Goppert.

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
*/
13
13
 
14
14
#include <osgGA/TerrainManipulator>
15
 
#include <osg/Quat>
16
 
#include <osg/Notify>
 
15
#include <osgUtil/LineSegmentIntersector>
17
16
#include <osg/io_utils>
18
 
#include <osgUtil/LineSegmentIntersector>
19
17
 
20
18
using namespace osg;
21
19
using namespace osgGA;
22
20
 
23
 
TerrainManipulator::TerrainManipulator()
24
 
{
25
 
    _rotationMode =ELEVATION_AZIM;
26
 
    _distance = 1.0;
27
 
 
28
 
    _thrown = false;
29
 
 
30
 
}
31
 
 
32
 
 
33
 
TerrainManipulator::~TerrainManipulator()
34
 
{
35
 
}
36
 
 
37
 
 
38
 
void TerrainManipulator::setRotationMode(RotationMode mode)
39
 
{
40
 
    _rotationMode = mode;
41
 
 
42
 
    // need to correct rotation.
43
 
}
44
 
 
45
 
void TerrainManipulator::setNode(osg::Node* node)
46
 
{
47
 
    _node = node;
48
 
 
49
 
    if (_node.get())
50
 
    {
51
 
        const osg::BoundingSphere& boundingSphere=_node->getBound();
52
 
        const float minimumDistanceScale = 0.001f;
53
 
        _minimumDistance = osg::clampBetween(
54
 
            float(boundingSphere._radius) * minimumDistanceScale,
55
 
            0.00001f,1.0f);
56
 
 
57
 
        osg::notify(osg::INFO)<<"Setting terrain manipulator _minimumDistance to "<<_minimumDistance<<std::endl;
58
 
    }
59
 
    if (getAutoComputeHomePosition()) computeHomePosition();
60
 
}
61
 
 
62
 
 
63
 
const osg::Node* TerrainManipulator::getNode() const
64
 
{
65
 
    return _node.get();
66
 
}
67
 
 
68
 
 
69
 
osg::Node* TerrainManipulator::getNode()
70
 
{
71
 
    return _node.get();
72
 
}
73
 
 
74
 
 
75
 
 
76
 
bool TerrainManipulator::intersect(const osg::Vec3d& start, const osg::Vec3d& end, osg::Vec3d& intersection) const
77
 
{
78
 
    osg::ref_ptr<osgUtil::LineSegmentIntersector> lsi = new osgUtil::LineSegmentIntersector(start,end);
79
 
 
80
 
    osgUtil::IntersectionVisitor iv(lsi.get());
81
 
    iv.setTraversalMask(_intersectTraversalMask);
82
 
    
83
 
    _node->accept(iv);
84
 
    
85
 
    if (lsi->containsIntersections())
86
 
    {
87
 
        intersection = lsi->getIntersections().begin()->getWorldIntersectPoint();
88
 
        return true;
89
 
    }
90
 
    return false;
91
 
}
92
 
 
93
 
 
94
 
void TerrainManipulator::home(const GUIEventAdapter& ,GUIActionAdapter& us)
95
 
{
96
 
    if (getAutoComputeHomePosition()) computeHomePosition();
97
 
 
98
 
    computePosition(_homeEye, _homeCenter, _homeUp);
99
 
    us.requestRedraw();
100
 
}
101
 
 
102
 
 
103
 
void TerrainManipulator::init(const GUIEventAdapter& ,GUIActionAdapter& )
104
 
{
105
 
    flushMouseEventStack();
106
 
}
107
 
 
108
 
 
109
 
void TerrainManipulator::getUsage(osg::ApplicationUsage& usage) const
110
 
{
111
 
    usage.addKeyboardMouseBinding("Terrain: Space","Reset the viewing position to home");
112
 
    usage.addKeyboardMouseBinding("Terrain: +","When in stereo, increase the fusion distance");
113
 
    usage.addKeyboardMouseBinding("Terrain: -","When in stereo, reduce the fusion distance");
114
 
}
115
 
 
116
 
bool TerrainManipulator::handle(const GUIEventAdapter& ea,GUIActionAdapter& us)
117
 
{
118
 
 
119
 
    switch(ea.getEventType())
120
 
    {
121
 
        case(GUIEventAdapter::FRAME):
122
 
            if (_thrown)
123
 
            {
124
 
                if (calcMovement()) us.requestRedraw();
125
 
            }
126
 
            return false;
127
 
        default:
128
 
            break;
129
 
    }
130
 
 
131
 
 
132
 
    if (ea.getHandled()) return false;
133
 
 
134
 
 
135
 
    switch(ea.getEventType())
136
 
    {
137
 
        case(GUIEventAdapter::PUSH):
138
 
        {
139
 
            flushMouseEventStack();
140
 
            addMouseEvent(ea);
141
 
            if (calcMovement()) us.requestRedraw();
142
 
            us.requestContinuousUpdate(false);
143
 
            _thrown = false;
144
 
            return true;
145
 
        }
146
 
 
147
 
        case(GUIEventAdapter::RELEASE):
148
 
        {
149
 
            if (ea.getButtonMask()==0)
150
 
            {
151
 
 
152
 
                if (isMouseMoving())
153
 
                {
154
 
                    if (calcMovement())
155
 
                    {
156
 
                        us.requestRedraw();
157
 
                        us.requestContinuousUpdate(true);
158
 
                        _thrown = true;
159
 
                    }
160
 
                }
161
 
                else
162
 
                {
163
 
                    flushMouseEventStack();
164
 
                    addMouseEvent(ea);
165
 
                    if (calcMovement()) us.requestRedraw();
166
 
                    us.requestContinuousUpdate(false);
167
 
                    _thrown = false;
168
 
                }
169
 
 
170
 
            }
171
 
            else
172
 
            {
173
 
                flushMouseEventStack();
174
 
                addMouseEvent(ea);
175
 
                if (calcMovement()) us.requestRedraw();
176
 
                us.requestContinuousUpdate(false);
177
 
                _thrown = false;
178
 
            }
179
 
            return true;
180
 
        }
181
 
 
182
 
        case(GUIEventAdapter::DRAG):
183
 
        {
184
 
            addMouseEvent(ea);
185
 
            if (calcMovement()) us.requestRedraw();
186
 
            us.requestContinuousUpdate(false);
187
 
            _thrown = false;
188
 
            return true;
189
 
        }
190
 
 
191
 
        case(GUIEventAdapter::MOVE):
192
 
        {
193
 
            return false;
194
 
        }
195
 
 
196
 
        case(GUIEventAdapter::KEYDOWN):
197
 
            if (ea.getKey()== GUIEventAdapter::KEY_Space)
198
 
            {
199
 
                flushMouseEventStack();
200
 
                _thrown = false;
201
 
                home(ea,us);
202
 
                us.requestRedraw();
203
 
                us.requestContinuousUpdate(false);
204
 
                return true;
205
 
            }
206
 
            return false;
207
 
        default:
208
 
            return false;
209
 
    }
210
 
}
211
 
 
212
 
 
213
 
bool TerrainManipulator::isMouseMoving()
214
 
{
215
 
    if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false;
216
 
 
217
 
    static const float velocity = 0.1f;
218
 
 
219
 
    float dx = _ga_t0->getXnormalized()-_ga_t1->getXnormalized();
220
 
    float dy = _ga_t0->getYnormalized()-_ga_t1->getYnormalized();
221
 
    float len = sqrtf(dx*dx+dy*dy);
222
 
    float dt = _ga_t0->getTime()-_ga_t1->getTime();
223
 
 
224
 
    return (len>dt*velocity);
225
 
}
226
 
 
227
 
 
228
 
void TerrainManipulator::flushMouseEventStack()
229
 
{
230
 
    _ga_t1 = NULL;
231
 
    _ga_t0 = NULL;
232
 
}
233
 
 
234
 
 
235
 
void TerrainManipulator::addMouseEvent(const GUIEventAdapter& ea)
236
 
{
237
 
    _ga_t1 = _ga_t0;
238
 
    _ga_t0 = &ea;
239
 
}
240
 
void TerrainManipulator::setByMatrix(const osg::Matrixd& matrix)
241
 
{
242
 
 
243
 
    osg::Vec3d lookVector(- matrix(2,0),-matrix(2,1),-matrix(2,2));
244
 
    osg::Vec3d eye(matrix(3,0),matrix(3,1),matrix(3,2));
245
 
 
246
 
    osg::notify(INFO)<<"eye point "<<eye<<std::endl;
247
 
    osg::notify(INFO)<<"lookVector "<<lookVector<<std::endl;
 
21
 
 
22
 
 
23
/// Constructor.
 
24
TerrainManipulator::TerrainManipulator( int flags )
 
25
    : inherited( flags )
 
26
{
 
27
}
 
28
 
 
29
 
 
30
/// Constructor.
 
31
TerrainManipulator::TerrainManipulator( const TerrainManipulator& tm, const CopyOp& copyOp )
 
32
    : inherited( tm, copyOp ),
 
33
      _previousUp( tm._previousUp )
 
34
{
 
35
}
 
36
 
 
37
 
 
38
/** Sets the manipulator rotation mode. RotationMode is now deprecated by
 
39
    osgGA::StandardManipulator::setVerticalAxisFixed() functionality,
 
40
    that is used across StandardManipulator derived classes.*/
 
41
void TerrainManipulator::setRotationMode( TerrainManipulator::RotationMode mode )
 
42
{
 
43
    setVerticalAxisFixed( mode == ELEVATION_AZIM );
 
44
}
 
45
 
 
46
 
 
47
/** Returns the manipulator rotation mode.*/
 
48
TerrainManipulator::RotationMode TerrainManipulator::getRotationMode() const
 
49
{
 
50
    return getVerticalAxisFixed() ? ELEVATION_AZIM : ELEVATION_AZIM_ROLL;
 
51
}
 
52
 
 
53
 
 
54
void TerrainManipulator::setNode( Node* node )
 
55
{
 
56
    inherited::setNode( node );
 
57
 
 
58
    // update model size
 
59
    if( _flags & UPDATE_MODEL_SIZE )
 
60
    {
 
61
        if( _node.valid() )
 
62
        {
 
63
            setMinimumDistance( clampBetween( _modelSize * 0.001, 0.00001, 1.0 ) );
 
64
            OSG_INFO << "TerrainManipulator: setting _minimumDistance to "
 
65
                     << _minimumDistance << std::endl;
 
66
        }
 
67
    }
 
68
}
 
69
 
 
70
 
 
71
void TerrainManipulator::setByMatrix(const Matrixd& matrix)
 
72
{
 
73
 
 
74
    Vec3d lookVector(- matrix(2,0),-matrix(2,1),-matrix(2,2));
 
75
    Vec3d eye(matrix(3,0),matrix(3,1),matrix(3,2));
 
76
 
 
77
    OSG_INFO<<"eye point "<<eye<<std::endl;
 
78
    OSG_INFO<<"lookVector "<<lookVector<<std::endl;
248
79
 
249
80
    if (!_node)
250
81
    {
256
87
 
257
88
 
258
89
    // need to reintersect with the terrain
259
 
    const osg::BoundingSphere& bs = _node->getBound();
 
90
    const BoundingSphere& bs = _node->getBound();
260
91
    float distance = (eye-bs.center()).length() + _node->getBound().radius();
261
 
    osg::Vec3d start_segment = eye;
262
 
    osg::Vec3d end_segment = eye + lookVector*distance;
263
 
    
264
 
    osg::Vec3d ip;
 
92
    Vec3d start_segment = eye;
 
93
    Vec3d end_segment = eye + lookVector*distance;
 
94
 
 
95
    Vec3d ip;
265
96
    bool hitFound = false;
266
97
    if (intersect(start_segment, end_segment, ip))
267
98
    {
268
 
        notify(INFO) << "Hit terrain ok A"<< std::endl;
 
99
        OSG_INFO << "Hit terrain ok A"<< std::endl;
269
100
        _center = ip;
270
101
 
271
102
        _distance = (eye-ip).length();
272
103
 
273
 
        osg::Matrixd rotation_matrix = osg::Matrixd::translate(0.0,0.0,-_distance)*
274
 
                                       matrix*
275
 
                                       osg::Matrixd::translate(-_center);
 
104
        Matrixd rotation_matrix = Matrixd::translate(0.0,0.0,-_distance)*
 
105
                                  matrix*
 
106
                                  Matrixd::translate(-_center);
276
107
 
277
108
        _rotation = rotation_matrix.getRotate();
278
109
 
304
135
    clampOrientation();
305
136
}
306
137
 
307
 
osg::Matrixd TerrainManipulator::getMatrix() const
308
 
{
309
 
    return osg::Matrixd::translate(0.0,0.0,_distance)*osg::Matrixd::rotate(_rotation)*osg::Matrixd::translate(_center);
310
 
}
311
 
 
312
 
osg::Matrixd TerrainManipulator::getInverseMatrix() const
313
 
{
314
 
    return osg::Matrixd::translate(-_center)*osg::Matrixd::rotate(_rotation.inverse())*osg::Matrixd::translate(0.0,0.0,-_distance);
315
 
}
316
 
 
317
 
void TerrainManipulator::computePosition(const osg::Vec3d& eye,const osg::Vec3d& center,const osg::Vec3d& up)
 
138
 
 
139
void TerrainManipulator::setTransformation( const osg::Vec3d& eye, const osg::Vec3d& center, const osg::Vec3d& up )
318
140
{
319
141
    if (!_node) return;
320
142
 
321
143
    // compute rotation matrix
322
 
    osg::Vec3d lv(center-eye);
 
144
    Vec3d lv(center-eye);
323
145
    _distance = lv.length();
324
146
    _center = center;
325
147
 
326
 
    osg::notify(osg::INFO) << "In compute"<< std::endl;
 
148
    OSG_INFO << "In compute"<< std::endl;
327
149
 
328
150
    if (_node.valid())
329
151
    {
331
153
 
332
154
        double distance = lv.length();
333
155
        double maxDistance = distance+2*(eye-_node->getBound().center()).length();
334
 
        osg::Vec3d farPosition = eye+lv*(maxDistance/distance);
335
 
        osg::Vec3d endPoint = center;
 
156
        Vec3d farPosition = eye+lv*(maxDistance/distance);
 
157
        Vec3d endPoint = center;
336
158
        for(int i=0;
337
159
            !hitFound && i<2;
338
160
            ++i, endPoint = farPosition)
339
161
        {
340
162
            // compute the intersection with the scene.
341
 
            
342
 
            osg::Vec3d ip;
 
163
 
 
164
            Vec3d ip;
343
165
            if (intersect(eye, endPoint, ip))
344
166
            {
345
167
                _center = ip;
353
175
    // note LookAt = inv(CF)*inv(RM)*inv(T) which is equivalent to:
354
176
    // inv(R) = CF*LookAt.
355
177
 
356
 
    osg::Matrixd rotation_matrix = osg::Matrixd::lookAt(eye,center,up);
 
178
    Matrixd rotation_matrix = Matrixd::lookAt(eye,center,up);
357
179
 
358
180
    _rotation = rotation_matrix.getRotate().inverse();
359
181
 
364
186
}
365
187
 
366
188
 
367
 
bool TerrainManipulator::calcMovement()
368
 
{
369
 
    // return if less then two events have been added.
370
 
    if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false;
371
 
 
372
 
    double dx = _ga_t0->getXnormalized()-_ga_t1->getXnormalized();
373
 
    double dy = _ga_t0->getYnormalized()-_ga_t1->getYnormalized();
374
 
 
375
 
 
376
 
    // return if there is no movement.
377
 
    if (dx==0 && dy==0) return false;
378
 
 
379
 
    unsigned int buttonMask = _ga_t1->getButtonMask();
380
 
    if (buttonMask==GUIEventAdapter::LEFT_MOUSE_BUTTON)
381
 
    {
382
 
 
383
 
        if (_rotationMode==ELEVATION_AZIM_ROLL)
384
 
        {
385
 
            // rotate camera.
386
 
            osg::Vec3 axis;
387
 
            double angle;
388
 
 
389
 
            double px0 = _ga_t0->getXnormalized();
390
 
            double py0 = _ga_t0->getYnormalized();
391
 
 
392
 
            double px1 = _ga_t1->getXnormalized();
393
 
            double py1 = _ga_t1->getYnormalized();
394
 
 
395
 
 
396
 
            trackball(axis,angle,px1,py1,px0,py0);
397
 
 
398
 
            osg::Quat new_rotate;
399
 
            new_rotate.makeRotate(angle,axis);
400
 
 
401
 
            _rotation = _rotation*new_rotate;
 
189
bool TerrainManipulator::intersect( const Vec3d& start, const Vec3d& end, Vec3d& intersection ) const
 
190
{
 
191
    ref_ptr<osgUtil::LineSegmentIntersector> lsi = new osgUtil::LineSegmentIntersector(start,end);
 
192
 
 
193
    osgUtil::IntersectionVisitor iv(lsi.get());
 
194
    iv.setTraversalMask(_intersectTraversalMask);
 
195
 
 
196
    _node->accept(iv);
 
197
 
 
198
    if (lsi->containsIntersections())
 
199
    {
 
200
        intersection = lsi->getIntersections().begin()->getWorldIntersectPoint();
 
201
        return true;
 
202
    }
 
203
    return false;
 
204
}
 
205
 
 
206
 
 
207
bool TerrainManipulator::performMovementMiddleMouseButton( const double eventTimeDelta, const double dx, const double dy )
 
208
{
 
209
    // pan model.
 
210
    double scale = -0.3f * _distance * getThrowScale( eventTimeDelta );
 
211
 
 
212
    Matrixd rotation_matrix;
 
213
    rotation_matrix.makeRotate(_rotation);
 
214
 
 
215
 
 
216
    // compute look vector.
 
217
    Vec3d lookVector = -getUpVector(rotation_matrix);
 
218
    Vec3d sideVector = getSideVector(rotation_matrix);
 
219
    Vec3d upVector = getFrontVector(rotation_matrix);
 
220
 
 
221
    // CoordinateFrame coordinateFrame = getCoordinateFrame(_center);
 
222
    // Vec3d localUp = getUpVector(coordinateFrame);
 
223
    Vec3d localUp = _previousUp;
 
224
 
 
225
    Vec3d forwardVector =localUp^sideVector;
 
226
    sideVector = forwardVector^localUp;
 
227
 
 
228
    forwardVector.normalize();
 
229
    sideVector.normalize();
 
230
 
 
231
    Vec3d dv = forwardVector * (dy*scale) + sideVector * (dx*scale);
 
232
 
 
233
    _center += dv;
 
234
 
 
235
    // need to recompute the intersection point along the look vector.
 
236
 
 
237
    bool hitFound = false;
 
238
 
 
239
    if (_node.valid())
 
240
    {
 
241
        // now reorientate the coordinate frame to the frame coords.
 
242
        CoordinateFrame coordinateFrame =  getCoordinateFrame(_center);
 
243
 
 
244
        // need to reintersect with the terrain
 
245
        double distance = _node->getBound().radius()*0.25f;
 
246
 
 
247
        Vec3d ip1;
 
248
        Vec3d ip2;
 
249
        bool hit_ip1 = intersect(_center, _center + getUpVector(coordinateFrame) * distance, ip1);
 
250
        bool hit_ip2 = intersect(_center, _center - getUpVector(coordinateFrame) * distance, ip2);
 
251
        if (hit_ip1)
 
252
        {
 
253
            if (hit_ip2)
 
254
            {
 
255
                _center = (_center-ip1).length2() < (_center-ip2).length2() ?
 
256
                            ip1 :
 
257
                            ip2;
 
258
 
 
259
                hitFound = true;
 
260
            }
 
261
            else
 
262
            {
 
263
                _center = ip1;
 
264
                hitFound = true;
 
265
            }
 
266
        }
 
267
        else if (hit_ip2)
 
268
        {
 
269
            _center = ip2;
 
270
            hitFound = true;
 
271
        }
 
272
 
 
273
        if (!hitFound)
 
274
        {
 
275
            // ??
 
276
            OSG_INFO<<"TerrainManipulator unable to intersect with terrain."<<std::endl;
 
277
        }
 
278
 
 
279
        coordinateFrame = getCoordinateFrame(_center);
 
280
        Vec3d new_localUp = getUpVector(coordinateFrame);
 
281
 
 
282
 
 
283
        Quat pan_rotation;
 
284
        pan_rotation.makeRotate(localUp,new_localUp);
 
285
 
 
286
        if (!pan_rotation.zeroRotation())
 
287
        {
 
288
            _rotation = _rotation * pan_rotation;
 
289
            _previousUp = new_localUp;
 
290
            //OSG_NOTICE<<"Rotating from "<<localUp<<" to "<<new_localUp<<"  angle = "<<acos(localUp*new_localUp/(localUp.length()*new_localUp.length()))<<std::endl;
 
291
 
 
292
            //clampOrientation();
402
293
        }
403
294
        else
404
295
        {
405
 
            osg::Matrix rotation_matrix;
406
 
            rotation_matrix.makeRotate(_rotation);
407
 
 
408
 
            osg::Vec3d lookVector = -getUpVector(rotation_matrix);
409
 
            osg::Vec3d sideVector = getSideVector(rotation_matrix);
410
 
            osg::Vec3d upVector = getFrontVector(rotation_matrix);
411
 
 
412
 
            CoordinateFrame coordinateFrame = getCoordinateFrame(_center);
413
 
            osg::Vec3d localUp = getUpVector(coordinateFrame);
414
 
            //osg::Vec3d localUp = _previousUp;
415
 
 
416
 
 
417
 
            osg::Vec3d forwardVector = localUp^sideVector;
418
 
            sideVector = forwardVector^localUp;
419
 
 
420
 
            forwardVector.normalize();
421
 
            sideVector.normalize();
422
 
 
423
 
            osg::Quat rotate_elevation;
424
 
            rotate_elevation.makeRotate(dy,sideVector);
425
 
 
426
 
            osg::Quat rotate_azim;
427
 
            rotate_azim.makeRotate(-dx,localUp);
428
 
 
429
 
            _rotation = _rotation * rotate_elevation * rotate_azim;
430
 
 
431
 
        }
432
 
 
433
 
        return true;
434
 
 
435
 
    }
436
 
    else if (buttonMask==GUIEventAdapter::MIDDLE_MOUSE_BUTTON ||
437
 
        buttonMask==(GUIEventAdapter::LEFT_MOUSE_BUTTON|GUIEventAdapter::RIGHT_MOUSE_BUTTON))
438
 
    {
439
 
 
440
 
        // pan model.
441
 
        double scale = -0.3f*_distance;
442
 
 
443
 
        osg::Matrixd rotation_matrix;
444
 
        rotation_matrix.makeRotate(_rotation);
445
 
 
446
 
 
447
 
        // compute look vector.
448
 
        osg::Vec3d lookVector = -getUpVector(rotation_matrix);
449
 
        osg::Vec3d sideVector = getSideVector(rotation_matrix);
450
 
        osg::Vec3d upVector = getFrontVector(rotation_matrix);
451
 
 
452
 
        // CoordinateFrame coordinateFrame = getCoordinateFrame(_center);
453
 
        // osg::Vec3d localUp = getUpVector(coordinateFrame);
454
 
        osg::Vec3d localUp = _previousUp;
455
 
 
456
 
        osg::Vec3d forwardVector =localUp^sideVector;
457
 
        sideVector = forwardVector^localUp;
458
 
 
459
 
        forwardVector.normalize();
460
 
        sideVector.normalize();
461
 
 
462
 
        osg::Vec3d dv = forwardVector * (dy*scale) + sideVector * (dx*scale);
463
 
 
464
 
        _center += dv;
465
 
 
466
 
        // need to recompute the intersection point along the look vector.
467
 
 
468
 
        bool hitFound = false;
469
 
 
470
 
        if (_node.valid())
471
 
        {
472
 
 
473
 
            // now reorientate the coordinate frame to the frame coords.
474
 
            CoordinateFrame coordinateFrame =  getCoordinateFrame(_center);
475
 
 
476
 
            // need to reintersect with the terrain
477
 
            double distance = _node->getBound().radius()*0.25f;
478
 
            
479
 
            osg::Vec3d ip1;
480
 
            osg::Vec3d ip2;
481
 
            bool hit_ip1 = intersect(_center, _center + getUpVector(coordinateFrame) * distance, ip1);
482
 
            bool hit_ip2 = intersect(_center, _center - getUpVector(coordinateFrame) * distance, ip2);
483
 
            if (hit_ip1)
484
 
            {
485
 
                if (hit_ip2)
486
 
                {
487
 
                    _center = (_center-ip1).length2() < (_center-ip2).length2() ?
488
 
                                ip1 :
489
 
                                ip2;
490
 
                                
491
 
                    hitFound = true;
492
 
                }
493
 
                else
494
 
                {
495
 
                    _center = ip1;
496
 
                    hitFound = true;
497
 
                }
498
 
            }
499
 
            else if (hit_ip2)
500
 
            {
501
 
                _center = ip2;
502
 
                hitFound = true;
503
 
            }
504
 
            
505
 
            if (!hitFound)
506
 
            {
507
 
                // ??
508
 
                osg::notify(INFO)<<"TerrainManipulator unable to intersect with terrain."<<std::endl;
509
 
            }
510
 
 
511
 
            coordinateFrame = getCoordinateFrame(_center);
512
 
            osg::Vec3d new_localUp = getUpVector(coordinateFrame);
513
 
 
514
 
 
515
 
            osg::Quat pan_rotation;
516
 
            pan_rotation.makeRotate(localUp,new_localUp);
517
 
 
518
 
            if (!pan_rotation.zeroRotation())
519
 
            {
520
 
                _rotation = _rotation * pan_rotation;
521
 
                _previousUp = new_localUp;
522
 
                //osg::notify(osg::NOTICE)<<"Rotating from "<<localUp<<" to "<<new_localUp<<"  angle = "<<acos(localUp*new_localUp/(localUp.length()*new_localUp.length()))<<std::endl;
523
 
 
524
 
                //clampOrientation();
525
 
            }
526
 
            else
527
 
            {
528
 
                osg::notify(osg::INFO)<<"New up orientation nearly inline - no need to rotate"<<std::endl;
529
 
            }
530
 
        }
531
 
 
532
 
        return true;
533
 
    }
534
 
    else if (buttonMask==GUIEventAdapter::RIGHT_MOUSE_BUTTON)
535
 
    {
536
 
 
537
 
        // zoom model.
538
 
 
539
 
        double fd = _distance;
540
 
        double scale = 1.0f+dy;
541
 
        if (fd*scale>_minimumDistance)
542
 
        {
543
 
 
544
 
            _distance *= scale;
545
 
 
546
 
        } else
547
 
        {
548
 
            _distance = _minimumDistance;
549
 
        }
550
 
 
551
 
        return true;
552
 
 
553
 
    }
554
 
 
555
 
    return false;
556
 
}
 
296
            OSG_INFO<<"New up orientation nearly inline - no need to rotate"<<std::endl;
 
297
        }
 
298
    }
 
299
 
 
300
    return true;
 
301
}
 
302
 
 
303
 
 
304
bool TerrainManipulator::performMovementRightMouseButton( const double eventTimeDelta, const double dx, const double dy )
 
305
{
 
306
    // zoom model
 
307
    zoomModel( dy * getThrowScale( eventTimeDelta ), false );
 
308
    return true;
 
309
}
 
310
 
557
311
 
558
312
void TerrainManipulator::clampOrientation()
559
313
{
560
 
    if (_rotationMode==ELEVATION_AZIM)
 
314
    if (!getVerticalAxisFixed())
561
315
    {
562
 
        osg::Matrixd rotation_matrix;
 
316
        Matrixd rotation_matrix;
563
317
        rotation_matrix.makeRotate(_rotation);
564
318
 
565
 
        osg::Vec3d lookVector = -getUpVector(rotation_matrix);
566
 
        osg::Vec3d upVector = getFrontVector(rotation_matrix);
 
319
        Vec3d lookVector = -getUpVector(rotation_matrix);
 
320
        Vec3d upVector = getFrontVector(rotation_matrix);
567
321
 
568
322
        CoordinateFrame coordinateFrame = getCoordinateFrame(_center);
569
 
        osg::Vec3d localUp = getUpVector(coordinateFrame);
570
 
        //osg::Vec3d localUp = _previousUp;
 
323
        Vec3d localUp = getUpVector(coordinateFrame);
 
324
        //Vec3d localUp = _previousUp;
571
325
 
572
 
        osg::Vec3d sideVector = lookVector ^ localUp;
 
326
        Vec3d sideVector = lookVector ^ localUp;
573
327
 
574
328
        if (sideVector.length()<0.1)
575
329
        {
576
 
            osg::notify(osg::INFO)<<"Side vector short "<<sideVector.length()<<std::endl;
 
330
            OSG_INFO<<"Side vector short "<<sideVector.length()<<std::endl;
577
331
 
578
332
            sideVector = upVector^localUp;
579
333
            sideVector.normalize();
580
 
 
581
334
        }
582
335
 
583
336
        Vec3d newUpVector = sideVector^lookVector;
584
337
        newUpVector.normalize();
585
338
 
586
 
        osg::Quat rotate_roll;
 
339
        Quat rotate_roll;
587
340
        rotate_roll.makeRotate(upVector,newUpVector);
588
341
 
589
342
        if (!rotate_roll.zeroRotation())
592
345
        }
593
346
    }
594
347
}
595
 
 
596
 
 
597
 
/*
598
 
 * This size should really be based on the distance from the center of
599
 
 * rotation to the point on the object underneath the mouse.  That
600
 
 * point would then track the mouse as closely as possible.  This is a
601
 
 * simple example, though, so that is left as an Exercise for the
602
 
 * Programmer.
603
 
 */
604
 
const float TRACKBALLSIZE = 0.8f;
605
 
 
606
 
/*
607
 
 * Ok, simulate a track-ball.  Project the points onto the virtual
608
 
 * trackball, then figure out the axis of rotation, which is the cross
609
 
 * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0)
610
 
 * Note:  This is a deformed trackball-- is a trackball in the center,
611
 
 * but is deformed into a hyperbolic sheet of rotation away from the
612
 
 * center.  This particular function was chosen after trying out
613
 
 * several variations.
614
 
 *
615
 
 * It is assumed that the arguments to this routine are in the range
616
 
 * (-1.0 ... 1.0)
617
 
 */
618
 
void TerrainManipulator::trackball(osg::Vec3& axis,double & angle, double  p1x, double  p1y, double  p2x, double  p2y)
619
 
{
620
 
    /*
621
 
     * First, figure out z-coordinates for projection of P1 and P2 to
622
 
     * deformed sphere
623
 
     */
624
 
 
625
 
    osg::Matrix rotation_matrix(_rotation);
626
 
 
627
 
 
628
 
    osg::Vec3d uv = osg::Vec3d(0.0,1.0,0.0)*rotation_matrix;
629
 
    osg::Vec3d sv = osg::Vec3d(1.0,0.0,0.0)*rotation_matrix;
630
 
    osg::Vec3d lv = osg::Vec3d(0.0,0.0,-1.0)*rotation_matrix;
631
 
 
632
 
    osg::Vec3d p1 = sv*p1x+uv*p1y-lv*tb_project_to_sphere(TRACKBALLSIZE,p1x,p1y);
633
 
    osg::Vec3d p2 = sv*p2x+uv*p2y-lv*tb_project_to_sphere(TRACKBALLSIZE,p2x,p2y);
634
 
 
635
 
    /*
636
 
     *  Now, we want the cross product of P1 and P2
637
 
     */
638
 
 
639
 
// Robert,
640
 
//
641
 
// This was the quick 'n' dirty  fix to get the trackball doing the right
642
 
// thing after fixing the Quat rotations to be right-handed.  You may want
643
 
// to do something more elegant.
644
 
//   axis = p1^p2;
645
 
axis = p2^p1;
646
 
    axis.normalize();
647
 
 
648
 
    /*
649
 
     *  Figure out how much to rotate around that axis.
650
 
     */
651
 
    double t = (p2-p1).length() / (2.0*TRACKBALLSIZE);
652
 
 
653
 
    /*
654
 
     * Avoid problems with out-of-control values...
655
 
     */
656
 
    if (t > 1.0) t = 1.0;
657
 
    if (t < -1.0) t = -1.0;
658
 
    angle = inRadians(asin(t));
659
 
 
660
 
}
661
 
 
662
 
 
663
 
/*
664
 
 * Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
665
 
 * if we are away from the center of the sphere.
666
 
 */
667
 
double TerrainManipulator::tb_project_to_sphere(double  r, double  x, double  y)
668
 
{
669
 
    float d, t, z;
670
 
 
671
 
    d = sqrt(x*x + y*y);
672
 
                                 /* Inside sphere */
673
 
    if (d < r * 0.70710678118654752440)
674
 
    {
675
 
        z = sqrt(r*r - d*d);
676
 
    }                            /* On hyperbola */
677
 
    else
678
 
    {
679
 
        t = r / 1.41421356237309504880;
680
 
        z = t*t / d;
681
 
    }
682
 
    return z;
683
 
}