// Geometric Tools, LLC
// Copyright (c) 1998-2010
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
//
// File Version: 4.10.0 (2009/11/18)

#ifndef WM4TRIANGULATEEC_H
#define WM4TRIANGULATEEC_H

#include "Wm4FoundationLIB.h"
#include "Wm4Query2.h"
#include "Wm4Vector2.h"

//#define TRIANGULATEEC_DEBUG

namespace Wm4
{

template <class Real>
class WM4_FOUNDATION_ITEM TriangulateEC
{
public:
    // This class implements triangulation of polygons using ear clipping.
    // The method is O(n^2) for n input points.  There are five constructors.
    // The query type and epsilon parameters are discussed later.  In all
    // cases, the output is
    //
    //    triangles:
    //        An array of 3*T indices representing T triangles.  Each triple
    //        (i0,i1,i2) corresponds to the triangle (P[i0],P[i1],P[i2]),
    //        where P is the 'positions' input.  These triangles are all
    //        counterclockwise ordered.
    //
    // TriangulateEC(positions,queryType,epsilon,triangles)
    //    positions:
    //        An array of n vertex positions for a simple polygon.  The
    //        polygon is (P[0],P[1],...,P[n-1]).
    //               
    // TriangulateEC(positions,queryType,epsilon,polygon,triangles)
    //    positions:
    //        An array of vertex positions, not necessarily the exact set of
    //        positions for the polygon vertices.
    //    polygon:
    //        An array of n indices into 'positions'.  If the array is
    //        (I[0],I[1],...,I[n-1]), the polygon vertices are
    //        (P[I[0]],P[I[1]],...,P[I[n-1]]).
    //               
    // TriangulateEC(positions,queryType,epsilon,outerPolygon,innerPolygon,
    //               triangles)
    //    positions:
    //        An array of vertex positions, not necessarily the exact set of
    //        positions for the polygon vertices.
    //    outerPolygon:
    //        An array of n indices into 'positions' for the outer polygon.
    //        If the array is (I[0],I[1],...,I[n-1]), the outer polygon
    //        vertices are (P[I[0]],P[I[1]],...,P[I[n-1]]).
    //    innerPolygon:
    //        An array of m indices into 'positions' for the inner polygon.
    //        The inner polygon must be strictly inside the outer polygon.
    //        If the array is (J[0],J[1],...,J[m-1]), the inner polygon
    //        vertices are (P[J[0]],P[J[1]],...,P[J[m-1]]).
    //               
    // TriangulateEC(positions,queryType,epsilon,outerPolygon,innerPolygons,
    //               triangles)
    //    positions:
    //        An array of vertex positions, not necessarily the exact set of
    //        positions for the polygon vertices.
    //    outerPolygon:
    //        An array of n indices into 'positions' for the outer polygon.
    //        If the array is (I[0],I[1],...,I[n-1]), the outer polygon
    //        vertices are (P[I[0]],P[I[1]],...,P[I[n-1]]).
    //    innerPolygons:
    //        An array of arrays of indices, each index array representing
    //        an inner polygon.  The inner polygons must be nonoverlapping and
    //        strictly contained in the outer polygon.  If innerPolygons[i]
    //        is the array (J[0],J[1],...,J[m-1]), the inner polygon
    //        vertices are (P[J[0]],P[J[1]],...,P[J[m-1]]).
    //               
    // TriangulateEC(positions,queryType,epsilon,tree,triangles)
    //    positions:
    //        An array of vertex positions, not necessarily the exact set of
    //        positions for the polygon vertices.
    //    tree:
    //        A hierarchy of nested polygons.  The root node corresponds to
    //        the outermost outer polygon.  The child nodes of the root
    //        correspond to inner polygons contained by the outer polygon.
    //        Each inner polygon may itself contain outer polygons, and
    //        those outer polygons may themselves contain inner polygons.
    //
    // You have a choice of speed versus accuracy.  The fastest choice is
    // Query::QT_INT64, but it gives up a lot of precision, scaling the points
    // to [0,2^{20}]^3.  The choice Query::QT_INTEGER gives up less precision,
    // scaling the points to [0,2^{24}]^3.  The choice Query::QT_RATIONAL uses
    // exact arithmetic, but is the slowest choice.  The choice Query::QT_REAL
    // uses floating-point arithmetic, but is not robust in all cases.  The
    // choice Query::QT_FILTERED uses floating-point arithmetic to compute
    // determinants whose signs are of interest.  If the floating-point value
    // is nearly zero, the determinant is recomputed using exact rational
    // arithmetic in order to correctly classify the sign.  The hope is to
    // have an exact result computed faster than with all rational arithmetic.
    // The value fEpsilon is used only for the Query::QT_FILTERED case and
    // should be in [0,1].  If 0, the method defaults to all exact rational
    // arithmetic.  If 1, the method defaults to all floating-point
    // arithmetic.  Generally, if M is the maximum absolute value of a
    // determinant and if d is the current determinant value computed as a
    // floating-point quantity, the recalculation with rational arithmetic
    // occurs when |d| < epsilon*M.

