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

    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/>.

Application
    geophaseTestExtremePoints

Description
    Find extreme points of a geometry along a projection axis. 
   
Author
    Tomislav Maric maric@mma.tu-darmstadt.de

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

#include <vector>
#include <algorithm>
#include <random>

#include "ExtremePoints.hpp"
#include "AxisAlignedBoundingBox.hpp" 
#include "Polygon.hpp"
#include "Polyhedron.hpp"
#include "Make.hpp"

using namespace geophase;

#include <fstream>
#include "gtest/gtest.h" 

TEST(assignLess, point)
{
    vector a = {0.,0.,0.};
    vector b = {1.,1.,1.};

    assign_less(b, a); 
    ASSERT_TRUE(a == b)
        << "a = " << a << std::endl
        << "b = " << b << std::endl;
}

TEST(assignGreater, point)
{
    vector a = {0.,0.,0.};
    vector b = {1.,1.,1.};

    assign_greater(a, b); 
    ASSERT_TRUE(a == b)
        << "a = " << a << std::endl
        << "b = " << b << std::endl;
}

TEST(extremePoints, goldenPoints) 
{
    vectorPolygon polygon = {{0.,0.,0.}, {-1.,-1., -1.}, {2., 3., 4.}, {-2., 6., -8.}}; 

    auto extrPointPair = extreme_points(polygon); 

    ASSERT_TRUE(extrPointPair.first == point(-2., -1., -8.)) 
        << "Minimal point = " << extrPointPair.first << std::endl;
    ASSERT_TRUE(extrPointPair.second == point(2., 6., 4.))
        << "Maximal point = " << extrPointPair.second << std::endl;

    aabbox box(polygon); 

    ASSERT_TRUE(box.minPoint() == point(-2., -1., -8.)) 
        << "Minimal point = " << extrPointPair.first << std::endl;
    ASSERT_TRUE(box.maxPoint() == point(2., 6., 4.))
        << "Maximal point = " << extrPointPair.second << std::endl;
}

TEST(extremeProjectedPoints, goldenPoints) 
{
    vectorPolygon polygon = {{0.,0.,0.}, {-1.,-1., -1.}, {2., 3., 4.}, {-2., 6., -8.}}; 
    auto extrPointPair = extreme_points(polygon, vector(1.,0.,0.)); 

    ASSERT_TRUE(extrPointPair.first == polygon.back()); 
    ASSERT_TRUE(extrPointPair.second == polygon[2]); 
}

TEST(extremeProjectedPoints, cubeSpatialDiagonalPoints) 
{
    auto cube = make<vectorPolyhedron>(point(0.,0.,0.), point(1.,1.,1.));

    vector direction (1.,1.,1.); 
    auto result = extreme_points(cube, direction); 
    
    ASSERT_TRUE(result.first == point(0.,0.,0.)); 
    ASSERT_TRUE(result.second == point(1.,1.,1.)); 

    direction = vector(1.,1.,0.); 
    result = extreme_points(cube, direction); 
    
    ASSERT_TRUE(result.first == point(0.,0.,0.) || result.first == point(0., 0., 1.))
        << result.first[0] << " " 
        << result.first[1] << " " 
        << result.first[2] << "\n";
    ASSERT_TRUE(result.second == point(1.,1.,0.) || result.second == point(1.,1.,1.))
        << result.second[0] << " " 
        << result.second[1] << " " 
        << result.second[2] << "\n";
}

int main(int argc, char *argv[])
{
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}



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