/*---------------------------------------------------------------------------*\

    geophase: A C++ template library for geometrical operations on non-convex
    polyhedra with non-planar faces
     
    Copyright (C) 2019 Tomislav Maric, TU Darmstadt 

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.


Description
    Axis aligned bounding box intersection tests. 

Authors
    Tomislav Maric maric@mma.tu-darmstadt.de

\*---------------------------------------------------------------------------*/

#ifndef AABBintersectionTest_H 
#define AABBintersectionTest_H 

#include "dimension.H"
#include "AABBox.H"
#include "PointSequence.H"
#include "PolygonSequence.H"
#include "Build.H"

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

namespace Foam { namespace GeometricalTransport { 
    
    template
    <
        int D, 
        typename Point1, 
        typename Point2
    > 
    struct overlap
    {
        static bool apply(
            Point1 const& b1min, 
            Point1 const& b1max, 
            Point2 const& b2min, 
            Point2 const& b2max,
            const double tolerance = Traits::tolerance<Point1>::value() 
        )
        {
            if ((b1min[D-1] >=  b2max[D-1]) || (b2min[D-1] >= b1max[D-1]))
            {
                return false; 
            }

            return overlap<D-1, Point1, Point2>::apply(b1min, b1max, b2min, b2max, tolerance); 
        }
    };

    template<typename Point1, typename Point2>
    struct overlap<0, Point1, Point2>
    {
        static bool apply(
            Point1 const& b1min, 
            Point1 const& b1max, 
            Point2 const& b2min, 
            Point2 const& b2max,
            const double tolerance 
        )
        {
            return true;  
        }
    };

    template<typename Box>
    typename std::enable_if
    <
        Traits::tag_enabled<Box, aabbox_tag>::value,
        bool 
    >::type
    aabb_do_intersect(
        Box const& b1, 
        Box const& b2,
        const double tolerance = Traits::tolerance<Box>::value()
    )
    {
        const auto& b1min = b1.minPoint();  
        const auto& b1max = b1.maxPoint();  

        const auto& b2min = b2.minPoint();  
        const auto& b2max = b2.maxPoint();  

        return overlap
        <
            Traits::dimension<decltype(b1min)>::D, 
            decltype(b1min), 
            decltype(b2min)
        >::apply(b1min, b1max, b2min, b2max, tolerance);  
    }

    // Specialize for box type: do not build boxes from boxes.
    template<typename FirstGeometry, typename SecondGeometry>
    bool aabb_do_intersect(
        FirstGeometry const& first, 
        SecondGeometry const& second,
        const double tolerance = Traits::tolerance<FirstGeometry>::value()
    )
    {
        typedef AABBox<point> aabbox; 

        auto b1 = build<aabbox>(first); 
        auto b2 = build<aabbox>(second);

        return aabb_do_intersect(b1,b2); 
    }

    struct aabb_test
    {
        template
        <
            typename FirstGeometry, 
            typename SecondGeometry
        >
        static bool apply(
            FirstGeometry const & first, 
            SecondGeometry const & second,
            const double tolerance = Traits::tolerance<FirstGeometry>::value()
        )
        {
            return aabb_do_intersect(first, second, tolerance);
        }
    };

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

}} // End namespace Foam::GeometricalTransport::Geometry 

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

#endif

// ************************************************************************* //
