class CMSpline | .h |
constructor | CMSpline() |
destructor | ~CMSpline() |
AllocatePoints | void AllocatePoints(int n) |
Reset | void Reset() |
GetPoint | cmfloat GetPoint(int n) |
AddPoint | void AddPoint(cmfloat v,int n) if n==-1, the next point is sel'd |
RemovePoint | void RemovePoint(int n) |
SetPointType | void SetPointType(int n,int type) |
GetValue | cmfloat GetValue(cmfloat t) t=0..points Automatically moves through control points Catmull-Rom splines takes 4 points; P(i-1) upto P(i+2) |
GetPointType | int 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];
}