// David Eberly, Geometric Tools, Redmond WA 98052
// Copyright (c) 1998-2020
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
// https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
// Version: 4.0.2019.08.13

#pragma once

#include <Mathematics/IntrLine3Plane3.h>
#include <Mathematics/Segment.h>

namespace WwiseGTE
{
    template <typename Real>
    class TIQuery<Real, Segment3<Real>, Plane3<Real>>
    {
    public:
        struct Result
        {
            bool intersect;
        };

        Result operator()(Segment3<Real> const& segment, Plane3<Real> const& plane)
        {
            Result result;

            // Compute the (signed) distance from the segment endpoints to the
            // plane.
            DCPQuery<Real, Vector3<Real>, Plane3<Real>> vpQuery;
            Real sdistance0 = vpQuery(segment.p[0], plane).signedDistance;
            if (sdistance0 == (Real)0)
            {
                // Endpoint p[0] is on the plane.
                result.intersect = true;
                return result;
            }

            Real sdistance1 = vpQuery(segment.p[1], plane).signedDistance;
            if (sdistance1 == (Real)0)
            {
                // Endpoint p[1] is on the plane.
                result.intersect = true;
                return result;
            }

            // Test whether the segment transversely intersects the plane.
            result.intersect = (sdistance0 * sdistance1 < (Real)0);
            return result;
        }
    };

    template <typename Real>
    class FIQuery<Real, Segment3<Real>, Plane3<Real>>
        :
        public FIQuery<Real, Line3<Real>, Plane3<Real>>
    {
    public:
        struct Result
            :
            public FIQuery<Real, Line3<Real>, Plane3<Real>>::Result
        {
            // No additional information to compute.
        };

        Result operator()(Segment3<Real> const& segment, Plane3<Real> const& plane)
        {
            Vector3<Real> segOrigin, segDirection;
            Real segExtent;
            segment.GetCenteredForm(segOrigin, segDirection, segExtent);

            Result result;
            DoQuery(segOrigin, segDirection, segExtent, plane, result);
            if (result.intersect)
            {
                result.point = segOrigin + result.parameter * segDirection;
            }
            return result;
        }

    protected:
        void DoQuery(Vector3<Real> const& segOrigin,
            Vector3<Real> const& segDirection, Real segExtent,
            Plane3<Real> const& plane, Result& result)
        {
            FIQuery<Real, Line3<Real>, Plane3<Real>>::DoQuery(segOrigin,
                segDirection, plane, result);
            if (result.intersect)
            {
                // The line intersects the plane in a point that might not be
                // on the segment.
                if (std::fabs(result.parameter) > segExtent)
                {
                    result.intersect = false;
                    result.numIntersections = 0;
                }
            }
        }
    };
}