/********************************************************************************
* ReactPhysics3D physics library, http://www.reactphysics3d.com                 *
* Copyright (c) 2010-2015 Daniel Chappuis                                       *
*********************************************************************************
*                                                                               *
* This software is provided 'as-is', without any express or implied warranty.   *
* In no event will the authors be held liable for any damages arising from the  *
* use of this software.                                                         *
*                                                                               *
* Permission is granted to anyone to use this software for any purpose,         *
* including commercial applications, and to alter it and redistribute it        *
* freely, subject to the following restrictions:                                *
*                                                                               *
* 1. The origin of this software must not be misrepresented; you must not claim *
*    that you wrote the original software. If you use this software in a        *
*    product, an acknowledgment in the product documentation would be           *
*    appreciated but is not required.                                           *
*                                                                               *
* 2. Altered source versions must be plainly marked as such, and must not be    *
*    misrepresented as being the original software.                             *
*                                                                               *
* 3. This notice may not be removed or altered from any source distribution.    *
*                                                                               *
********************************************************************************/


// Libraries
#include "TriangleEPA.h"
#include "EdgeEPA.h"
#include "TrianglesStore.h"

// We use the ReactPhysics3D namespace
using namespace reactphysics3d;

// Constructor
TriangleEPA::TriangleEPA() {
    
}

// Constructor
TriangleEPA::TriangleEPA(uint indexVertex1, uint indexVertex2, uint indexVertex3)
            : mIsObsolete(false) {
    mIndicesVertices[0] = indexVertex1;
    mIndicesVertices[1] = indexVertex2;
    mIndicesVertices[2] = indexVertex3;
}

// Destructor
TriangleEPA::~TriangleEPA() {

}

// Compute the point v closest to the origin of this triangle
bool TriangleEPA::computeClosestPoint(const Vector3* vertices) {
    const Vector3& p0 = vertices[mIndicesVertices[0]];

    Vector3 v1 = vertices[mIndicesVertices[1]] - p0;
    Vector3 v2 = vertices[mIndicesVertices[2]] - p0;
    decimal v1Dotv1 = v1.dot(v1);
    decimal v1Dotv2 = v1.dot(v2);
    decimal v2Dotv2 = v2.dot(v2);
    decimal p0Dotv1 = p0.dot(v1);
    decimal p0Dotv2 = p0.dot(v2);

    // Compute determinant
    mDet = v1Dotv1 * v2Dotv2 - v1Dotv2 * v1Dotv2;

    // Compute lambda values
    mLambda1 = p0Dotv2 * v1Dotv2 - p0Dotv1 * v2Dotv2;
    mLambda2 = p0Dotv1 * v1Dotv2 - p0Dotv2 * v1Dotv1;

    // If the determinant is positive
    if (mDet > 0.0) {
        // Compute the closest point v
        mClosestPoint = p0 + decimal(1.0) / mDet * (mLambda1 * v1 + mLambda2 * v2);

        // Compute the square distance of closest point to the origin
        mDistSquare = mClosestPoint.dot(mClosestPoint);

        return true;
    }

    return false;
}

/// Link an edge with another one. It means that the current edge of a triangle will
/// be associated with the edge of another triangle in order that both triangles
/// are neighbour along both edges).
bool reactphysics3d::link(const EdgeEPA& edge0, const EdgeEPA& edge1) {
    bool isPossible = (edge0.getSourceVertexIndex() == edge1.getTargetVertexIndex() &&
                       edge0.getTargetVertexIndex() == edge1.getSourceVertexIndex());

    if (isPossible) {
        edge0.getOwnerTriangle()->mAdjacentEdges[edge0.getIndex()] = edge1;
        edge1.getOwnerTriangle()->mAdjacentEdges[edge1.getIndex()] = edge0;
    }

    return isPossible;
}

/// Make an half link of an edge with another one from another triangle. An half-link
/// between an edge "edge0" and an edge "edge1" represents the fact that "edge1" is an
/// adjacent edge of "edge0" but not the opposite. The opposite edge connection will
/// be made later.
void reactphysics3d::halfLink(const EdgeEPA& edge0, const EdgeEPA& edge1) {
    assert(edge0.getSourceVertexIndex() == edge1.getTargetVertexIndex() &&
           edge0.getTargetVertexIndex() == edge1.getSourceVertexIndex());

    // Link
    edge0.getOwnerTriangle()->mAdjacentEdges[edge0.getIndex()] = edge1;
}

// Execute the recursive silhouette algorithm from this triangle face.
/// The parameter "vertices" is an array that contains the vertices of the current polytope and the
/// parameter "indexNewVertex" is the index of the new vertex in this array. The goal of the
/// silhouette algorithm is to add the new vertex in the polytope by keeping it convex. Therefore,
/// the triangle faces that are visible from the new vertex must be removed from the polytope and we
/// need to add triangle faces where each face contains the new vertex and an edge of the silhouette.
/// The silhouette is the connected set of edges that are part of the border between faces that
/// are seen and faces that are not seen from the new vertex. This method starts from the nearest
/// face from the new vertex, computes the silhouette and create the new faces from the new vertex in
/// order that we always have a convex polytope. The faces visible from the new vertex are set
/// obselete and will not be considered as being a candidate face in the future.
bool TriangleEPA::computeSilhouette(const Vector3* vertices, uint indexNewVertex,
                                    TrianglesStore& triangleStore) {
    
    uint first = triangleStore.getNbTriangles();

    // Mark the current triangle as obsolete because it
    setIsObsolete(true);

    // Execute recursively the silhouette algorithm for the adjacent edges of neighboring
    // triangles of the current triangle
    bool result = mAdjacentEdges[0].computeSilhouette(vertices, indexNewVertex, triangleStore) &&
                  mAdjacentEdges[1].computeSilhouette(vertices, indexNewVertex, triangleStore) &&
                  mAdjacentEdges[2].computeSilhouette(vertices, indexNewVertex, triangleStore);

    if (result) {
        int i,j;

        // For each triangle face that contains the new vertex and an edge of the silhouette
        for (i=first, j=triangleStore.getNbTriangles()-1;
             i != triangleStore.getNbTriangles(); j = i++) {
            TriangleEPA* triangle = &triangleStore[i];
            halfLink(triangle->getAdjacentEdge(1), EdgeEPA(triangle, 1));

            if (!link(EdgeEPA(triangle, 0), EdgeEPA(&triangleStore[j], 2))) {
                return false;
            }
        }

    }

    return result;
}
