void StrokeIntersector::intersect(osgUtil::IntersectionVisitor &iv, osg::Drawable *drawable)
{
    osg::BoundingBox bb = drawable->getBoundingBox();
    bb.xMin() -= m_offset; bb.xMax() += m_offset;
    bb.yMin() -= m_offset; bb.yMax() += m_offset;
    bb.zMin() -= m_offset; bb.zMax() += m_offset;

    osg::Vec3d s(_start), e(_end);
    if (!intersectAndClip(s, e, bb)) return;
    if (iv.getDoDummyTraversal()) return;

    entity::Stroke* geometry = dynamic_cast<entity::Stroke*>(drawable->asGeometry());
    if (geometry)
    {
        osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
        if (!vertices) return;

        for (unsigned int i=1; i<vertices->size(); ++i)
        {

            double distance = Utilities::getSkewLinesDistance(s,e,(*vertices)[i], (*vertices)[i-1]);

            if (m_offset<distance) continue;

            Intersection hit;
            hit.ratio = distance;
            hit.nodePath = iv.getNodePath();
            hit.drawable = drawable;
            hit.matrix = iv.getModelMatrix();
            hit.localIntersectionPoint = (*vertices)[i];
            m_hitIndices.push_back(i);
            insertIntersection(hit);
        }
    }
}
void PolytopeIntersector::intersect(osgUtil::IntersectionVisitor& iv, osg::Drawable* drawable)
{
    if (reachedLimit()) return;

    if ( !_polytope.contains( drawable->getBoundingBox() ) ) return;

    osg::TemplatePrimitiveFunctor<PolytopeIntersectorUtils::PolytopePrimitiveIntersector> func;
    func.setPolytope( _polytope, _referencePlane );
    func.setDimensionMask( _dimensionMask );
    func.setLimitOneIntersection( _intersectionLimit == LIMIT_ONE_PER_DRAWABLE || _intersectionLimit == LIMIT_ONE );

    drawable->accept(func);

    if (func.intersections.empty()) return;


    for(PolytopeIntersectorUtils::Intersections::const_iterator it=func.intersections.begin();
        it!=func.intersections.end();
        ++it)
    {
        const PolytopeIntersectorUtils::PolytopeIntersection& intersection = *it;

        Intersection hit;
        hit.distance = intersection._distance;
        hit.maxDistance = intersection._maxDistance;
        hit.primitiveIndex = intersection._index;
        hit.nodePath = iv.getNodePath();
        hit.drawable = drawable;
        hit.matrix = iv.getModelMatrix();

        PolytopeIntersectorUtils::Vec3_type center;
        for (unsigned int i=0; i<intersection._numPoints; ++i)
        {
            center += intersection._points[i];
        }
        center /= PolytopeIntersectorUtils::value_type(intersection._numPoints);
        hit.localIntersectionPoint = center;

        hit.numIntersectionPoints = intersection._numPoints;
        std::copy(&intersection._points[0], &intersection._points[intersection._numPoints],
              &hit.intersectionPoints[0]);

        insertIntersection(hit);
    }
}
void PrimitiveIntersector::intersect(osgUtil::IntersectionVisitor& iv, osg::Drawable* drawable)
{
    if (reachedLimit() || !drawable) return;

    osg::BoundingBox bb = drawable->getBoundingBox();

    if (bb.valid())
        bb.expandBy(osg::BoundingSphere(bb.center(), (_thickness - _start).length()));

    osg::Vec3d s(_start), e(_end);
    if ( !intersectAndClip( s, e, bb ) ) return;

    if (iv.getDoDummyTraversal()) return;


    osg::TemplatePrimitiveFunctor<PrimitiveIntersectorFunctor> ti;

    ti.set(s,e,_thickness-_start);
    ti._limitOneIntersection = (_intersectionLimit == LIMIT_ONE_PER_DRAWABLE || _intersectionLimit == LIMIT_ONE);
    drawable->accept(ti);

    if (ti._hit)
    {
        osg::Geometry* geometry = drawable->asGeometry();

        for(PrimitiveIntersections::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();

            if ( _intersectionLimit == LIMIT_NEAREST && !getIntersections().empty() )
            {
                if (remap_ratio >= getIntersections().begin()->ratio )
                    break;
                else
                    getIntersections().clear();
            }

            PrimitiveIntersection& triHit = thitr->second;

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

            hit.localIntersectionPoint = _start*(1.0-remap_ratio) + _end*remap_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
DPLineSegmentIntersector::intersect(osgUtil::IntersectionVisitor& iv, osg::Drawable* drawable)
{
    if (reachedLimit()) return;

    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_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_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;
    }

    // GW: changed this ONE line
    osg::TriangleFunctor<DoublePrecisionTriangleIntersector> ti;

    ti.set(s,e);
    ti._limitOneIntersection = (_intersectionLimit == LIMIT_ONE_PER_DRAWABLE || _intersectionLimit == LIMIT_ONE);
    drawable->accept(ti);

    if (ti._hit)
    {
        osg::Geometry* geometry = drawable->asGeometry();

        for(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();

            if ( _intersectionLimit == LIMIT_NEAREST && !getIntersections().empty() )
            {
                if (remap_ratio >= getIntersections().begin()->ratio )
                    break;
                else
                    getIntersections().clear();
            }

            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_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 intersectWithQuadTree(osgUtil::IntersectionVisitor& iv, osg::Drawable* drawable
    , const osg::Vec3d s, const osg::Vec3d e
    , const osg::Vec3d _start, const osg::Vec3d _end
    , QuadTree* quadTree
    , DPLineSegmentIntersector& intersector)
{
    QuadTree::LineSegmentIntersections intersections;
    intersections.reserve(4);
    if (quadTree->intersect(s,e,intersections))
    {
        // OSG_NOTICE<<"Got QuadTree intersections"<<std::endl;
        for(QuadTree::LineSegmentIntersections::iterator itr = intersections.begin();
            itr != intersections.end();
            ++itr)
        {
            QuadTree::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();


            osgUtil::LineSegmentIntersector::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_NOTICE<<"QuadTree: 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);
            }

            intersector.insertIntersection(hit);
        }
    }
}