From 9a9c543ffaf0236119fff400cde721c43feb30dd Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Sat, 5 Jul 2008 16:39:28 +0000 Subject: [PATCH] Ported intersection code to use new osgUtil::LineSegmentIntersector/IntersectionVisitor. --- include/osgGA/DriveManipulator | 2 + include/osgGA/TerrainManipulator | 4 +- src/osgGA/DriveManipulator.cpp | 281 +++++++++++-------------------- src/osgGA/TerrainManipulator.cpp | 85 ++++------ 4 files changed, 132 insertions(+), 240 deletions(-) diff --git a/include/osgGA/DriveManipulator b/include/osgGA/DriveManipulator index ea3df3d81..ad87897b8 100644 --- a/include/osgGA/DriveManipulator +++ b/include/osgGA/DriveManipulator @@ -76,6 +76,8 @@ class OSGGA_EXPORT DriveManipulator : public MatrixManipulator virtual ~DriveManipulator(); + bool intersect(const osg::Vec3d& start, const osg::Vec3d& end, osg::Vec3d& intersection, osg::Vec3d& normal) const; + /** Reset the internal GUIEvent stack.*/ void flushMouseEventStack(); diff --git a/include/osgGA/TerrainManipulator b/include/osgGA/TerrainManipulator index ea8aa76b7..6f77e0122 100644 --- a/include/osgGA/TerrainManipulator +++ b/include/osgGA/TerrainManipulator @@ -85,7 +85,7 @@ class OSGGA_EXPORT TerrainManipulator : public MatrixManipulator virtual ~TerrainManipulator(); - bool intersect(const osg::Vec3d& start, const osg::Vec3d& end, osg::Vec3d& intersection); + bool intersect(const osg::Vec3d& start, const osg::Vec3d& end, osg::Vec3d& intersection) const; /** Reset the internal GUIEvent stack.*/ void flushMouseEventStack(); @@ -122,7 +122,7 @@ class OSGGA_EXPORT TerrainManipulator : public MatrixManipulator osg::Vec3d _center; osg::Quat _rotation; - float _distance; + double _distance; osg::Vec3d _previousUp; }; diff --git a/src/osgGA/DriveManipulator.cpp b/src/osgGA/DriveManipulator.cpp index 2bbe4e1fc..769c165db 100644 --- a/src/osgGA/DriveManipulator.cpp +++ b/src/osgGA/DriveManipulator.cpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include using namespace osg; @@ -31,9 +31,9 @@ using namespace osgGA; // #define INCREMENTAL_PITCH 1 #define KEYBOARD_PITCH 1 -static float getHeightOfDriver() +static double getHeightOfDriver() { - float height = 1.5f; + double height = 1.5; if (getenv("OSG_DRIVE_MANIPULATOR_HEIGHT")) { height = atof(getenv("OSG_DRIVE_MANIPULATOR_HEIGHT")); @@ -44,8 +44,8 @@ static float getHeightOfDriver() DriveManipulator::DriveManipulator() { - _modelScale = 0.01f; - _velocity = 0.0f; + _modelScale = 1.0; + _velocity = 0.0; _height = getHeightOfDriver(); _buffer = _height*1.3; _pitch = 0.0; @@ -69,9 +69,10 @@ void DriveManipulator::setNode(osg::Node* node) if (_node.get()) { const osg::BoundingSphere& boundingSphere=_node->getBound(); + _modelScale = boundingSphere._radius; - //_height = sqrtf(_modelScale)*0.03f; - //_buffer = sqrtf(_modelScale)*0.05f; + //_height = sqrtf(_modelScale)*0.03; + //_buffer = sqrtf(_modelScale)*0.05; _height = getHeightOfDriver(); _buffer = _height*1.3; @@ -91,6 +92,25 @@ osg::Node* DriveManipulator::getNode() return _node.get(); } +bool DriveManipulator::intersect(const osg::Vec3d& start, const osg::Vec3d& end, osg::Vec3d& intersection, osg::Vec3d& normal) const +{ + osg::ref_ptr lsi = new osgUtil::LineSegmentIntersector(start,end); + + osgUtil::IntersectionVisitor iv(lsi.get()); + iv.setTraversalMask(_intersectTraversalMask); + + _node->accept(iv); + + if (lsi->containsIntersections()) + { + intersection = lsi->getIntersections().begin()->getWorldIntersectPoint(); + normal = lsi->getIntersections().begin()->getWorldIntersectNormal(); + return true; + } + return false; +} + + void DriveManipulator::computeHomePosition() { if(_node.get()) @@ -106,39 +126,22 @@ void DriveManipulator::computeHomePosition() bp -= getUpVector(cf)* _modelScale; // check to see if any obstruction in front. - osgUtil::IntersectVisitor iv; - iv.setTraversalMask(_intersectTraversalMask); - bool positionSet = false; - osg::ref_ptr segDown = new osg::LineSegment; - segDown->set(ep,bp); - iv.addLineSegment(segDown.get()); - - _node->accept(iv); - - if (iv.hits()) + osg::Vec3d ip, np; + if (intersect(ep, bp, ip, np)) { - osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segDown.get()); - if (!hitList.empty()) - { - // notify(INFO) << "Hit terrain ok"<< std::endl; - osg::Vec3d ip = hitList.front().getWorldIntersectPoint(); - osg::Vec3d np = hitList.front().getWorldIntersectNormal(); + osg::Vec3d uv; + if (np * getUpVector(cf)>0.0) uv = np; + else uv = -np; - osg::Vec3d uv; - if (np * getUpVector(cf)>0.0) uv = np; - else uv = -np; + ep = ip; + ep += getUpVector(cf)*_height; + osg::Vec3 lv = uv^osg::Vec3d(1.0,0.0,0.0); - ep = ip; - ep += getUpVector(cf)*_height; - osg::Vec3 lv = uv^osg::Vec3d(1.0,0.0,0.0); + setHomePosition(ep,ep+lv,uv); - setHomePosition(ep,ep+lv,uv); - - positionSet = true; - - } + positionSet = true; } @@ -147,33 +150,20 @@ void DriveManipulator::computeHomePosition() bp = ep; bp += getUpVector(cf)*_modelScale; - osg::ref_ptr segUp = new osg::LineSegment; - segUp->set(ep,bp); - iv.addLineSegment(segUp.get()); - _node->accept(iv); - - if (iv.hits()) + if (intersect(ep, bp, ip, np)) { - osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segUp.get()); - if (!hitList.empty()) - { - // notify(INFO) << "Hit terrain ok"<< std::endl; - osg::Vec3d ip = hitList.front().getWorldIntersectPoint(); - osg::Vec3d np = hitList.front().getWorldIntersectNormal(); - osg::Vec3d uv; - if (np*getUpVector(cf)>0.0) uv = np; - else uv = -np; + osg::Vec3d uv; + if (np*getUpVector(cf)>0.0) uv = np; + else uv = -np; - ep = ip; - ep += getUpVector(cf)*_height; - osg::Vec3 lv = uv^osg::Vec3d(1.0,0.0,0.0); - setHomePosition(ep,ep+lv,uv); + ep = ip; + ep += getUpVector(cf)*_height; + osg::Vec3 lv = uv^osg::Vec3d(1.0,0.0,0.0); + setHomePosition(ep,ep+lv,uv); - positionSet = true; - - } + positionSet = true; } } @@ -213,7 +203,7 @@ void DriveManipulator::init(const GUIEventAdapter& ea,GUIActionAdapter& us) us.requestContinuousUpdate(false); - _velocity = 0.0f; + _velocity = 0.0; osg::Vec3d ep = _eye; @@ -225,39 +215,21 @@ void DriveManipulator::init(const GUIEventAdapter& ea,GUIActionAdapter& us) osg::Vec3d bp = ep; bp -= getUpVector(cf)*_modelScale; - // check to see if any obstruction in front. - osgUtil::IntersectVisitor iv; - iv.setTraversalMask(_intersectTraversalMask); - bool positionSet = false; - - osg::ref_ptr segDown = new osg::LineSegment; - segDown->set(ep,bp); - iv.addLineSegment(segDown.get()); - - _node->accept(iv); - - if (iv.hits()) + osg::Vec3d ip, np; + if (intersect(ep, bp, ip, np)) { - osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segDown.get()); - if (!hitList.empty()) - { - // notify(INFO) << "Hit terrain ok"<< std::endl; - osg::Vec3d ip = hitList.front().getWorldIntersectPoint(); - osg::Vec3d np = hitList.front().getWorldIntersectNormal(); - osg::Vec3d uv; - if (np*getUpVector(cf)>0.0) uv = np; - else uv = -np; + osg::Vec3d uv; + if (np*getUpVector(cf)>0.0) uv = np; + else uv = -np; - ep = ip+uv*_height; - osg::Vec3d lv = uv^sv; + ep = ip+uv*_height; + osg::Vec3d lv = uv^sv; - computePosition(ep,ep+lv,uv); - - positionSet = true; - } + computePosition(ep,ep+lv,uv); + positionSet = true; } if (!positionSet) @@ -265,33 +237,19 @@ void DriveManipulator::init(const GUIEventAdapter& ea,GUIActionAdapter& us) bp = ep; bp += getUpVector(cf)*_modelScale; - osg::ref_ptr segUp = new osg::LineSegment; - segUp->set(ep,bp); - iv.addLineSegment(segUp.get()); - - _node->accept(iv); - - if (iv.hits()) + if (intersect(ep, bp, ip, np)) { - osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segUp.get()); - if (!hitList.empty()) - { - // notify(INFO) << "Hit terrain ok"<< std::endl; - osg::Vec3 ip = hitList.front().getWorldIntersectPoint(); - osg::Vec3 np = hitList.front().getWorldIntersectNormal(); - osg::Vec3 uv; - if (np*getUpVector(cf)>0.0f) uv = np; - else uv = -np; + osg::Vec3d uv; + if (np*getUpVector(cf)>0.0f) uv = np; + else uv = -np; - ep = ip+uv*_height; - osg::Vec3 lv = uv^sv; + ep = ip+uv*_height; + osg::Vec3 lv = uv^sv; - computePosition(ep,ep+lv,uv); - - positionSet = true; - } + computePosition(ep,ep+lv,uv); + positionSet = true; } } @@ -472,10 +430,10 @@ void DriveManipulator::computePosition(const osg::Vec3d& eye,const osg::Vec3d& c osg::Vec3d u(s^f); u.normalize(); - osg::Matrix rotation_matrix(s[0], u[0], -f[0], 0.0, - s[1], u[1], -f[1], 0.0, - s[2], u[2], -f[2], 0.0, - 0.0, 0.0, 0.0, 1.0); + osg::Matrixd rotation_matrix(s[0], u[0], -f[0], 0.0, + s[1], u[1], -f[1], 0.0, + s[2], u[2], -f[2], 0.0, + 0.0, 0.0, 0.0, 1.0); _eye = eye; _rotation = rotation_matrix.getRotate().inverse(); @@ -492,15 +450,17 @@ bool DriveManipulator::calcMovement() if (dt<0.0f) { notify(INFO) << "warning dt = "<getYnormalized(); - _velocity = _modelScale*0.2f*dy; + _velocity = _height*dy; break; } case(USE_MOUSE_BUTTONS_FOR_SPEED): @@ -510,7 +470,7 @@ bool DriveManipulator::calcMovement() { // pan model. - _velocity += dt*_modelScale*0.01; + _velocity += dt*accelerationFactor; } else if (buttonMask==GUIEventAdapter::MIDDLE_MOUSE_BUTTON || @@ -523,7 +483,7 @@ bool DriveManipulator::calcMovement() else if (buttonMask==GUIEventAdapter::RIGHT_MOUSE_BUTTON) { - _velocity -= dt*_modelScale*0.01; + _velocity -= dt*accelerationFactor; } break; @@ -532,7 +492,7 @@ bool DriveManipulator::calcMovement() osg::CoordinateFrame cf=getCoordinateFrame(_eye); - osg::Matrix rotation_matrix; + osg::Matrixd rotation_matrix; rotation_matrix.makeRotate(_rotation); osg::Vec3d up = osg::Vec3d(0.0,1.0,0.0) * rotation_matrix; @@ -542,7 +502,7 @@ bool DriveManipulator::calcMovement() // rotate the camera. double dx = _ga_t0->getXnormalized(); - double yaw = -inDegrees(dx*50.0f*dt); + double yaw = -inDegrees(dx*50.0*dt); #ifdef KEYBOARD_PITCH @@ -580,98 +540,51 @@ bool DriveManipulator::calcMovement() else signedBuffer=-_buffer; // check to see if any obstruction in front. - osgUtil::IntersectVisitor iv; - iv.setTraversalMask(_intersectTraversalMask); - - osg::ref_ptr segForward = new osg::LineSegment; - segForward->set(_eye,_eye+lv*(signedBuffer+distanceToMove)); - iv.addLineSegment(segForward.get()); - - _node->accept(iv); - - if (iv.hits()) + osg::Vec3d ip, np; + if (intersect(_eye,_eye+lv*(signedBuffer+distanceToMove), ip, np)) { - osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segForward.get()); - if (!hitList.empty()) - { - // notify(INFO) << "Hit obstruction"<< std::endl; - osg::Vec3d ip = hitList.front().getWorldIntersectPoint(); - distanceToMove = (ip-_eye).length()-_buffer; - _velocity = 0.0; - } - + distanceToMove = (ip-_eye).length()-_buffer; + _velocity = 0.0; } // check to see if forward point is correct height above terrain. - osg::Vec3d fp = _eye+lv*distanceToMove; - osg::Vec3d lfp = fp-up*_height*5; + osg::Vec3d fp = _eye + lv*distanceToMove; + osg::Vec3d lfp = fp - up*(_height*5.0); - iv.reset(); - osg::ref_ptr segNormal = new osg::LineSegment; - segNormal->set(fp,lfp); - iv.addLineSegment(segNormal.get()); - - _node->accept(iv); - - if (iv.hits()) + if (intersect(fp, lfp, ip, np)) { - osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segNormal.get()); - if (!hitList.empty()) - { - // notify(INFO) << "Hit terrain ok"<< std::endl; - osg::Vec3d ip = hitList.front().getWorldIntersectPoint(); - osg::Vec3d np = hitList.front().getWorldIntersectNormal(); + if (up*np>0.0) up = np; + else up = -np; - if (up*np>0.0) up = np; - else up = -np; + _eye = ip+up*_height; - _eye = ip+up*_height; + lv = up^sv; - lv = up^sv; + computePosition(_eye,_eye+lv,up); - computePosition(_eye,_eye+lv,up); - - return true; - - } + return true; } // no hit on the terrain found therefore resort to a fall under // under the influence of gravity. osg::Vec3d dp = lfp; - dp -= getUpVector(cf)* (2*_modelScale); + dp -= getUpVector(cf)* (2.0*_modelScale); - iv.reset(); - - osg::ref_ptr segFall = new osg::LineSegment; - segFall->set(lfp,dp); - iv.addLineSegment(segFall.get()); - - _node->accept(iv); - - if (iv.hits()) + if (intersect(lfp, dp, ip, np)) { - osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segFall.get()); - if (!hitList.empty()) - { - notify(INFO) << "Hit terrain on decent ok"<< std::endl; - osg::Vec3d ip = hitList.front().getWorldIntersectPoint(); - osg::Vec3d np = hitList.front().getWorldIntersectNormal(); + if (up*np>0.0) up = np; + else up = -np; - if (up*np>0.0) up = np; - else up = -np; + _eye = ip+up*_height; - _eye = ip+up*_height; + lv = up^sv; - lv = up^sv; + computePosition(_eye,_eye+lv,up); - computePosition(_eye,_eye+lv,up); - - return true; - } + return true; } // no collision with terrain has been found therefore track horizontally. diff --git a/src/osgGA/TerrainManipulator.cpp b/src/osgGA/TerrainManipulator.cpp index eb2f1f1f6..504fbd133 100644 --- a/src/osgGA/TerrainManipulator.cpp +++ b/src/osgGA/TerrainManipulator.cpp @@ -73,6 +73,25 @@ osg::Node* TerrainManipulator::getNode() } + +bool TerrainManipulator::intersect(const osg::Vec3d& start, const osg::Vec3d& end, osg::Vec3d& intersection) const +{ + osg::ref_ptr lsi = new osgUtil::LineSegmentIntersector(start,end); + + osgUtil::IntersectionVisitor iv(lsi.get()); + iv.setTraversalMask(_intersectTraversalMask); + + _node->accept(iv); + + if (lsi->containsIntersections()) + { + intersection = lsi->getIntersections().begin()->getWorldIntersectPoint(); + return true; + } + return false; +} + + void TerrainManipulator::home(const GUIEventAdapter& ,GUIActionAdapter& us) { if (getAutoComputeHomePosition()) computeHomePosition(); @@ -219,48 +238,6 @@ void TerrainManipulator::addMouseEvent(const GUIEventAdapter& ea) _ga_t1 = _ga_t0; _ga_t0 = &ea; } - -bool TerrainManipulator::intersect(const osg::Vec3d& start, const osg::Vec3d& end, osg::Vec3d& intersection) -{ -#if 0 - // need to reintersect with the terrain - osgUtil::IntersectVisitor iv; - iv.setTraversalMask(_intersectTraversalMask); - - osg::ref_ptr segLookVector = new osg::LineSegment; - segLookVector->set(start,end); - iv.addLineSegment(segLookVector.get()); - - _node->accept(iv); - - if (iv.hits()) - { - osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segLookVector.get()); - if (!hitList.empty()) - { - intersection = hitList.front().getWorldIntersectPoint(); - return true; - } - } - return false; -#else - - osg::ref_ptr lsi = new osgUtil::LineSegmentIntersector(start,end); - - osgUtil::IntersectionVisitor iv(lsi.get()); - iv.setTraversalMask(_intersectTraversalMask); - - _node->accept(iv); - - if (lsi->containsIntersections()) - { - intersection = lsi->getIntersections().begin()->getWorldIntersectPoint(); - return true; - } - return false; -#endif -} - void TerrainManipulator::setByMatrix(const osg::Matrixd& matrix) { @@ -294,9 +271,9 @@ void TerrainManipulator::setByMatrix(const osg::Matrixd& matrix) _distance = (eye-ip).length(); - osg::Matrix rotation_matrix = osg::Matrixd::translate(0.0,0.0,-_distance)* - matrix* - osg::Matrixd::translate(-_center); + osg::Matrixd rotation_matrix = osg::Matrixd::translate(0.0,0.0,-_distance)* + matrix* + osg::Matrixd::translate(-_center); _rotation = rotation_matrix.getRotate(); @@ -330,12 +307,12 @@ void TerrainManipulator::setByMatrix(const osg::Matrixd& matrix) osg::Matrixd TerrainManipulator::getMatrix() const { - return osg::Matrixd::translate(0.0,0.0,_distance)*osg::Matrixd::rotate(_rotation)*osg::Matrix::translate(_center); + return osg::Matrixd::translate(0.0,0.0,_distance)*osg::Matrixd::rotate(_rotation)*osg::Matrixd::translate(_center); } osg::Matrixd TerrainManipulator::getInverseMatrix() const { - return osg::Matrix::translate(-_center)*osg::Matrixd::rotate(_rotation.inverse())*osg::Matrixd::translate(0.0,0.0,-_distance); + return osg::Matrixd::translate(-_center)*osg::Matrixd::rotate(_rotation.inverse())*osg::Matrixd::translate(0.0,0.0,-_distance); } void TerrainManipulator::computePosition(const osg::Vec3d& eye,const osg::Vec3d& center,const osg::Vec3d& up) @@ -343,7 +320,7 @@ void TerrainManipulator::computePosition(const osg::Vec3d& eye,const osg::Vec3d& if (!_node) return; // compute rotation matrix - osg::Vec3 lv(center-eye); + osg::Vec3d lv(center-eye); _distance = lv.length(); _center = center; @@ -353,10 +330,10 @@ void TerrainManipulator::computePosition(const osg::Vec3d& eye,const osg::Vec3d& { bool hitFound = false; - float distance = lv.length(); - float maxDistance = distance+2*(eye-_node->getBound().center()).length(); - osg::Vec3 farPosition = eye+lv*(maxDistance/distance); - osg::Vec3 endPoint = center; + double distance = lv.length(); + double maxDistance = distance+2*(eye-_node->getBound().center()).length(); + osg::Vec3d farPosition = eye+lv*(maxDistance/distance); + osg::Vec3d endPoint = center; for(int i=0; !hitFound && i<2; ++i, endPoint = farPosition) @@ -464,7 +441,7 @@ bool TerrainManipulator::calcMovement() // pan model. double scale = -0.3f*_distance; - osg::Matrix rotation_matrix; + osg::Matrixd rotation_matrix; rotation_matrix.makeRotate(_rotation); @@ -571,7 +548,7 @@ void TerrainManipulator::clampOrientation() { if (_rotationMode==ELEVATION_AZIM) { - osg::Matrix rotation_matrix; + osg::Matrixd rotation_matrix; rotation_matrix.makeRotate(_rotation); osg::Vec3d lookVector = -getUpVector(rotation_matrix);