Module: cmspline.cpp

class CMSpline
.h

constructorCMSpline()
destructor~CMSpline()
AllocatePointsvoid AllocatePoints(int n)
Resetvoid Reset()
GetPointcmfloat GetPoint(int n)
AddPointvoid AddPoint(cmfloat v,int n)

if n==-1, the next point is sel'd

RemovePointvoid RemovePoint(int n)
SetPointTypevoid SetPointType(int n,int type)
GetValuecmfloat GetValue(cmfloat t)

t=0..points
Automatically moves through control points
Catmull-Rom splines takes 4 points; P(i-1) upto P(i+2)

GetPointTypeint GetPointType(int n)


/*
 * CMSpline - definition/implementation
 * NOTES:
 * - Generated by mkclass
 * BUGS:
 * - Resize array loses information
 * (C) 03-11-98 MarketGraph/RVG
 */

#include <qlib/cmspline.h>
#include <math.h>
#include <qlib/debug.h>
DEBUG_ENABLE

#define DEF_PTS     50          // Starting point

CMSpline::CMSpline()
{
  points=0;
  p=0;
  AllocatePoints(DEF_PTS);
}

CMSpline::~CMSpline()
{ if(p)qfree(p);
}

void CMSpline::AllocatePoints(int n)
{
  if(p)qfree(p);
  pointsAllocated=n;
  p=(cmfloat*)qcalloc(pointsAllocated*sizeof(cmfloat));
  if(!p)qerr("CMSpline: out of memory for point array (%d pts)\n",points);
  pType=(int*)qcalloc(pointsAllocated*sizeof(int));
  if(!pType)qerr("CMSpline: out of memory for type array (%d pts)\n",points);
}

void CMSpline::Reset()
{
  points=0;
}

cmfloat CMSpline::GetPoint(int n)
{
  if(points==0)return 0;
  if(n<0)return 0;
  if(n>=points)return 0;
  return p[n];
}

void CMSpline::AddPoint(cmfloat v,int n)
// if n==-1, the next point is sel'd
{
  if(n==-1)n=points;
  if(n>pointsAllocated)
  { // Resize array
    AllocatePoints(n+50);
  }
  if(p)
  {
    p[n]=v;
    // New point added?
    if(n==points)
      points++;
  }
}
void CMSpline::RemovePoint(int n)
{
  if(points==0)return;
  if(n<0)return;
  if(n>=points)return;
  // Shift array
  int i;
  for(i=n;i<points-1;i++)
  { p[i]=p[i+1];
  }
  points--;
}
void CMSpline::SetPointType(int n,int type)
{
  if(n<0)return;
  if(n>=points)return;
  pType[n]=type;
}

cmfloat CMSpline::GetValue(cmfloat t)
// t=0..points
// Automatically moves through control points
// Catmull-Rom splines takes 4 points; P(i-1) upto P(i+2)
{
  int i;
  cmfloat ti,t2,t3;
  cmfloat p1,p2,p3,p4;
  cmfloat pt;
  
  if(!points)return 0.0;
  
  // Calc base control point index
  ti=ftrunc(t);
  i=(int)ti;
  //qdbg("t=%f, ti=%f\n",t,ti);
  //qdbg("i=%f\n",i);
  // Bring t back to 0..1
  t=t-ti;
  // Get control values/points; make sure they exist
  if(i>0)p1=p[i-1]; else p1=p[0];
  p2=p[i];
  // Next points
  if(pType[i]==CMS_LINEAR)
  { // Linear knot
    //p3=p2; p4=p2;
    p1=p2;
  }
  // Curve
  if(i+1<points)
  { p3=p[i+1];
    if(pType[i+1]==CMS_LINEAR)
    { p4=p3;
      goto skip4;
    }
  } else p3=p[points-1];
  if(i+2<points)p4=p[i+2]; else p4=p[points-1];
 skip4:
  ;
  
  //qdbg("p1-4=%f,%f,%f,%f\n",p1,p2,p3,p4);
  
  // Calc matrix mult
  t2=t*t;               // t squared
  t3=t2*t;              // t^3
  // Just a couple of cycles burned here!
  pt=-.5*t3*p1+1.5*t3*p2-1.5*t3*p3+.5*t3*p4
     +t2*p1-2.5*t2*p2+2*t2*p3-.5*t2*p4
     -.5*t*p1+.5*t*p3
     +p2;
  //qdbg("pt=%f\n",pt);
  return pt;
}
int CMSpline::GetPointType(int n)
{
  if(n<0)return 0;
  if(n>=points)return 0;
  return pType[n];
}