
// CubicInfo.hpp - interface to class to compute facet angle from cubic Bezier segment

#ifndef __CubicInfo_hpp__
#define __CubicInfo_hpp__

#include <Cg/vector/xyzw.hpp>
#include <Cg/double.hpp>
#include <Cg/vector.hpp>
#include <Cg/matrix.hpp>

using namespace Cg;

class CubicInfo {
    float3 cp[4];

    double2 A;
    double2 B;
    double2 C;

    float limit_angle;
    double2 limit_direction;

    enum CubicToplogy {
        LOOP,
        SERPENTINE,
        REVERSING_LINE
    } kind;

    // Serpentine cubics have num_inflections==2 so need this state.
    float inflection_t[2];
    double t_bound[4];
    float angle_bound[4];
    double curvature[3];

    float findCorrectSerpentineT(int interval, float angle, float orig_t, float t_direction);
    double fromBiasedAngleFindSerpentineT(float theta, int interval, float t, float t_direction, float bias);
    double fromBiasedAngleFindReversingLineT(float theta, int interval, float t, float t_direction, float bias);
    float fixOutOfBoundsTheta(float theta, float t, int num_bounds, bool theta_in_interval[/*num_bounds-1*/]);
    double2 computeSerpentineCubicFacetTPair(float t, float theta, float max_turning_angle_delta, int step_mode);
    double2 computeReversingLineCubicFacetTPair(float t, float theta, float max_turning_angle_delta, int step_mode);
    double pickBetterIntervalBound(int interval, float angle, float orig_t, float t_direction);

    double2 computeLoopCubicFacetTPair(float t, float theta, float max_turning_angle_delta, int step_mode);
    float biasCubicFacetAngleLoop(float t, float t_direction, float theta, float bias);
    double fromBiasedAngleFindLoopT(float theta, float t, float t_direction, float bias);
    float findCorrectLoopT(float angle, float orig_t, float t_direction);

    // ctor helpers
    void computeLimitAngleAndDirection();
    void computeMonomialCoeffs();
    void computeLoopCurvatureState(/*no inflection key_point's*/);
    void computeReversingLineCurvatureState(const double key_point[1]);
    void computeSerpintineCurvatureState(const double key_point[2]);
    void computeCurvatureState();

public:
    CubicInfo(const float3 cps[4]);
    float computeFacetAngle(float t, float max_turning_angle_delta, int step_mode);
};

template <typename FLOAT, typename FLOAT2, typename FLOAT3>
FLOAT3 get_abc(FLOAT theta, const FLOAT2& A, const FLOAT2& B, const FLOAT2& C)
{
    // Rotate A, B, and C by theta
    FLOAT a = sin(theta)*A.x - A.y*cos(theta);
    FLOAT b = sin(theta)*B.x - B.y*cos(theta);
    FLOAT c = sin(theta)*C.x - C.y*cos(theta);

    return FLOAT3(a,b,c);
}

#endif // __CubicInfo_hpp__
