Hi Robert,

Attached is a solution for the problem of finding intersection point described 
in the test example.

I only copied the code from KdTree.cpp where the final calculations on 
triangles are done.

Of course I had to do some small changes (e.g. continue -> return).

Look at the similarities between "struct TriangleIntersector" in 
LineSegmentIntersector.cpp and "struct IntersectKdTree" in KdTree.cpp.

Probably you do not want to check in my file into svn/trunk because this piece 
of code could or maybe should be shared. But I do not know the correct way to 
do it.

Regards,
Lars.



-----Original Message-----
From: [email protected] 
[mailto:[email protected]] On Behalf Of Nilsson 
Lars
Sent: den 2 februari 2010 10:21
To: OpenSceneGraph Submissions
Subject: Re: [osg-submissions] LineSegmentIntersector using KdTree sometimes 
fails

Hi Robert,

You are quite right, not to merge the changes in the IntersectKdTree::intersect 
method. I have tested our application/datasets against svn/trunk 11008 with the 
merged KdTree files.

It solved that problem. 

However, during the testing, I found another combination that fails to find 
intersections. This time KdTree works fine, but the other way (without KdTree) 
it fails.

It could easily be reproduced by just changing a little in the test example, 
which is updated and attached.

I do not have any solution to this problem yet. Shall I continue with this 
thread or submit in a new one, if I find a way to solve the new problem.

