
// cg4cpp_tangent.hpp - templated routines for tangent vectors

#ifndef __cg4cpp_tangent_hpp__
#define __cg4cpp_tangent_hpp__

#if !defined(HAS_INCLUDED_OPENGL_HEADERS)
# include "gl_headers.h"
#endif

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

#include <Cg/length.hpp>

// Return a 2D vector orthogonal to the input vector.
template <typename Tvec>
Tvec ortho(const Tvec& v)
{
    return Tvec(v.y, -v.x);
}

// Be more robust about finding an initial tangent
// of a Bezier curve.
//
// The analytical initial tangent for a cubic curve
// is algebraically normalize(P1-P0), but if P1 equals P0, the
// tangent is degenerate.
//
// This routine avoids degenerate tangents in the presence
// of duplicate control points.
template <int numPoints, typename Tvec>
static Tvec startTangent(const Tvec cp[])
{
    assert(numPoints >= 2);
    for (int i=1; i<numPoints; i++) {
        Tvec diff = cp[i]-cp[0];
        double len = length(double2(diff));
        if (len > 0) {
            return Tvec(diff/len);
        }
    }
    return Tvec(0);
}

// Be more robust about finding a final tangent
// of a Bezier curve.
//
// The analytical initial tangent for a cubic curve
// is algebraically normalize(Pn-Pm), but if the final
// control point Pn equals the next to final control
// point Pm, the tangent is degenerate.
//
// This routine avoids degenerate tangents in the presence
// of duplicate control points.
template <int numPoints, typename Tvec>
static Tvec endTangent(const Tvec cp[])
{
    assert(numPoints >= 2);
    for (int i=numPoints-2; i>=0; i--) {
        Tvec diff = cp[numPoints-1]-cp[i];
        double len = length(double2(diff));
        if (len > 0) {
            return Tvec(diff/len);
        }
    }
    return Tvec(0);
}

#endif // __cg4cpp_tangent_hpp__
