The meaning of ratio in LineSegmentIntersector::Intersections and the description of intersection points of LineSegmentIntersector

osg uses the LineSegmentIntersector and IntersectionVisitor classes in the osgUtil library to find the intersection of the line segment and the 3D model

The following code:

#include <QtCore/QCoreApplication>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgViewer/CompositeViewer>
#include <osgUtil/IntersectionVisitor>
#include <osgUtil/LineSegmentIntersector>
#include <iostream>

//create box
osg::ref_ptr<osg::Geode> createBox()
{
    osg::ref_ptr<osg::Geode> geode1 = new osg::Geode;
    auto box1 = new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0, 0.0, 0.0), 10.0, 8.0, 6.0));
    geode1->addDrawable(box1);

   // geode1->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0, 0.0, 0.0), 0.1, 0.1, 20)));
    return geode1;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    osg::ref_ptr<osgViewer::Viewer> viewer1 = new osgViewer::Viewer;
    osg::ref_ptr<osg::Group> group1 = new osg::Group;

     osg::ref_ptr<osgUtil::LineSegmentIntersector> lineSegmentIntesector = new osgUtil::LineSegmentIntersector(osg::Vec3(0, 0,15), osg::Vec3(0, 0, -15));
    osg::ref_ptr<osgUtil::IntersectionVisitor> intersectionVisitor1 = new osgUtil::IntersectionVisitor(lineSegmentIntesector);

    group1->addChild(createBox());
    group1->accept(*intersectionVisitor1.get());

    osgUtil::LineSegmentIntersector::Intersections intersections;

    // output intersection point
    intersections = lineSegmentIntesector->getIntersections();
    osgUtil::LineSegmentIntersector::Intersections::iterator iter;
    for (iter = intersections. begin(); iter != intersections. end(); + + iter)
    {
        std::cout << "ratio:" << " " << iter->ratio << " x:" << iter->getWorldIntersectPoint().x() << " y: " << iter->getWorldIntersectPoint().y() << " z:" << iter->getWorldIntersectPoint().z() << std::endl;
    }

    viewer1->setSceneData(group1.get());
    viewer1->setUpViewInWindow(200, 200, 800, 600, 0);

    return viewer1->run();
}

The above code constructs a line segment, and the starting coordinates of the line segment are as follows:

Vec3(0, 0,15)

The coordinates of the end point are as follows:

osg::Vec3(0, 0, -15)

At the same time, a cuboid is constructed. The center of the cuboid is at the origin, and the length, width, and height are 5, 4, and 3, respectively.

The effect is as follows (note: for the convenience of observation, I rotated the cuboid around the X axis counterclockwise by a certain angle):

figure 1

Lines 27 and 28 of the above code construct an intersection and intersection accessor objects. Through the mutual cooperation between the intersection seeker and the intersection accessor object, and by calling the accept function of the code on line 31, the intersection point of the line segment and the cuboid can be obtained, and the result is as follows:

figure 2

The meaning of ratio is as follows:

 ( Ls_z - Is_z ) / Line_Z_Length

Among them, Ls_z indicates the z coordinate value of the starting point of the line segment; Is_z indicates the z coordinate of the cuboid at the intersection point when the line segment and the cuboid intersect; Line_Z_Length indicates the total length of the line segment on the Z axis. In the above example, the z coordinate of the starting point of the line segment is 15, and the total length of the line segment on the Z axis is 15 -(-15) = 30. As shown in Figure 2, the z coordinate of the cuboid at the first intersection point is 3, and the first ratio is:

(15 - 3) / 30 = 0.4

Similarly, the ratio of the last intersection point can be calculated as:

 [ 15 - (-3 )] / 30 = 0.6

When the coordinates of the starting point and ending point of the line segment on line 27 are replaced with the following code:

osg::ref_ptr<osgUtil::LineSegmentIntersector> lineSegmentIntesector = new osgUtil::LineSegmentIntersector(osg::Vec3(1, 5, 2), osg::Vec3(15, 0, -2));</pre >
<p>Then the result is as follows:</p>
<p><img alt="" src="//i2.wp.com/img-blog.csdnimg.cn/a6d1df7db97d462c808f04c2d96ce78d.png"></p>
<p>image 3 </p>
<p> According to the ratio calculation method mentioned above, the z coordinate of the starting point of the line segment is 2, and the total length of the line segment on the Z axis is 2 -(-2) = 4. As shown in Figure 3, the z coordinate of the cuboid at the first intersection point is 1.2, Then the first ratio is:</p>
<pre> (2 - 1.2) / 4.0 = 0.2

Similarly, the second ratio is:

 ( 2 - 0.857143 ) / 4 = 0.285714

In normal development, you can know the ratio of the intersection point to the z-axis of the entire line segment according to the ratio.

In Figure 2, it can be seen that the first and second intersection points are the same point; the third and fourth intersection points are also the same point, why are there two identical intersection points? The following analysis is as follows:

Follow up to the underlying source code through breakpoints and find that although the six sides of the cuboid are quadrilaterals, OPenGl realizes a quadrilateral by drawing two triangles. That is, the quadrilaterals on the top and bottom of the cuboid are drawn as follows:

Figure 4

Draw two triangles twice in the for loop to form a quadrilateral (the quadrilateral is formed by splicing two triangles. In the underlying hardware implementation, most polygons are drawn by dividing them into triangles, which is more efficient) . The first cycle draws a v0v1v2 (or v0v2v3) triangle, and at this time it is detected that the line segment and the triangle intersect at point A; the second cycle draws a v0v2v3 (or v0v1v2) triangle, and at this time it is detected that the line segment and the triangle intersect at point A , which is why the above intersection is output twice.

If you change line 13 of the above code to the following:

    auto box1 = new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0, 0.0, 0.0), 0.1, 0.1, 20))

That is, make the width and height of the cuboid as small as possible, and the result is as follows (note: for the convenience of observation, I rotated the cuboid around the X-axis by a certain angle counterclockwise):

Figure 5

It can be seen that there is only one intersection point between the upper surface of the cuboid and the straight line, and the intersection point between the lower bottom surface and the straight line conforms to the triangle description mentioned above. Two identical intersection values are output. The upper surface and the lower bottom surface of the cuboid are parallel to the horizontal plane, which should be It is said that there is no difference between the upper top surface and the lower bottom surface. They should output 2 identical intersection values. Track the intersect function of the LineSegmentIntersector.cpp file:

void intersect(const osg::Vec3 & amp; v0, const osg::Vec3 & amp; v1, const osg::Vec3 & amp; v2)
    {


          ....... //Other codes are omitted
              if ((u + v) > det)
            {
                return; // The top surface should have output 2 identical intersection points, but there is a triangle detection, and returned from here
            }

           ....... //Other codes are omitted
   }

The upper top surface should have output 2 identical intersection points, but when there is a triangle detection on the upper top surface, it returned from return, resulting in the intersection point not being inserted into the intersection point container. .

Through testing, it is found that as long as the length, width, and height of the cuboid are less than 1, this problem will exist.