    // Convenient typedefs.
    typedef std::vector<Vector2<Real> > Positions;
    typedef std::vector<int> Indices;
    typedef std::vector<Indices*> IndicesArray;
    typedef std::map<int,int> IndexMap;

    // The input rkPosition represents an array of vertices for a simple
    // polygon. The vertices are rkPosition[0] through rkPosition[n-1], where
    // n = rkPolygon.size(), and are listed in counterclockwise order.
    TriangulateEC (const Positions& rkPositions, Query::Type eQueryType,
        Real fEpsilon, Indices& rkTriangles);

    // The input rkPositions represents an array of vertices that contains the
    // vertices of a simple polygon.  The input rkPolygon represents a simple
    // polygon whose vertices are rkPositions[rkPolygon[0]] through
    // rkPositions[rkPolygon[m-1]], where m = rkPolygon.size(), and are listed
    // in counterclockwise ordered.
    TriangulateEC (const Positions& rkPositions, Query::Type eQueryType,
        Real fEpsilon, const Indices& rkPolygon, Indices& rkTriangles);

    // The input rkPositions is a shared array of vertices that contains the
    // vertices for two simple polygons, an outer polygon and an inner
    // polygon.  The inner polygon must be strictly inside the outer polygon.
    // The input rkOuter represents the outer polygon whose vertices are
    // rkPositions[rkOuter[0]] through rkPositions[rkOuter[n-1]], where
    // n = rkOuter.size(), and are listed in counterclockwise order.  The
    // input rkInner represents the inner polygon whose vertices are
    // rkPositions[rkInner[0]] through rkPositions[rkInner[m-1]], where
    // m = rkInner.size(), and are listed in clockwise order.
    TriangulateEC (const Positions& rkPositions, Query::Type eQueryType,
        Real fEpsilon, const Indices& rkOuter, const Indices& rkInner,
        Indices& rkTriangles);

    // The input rkPositions is a shared array of vertices that contains the
    // vertices for multiple simple polygons, an outer polygon and one or more
    // inner polygons.  The inner polygons must be nonoverlapping and strictly
    // inside the outer polygon.  The input rkOuter represents the outer
    // polygon whose vertices are rkPositions[rkOuter[0]] through
    // rkPositions[rkOuter[n-1]], where n = rkOuter.size(), and are listed in
    // counterclockwise order.  The input element rkInners[i] represents the
    // i-th inner polygon whose vertices are rkPositions[rkInners[i][0]]
    // through rkPositions[rkInners[i][m-1]], where m = rkInners[i].size(),
    // and are listed in clockwise order.
    TriangulateEC (const Positions& rkPositions, Query::Type eQueryType,
        Real fEpsilon, const Indices& rkOuter, const IndicesArray& rkInners,
        Indices& rkTriangles);

    // A tree of nested polygons.  The root node corresponds to an outer
    // polygon.  The children of the root correspond to inner polygons, which
    // are nonoverlapping polygons strictly contained in the outer polygon.
    // Each inner polygon may itself contain an outer polygon, thus leading
    // to a hierarchy of polygons.  The outer polygons have vertices listed
    // in counterclockwise order.  The inner polygons have vertices listed in
    // clockwise order.
    class WM4_FOUNDATION_ITEM Tree
    {
    public:
        Indices Polygon;
        std::vector<Tree*> Child;
    };

    // The input rkPositions is a shared array of vertices that contains the
    // vertices for multiple simple polygons in a tree of polygons.
    TriangulateEC (const Positions& rkPositions, Query::Type eQueryType,
        Real fEpsilon, const Tree* pkTree, Indices& rkTriangles);

    ~TriangulateEC ();

