
// StrokerShaderConfig_util.cpp - utilities for working with StrokerShaderConfig

#include <cmath>

#include <Cg/double.hpp>

#include "StrokerShaderConfig_util.hpp"

#include <Cg/determinant.hpp>
#include <Cg/mul.hpp>
#include <Cg/transpose.hpp>
#include <Cg/upper2x2.hpp>

#include <Cg/iostream.hpp>

using namespace Cg;

static bool almostZero(double v)
{
    const double epsilon = 0.0001;
    if (fabs(v) < epsilon) {
        return true;
    } else {
        return false;
    }
}

static bool almostOneMagnitude(double v)
{
    return almostZero(1-fabs(v));
}

StrokeConfigTypes::TransformType matrixToTransformType(const float3x3& matrix)
{
    const size_t last_row = sizeof(matrix)/sizeof(matrix[0]) - 1;
    if (almostZero(matrix[last_row][0]) && almostZero(matrix[last_row][1])) {
        const double2x2 submatrix = upper2x2(matrix);
        const double2x2 submatrix_t = transpose(submatrix);
        const double2x2 combo = mul(submatrix, submatrix_t);
        const double det_combo = sqrt(determinant(combo));
        const double2x2 maybe_identity = combo/det_combo;
#if 0  // for debugging
        std::cout << "matrix = " << matrix << std::endl;
        std::cout << "submatrix = " << submatrix << std::endl;
        std::cout << "submatrix_t = " << submatrix_t << std::endl;
        std::cout << "combo = " << combo << std::endl;
        std::cout << "det_combo = " << det_combo << std::endl;
        std::cout << "maybe_identity = " << maybe_identity << std::endl;
#endif
        if (almostOneMagnitude(maybe_identity[0][0]) &&
            almostZero(maybe_identity[0][1]) &&
            almostZero(maybe_identity[1][0]) &&
            almostOneMagnitude(maybe_identity[1][1])) {
            return StrokeConfigTypes::SIMILIAR_AFFINE;
        } else {
            return StrokeConfigTypes::NON_SIMILAR_AFFINE;
        }
    } else {
        return StrokeConfigTypes::PROJECTIVE;
    }
}