intersect_line_triangle.hpp

Back to Intersection between shapes

pastel/geometry/intersect/

#ifndef PASTELGEOMETRY_INTERSECT_LINE_TRIANGLE_HPP
#define PASTELGEOMETRY_INTERSECT_LINE_TRIANGLE_HPP

#include "pastel/geometry/intersect/intersect_line_triangle.h"
#include "pastel/geometry/shape/line.h"
#include "pastel/geometry/shape/triangle.h"
#include "pastel/geometry/shape/plane.h"

#include "pastel/sys/mytypes.h"
#include "pastel/sys/vector.h"
#include "pastel/sys/vector/vector_tools.h"

namespace Pastel
{

    template <typename Real>
    bool intersect(
        const Line<Real, 2>& line,
        const PASTEL_TRIANGLE(Real, 2)& triangle,
        Vector<Real, 2>& hitList)
    {
        const Vector<Real, 2>& a = triangle[0];
        const Vector<Real, 2>& b = triangle[1];
        const Vector<Real, 2>& c = triangle[2];

        Real tMaxMin = -Infinity();
        Real tMinMax = Infinity();

        // Note: line-plane intersections
        // do not require normalized plane normals.

        // Side a.

        Plane<Real, 2> aPlane(a, cross(b - a));

        Real t;
        if (intersect(line, aPlane, t))
        {
            if (side(line.position(), aPlane) >= 0)
            {
                if (t > tMaxMin)
                {
                    tMaxMin = t;
                }
            }
            else
            {
                if (t < tMinMax)
                {
                    tMinMax = t;
                }
            }
        }

        if (tMaxMin > tMinMax)
        {
            return false;
        }

        // Side b.

        Plane<Real, 2> bPlane(b, cross(c - b));

        if (intersect(line, bPlane, t))
        {
            if (side(line.position(), bPlane) >= 0)
            {
                if (t > tMaxMin)
                {
                    tMaxMin = t;
                }
            }
            else
            {
                if (t < tMinMax)
                {
                    tMinMax = t;
                }
            }
        }

        if (tMaxMin > tMinMax)
        {
            return false;
        }

        // Side c.

        Plane<Real, 2> cPlane(c, cross(a - c));

        if (intersect(line, cPlane, t))
        {
            if (side(line.position(), cPlane) >= 0)
            {
                if (t > tMaxMin)
                {
                    tMaxMin = t;
                }
            }
            else
            {
                if (t < tMinMax)
                {
                    tMinMax = t;
                }
            }
        }

        if (tMaxMin > tMinMax)
        {
            return false;
        }

        hitList.set(tMaxMin, tMinMax);

        return true;
    }

    template <typename Real>
    bool intersect(
        const Line<Real, 3>& line,
        const PASTEL_TRIANGLE(Real, 3)& triangle,
        Real& tIntersection,
        Real& uIntersection,
        Real& vIntersection)
    {
        // Moeller-Trumbore line-triangle intersection algorithm
        // from the book "Real-time rendering", page 581

        Vector<Real, 3> e1 =
            triangle[1] - triangle[0];
        Vector<Real, 3> e2 =
            triangle[2] - triangle[0];

        Vector<Real, 3> p =
            cross(line.direction(), e2);

        Real a = dot(e1, p);

        // Test for parallel plane case

        /*
       static constexpr Real EPSILON(stringAsReal<Real>("0.01"));

       // EPSILON
       if (a * a <= dot(p, p) * dot(e1, e1) * EPSILON * EPSILON)
       {
           return false;
       }
       */

        // EPSILON
        if (a == 0)
        {
            return false;
        }

        // Find barycentric coordinates of the
        // plane-line intersection point
        // to test if it is inside the triangle

        Real f = inverse(a);

        Vector<Real, 3> s =
            line.position() - triangle[0];

        const Real u = dot(s, p) * f;

        if (u < 0 || u > 1)
        {
            // Intersection point not inside the triangle

            return false;
        }

        Vector<Real, 3> q = cross(s, e1);

        const Real v = dot(line.direction(), q) * f;

        if (v < 0 || u + v > 1)
        {
            // Intersection point not inside the triangle

            return false;
        }

        // Intersection point inside the triangle
        // => intersection

        const Real t = dot(e2, q) * f;

        tIntersection = t;
        uIntersection = u;
        vIntersection = v;

        return true;
    }

}

#endif