// Magic Software, Inc.
// http://www.magic-software.com
// Copyright (c) 2000, All Rights Reserved
//
// Source code from Magic Software is supplied under the terms of a license
// agreement and may not be copied or disclosed except in accordance with the
// terms of that agreement.  The various license agreements may be found at
// the Magic Software web site.  This file is subject to the license
//
// FREE SOURCE CODE
// http://www.magic-software.com/License/free.pdf

#include "MgcRTLib.h"

//----------------------------------------------------------------------------
template <class Vector>
MgcCurve<Vector>::MgcCurve (float fTMin, float fTMax)
{
    m_fTMin = fTMin;
    m_fTMax = fTMax;
}
//----------------------------------------------------------------------------
template <class Vector>
MgcCurve<Vector>::~MgcCurve ()
{
}
//---------------------------------------------------------------------------
template <class Vector>
float MgcCurve<Vector>::GetMinTime () const
{
    return m_fTMin;
}
//---------------------------------------------------------------------------
template <class Vector>
float MgcCurve<Vector>::GetMaxTime () const
{
    return m_fTMax;
}
//---------------------------------------------------------------------------
template <class Vector>
Vector MgcCurve<Vector>::GetTangent (float fTime) const
{
    Vector kVelocity = GetFirstDerivative(fTime);
    kVelocity.Unitize();
    return kVelocity;
}
//---------------------------------------------------------------------------
template <class Vector>
float MgcCurve<Vector>::GetSpeed (float fTime) const
{
    Vector kVelocity = GetFirstDerivative(fTime);
    float fSpeed = kVelocity.Length();
    return fSpeed;
}
//---------------------------------------------------------------------------
template <class Vector>
float MgcCurve<Vector>::GetTotalLength () const
{
    return GetLength(m_fTMin,m_fTMax);
}
//---------------------------------------------------------------------------
template <class Vector>
void MgcCurve<Vector>::SubdivideByTime (int iNumPoints,
    Vector*& rakPoint) const
{
    assert( iNumPoints >= 2 );
    rakPoint = new Vector[iNumPoints];

    float fDelta = (m_fTMax - m_fTMin)/(iNumPoints-1);

    for (int i = 0; i < iNumPoints; i++)
    {
        float fTime = m_fTMin + fDelta*i;
        rakPoint[i] = GetPosition(fTime);
    }
}
//---------------------------------------------------------------------------
template <class Vector>
void MgcCurve<Vector>::SubdivideByLength (int iNumPoints,
    Vector*& rakPoint) const
{
    assert( iNumPoints >= 2 );
    rakPoint = new Vector[iNumPoints];

    float fDelta = GetTotalLength()/(iNumPoints-1);

    for (int i = 0; i < iNumPoints; i++)
    {
        float fLength = fDelta*i;
        float fTime = GetTime(fLength);
        rakPoint[i] = GetPosition(fTime);
    }
}
//---------------------------------------------------------------------------
template <class Vector>
void MgcCurve<Vector>::SubdivideByVariation (float fT0, const Vector& rkP0,
    float fT1, const Vector& rkP1, float kMinVariation,
    unsigned int uiLevel, int& iNumPoints, PointList*& rpkList) const
{
    if ( uiLevel > 0 && GetVariation(fT0,rkP0,fT1,rkP1) > fMinVariation )
    {
        // too much variation, subdivide interval
        uiLevel--;
        float fTMid = 0.5*(fT0+fT1);
        Vector kPMid = GetPosition(fTMid);

        SubdivideByVariation(fT0,rkP0,fTMid,kPMid,fMinVariation,uiLevel,
            iNumPoints,rpkList);

        SubdivideByVariation(fTMid,kPMid,fT1,rkP1,fMinVariation,uiLevel,
            iNumPoints,rpkList);
    }
    else
    {
        // add right end point, left end point was added by neighbor
        rpkList = new PointList(rkP1);
        iNumPoints++;
    }
}
//---------------------------------------------------------------------------
template <class Vector>
void MgcCurve<Vector>::SubdivideByVariation (float fMinVariation,
    unsigned int uiMaxLevel, int& iNumPoints, Vector*& rakPoint) const
{
    // compute end points of curve
    Vector kPMin = GetPosition(m_fTMin);
    Vector kPMax = GetPosition(m_fTMax);

    // add left end point to list
    PointList* pkList = new PointList(kPMin);
    iNumPoints = 1;

    // binary subdivision, leaf nodes add right end point of subinterval
    SubdivideByVariation(m_fTMin,kPMin,m_fTMax,kPMax,fMinVariation,
        uiMaxLevel,iNumPoints,pkList->m_kNext);

    // repackage points in an array
    assert( iNumPoints >= 2 );
    rakPoint = new Vector[iNumPoints];
    for (int i = 0; i < iNumPoints; i++)
    {
        rakPoint[i] = pkList->m_kPoint;

        PointList* pkSave = pkList;
        pkList = pkList->m_kNext;
        delete pkSave;
    }
    assert( pkList == 0 );
}
//---------------------------------------------------------------------------
