Hi,

The LineSegmentIntersector creates NaN warnings when applied to a node with 
zero scale. I've attached a 3 line change to osgintersection.cpp to reproduce 
the issue.

The NaN's first pop up when OSG tries to invert a zero matrix here: 
https://github.com/openscenegraph/osg/blob/master/src/osgUtil/LineSegmentIntersector.cpp#L294

Check with the following code snippet:

Code:

        osg::Matrix zero(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1);

        if (zero.invert(zero))
            std::cout << "inverted " << zero << std::endl;



invert() returns true but the inverted matrix is 

inverted {
        -nan -nan -nan 0 
        -nan -nan -nan 0 
        -nan -nan -nan 0 
        nan nan nan 1 
}

This looks like a bug in the Matrix invert function.

However even if the matrix was still zero instead of NaN, there is another 
issue here:

    osg::ref_ptr<LineSegmentIntersector> lsi = new 
LineSegmentIntersector(_start * matrix, _end * matrix);

Multiplying a vec3 with a zero matrix will cause NaN's, because there is an 1.0 
/ (mat * vec ...) in the Matrix::preMult(Vec3) function.

Not sure on the best way to fix this. Should we add explicit checks for zero 
scaled matrices in the LineSegmentIntersector, or fix the Matrix and Vec 
classes so they don't produce NaN's under any circumstances for (borderline) 
valid input? The latter seems the cleaner fix but would have a performance 
impact all over OSG.

Thank you!

Cheers,
Jannik

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=65720#65720



/* OpenSceneGraph example, osgintersection.
*
*  Permission is hereby granted, free of charge, to any person obtaining a copy
*  of this software and associated documentation files (the "Software"), to deal
*  in the Software without restriction, including without limitation the rights
*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
*  copies of the Software, and to permit persons to whom the Software is
*  furnished to do so, subject to the following conditions:
*
*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
*  THE SOFTWARE.
*/

#include <osg/ArgumentParser>
#include <osg/ApplicationUsage>
#include <osg/Timer>
#include <osg/CoordinateSystemNode>
#include <osg/Notify>
#include <osg/io_utils>

#include <osg/PositionAttitudeTransform>

#include <osgDB/ReadFile>

#include <osgUtil/IntersectionVisitor>
#include <osgUtil/LineSegmentIntersector>

#include <osgSim/LineOfSight>
#include <osgSim/HeightAboveTerrain>
#include <osgSim/ElevationSlice>

#include <iostream>

struct MyReadCallback : public osgUtil::IntersectionVisitor::ReadCallback
{
#if 0
    virtual osg::Node* readNodeFile(const std::string& filename)
    {
        return osgDB::readRefNodeFile(filename).release();
    }
#endif
    virtual osg::ref_ptr<osg::Node> readNodeFile(const std::string& filename)
    {
        return osgDB::readRefNodeFile(filename);
    }
};


