14
14
#include <osgGA/TerrainManipulator>
15
#include <osgUtil/LineSegmentIntersector>
17
16
#include <osg/io_utils>
18
#include <osgUtil/LineSegmentIntersector>
20
18
using namespace osg;
21
19
using namespace osgGA;
23
TerrainManipulator::TerrainManipulator()
25
_rotationMode =ELEVATION_AZIM;
33
TerrainManipulator::~TerrainManipulator()
38
void TerrainManipulator::setRotationMode(RotationMode mode)
42
// need to correct rotation.
45
void TerrainManipulator::setNode(osg::Node* node)
51
const osg::BoundingSphere& boundingSphere=_node->getBound();
52
const float minimumDistanceScale = 0.001f;
53
_minimumDistance = osg::clampBetween(
54
float(boundingSphere._radius) * minimumDistanceScale,
57
osg::notify(osg::INFO)<<"Setting terrain manipulator _minimumDistance to "<<_minimumDistance<<std::endl;
59
if (getAutoComputeHomePosition()) computeHomePosition();
63
const osg::Node* TerrainManipulator::getNode() const
69
osg::Node* TerrainManipulator::getNode()
76
bool TerrainManipulator::intersect(const osg::Vec3d& start, const osg::Vec3d& end, osg::Vec3d& intersection) const
78
osg::ref_ptr<osgUtil::LineSegmentIntersector> lsi = new osgUtil::LineSegmentIntersector(start,end);
80
osgUtil::IntersectionVisitor iv(lsi.get());
81
iv.setTraversalMask(_intersectTraversalMask);
85
if (lsi->containsIntersections())
87
intersection = lsi->getIntersections().begin()->getWorldIntersectPoint();
94
void TerrainManipulator::home(const GUIEventAdapter& ,GUIActionAdapter& us)
96
if (getAutoComputeHomePosition()) computeHomePosition();
98
computePosition(_homeEye, _homeCenter, _homeUp);
103
void TerrainManipulator::init(const GUIEventAdapter& ,GUIActionAdapter& )
105
flushMouseEventStack();
109
void TerrainManipulator::getUsage(osg::ApplicationUsage& usage) const
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");
116
bool TerrainManipulator::handle(const GUIEventAdapter& ea,GUIActionAdapter& us)
119
switch(ea.getEventType())
121
case(GUIEventAdapter::FRAME):
124
if (calcMovement()) us.requestRedraw();
132
if (ea.getHandled()) return false;
135
switch(ea.getEventType())
137
case(GUIEventAdapter::PUSH):
139
flushMouseEventStack();
141
if (calcMovement()) us.requestRedraw();
142
us.requestContinuousUpdate(false);
147
case(GUIEventAdapter::RELEASE):
149
if (ea.getButtonMask()==0)
157
us.requestContinuousUpdate(true);
163
flushMouseEventStack();
165
if (calcMovement()) us.requestRedraw();
166
us.requestContinuousUpdate(false);
173
flushMouseEventStack();
175
if (calcMovement()) us.requestRedraw();
176
us.requestContinuousUpdate(false);
182
case(GUIEventAdapter::DRAG):
185
if (calcMovement()) us.requestRedraw();
186
us.requestContinuousUpdate(false);
191
case(GUIEventAdapter::MOVE):
196
case(GUIEventAdapter::KEYDOWN):
197
if (ea.getKey()== GUIEventAdapter::KEY_Space)
199
flushMouseEventStack();
203
us.requestContinuousUpdate(false);
213
bool TerrainManipulator::isMouseMoving()
215
if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false;
217
static const float velocity = 0.1f;
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();
224
return (len>dt*velocity);
228
void TerrainManipulator::flushMouseEventStack()
235
void TerrainManipulator::addMouseEvent(const GUIEventAdapter& ea)
240
void TerrainManipulator::setByMatrix(const osg::Matrixd& matrix)
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));
246
osg::notify(INFO)<<"eye point "<<eye<<std::endl;
247
osg::notify(INFO)<<"lookVector "<<lookVector<<std::endl;
24
TerrainManipulator::TerrainManipulator( int flags )
31
TerrainManipulator::TerrainManipulator( const TerrainManipulator& tm, const CopyOp& copyOp )
32
: inherited( tm, copyOp ),
33
_previousUp( tm._previousUp )
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 )
43
setVerticalAxisFixed( mode == ELEVATION_AZIM );
47
/** Returns the manipulator rotation mode.*/
48
TerrainManipulator::RotationMode TerrainManipulator::getRotationMode() const
50
return getVerticalAxisFixed() ? ELEVATION_AZIM : ELEVATION_AZIM_ROLL;
54
void TerrainManipulator::setNode( Node* node )
56
inherited::setNode( node );
59
if( _flags & UPDATE_MODEL_SIZE )
63
setMinimumDistance( clampBetween( _modelSize * 0.001, 0.00001, 1.0 ) );
64
OSG_INFO << "TerrainManipulator: setting _minimumDistance to "
65
<< _minimumDistance << std::endl;
71
void TerrainManipulator::setByMatrix(const Matrixd& matrix)
74
Vec3d lookVector(- matrix(2,0),-matrix(2,1),-matrix(2,2));
75
Vec3d eye(matrix(3,0),matrix(3,1),matrix(3,2));
77
OSG_INFO<<"eye point "<<eye<<std::endl;
78
OSG_INFO<<"lookVector "<<lookVector<<std::endl;
367
bool TerrainManipulator::calcMovement()
369
// return if less then two events have been added.
370
if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false;
372
double dx = _ga_t0->getXnormalized()-_ga_t1->getXnormalized();
373
double dy = _ga_t0->getYnormalized()-_ga_t1->getYnormalized();
376
// return if there is no movement.
377
if (dx==0 && dy==0) return false;
379
unsigned int buttonMask = _ga_t1->getButtonMask();
380
if (buttonMask==GUIEventAdapter::LEFT_MOUSE_BUTTON)
383
if (_rotationMode==ELEVATION_AZIM_ROLL)
389
double px0 = _ga_t0->getXnormalized();
390
double py0 = _ga_t0->getYnormalized();
392
double px1 = _ga_t1->getXnormalized();
393
double py1 = _ga_t1->getYnormalized();
396
trackball(axis,angle,px1,py1,px0,py0);
398
osg::Quat new_rotate;
399
new_rotate.makeRotate(angle,axis);
401
_rotation = _rotation*new_rotate;
189
bool TerrainManipulator::intersect( const Vec3d& start, const Vec3d& end, Vec3d& intersection ) const
191
ref_ptr<osgUtil::LineSegmentIntersector> lsi = new osgUtil::LineSegmentIntersector(start,end);
193
osgUtil::IntersectionVisitor iv(lsi.get());
194
iv.setTraversalMask(_intersectTraversalMask);
198
if (lsi->containsIntersections())
200
intersection = lsi->getIntersections().begin()->getWorldIntersectPoint();
207
bool TerrainManipulator::performMovementMiddleMouseButton( const double eventTimeDelta, const double dx, const double dy )
210
double scale = -0.3f * _distance * getThrowScale( eventTimeDelta );
212
Matrixd rotation_matrix;
213
rotation_matrix.makeRotate(_rotation);
216
// compute look vector.
217
Vec3d lookVector = -getUpVector(rotation_matrix);
218
Vec3d sideVector = getSideVector(rotation_matrix);
219
Vec3d upVector = getFrontVector(rotation_matrix);
221
// CoordinateFrame coordinateFrame = getCoordinateFrame(_center);
222
// Vec3d localUp = getUpVector(coordinateFrame);
223
Vec3d localUp = _previousUp;
225
Vec3d forwardVector =localUp^sideVector;
226
sideVector = forwardVector^localUp;
228
forwardVector.normalize();
229
sideVector.normalize();
231
Vec3d dv = forwardVector * (dy*scale) + sideVector * (dx*scale);
235
// need to recompute the intersection point along the look vector.
237
bool hitFound = false;
241
// now reorientate the coordinate frame to the frame coords.
242
CoordinateFrame coordinateFrame = getCoordinateFrame(_center);
244
// need to reintersect with the terrain
245
double distance = _node->getBound().radius()*0.25f;
249
bool hit_ip1 = intersect(_center, _center + getUpVector(coordinateFrame) * distance, ip1);
250
bool hit_ip2 = intersect(_center, _center - getUpVector(coordinateFrame) * distance, ip2);
255
_center = (_center-ip1).length2() < (_center-ip2).length2() ?
276
OSG_INFO<<"TerrainManipulator unable to intersect with terrain."<<std::endl;
279
coordinateFrame = getCoordinateFrame(_center);
280
Vec3d new_localUp = getUpVector(coordinateFrame);
284
pan_rotation.makeRotate(localUp,new_localUp);
286
if (!pan_rotation.zeroRotation())
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;
292
//clampOrientation();
405
osg::Matrix rotation_matrix;
406
rotation_matrix.makeRotate(_rotation);
408
osg::Vec3d lookVector = -getUpVector(rotation_matrix);
409
osg::Vec3d sideVector = getSideVector(rotation_matrix);
410
osg::Vec3d upVector = getFrontVector(rotation_matrix);
412
CoordinateFrame coordinateFrame = getCoordinateFrame(_center);
413
osg::Vec3d localUp = getUpVector(coordinateFrame);
414
//osg::Vec3d localUp = _previousUp;
417
osg::Vec3d forwardVector = localUp^sideVector;
418
sideVector = forwardVector^localUp;
420
forwardVector.normalize();
421
sideVector.normalize();
423
osg::Quat rotate_elevation;
424
rotate_elevation.makeRotate(dy,sideVector);
426
osg::Quat rotate_azim;
427
rotate_azim.makeRotate(-dx,localUp);
429
_rotation = _rotation * rotate_elevation * rotate_azim;
436
else if (buttonMask==GUIEventAdapter::MIDDLE_MOUSE_BUTTON ||
437
buttonMask==(GUIEventAdapter::LEFT_MOUSE_BUTTON|GUIEventAdapter::RIGHT_MOUSE_BUTTON))
441
double scale = -0.3f*_distance;
443
osg::Matrixd rotation_matrix;
444
rotation_matrix.makeRotate(_rotation);
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);
452
// CoordinateFrame coordinateFrame = getCoordinateFrame(_center);
453
// osg::Vec3d localUp = getUpVector(coordinateFrame);
454
osg::Vec3d localUp = _previousUp;
456
osg::Vec3d forwardVector =localUp^sideVector;
457
sideVector = forwardVector^localUp;
459
forwardVector.normalize();
460
sideVector.normalize();
462
osg::Vec3d dv = forwardVector * (dy*scale) + sideVector * (dx*scale);
466
// need to recompute the intersection point along the look vector.
468
bool hitFound = false;
473
// now reorientate the coordinate frame to the frame coords.
474
CoordinateFrame coordinateFrame = getCoordinateFrame(_center);
476
// need to reintersect with the terrain
477
double distance = _node->getBound().radius()*0.25f;
481
bool hit_ip1 = intersect(_center, _center + getUpVector(coordinateFrame) * distance, ip1);
482
bool hit_ip2 = intersect(_center, _center - getUpVector(coordinateFrame) * distance, ip2);
487
_center = (_center-ip1).length2() < (_center-ip2).length2() ?
508
osg::notify(INFO)<<"TerrainManipulator unable to intersect with terrain."<<std::endl;
511
coordinateFrame = getCoordinateFrame(_center);
512
osg::Vec3d new_localUp = getUpVector(coordinateFrame);
515
osg::Quat pan_rotation;
516
pan_rotation.makeRotate(localUp,new_localUp);
518
if (!pan_rotation.zeroRotation())
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;
524
//clampOrientation();
528
osg::notify(osg::INFO)<<"New up orientation nearly inline - no need to rotate"<<std::endl;
534
else if (buttonMask==GUIEventAdapter::RIGHT_MOUSE_BUTTON)
539
double fd = _distance;
540
double scale = 1.0f+dy;
541
if (fd*scale>_minimumDistance)
548
_distance = _minimumDistance;
296
OSG_INFO<<"New up orientation nearly inline - no need to rotate"<<std::endl;
304
bool TerrainManipulator::performMovementRightMouseButton( const double eventTimeDelta, const double dx, const double dy )
307
zoomModel( dy * getThrowScale( eventTimeDelta ), false );
558
312
void TerrainManipulator::clampOrientation()
560
if (_rotationMode==ELEVATION_AZIM)
314
if (!getVerticalAxisFixed())
562
osg::Matrixd rotation_matrix;
316
Matrixd rotation_matrix;
563
317
rotation_matrix.makeRotate(_rotation);
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);
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;
572
osg::Vec3d sideVector = lookVector ^ localUp;
326
Vec3d sideVector = lookVector ^ localUp;
574
328
if (sideVector.length()<0.1)
576
osg::notify(osg::INFO)<<"Side vector short "<<sideVector.length()<<std::endl;
330
OSG_INFO<<"Side vector short "<<sideVector.length()<<std::endl;
578
332
sideVector = upVector^localUp;
579
333
sideVector.normalize();
583
336
Vec3d newUpVector = sideVector^lookVector;
584
337
newUpVector.normalize();
586
osg::Quat rotate_roll;
587
340
rotate_roll.makeRotate(upVector,newUpVector);
589
342
if (!rotate_roll.zeroRotation())
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
604
const float TRACKBALLSIZE = 0.8f;
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.
615
* It is assumed that the arguments to this routine are in the range
618
void TerrainManipulator::trackball(osg::Vec3& axis,double & angle, double p1x, double p1y, double p2x, double p2y)
621
* First, figure out z-coordinates for projection of P1 and P2 to
625
osg::Matrix rotation_matrix(_rotation);
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;
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);
636
* Now, we want the cross product of P1 and P2
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.
649
* Figure out how much to rotate around that axis.
651
double t = (p2-p1).length() / (2.0*TRACKBALLSIZE);
654
* Avoid problems with out-of-control values...
656
if (t > 1.0) t = 1.0;
657
if (t < -1.0) t = -1.0;
658
angle = inRadians(asin(t));
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.
667
double TerrainManipulator::tb_project_to_sphere(double r, double x, double y)
673
if (d < r * 0.70710678118654752440)
679
t = r / 1.41421356237309504880;