Hi Judd,

Could you post your ammendments to osg-submissions.

Cheers,
Robert.

On Thu, Aug 14, 2008 at 5:11 PM, Judd Tracy <[EMAIL PROTECTED]> wrote:
> Robert
>
> I have added a method called set (did not know what to call it) that allows
> you to set the start and end points for the LinSegmentIntersector using the
> CooridnateFrame and the x, y values like one of the constructors does.  It
> just makes it easier to reset the start and end points without having to
> know which values to use depending on the CoordinateFrame.
>
> Judd
>
> Robert Osfield wrote:
>>
>> Hi Judd,
>>
>> I have done some work on osgUtil::IntersectionVisitor to add proper
>> support for Billboards.  Could you try out the attached
>> IntersectionVisitor header/source files and let me know how you get
>> on.  This builds against OSG-2.6/OSG-SVN, but might also compile
>> against 2.4.
>>
>> In my own testing 'osgpick lz.osg' now works fine, whereas before this
>> fix it failed to pick the billboarded trees.
>>
>> Robert.
>>
>
>
> /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
>  *
>  * This library is open source and may be redistributed and/or modified
> under
>  * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
>  * (at your option) any later version.  The full license is in LICENSE file
>  * included with this distribution, and on the openscenegraph.org website.
>  *
>  * This library is distributed in the hope that it will be useful,
>  * but WITHOUT ANY WARRANTY; without even the implied warranty of
>  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>  * OpenSceneGraph Public License for more details.
> */
>
>
> #include <osgUtil/LineSegmentIntersector>
>
> #include <osg/Geometry>
> #include <osg/Notify>
> #include <osg/io_utils>
> #include <osg/TriangleFunctor>
>
> using namespace osgUtil;
>
> namespace LineSegmentIntersectorUtils
> {
>
>    struct TriangleIntersection
>    {
>        TriangleIntersection(unsigned int index, const osg::Vec3& normal,
> float r1, const osg::Vec3* v1, float r2, const osg::Vec3* v2, float r3,
> const osg::Vec3* v3):
>            _index(index),
>            _normal(normal),
>            _r1(r1),
>            _v1(v1),
>            _r2(r2),
>            _v2(v2),
>            _r3(r3),
>            _v3(v3) {}
>
>        unsigned int        _index;
>        const osg::Vec3     _normal;
>        float               _r1;
>        const osg::Vec3*    _v1;
>        float               _r2;
>        const osg::Vec3*    _v2;
>        float               _r3;
>        const osg::Vec3*    _v3;
>    };
>
>    typedef std::multimap<float,TriangleIntersection> TriangleIntersections;
>
>    struct TriangleIntersector
>    {
>        osg::Vec3   _s;
>        osg::Vec3   _d;
>        float       _length;
>
>        int         _index;
>        float       _ratio;
>        bool        _hit;
>
>        TriangleIntersections _intersections;
>
>        TriangleIntersector()
>        {
>            _length = 0.0f;
>            _index = 0;
>            _ratio = 0.0f;
>            _hit = false;
>        }
>
>        void set(const osg::Vec3d& start, osg::Vec3d& end, float
> ratio=FLT_MAX)
>        {
>            _hit=false;
>            _index = 0;
>            _ratio = ratio;
>
>            _s = start;
>            _d = end - start;
>            _length = _d.length();
>            _d /= _length;
>        }
>
>        inline void operator () (const osg::Vec3& v1,const osg::Vec3&
> v2,const osg::Vec3& v3, bool treatVertexDataAsTemporary)
>        {
>            ++_index;
>
>            if (v1==v2 || v2==v3 || v1==v3) return;
>
>            osg::Vec3 v12 = v2-v1;
>            osg::Vec3 n12 = v12^_d;
>            float ds12 = (_s-v1)*n12;
>            float d312 = (v3-v1)*n12;
>            if (d312>=0.0f)
>            {
>                if (ds12<0.0f) return;
>                if (ds12>d312) return;
>            }
>            else                     // d312 < 0
>            {
>                if (ds12>0.0f) return;
>                if (ds12<d312) return;
>            }
>
>            osg::Vec3 v23 = v3-v2;
>            osg::Vec3 n23 = v23^_d;
>            float ds23 = (_s-v2)*n23;
>            float d123 = (v1-v2)*n23;
>            if (d123>=0.0f)
>            {
>                if (ds23<0.0f) return;
>                if (ds23>d123) return;
>            }
>            else                     // d123 < 0
>            {
>                if (ds23>0.0f) return;
>                if (ds23<d123) return;
>            }
>
>            osg::Vec3 v31 = v1-v3;
>            osg::Vec3 n31 = v31^_d;
>            float ds31 = (_s-v3)*n31;
>            float d231 = (v2-v3)*n31;
>            if (d231>=0.0f)
>            {
>                if (ds31<0.0f) return;
>                if (ds31>d231) return;
>            }
>            else                     // d231 < 0
>            {
>                if (ds31>0.0f) return;
>                if (ds31<d231) return;
>            }
>
>
>            float r3;
>            if (ds12==0.0f) r3=0.0f;
>            else if (d312!=0.0f) r3 = ds12/d312;
>            else return; // the triangle and the line must be parallel
> intersection.
>
>            float r1;
>            if (ds23==0.0f) r1=0.0f;
>            else if (d123!=0.0f) r1 = ds23/d123;
>            else return; // the triangle and the line must be parallel
> intersection.
>
>            float r2;
>            if (ds31==0.0f) r2=0.0f;
>            else if (d231!=0.0f) r2 = ds31/d231;
>            else return; // the triangle and the line must be parallel
> intersection.
>
>            float total_r = (r1+r2+r3);
>            if (total_r!=1.0f)
>            {
>                if (total_r==0.0f) return; // the triangle and the line must
> be parallel intersection.
>                float inv_total_r = 1.0f/total_r;
>                r1 *= inv_total_r;
>                r2 *= inv_total_r;
>                r3 *= inv_total_r;
>            }
>
>            osg::Vec3 in = v1*r1+v2*r2+v3*r3;
>            if (!in.valid())
>            {
>                osg::notify(osg::WARN)<<"Warning:: Picked up error in
> TriangleIntersect"<<std::endl;
>                osg::notify(osg::WARN)<<"
> ("<<v1<<",\t"<<v2<<",\t"<<v3<<")"<<std::endl;
>                osg::notify(osg::WARN)<<"
> ("<<r1<<",\t"<<r2<<",\t"<<r3<<")"<<std::endl;
>                return;
>            }
>
>            float d = (in-_s)*_d;
>
>            if (d<0.0f) return;
>            if (d>_length) return;
>
>            osg::Vec3 normal = v12^v23;
>            normal.normalize();
>
>            float r = d/_length;
>
>
>            if (treatVertexDataAsTemporary)
>            {
>                _intersections.insert(std::pair<const
> float,TriangleIntersection>(r,TriangleIntersection(_index-1,normal,r1,0,r2,0,r3,0)));
>            }
>            else
>            {
>                _intersections.insert(std::pair<const
> float,TriangleIntersection>(r,TriangleIntersection(_index-1,normal,r1,&v1,r2,&v2,r3,&v3)));
>            }
>            _hit = true;
>
>        }
>
>    };
>
> }
>
> ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
> //
> //  LineSegmentIntersector
> //
>
> LineSegmentIntersector::LineSegmentIntersector(const osg::Vec3d& start,
> const osg::Vec3d& end):
>    _parent(0),
>    _start(start),
>    _end(end)
> {
> }
>
> LineSegmentIntersector::LineSegmentIntersector(CoordinateFrame cf, const
> osg::Vec3d& start, const osg::Vec3d& end):
>    Intersector(cf),
>    _parent(0),
>    _start(start),
>    _end(end)
> {
> }
>
> LineSegmentIntersector::LineSegmentIntersector(CoordinateFrame cf, double x,
> double y):
>    Intersector(cf),
>    _parent(0)
> {
>    set (cf, x, y);
> }
>
>
> void LineSegmentIntersector::set (CoordinateFrame cf, double x, double y)
> {
>    switch(cf)
>    {
>        case WINDOW : _start.set(x,y,0.0); _end.set(x,y,1.0); break;
>        case PROJECTION : _start.set(x,y,-1.0); _end.set(x,y,1.0); break;
>        case VIEW : _start.set(x,y,0.0); _end.set(x,y,1.0); break;
>        case MODEL : _start.set(x,y,0.0); _end.set(x,y,1.0); break;
>    }
> }
>
>
> Intersector* LineSegmentIntersector::clone(osgUtil::IntersectionVisitor& iv)
> {
>    if (_coordinateFrame==MODEL && iv.getModelMatrix()==0)
>    {
>        osg::ref_ptr<LineSegmentIntersector> lsi = new
> LineSegmentIntersector(_start, _end);
>        lsi->_parent = this;
>        return lsi.release();
>    }
>
>    // compute the matrix that takes this Intersector from its
> CoordinateFrame into the local MODEL coordinate frame
>    // that geometry in the scene graph will always be in.
>    osg::Matrix matrix;
>    switch (_coordinateFrame)
>    {
>        case(WINDOW):
>            if (iv.getWindowMatrix()) matrix.preMult( *iv.getWindowMatrix()
> );
>            if (iv.getProjectionMatrix()) matrix.preMult(
> *iv.getProjectionMatrix() );
>            if (iv.getViewMatrix()) matrix.preMult( *iv.getViewMatrix() );
>            if (iv.getModelMatrix()) matrix.preMult( *iv.getModelMatrix() );
>            break;
>        case(PROJECTION):
>            if (iv.getProjectionMatrix()) matrix.preMult(
> *iv.getProjectionMatrix() );
>            if (iv.getViewMatrix()) matrix.preMult( *iv.getViewMatrix() );
>            if (iv.getModelMatrix()) matrix.preMult( *iv.getModelMatrix() );
>            break;
>        case(VIEW):
>            if (iv.getViewMatrix()) matrix.preMult( *iv.getViewMatrix() );
>            if (iv.getModelMatrix()) matrix.preMult( *iv.getModelMatrix() );
>            break;
>        case(MODEL):
>            if (iv.getModelMatrix()) matrix = *iv.getModelMatrix();
>            break;
>    }
>
>    osg::Matrix inverse;
>    inverse.invert(matrix);
>
>    osg::ref_ptr<LineSegmentIntersector> lsi = new
> LineSegmentIntersector(_start * inverse, _end * inverse);
>    lsi->_parent = this;
>    return lsi.release();
> }
>
> bool LineSegmentIntersector::enter(const osg::Node& node)
> {
>    return !node.isCullingActive() || intersects( node.getBound() );
> }
>
> void LineSegmentIntersector::leave()
> {
>    // do nothing
> }
>
> void LineSegmentIntersector::intersect(osgUtil::IntersectionVisitor& iv,
> osg::Drawable* drawable)
> {
>    osg::Vec3d s(_start), e(_end);
>    if ( !intersectAndClip( s, e, drawable->getBound() ) ) return;
>
>    // reset the clipped range as it can be too close in on the BB, and cause
> missing due precission issues.
>    s = _start;
>    e = _end;
>
>    osg::TriangleFunctor<LineSegmentIntersectorUtils::TriangleIntersector>
> ti;
>    ti.set(s,e);
>    drawable->accept(ti);
>
>    if (ti._hit)
>    {
>        osg::Geometry* geometry = drawable->asGeometry();
>
>        for(LineSegmentIntersectorUtils::TriangleIntersections::iterator
> thitr = ti._intersections.begin();
>            thitr != ti._intersections.end();
>            ++thitr)
>        {
>
>            // get ratio in s,e range
>            float ratio = thitr->first;
>
>            // remap ratio into _start, _end range
>            ratio = ((s-_start).length() + ratio * (e-s).length()
> )/(_end-_start).length();
>
>            LineSegmentIntersectorUtils::TriangleIntersection& triHit =
> thitr->second;
>
>            Intersection hit;
>            hit.ratio = ratio;
>            hit.matrix = iv.getModelMatrix();
>            hit.nodePath = iv.getNodePath();
>            hit.drawable = drawable;
>            hit.primitiveIndex = triHit._index;
>
>            hit.localIntersectionPoint = s*(1.0f-ratio) + e*ratio;
>            hit.localIntersectionNormal = triHit._normal;
>
>            if (geometry)
>            {
>                osg::Vec3Array* vertices =
> dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
>                if (vertices)
>                {
>                    osg::Vec3* first = &(vertices->front());
>                    if (triHit._v1)
>                    {
>                        hit.indexList.push_back(triHit._v1-first);
>                        hit.ratioList.push_back(triHit._r1);
>                    }
>                    if (triHit._v2)
>                    {
>                        hit.indexList.push_back(triHit._v2-first);
>                        hit.ratioList.push_back(triHit._r2);
>                    }
>                    if (triHit._v3)
>                    {
>                        hit.indexList.push_back(triHit._v3-first);
>                        hit.ratioList.push_back(triHit._r3);
>                    }
>                }
>            }
>
>            insertIntersection(hit);
>
>        }
>    }
>
> }
>
> void LineSegmentIntersector::reset()
> {
>    Intersector::reset();
>
>    _intersections.clear();
> }
>
> bool LineSegmentIntersector::intersects(const osg::BoundingSphere& bs)
> {
>    // if bs not valid then return true based on the assumption that an
> invalid sphere is yet to be defined.
>    if (!bs.valid()) return true;
>
>    osg::Vec3d sm = _start - bs._center;
>    double c = sm.length2()-bs._radius*bs._radius;
>    if (c<0.0) return true;
>
>    osg::Vec3d se = _end-_start;
>    double a = se.length2();
>    double b = (sm*se)*2.0;
>    double d = b*b-4.0*a*c;
>
>    if (d<0.0) return false;
>
>    d = sqrt(d);
>
>    double div = 1.0/(2.0*a);
>
>    double r1 = (-b-d)*div;
>    double r2 = (-b+d)*div;
>
>    if (r1<=0.0 && r2<=0.0) return false;
>
>    if (r1>=1.0 && r2>=1.0) return false;
>
>    // passed all the rejection tests so line must intersect bounding sphere,
> return true.
>    return true;
> }
>
> bool LineSegmentIntersector::intersectAndClip(osg::Vec3d& s, osg::Vec3d&
> e,const osg::BoundingBox& bb)
> {
>    // compate s and e against the xMin to xMax range of bb.
>    if (s.x()<=e.x())
>    {
>
>        // trivial reject of segment wholely outside.
>        if (e.x()<bb.xMin()) return false;
>        if (s.x()>bb.xMax()) return false;
>
>        if (s.x()<bb.xMin())
>        {
>            // clip s to xMin.
>            s = s+(e-s)*(bb.xMin()-s.x())/(e.x()-s.x());
>        }
>
>        if (e.x()>bb.xMax())
>        {
>            // clip e to xMax.
>            e = s+(e-s)*(bb.xMax()-s.x())/(e.x()-s.x());
>        }
>    }
>    else
>    {
>        if (s.x()<bb.xMin()) return false;
>        if (e.x()>bb.xMax()) return false;
>
>        if (e.x()<bb.xMin())
>        {
>            // clip s to xMin.
>            e = s+(e-s)*(bb.xMin()-s.x())/(e.x()-s.x());
>        }
>
>        if (s.x()>bb.xMax())
>        {
>            // clip e to xMax.
>            s = s+(e-s)*(bb.xMax()-s.x())/(e.x()-s.x());
>        }
>    }
>
>    // compate s and e against the yMin to yMax range of bb.
>    if (s.y()<=e.y())
>    {
>
>        // trivial reject of segment wholely outside.
>        if (e.y()<bb.yMin()) return false;
>        if (s.y()>bb.yMax()) return false;
>
>        if (s.y()<bb.yMin())
>        {
>            // clip s to yMin.
>            s = s+(e-s)*(bb.yMin()-s.y())/(e.y()-s.y());
>        }
>
>        if (e.y()>bb.yMax())
>        {
>            // clip e to yMax.
>            e = s+(e-s)*(bb.yMax()-s.y())/(e.y()-s.y());
>        }
>    }
>    else
>    {
>        if (s.y()<bb.yMin()) return false;
>        if (e.y()>bb.yMax()) return false;
>
>        if (e.y()<bb.yMin())
>        {
>            // clip s to yMin.
>            e = s+(e-s)*(bb.yMin()-s.y())/(e.y()-s.y());
>        }
>
>        if (s.y()>bb.yMax())
>        {
>            // clip e to yMax.
>            s = s+(e-s)*(bb.yMax()-s.y())/(e.y()-s.y());
>        }
>    }
>
>    // compate s and e against the zMin to zMax range of bb.
>    if (s.z()<=e.z())
>    {
>
>        // trivial reject of segment wholely outside.
>        if (e.z()<bb.zMin()) return false;
>        if (s.z()>bb.zMax()) return false;
>
>        if (s.z()<bb.zMin())
>        {
>            // clip s to zMin.
>            s = s+(e-s)*(bb.zMin()-s.z())/(e.z()-s.z());
>        }
>
>        if (e.z()>bb.zMax())
>        {
>            // clip e to zMax.
>            e = s+(e-s)*(bb.zMax()-s.z())/(e.z()-s.z());
>        }
>    }
>    else
>    {
>        if (s.z()<bb.zMin()) return false;
>        if (e.z()>bb.zMax()) return false;
>
>        if (e.z()<bb.zMin())
>        {
>            // clip s to zMin.
>            e = s+(e-s)*(bb.zMin()-s.z())/(e.z()-s.z());
>        }
>
>        if (s.z()>bb.zMax())
>        {
>            // clip e to zMax.
>            s = s+(e-s)*(bb.zMax()-s.z())/(e.z()-s.z());
>        }
>    }
>
>    // osg::notify(osg::NOTICE)<<"clampped segment "<<s<<" "<<e<<std::endl;
>
>    // if (s==e) return false;
>
>    return true;
> }
>
> /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
>  *
>  * This library is open source and may be redistributed and/or modified
> under
>  * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
>  * (at your option) any later version.  The full license is in LICENSE file
>  * included with this distribution, and on the openscenegraph.org website.
>  *
>  * This library is distributed in the hope that it will be useful,
>  * but WITHOUT ANY WARRANTY; without even the implied warranty of
>  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>  * OpenSceneGraph Public License for more details.
> */
>
> #ifndef OSGUTIL_LINESEGMENTINTERSECTOR
> #define OSGUTIL_LINESEGMENTINTERSECTOR 1
>
> #include <osgUtil/IntersectionVisitor>
>
> namespace osgUtil
> {
>
> /** Concrete class for implementing line intersections with the scene graph.
>  * To be used in conjunction with IntersectionVisitor. */
> class OSGUTIL_EXPORT LineSegmentIntersector : public Intersector
> {
>    public:
>
>        /** Construct a LineSegmentIntersector the runs between the specified
> start and end points in MODEL coordinates. */
>        LineSegmentIntersector(const osg::Vec3d& start, const osg::Vec3d&
> end);
>
>        /** Construct a LineSegmentIntersector the runs between the specified
> start and end points in the specified coordinate frame. */
>        LineSegmentIntersector(CoordinateFrame cf, const osg::Vec3d& start,
> const osg::Vec3d& end);
>
>        /** Convenience constructor for supporting picking in WINDOW, or
> PROJECTION coordinates
>          * In WINDOW coordinates creates a start value of (x,y,0) and end
> value of (x,y,1).
>          * In PROJECTION coordinates (clip space cube) creates a start value
> of (x,y,-1) and end value of (x,y,1).
>          * In VIEW and MODEL coordinates creates a start value of (x,y,0)
> and end value of (x,y,1).*/
>        LineSegmentIntersector(CoordinateFrame cf, double x, double y);
>
>        struct Intersection
>        {
>            Intersection():
>                ratio(-1.0),
>                primitiveIndex(0) {}
>
>            bool operator < (const Intersection& rhs) const { return ratio <
> rhs.ratio; }
>
>            typedef std::vector<unsigned int>   IndexList;
>            typedef std::vector<double>         RatioList;
>
>            double                          ratio;
>            osg::NodePath                   nodePath;
>            osg::ref_ptr<osg::Drawable>     drawable;
>            osg::ref_ptr<osg::RefMatrix>    matrix;
>            osg::Vec3d                      localIntersectionPoint;
>            osg::Vec3                       localIntersectionNormal;
>            IndexList                       indexList;
>            RatioList                       ratioList;
>            unsigned int                    primitiveIndex;
>
>            const osg::Vec3d& getLocalIntersectPoint() const { return
> localIntersectionPoint; }
>            osg::Vec3d getWorldIntersectPoint() const { return matrix.valid()
> ? localIntersectionPoint * (*matrix) : localIntersectionPoint; }
>
>            const osg::Vec3& getLocalIntersectNormal() const { return
> localIntersectionNormal; }
>            osg::Vec3 getWorldIntersectNormal() const { return matrix.valid()
> ?
> osg::Matrix::transform3x3(osg::Matrix::inverse(*matrix),localIntersectionNormal)
> : localIntersectionNormal; }
>        };
>
>        typedef std::multiset<Intersection> Intersections;
>
>        inline void insertIntersection(const Intersection& intersection) {
> getIntersections().insert(intersection); }
>
>        inline Intersections& getIntersections() { return _parent ?
> _parent->_intersections : _intersections; }
>
>        inline Intersection getFirstIntersection() { Intersections&
> intersections = getIntersections(); return intersections.empty() ?
> Intersection() : *(intersections.begin()); }
>
>        inline void setStart(const osg::Vec3d& start) { _start = start; }
>        inline const osg::Vec3d& getStart() const { return _start; }
>
>        inline void setEnd(const osg::Vec3d& end) { _end = end; }
>        inline const osg::Vec3d& setEnd() const { return _end; }
>
>        /** Method to set the start and end points to support picking in
> WINDOW, or PROJECTION coordinates
>          * In WINDOW coordinates creates a start value of (x,y,0) and end
> value of (x,y,1).
>          * In PROJECTION coordinates (clip space cube) creates a start value
> of (x,y,-1) and end value of (x,y,1).
>          * In VIEW and MODEL coordinates creates a start value of (x,y,0)
> and end value of (x,y,1).*/
>        void set (CoordinateFrame cf, double x, double y);
>
>
>    public:
>
>        virtual Intersector* clone(osgUtil::IntersectionVisitor& iv);
>
>        virtual bool enter(const osg::Node& node);
>
>        virtual void leave();
>
>        virtual void intersect(osgUtil::IntersectionVisitor& iv,
> osg::Drawable* drawable);
>
>        virtual void reset();
>
>        virtual bool containsIntersections() { return
> !_intersections.empty(); }
>
>    protected:
>
>        bool intersects(const osg::BoundingSphere& bs);
>        bool intersectAndClip(osg::Vec3d& s, osg::Vec3d& e,const
> osg::BoundingBox& bb);
>
>        LineSegmentIntersector* _parent;
>
>        osg::Vec3d  _start;
>        osg::Vec3d  _end;
>
>        Intersections _intersections;
>
> };
>
> }
>
> #endif
>
>
> _______________________________________________
> osg-users mailing list
> [email protected]
> http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
>
>
_______________________________________________
osg-users mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org

Reply via email to