diff --git a/include/osgUtil/IntersectVisitor b/include/osgUtil/IntersectVisitor index 1414eb81c..502f2da07 100644 --- a/include/osgUtil/IntersectVisitor +++ b/include/osgUtil/IntersectVisitor @@ -115,6 +115,8 @@ class OSGUTIL_EXPORT IntersectVisitor : public osg::NodeVisitor HitList& getHitList(const osg::LineSegment* seg) { return _segHitList[seg]; } int getNumHits(const osg::LineSegment* seg) { return _segHitList[seg].size(); } + + LineSegmentHitListMap& getSegHitList() { return _segHitList; } bool hits(); diff --git a/src/osgProducer/Viewer.cpp b/src/osgProducer/Viewer.cpp index 1a8e1240d..c5897b5f2 100644 --- a/src/osgProducer/Viewer.cpp +++ b/src/osgProducer/Viewer.cpp @@ -34,143 +34,84 @@ using namespace osg; // // Picking intersection visitor. // - -class PickIntersectVisitor : public osgUtil::IntersectVisitor +class PickVisitor : public osgUtil::IntersectVisitor { public: - PickIntersectVisitor() - { + + + PickVisitor(const osg::Viewport* viewport, const osg::Matrixd& proj, const osg::Matrixd& view, float mx, float my): + _mx(mx), + _my(my), + _lastViewport(viewport), + _lastProjectionMatrix(proj), + _lastViewMatrix(view) + { + if (viewport && + mx >= static_cast(viewport->x()) && + my >= static_cast(viewport->y()) && + mx < static_cast(viewport->x()+viewport->width()) && + my < static_cast(viewport->y()+viewport->height())) + { + + // mouse pointer intersect viewport so we can proceed to set up a line segment + osg::Matrix MVPW = view * proj * viewport->computeWindowMatrix(); + osg::Matrixd inverseMVPW; + inverseMVPW.invert(MVPW); + + osg::Vec3 nearPoint = osg::Vec3(mx,my,0.0f) * inverseMVPW; + osg::Vec3 farPoint = osg::Vec3(mx,my,1.0f) * inverseMVPW; + osg::LineSegment* lineSegment = new osg::LineSegment; + lineSegment->set(nearPoint, farPoint); + + addLineSegment(lineSegment); + } + } - virtual ~PickIntersectVisitor() {} - HitList& getIntersections(osg::Node *scene, osg::Vec3 nr, osg::Vec3 fr) - { - // option for non-sceneView users: you need to get the screen perp line and call getIntersections - // if you are using Projection nodes you should also call setxy to define the xp,yp positions for use with - // the ray transformed by Projection - _lineSegment = new osg::LineSegment; - _lineSegment->set(nr,fr); // make a line segment - - //std::cout<<"near "<accept(*this); - return getHitList(_lineSegment.get()); - } -private: - osg::ref_ptr _lineSegment; - friend class osgUtil::IntersectVisitor; -}; - -// PickVisitor traverses whole scene and checks below all Projection nodes -class PickVisitor : public osg::NodeVisitor -{ -public: - PickVisitor() - { - xp=yp=0; - setTraversalMode(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN); - } - ~PickVisitor() + void runNestedPickVisitor(osg::Node& node, const osg::Viewport* viewport, const osg::Matrix& proj, const osg::Matrix& view, float mx, float my) { - } - - void setTraversalMask(osg::Node::NodeMask traversalMask) - { - NodeVisitor::setTraversalMask(traversalMask); - _piv.setTraversalMask(traversalMask); - } - - // Aug 2003 added to pass the nodemaskOverride to the PickIntersectVisitor - // may be used make the visitor override the nodemask to visit invisible actions - inline void setNodeMaskOverride(osg::Node::NodeMask mask) - { - _piv.setNodeMaskOverride(mask); - _nodeMaskOverride = mask; - } - - - virtual void apply(osg::Projection& pr) - { - osg::Matrixd mt; - mt.invert(pr.getMatrix()); - osg::Vec3 npt=osg::Vec3(xp,yp,-1.0f) * mt, farpt=osg::Vec3(xp,yp,1.0f) * mt; - - // traversing the nodes children, using the projection direction - for (unsigned int i=0; iaccept(*this); - - return _PIVsegHitList; - } - - inline void setxy(float xpt, float ypt) { xp=xpt; yp=ypt; } - inline bool hits() const { return _PIVsegHitList.size()>0;} -private: + PickVisitor newPickVisitor( viewport, proj, view, _mx, _my ); + newPickVisitor.setTraversalMask(getTraversalMask()); + + // the new pickvisitor over the nodes children. + node.traverse( newPickVisitor ); + + for(LineSegmentHitListMap::iterator itr = newPickVisitor._segHitList.begin(); + itr != newPickVisitor._segHitList.end(); + ++itr) + { + _segHitList.insert(*itr); + } + } + + void apply(osg::Projection& projection) + { + runNestedPickVisitor( projection, + _lastViewport.get(), + projection.getMatrix(), + _lastViewMatrix, + _mx, _my ); + } + + void apply(osg::CameraNode& camera) + { + runNestedPickVisitor( camera, + camera.getViewport() ? camera.getViewport() : _lastViewport.get(), + camera.getProjectionMatrix(), + camera.getViewMatrix(), + _mx, _my ); + } + + + float _mx; + float _my; - PickIntersectVisitor _piv; - float xp, yp; // start point in viewport fraction coordiantes - osgUtil::IntersectVisitor::HitList _PIVsegHitList; + osg::ref_ptr _lastViewport; + osg::Matrixd _lastProjectionMatrix; + osg::Matrixd _lastViewMatrix; }; - class CollectedCoordinateSystemNodesVisitor : public osg::NodeVisitor { public: @@ -878,7 +819,7 @@ bool Viewer::computeNearFarPoints(float x,float y,unsigned int cameraNum,osg::Ve } -bool Viewer::computeIntersections(float x,float y,unsigned int cameraNum,osg::Node *node,osgUtil::IntersectVisitor::HitList& hits,osg::Node::NodeMask traversalMask) +bool Viewer::computeIntersections(float x,float y,unsigned int cameraNum,osg::Node* node,osgUtil::IntersectVisitor::HitList& hits,osg::Node::NodeMask traversalMask) { float pixel_x,pixel_y; if (computePixelCoords(x,y,cameraNum,pixel_x,pixel_y)) @@ -886,39 +827,38 @@ bool Viewer::computeIntersections(float x,float y,unsigned int cameraNum,osg::No Producer::Camera* camera=getCamera(cameraNum); - int pr_wx, pr_wy; - unsigned int pr_width, pr_height; - camera->getProjectionRectangle( pr_wx, pr_wy, pr_width, pr_height ); - - // convert into clip coords. - float rx = 2.0f*(pixel_x - (float)pr_wx)/(float)pr_width-1.0f; - float ry = 2.0f*(pixel_y - (float)pr_wy)/(float)pr_height-1.0f; - - //std::cout << " rx "<(camera->getSceneHandler()); - osgUtil::SceneView* sv = sh?sh->getSceneView():0; - osg::Matrixd vum; + osgUtil::SceneView* sv = sh ? sh->getSceneView() : 0; + osg::Matrixd proj; + osg::Matrixd view; + const osg::Viewport* viewport = 0; if (sv!=0) { - vum.set(sv->getViewMatrix() * - sv->getProjectionMatrix()); + viewport = sv->getViewport(); + proj = sv->getProjectionMatrix(); + view = sv->getViewMatrix(); } else { - vum.set(osg::Matrixd(camera->getViewMatrix()) * - osg::Matrixd(camera->getProjectionMatrix())); + viewport = 0; + proj = osg::Matrixd(camera->getProjectionMatrix()); + view = osg::Matrixd(camera->getViewMatrix()); } - PickVisitor iv; - iv.setTraversalMask(traversalMask); + node = node->getParent(0); + + PickVisitor pick(viewport, proj, view, pixel_x, pixel_y); + pick.setTraversalMask(traversalMask); + node->accept(pick); - osgUtil::IntersectVisitor::HitList localHits; - localHits = iv.getHits(node, vum, rx,ry); - if (localHits.empty()) return false; - - hits.insert(hits.begin(),localHits.begin(),localHits.end()); + // copy all the hits across to the external hits list + for(osgUtil::IntersectVisitor::LineSegmentHitListMap::iterator itr = pick.getSegHitList().begin(); + itr != pick.getSegHitList().end(); + ++itr) + { + hits.insert(hits.end(),itr->second.begin(), itr->second.end()); + } return true; } diff --git a/src/osgWrappers/osgUtil/IntersectVisitor.cpp b/src/osgWrappers/osgUtil/IntersectVisitor.cpp index 280318dab..03f750d2b 100644 --- a/src/osgWrappers/osgUtil/IntersectVisitor.cpp +++ b/src/osgWrappers/osgUtil/IntersectVisitor.cpp @@ -84,6 +84,7 @@ BEGIN_OBJECT_REFLECTOR(osgUtil::IntersectVisitor) I_Method1(void, addLineSegment, IN, osg::LineSegment *, seg); I_Method1(osgUtil::IntersectVisitor::HitList &, getHitList, IN, const osg::LineSegment *, seg); I_Method1(int, getNumHits, IN, const osg::LineSegment *, seg); + I_Method0(osgUtil::IntersectVisitor::LineSegmentHitListMap &, getSegHitList); I_Method0(bool, hits); I_Method1(void, setLODSelectionMode, IN, osgUtil::IntersectVisitor::LODSelectionMode, mode); I_Method0(osgUtil::IntersectVisitor::LODSelectionMode, getLODSelectionMode); @@ -99,6 +100,7 @@ BEGIN_OBJECT_REFLECTOR(osgUtil::IntersectVisitor) I_Method1(void, apply, IN, osg::LOD &, node); I_ReadOnlyProperty(osg::Vec3, EyePoint); I_Property(osgUtil::IntersectVisitor::LODSelectionMode, LODSelectionMode); + I_ReadOnlyProperty(osgUtil::IntersectVisitor::LineSegmentHitListMap &, SegHitList); END_REFLECTOR STD_MAP_REFLECTOR(std::map< const osg::LineSegment * COMMA osgUtil::IntersectVisitor::HitList >);