Regards,
Lars.
/* -*-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>
#include <osg/KdTree>
#include <osg/Timer>

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;
        
    protected:
    
        TriangleIntersection& operator = (const TriangleIntersection&) { return 
*this; }
    };

    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& v0,const osg::Vec3& v1,const 
osg::Vec3& v2, bool treatVertexDataAsTemporary)
        {


          // note v1,v2,v3 has been changed to v0,v1,v2


            ++_index;

            if (v0==v1 || v1==v2 || v0==v2) return;





            osg::Vec3 T = _s - v0;
            osg::Vec3 E2 = v2 - v0;
            osg::Vec3 E1 = v1 - v0;
            
            osg::Vec3 P =  _d ^ E2;
            
            float det = P * E1;
            
            float r,r0,r1,r2;
            
            const float esplison = 1e-10f;
            if (det>esplison)
            {
                float u = (P*T);
                if (u<0.0 || u>det) return;
                
                osg::Vec3 Q = T ^ E1;
                float v = (Q*_d);
                if (v<0.0 || v>det) return;
                
                if ((u+v)> det) return;

                float inv_det = 1.0f/det;                
                float t = (Q*E2)*inv_det;            
                if (t<0.0 || t>_length) return;

                u *= inv_det;
                v *= inv_det;

                r0 = 1.0f-u-v;
                r1 = u;
                r2 = v; 
                //                r = t * _inverse_length;
                r = t / _length;
            }
            else if (det<-esplison)
            {

                float u = (P*T);
                if (u>0.0 || u<det) return;
                
                osg::Vec3 Q = T ^ E1;
                float v = (Q*_d);
                if (v>0.0 || v<det) return;
                
                if ((u+v) < det) return;

                float inv_det = 1.0f/det;                
                float t = (Q*E2)*inv_det;            
                if (t<0.0 || t>_length) return;

                u *= inv_det;
                v *= inv_det;

                r0 = 1.0f-u-v;
                r1 = u;
                r2 = v;
                //                r = t * _inverse_length;
                r = t / _length;
            }
            else
            {
                return;
            }

            //            osg::Vec3 in = v0*r0 + v1*r1 + v2*r2;
            osg::Vec3 normal = E1^E2;
            normal.normalize();







            if (treatVertexDataAsTemporary)
            {
                _intersections.insert(std::pair<const 
float,TriangleIntersection>(r,TriangleIntersection(_index-1,normal,r0,0,r1,0,r2,0)));
            }
            else
            {
                _intersections.insert(std::pair<const 
float,TriangleIntersection>(r,TriangleIntersection(_index-1,normal,r0,&v0,r1,&v1,r2,&v2)));
            }
            _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)
{
    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;

    if (iv.getDoDummyTraversal()) return;

    osg::KdTree* kdTree = iv.getUseKdTreeWhenAvailable() ? 
dynamic_cast<osg::KdTree*>(drawable->getShape()) : 0;
    if (kdTree)
    {
        osg::KdTree::LineSegmentIntersections intersections;
        intersections.reserve(4);
        if (kdTree->intersect(s,e,intersections))
        {
            // osg::notify(osg::NOTICE)<<"Got KdTree intersections"<<std::endl;
            for(osg::KdTree::LineSegmentIntersections::iterator itr = 
intersections.begin();
                itr != intersections.end();
                ++itr)
            {
                osg::KdTree::LineSegmentIntersection& lsi = *(itr);
                
                // get ratio in s,e range
                double ratio = lsi.ratio;

                // remap ratio into _start, _end range
                double remap_ratio = ((s-_start).length() + ratio * 
(e-s).length() )/(_end-_start).length();


                Intersection hit;
                hit.ratio = remap_ratio;
                hit.matrix = iv.getModelMatrix();
                hit.nodePath = iv.getNodePath();
                hit.drawable = drawable;
                hit.primitiveIndex = lsi.primitiveIndex;

                hit.localIntersectionPoint = _start*(1.0-remap_ratio) + 
_end*remap_ratio;
                
                // osg::notify(osg::NOTICE)<<"KdTree: ratio="<<hit.ratio<<" 
("<<hit.localIntersectionPoint<<")"<<std::endl;
                
                hit.localIntersectionNormal = lsi.intersectionNormal;
                
                hit.indexList.reserve(3);
                hit.ratioList.reserve(3);
                if (lsi.r0!=0.0f) 
                {
                    hit.indexList.push_back(lsi.p0);
                    hit.ratioList.push_back(lsi.r0);
                }
                
                if (lsi.r1!=0.0f) 
                {
                    hit.indexList.push_back(lsi.p1);
                    hit.ratioList.push_back(lsi.r1);
                }

                if (lsi.r2!=0.0f) 
                {
                    hit.indexList.push_back(lsi.p2);
                    hit.ratioList.push_back(lsi.r2);
                }

                insertIntersection(hit);
            }
        }
        
        return;
    }

    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
            double ratio = thitr->first;

            // remap ratio into _start, _end range
            double remap_ratio = ((s-_start).length() + ratio * (e-s).length() 
)/(_end-_start).length();

            LineSegmentIntersectorUtils::TriangleIntersection& triHit = 
thitr->second;

            Intersection hit;
            hit.ratio = remap_ratio;
            hit.matrix = iv.getModelMatrix();
            hit.nodePath = iv.getNodePath();
            hit.drawable = drawable;
            hit.primitiveIndex = triHit._index;

            hit.localIntersectionPoint = _start*(1.0-remap_ratio) + 
_end*remap_ratio;

            // osg::notify(osg::NOTICE)<<"Conventional: ratio="<<hit.ratio<<" 
("<<hit.localIntersectionPoint<<")"<<std::endl;

            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& bbInput)
{
    osg::Vec3d bb_min(bbInput._min);
    osg::Vec3d bb_max(bbInput._max);

#if 1
    double epsilon = 1e-4;
    bb_min.x() -= epsilon;
    bb_min.y() -= epsilon;
    bb_min.z() -= epsilon;
    bb_max.x() += epsilon;
    bb_max.y() += epsilon;
    bb_max.z() += epsilon;
#endif

    // 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_min.x()) return false;
        if (s.x()>bb_max.x()) return false;

        if (s.x()<bb_min.x())
        {
            // clip s to xMin.
            s = s+(e-s)*(bb_min.x()-s.x())/(e.x()-s.x());
        }

        if (e.x()>bb_max.x())
        {
            // clip e to xMax.
            e = s+(e-s)*(bb_max.x()-s.x())/(e.x()-s.x());
        }
    }
    else
    {
        if (s.x()<bb_min.x()) return false;
        if (e.x()>bb_max.x()) return false;

        if (e.x()<bb_min.x())
        {
            // clip s to xMin.
            e = s+(e-s)*(bb_min.x()-s.x())/(e.x()-s.x());
        }

        if (s.x()>bb_max.x())
        {
            // clip e to xMax.
            s = s+(e-s)*(bb_max.x()-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_min.y()) return false;
        if (s.y()>bb_max.y()) return false;

        if (s.y()<bb_min.y())
        {
            // clip s to yMin.
            s = s+(e-s)*(bb_min.y()-s.y())/(e.y()-s.y());
        }

        if (e.y()>bb_max.y())
        {
            // clip e to yMax.
            e = s+(e-s)*(bb_max.y()-s.y())/(e.y()-s.y());
        }
    }
    else
    {
        if (s.y()<bb_min.y()) return false;
        if (e.y()>bb_max.y()) return false;

        if (e.y()<bb_min.y())
        {
            // clip s to yMin.
            e = s+(e-s)*(bb_min.y()-s.y())/(e.y()-s.y());
        }

        if (s.y()>bb_max.y())
        {
            // clip e to yMax.
            s = s+(e-s)*(bb_max.y()-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_min.z()) return false;
        if (s.z()>bb_max.z()) return false;

        if (s.z()<bb_min.z())
        {
            // clip s to zMin.
            s = s+(e-s)*(bb_min.z()-s.z())/(e.z()-s.z());
        }

        if (e.z()>bb_max.z())
        {
            // clip e to zMax.
            e = s+(e-s)*(bb_max.z()-s.z())/(e.z()-s.z());
        }
    }
    else
    {
        if (s.z()<bb_min.z()) return false;
        if (e.z()>bb_max.z()) return false;

        if (e.z()<bb_min.z())
        {
            // clip s to zMin.
            e = s+(e-s)*(bb_min.z()-s.z())/(e.z()-s.z());
        }

        if (s.z()>bb_max.z())
        {
            // clip e to zMax.
            s = s+(e-s)*(bb_max.z()-s.z())/(e.z()-s.z());
        }
    }
    
    // osg::notify(osg::NOTICE)<<"clampped segment "<<s<<" "<<e<<std::endl;
    
    // if (s==e) return false;

    return true;
}
#include <iostream>

#include <osg/Geode>
#include <osg/KdTree>
#include <osgUtil/LineSegmentIntersector>

int main(int argc, char *argv[])
{
  for (int i=0; i<2; ++i) {
    const bool useKdTree = (i == 0);

    const float Z = 3000.0; 
    osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
    vertices->push_back(osg::Vec3(86093.9, 30625.9, Z));
    vertices->push_back(osg::Vec3(86077.8, 30669.0, Z));
    vertices->push_back(osg::Vec3(83483.4, 29653.5, Z));
    vertices->push_back(osg::Vec3(83000.0, 30000.0, Z));
    vertices->push_back(osg::Vec3(80000.0, 30000.0, Z)); // at least 5 vertices 
are needed to invoke KdTree (default)

    osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
    geometry->setVertexArray(vertices.get());
    geometry->addPrimitiveSet(new 
osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_STRIP, 0, vertices->size()));

    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
    geode->addDrawable(geometry.get());

    if (useKdTree) {
      osg::ref_ptr<osg::KdTreeBuilder> kdTreeBuilder = new osg::KdTreeBuilder;
      geode->accept(*(kdTreeBuilder.get()));
    }

    const osg::Vec2d XY(84718.3, 30129.7); 
    const osg::Vec3d start(XY, 0.0);
    const osg::Vec3d end(XY, 1e9);
    osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector = new 
osgUtil::LineSegmentIntersector(start, end);

    osgUtil::IntersectionVisitor iv(intersector.get());
    iv.reset();
    geode->accept(iv);

    osgUtil::LineSegmentIntersector::Intersections& intersections = 
intersector->getIntersections();

    std::cout << "KdTree " << (useKdTree ? "on  " : "off ");
    if (intersections.empty()) std::cout << "No intersections ";
    else std::cout << intersections.begin()->localIntersectionPoint[2];
    std::cout << std::endl;
  }

  return 0;
}
_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org

Reply via email to