int main(int argc, char **argv)
{
    // use an ArgumentParser object to manage the program arguments.
    osg::ArgumentParser arguments(&argc,argv);

    osg::ref_ptr<osg::Node> scene = osgDB::readRefNodeFiles(arguments);

    if (!scene)
    {
        std::cout<<"No model loaded, please specify a valid model on the command line."<<std::endl;
        return 0;
    }

    osg::ref_ptr<osg::PositionAttitudeTransform> transform (new osg::PositionAttitudeTransform);
    transform->addChild(scene);
    transform->setScale(osg::Vec3f(0,0,0));
    transform->setCullingActive(false);


    std::cout<<"Intersection "<<std::endl;


    osg::BoundingSphere bs = scene->getBound();

    scene = transform;


    bool useIntersectorGroup = true;
    bool useLineOfSight = true;

    //osg::CoordinateSystemNode* csn = dynamic_cast<osg::CoordinateSystemNode*>(scene.get());
    //osg::EllipsoidModel* em = csn ? csn->getEllipsoidModel() : 0;

    if (useLineOfSight)
    {

        osg::Vec3d start = bs.center() + osg::Vec3d(0.0,bs.radius(),0.0);
        osg::Vec3d end = bs.center() - osg::Vec3d(0.0, bs.radius(),0.0);
        osg::Vec3d deltaRow( 0.0, 0.0, bs.radius()*0.01);
        osg::Vec3d deltaColumn( bs.radius()*0.01, 0.0, 0.0);

        osgSim::LineOfSight los;

#if 1
        unsigned int numRows = 20;
        unsigned int numColumns = 20;
        osgSim::HeightAboveTerrain hat;
        hat.setDatabaseCacheReadCallback(los.getDatabaseCacheReadCallback());

        for(unsigned int r=0; r<numRows; ++r)
        {
            for(unsigned int c=0; c<numColumns; ++c)
            {
                osg::Vec3d s = start + deltaColumn * double(c) + deltaRow * double(r);
                osg::Vec3d e = end + deltaColumn * double(c) + deltaRow * double(r);
                los.addLOS(s,e);
                hat.addPoint(s);
            }
        }


        {
            std::cout<<"Computing LineOfSight"<<std::endl;

            osg::Timer_t startTick = osg::Timer::instance()->tick();

            los.computeIntersections(scene.get());

            osg::Timer_t endTick = osg::Timer::instance()->tick();

            std::cout<<"Completed in "<<osg::Timer::instance()->delta_s(startTick,endTick)<<std::endl;

            for(unsigned int i=0; i<los.getNumLOS(); i++)
            {
                const osgSim::LineOfSight::Intersections& intersections = los.getIntersections(i);
                for(osgSim::LineOfSight::Intersections::const_iterator itr = intersections.begin();
                    itr != intersections.end();
                    ++itr)
                {
                     std::cout<<"  point "<<*itr<<std::endl;
                }
            }
        }

        {
            // now do a second traversal to test performance of cache.
            osg::Timer_t startTick = osg::Timer::instance()->tick();

            std::cout<<"Computing HeightAboveTerrain"<<std::endl;

            hat.computeIntersections(scene.get());

            osg::Timer_t endTick = osg::Timer::instance()->tick();

            for(unsigned int i=0; i<hat.getNumPoints(); i++)
            {
                 std::cout<<"  point = "<<hat.getPoint(i)<<" hat = "<<hat.getHeightAboveTerrain(i)<<std::endl;
            }


            std::cout<<"Completed in "<<osg::Timer::instance()->delta_s(startTick,endTick)<<std::endl;
        }
#endif

        {
            // now do a second traversal to test performance of cache.
            osg::Timer_t startTick = osg::Timer::instance()->tick();

            std::cout<<"Computing ElevationSlice"<<std::endl;
            osgSim::ElevationSlice es;
            es.setDatabaseCacheReadCallback(los.getDatabaseCacheReadCallback());

            es.setStartPoint(bs.center()+osg::Vec3d(bs.radius(),0.0,0.0) );
            es.setEndPoint(bs.center()+osg::Vec3d(0.0,0.0, bs.radius()) );

            es.computeIntersections(scene.get());

            osg::Timer_t endTick = osg::Timer::instance()->tick();

            std::cout<<"Completed in "<<osg::Timer::instance()->delta_s(startTick,endTick)<<std::endl;

            typedef osgSim::ElevationSlice::DistanceHeightList DistanceHeightList;
            const DistanceHeightList& dhl = es.getDistanceHeightIntersections();
            std::cout<<"Number of intersections ="<<dhl.size()<<std::endl;
            for(DistanceHeightList::const_iterator dhitr = dhl.begin();
                dhitr != dhl.end();
                ++dhitr)
            {
                 std::cout.precision(10);
                 std::cout<<"  "<<dhitr->first<<" "<<dhitr->second<<std::endl;
            }


        }
    }
    else if (useIntersectorGroup)
    {
        osg::Timer_t startTick = osg::Timer::instance()->tick();

        osg::Vec3d start = bs.center() + osg::Vec3d(0.0,bs.radius(),0.0);
        osg::Vec3d end = bs.center();// - osg::Vec3d(0.0, bs.radius(),0.0);
        osg::Vec3d deltaRow( 0.0, 0.0, bs.radius()*0.01);
        osg::Vec3d deltaColumn( bs.radius()*0.01, 0.0, 0.0);
        unsigned int numRows = 20;
        unsigned int numColumns = 20;

        osg::ref_ptr<osgUtil::IntersectorGroup> intersectorGroup = new osgUtil::IntersectorGroup();

        for(unsigned int r=0; r<numRows; ++r)
        {
            for(unsigned int c=0; c<numColumns; ++c)
            {
                osg::Vec3d s = start + deltaColumn * double(c) + deltaRow * double(r);
                osg::Vec3d e = end + deltaColumn * double(c) + deltaRow * double(r);
                osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector = new osgUtil::LineSegmentIntersector(s, e);
                intersectorGroup->addIntersector( intersector.get() );
            }
        }


        osgUtil::IntersectionVisitor intersectVisitor( intersectorGroup.get(), new MyReadCallback );
        scene->accept(intersectVisitor);

        osg::Timer_t endTick = osg::Timer::instance()->tick();

        std::cout<<"Completed in "<<osg::Timer::instance()->delta_s(startTick,endTick)<<std::endl;

        if ( intersectorGroup->containsIntersections() )
        {
            std::cout<<"Found intersections "<<std::endl;

            osgUtil::IntersectorGroup::Intersectors& intersectors = intersectorGroup->getIntersectors();
            for(osgUtil::IntersectorGroup::Intersectors::iterator intersector_itr = intersectors.begin();
                intersector_itr != intersectors.end();
                ++intersector_itr)
            {
                osgUtil::LineSegmentIntersector* lsi = dynamic_cast<osgUtil::LineSegmentIntersector*>(intersector_itr->get());
                if (lsi)
                {
                    osgUtil::LineSegmentIntersector::Intersections& intersections = lsi->getIntersections();
                    for(osgUtil::LineSegmentIntersector::Intersections::iterator itr = intersections.begin();
                        itr != intersections.end();
                        ++itr)
                    {
                        const osgUtil::LineSegmentIntersector::Intersection& intersection = *itr;
                        std::cout<<"  ratio "<<intersection.ratio<<std::endl;
                        std::cout<<"  point "<<intersection.localIntersectionPoint<<std::endl;
                        std::cout<<"  normal "<<intersection.localIntersectionNormal<<std::endl;
                        std::cout<<"  indices "<<intersection.indexList.size()<<std::endl;
                        std::cout<<"  primitiveIndex "<<intersection.primitiveIndex<<std::endl;
                        std::cout<<std::endl;
                    }
                }
            }

        }

    }
    else
    {
        osg::Timer_t startTick = osg::Timer::instance()->tick();

    #if 1
        osg::Vec3d start = bs.center() + osg::Vec3d(0.0,bs.radius(),0.0);
        osg::Vec3d end = bs.center() - osg::Vec3d(0.0, bs.radius(),0.0);
    #else
        osg::Vec3d start = bs.center() + osg::Vec3d(0.0,0.0, bs.radius());
        osg::Vec3d end = bs.center() - osg::Vec3d(0.0, 0.0, bs.radius());
    #endif

        osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector = new osgUtil::LineSegmentIntersector(start, end);

        osgUtil::IntersectionVisitor intersectVisitor( intersector.get(), new MyReadCallback );

        scene->accept(intersectVisitor);

        osg::Timer_t endTick = osg::Timer::instance()->tick();

        std::cout<<"Completed in "<<osg::Timer::instance()->delta_s(startTick,endTick)<<std::endl;

        if ( intersector->containsIntersections() )
        {
            osgUtil::LineSegmentIntersector::Intersections& intersections = intersector->getIntersections();
            for(osgUtil::LineSegmentIntersector::Intersections::iterator itr = intersections.begin();
                itr != intersections.end();
                ++itr)
            {
                const osgUtil::LineSegmentIntersector::Intersection& intersection = *itr;
                std::cout<<"  ratio "<<intersection.ratio<<std::endl;
                std::cout<<"  point "<<intersection.localIntersectionPoint<<std::endl;
                std::cout<<"  normal "<<intersection.localIntersectionNormal<<std::endl;
                std::cout<<"  indices "<<intersection.indexList.size()<<std::endl;
                std::cout<<"  primitiveIndex "<<intersection.primitiveIndex<<std::endl;
                std::cout<<std::endl;
            }
        }
    }

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

Reply via email to