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

    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
    Area calculation.

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

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

#ifndef Area_H 
#define Area_H 

#include "tag.hpp"
#include "Polygon.hpp"
#include "Centroid.hpp"

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

namespace geophase {

    template <typename Cmpt, auto N>
    constexpr Cmpt area_oriented(Vector<Cmpt, N> const&)
    {
        return Cmpt{0}; 
    }

    template <typename Vector=vector, typename Polygon>
    std::enable_if_t<tag_base_of<Polygon, sequence_polygon_tag>(), Vector>
    area_normal_oriented(Polygon const& polygon)
    {
        Vector result {};

        const auto begin = polygon.cbegin(); 
        auto it (std::next(begin)); 
        auto it_next (std::next(it)); 
        for (int i = 0; 
             // Cast to int, otherwise with degenerate polygons of size 
             // 1, polygon.size() - 2 will cause an integer underflow, 
             // leading to max int value, and loop never stopping. TM.
             i < (int(polygon.size()) - 2); ++i, ++it, ++it_next)
        {
            result += cross((*it) - *begin, *it_next - *begin);
        }

        result *= 0.5; 

        return result; 
    }

    template<typename Polygon> 
    std::enable_if_t
    <
        tag_base_of<Polygon, sequence_polygon_tag>(), 
        typename Polygon::value_type::value_type
    >
    area_oriented(Polygon const& polygon)
    {
        return mag(area_normal_oriented(polygon));
    }

    template<typename Vector> 
    typename Vector::value_type 
    area_oriented(ArrayPolygon<Vector, 3> const& tri)
    {
        return 0.5 * mag(cross(tri[1] - tri[0],
                               tri[2] - tri[0]));
    }

    template<typename Vector> 
    typename Vector::value_type 
    area_oriented(ArrayPolygon<Vector, 4> const& rec)
    {
        auto rec02 = rec[2] - rec[0];
        return 0.5 * (mag(cross(rec[1] - rec[0], rec02)) + 
                     mag(cross(rec02, rec[3] - rec[0]))); 
    }


    template <typename Polygon>
    std::enable_if_t<tag_base_of<Polygon, sequence_polygon_tag>(), typename Polygon::value_type>
    area_normal_vector(typename Polygon::value_type const& centroid, Polygon const& polygon)
    {
        using Vector = typename Polygon::value_type;
        Vector result = {};

        auto it = polygon.begin(); 
        auto itnext (it); 
        ++itnext; 

        for (; itnext != polygon.end(); ++it, ++itnext)
            result += cross(*it - centroid, *itnext - centroid); 

        result += cross(*it - centroid, polygon.front() - centroid); 
        result *= 0.5; 

        return result; 
    }

    template <typename Polygon>
    std::enable_if_t<tag_base_of<Polygon, sequence_polygon_tag>(), typename Polygon::value_type>
    area_normal_vector(Polygon const& polygon)
    {
        return area_normal_vector(centroid(polygon), polygon); 
    }


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

} // End namespace geophase.

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

#endif

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