    // Helper function to delete Tree objects.  Call this only if all tree
    // nodes were dynamically allocated.
    static void Delete (Tree*& rpkRoot);

private:
    // Create the query object and scaled positions to be used during
    // triangulation.  Extra elements are required when triangulating polygons
    // with holes.  These are preallocated to avoid dynamic resizing during
    // the triangulation.
    void InitializePositions (const Positions& rkPositions,
        Query::Type eQueryType, Real fEpsilon, int iExtraElements);

    // Create the vertex objects that store the various lists required by the
    // ear-clipping algorithm.
    void InitializeVertices (int iVQuantity, const int* aiIndex);

    // Apply ear clipping to the input polygon.  Polygons with holes are
    // preprocessed to obtain an index array that is nearly a simple polygon.
    // This outer polygon has a pair of coincident edges per inner polygon.
    void DoEarClipping (int iVQuantity, const int* aiIndex,
        Indices& rkTriangles);

    // This function is used to help determine a pair of visible vertices
    // for the purpose of triangulating polygons with holes.  The query is
    // point-in-triangle, but is encapsulated here to use the same type of
    // query object that the user specified in the constructors.
    int TriangleQuery (const Vector2<Real>& rkPosition,
        Query::Type eQueryType, Real fEpsilon,
        const Vector2<Real> akTriangle[3]) const;

    // Given an outer polygon that contains an inner polygon, this function
    // determines a pair of visible vertices and inserts two coincident edges
    // to generate a nearly simple polygon.
    void CombinePolygons (Query::Type eQueryType, Real fEpsilon,
        int iNextElement, const Indices& rkOuter, const Indices& rkInner,
        IndexMap& rkMap, Indices& rkCombined);

    // Two extra elements are needed in the position array per outer-inners
    // polygon.  This function computes the total number of extra elements
    // needed for the input tree.  This number is passed to the function
    // InitializePositions.
    static int GetExtraElements (const Tree* pkTree);

    // Given an outer polygon that contains a set of nonoverlapping inner
    // polygons, this function determines pairs of visible vertices and
    // inserts coincident edges to generate a nearly simple polygon.  It
    // repeatedly calls CombinePolygons for each inner polygon of the outer
    // polygon.
    void ProcessOuterAndInners (Query::Type eQueryType, Real fEpsilon,
        const Indices& rkOuter, const IndicesArray& rkInners,
        int& rkNextElement, IndexMap& rkMap, Indices& rkCombined);

    // The insertion of coincident edges to obtain a nearly simple polygon
    // requires duplication of vertices in order that the ear-clipping
    // algorithm work correctly.  After the triangulation, the indices of
    // the duplicated vertices are converted to the original indices.
    void RemapIndices (const IndexMap& rkMap, Indices& rkTriangles) const;

    // Doubly linked lists for storing specially tagged vertices.
    class WM4_FOUNDATION_ITEM Vertex
    {
    public:
        Vertex ()
        {
            Index = -1;
            IsConvex = true;
            IsEar = false;
            VPrev = -1;
            VNext = -1;
            SPrev = -1;
            SNext = -1;
            EPrev = -1;
            ENext = -1;
        }

        int Index;  // index of vertex in position array
        bool IsConvex, IsEar;
        int VPrev, VNext; // vertex links for polygon
        int SPrev, SNext; // convex/reflex vertex links (disjoint lists)
        int EPrev, ENext; // ear links
    };

    Vertex& V (int i);
    bool IsConvex (int i);
    bool IsEar (int i);
    void InsertAfterC (int i);   // insert convex vertex
    void InsertAfterR (int i);   // insert reflex vertesx
    void InsertEndE (int i);     // insert ear at end of list
    void InsertAfterE (int i);   // insert ear after efirst
    void InsertBeforeE (int i);  // insert ear before efirst
    void RemoveV (int i);        // remove vertex
    void RemoveE (int i);        // remove ear at i
    void RemoveEFirst ();        // remove ear at m_iEFirst
    void RemoveR (int i);        // remove reflex vertex

    // The doubly linked list.
    std::vector<Vertex> m_kVertex;
    int m_iCFirst, m_iCLast;  // linear list of convex vertices
    int m_iRFirst, m_iRLast;  // linear list of reflex vertices
    int m_iEFirst, m_iELast;  // cyclical list of ears

    // For robust determinant calculation.
    Query2<Real>* m_pkQuery;
    std::vector<Vector2<Real> >m_kSPositions;

#ifdef TRIANGULATEEC_DEBUG
    void ValidateReflexList () const;
    void ValidateEarList () const;
#endif
};

}

#endif
