class QCurve | .h |
constructor | QCurve() |
destructor | ~QCurve() |
AllocatePoints | void AllocatePoints(int n) |
Reset | void Reset() |
GetPoint | QCurvePoint *GetPoint(int n) Returns point structure #n |
FindRightPoint | int FindRightPoint(qcfloat x) Returns point closest to the right of 'x' Returns 'points' if 'x' is more to the right than any of the points Could use binary search |
AddPoint | int AddPoint(qcfloat x,qcfloat y,int type) Add a point to the curve; insert where necessary Returns point index where it was inserted |
ModifyPoint | void ModifyPoint(int n,qcfloat x,qcfloat y) Rethink the x/y location |
RemovePoint | void RemovePoint(int n) |
SetPointType | void SetPointType(int n,int type) |
GetValue | qcfloat GetValue(qcfloat x) For a given x, approximate the y |
GetPointType | int GetPointType(int n) |
Load | bool Load(QInfo *info,cstring path) |
Save | bool Save(QInfo *info,cstring path) |
/*
* QCurve - curves
* NOTES:
* - Generated by mkclass
* BUGS:
* - Resize array loses information
* 15-09-00: Created! (based on class CMSpline)
* (C) MarketGraph/RvG
*/
#include <qlib/curve.h>
#include <math.h>
#include <qlib/debug.h>
DEBUG_ENABLE
#define DEF_PTS 50 // Starting point
#undef DBG_CLASS
#define DBG_CLASS "QCurve"
QCurve::QCurve()
{
DBG_C("ctor")
// Axes
xName="X-axis";
yName="Y-axis";
xSteps=ySteps=20;
xMin=yMin=0;
xMax=yMax=100;
points=0;
p=0;
AllocatePoints(DEF_PTS);
}
QCurve::~QCurve()
{
DBG_C("dtor")
if(p)qfree(p);
}
void QCurve::AllocatePoints(int n)
{
if(p)qfree(p);
pointsAllocated=n;
p=(QCurvePoint*)qcalloc(pointsAllocated*sizeof(QCurvePoint));
if(!p)qerr("QCurve: out of memory for point array (%d pts)\n",points);
}
void QCurve::Reset()
{
points=0;
}
QCurvePoint *QCurve::GetPoint(int n)
// Returns point structure #n
{
if(points==0)return 0;
if(n<0)return 0;
if(n>=points)return 0;
return &p[n];
}
int QCurve::FindRightPoint(qcfloat x)
// Returns point closest to the right of 'x'
// Returns 'points' if 'x' is more to the right than any of the points
// Could use binary search
{
int i;
for(i=0;i<points;i++)
{
if(p[i].x>x)break;
}
return i;
}
int QCurve::AddPoint(qcfloat x,qcfloat y,int type)
// Add a point to the curve; insert where necessary
// Returns point index where it was inserted
{
int i,insertIndex;
if(points+1>pointsAllocated)
{ // Resize array
AllocatePoints(points+50);
}
// Find place at which to insert new point
insertIndex=FindRightPoint(x);
// Shift array to accomodate new point
for(i=points;i>insertIndex;i--)
{ p[i]=p[i-1];
}
// Put new point in
p[insertIndex].x=x;
p[insertIndex].y=y;
p[insertIndex].type=type;
points++;
return insertIndex;
}
void QCurve::ModifyPoint(int n,qcfloat x,qcfloat y)
// Rethink the x/y location
{
if(n<0)return;
if(n>=points)return;
if(n>0)
{
// Bounce at previous entry
if(x<p[n-1].x)return;
}
if(n<points-1)
{ // Bounce at next entry
if(x>p[n+1].x)return;
}
// Set new coordinates
p[n].x=x;
p[n].y=y;
}
void QCurve::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 QCurve::SetPointType(int n,int type)
{
if(n<0)return;
if(n>=points)return;
p[n].type=type;
}
qcfloat QCurve::GetValue(qcfloat x)
// For a given x, approximate the y
{
//qdbg("QCurve(this=%p): GetValue(%f); points=%d\n",this,x,points);
// Any points at all?
if(!points)return 0.0;
int rp;
double dx,dy;
// Find right point of 'x'
rp=FindRightPoint(x);
//qdbg("QCurve: GetValue(%f); rp=%d\n",x,rp);
if(rp==0)
{ // To the left of the graph; use initial value
return p[0].y;
} else if(rp==points)
{ // To the right of the graph; use last value
return p[points-1].y;
}
// Interpolate between 'rp' and previous point
dx=p[rp].x-p[rp-1].x;
dy=p[rp].y-p[rp-1].y;
return (x-p[rp-1].x)/dx*dy+p[rp-1].y;
}
int QCurve::GetPointType(int n)
{
if(n<0)return 0;
if(n>=points)return 0;
return p[n].type;
}
/************
* LOAD/SAVE *
************/
bool QCurve::Load(QInfo *info,cstring path)
{
QASSERT_VALID()
DBG_C("Load")
DBG_ARG_P(info)
DBG_ARG_S(path)
char buf[128];
sprintf(buf,"%s.xname",path);
info->GetString(buf,xName);
sprintf(buf,"%s.yname",path);
info->GetString(buf,yName);
sprintf(buf,"%s.xsteps",path);
xSteps=info->GetInt(buf);
sprintf(buf,"%s.ysteps",path);
ySteps=info->GetInt(buf);
sprintf(buf,"%s.xmin",path);
xMin=info->GetInt(buf);
sprintf(buf,"%s.ymin",path);
yMin=info->GetInt(buf);
sprintf(buf,"%s.xmax",path);
xMax=info->GetInt(buf);
sprintf(buf,"%s.ymax",path);
yMax=info->GetInt(buf);
// Points
sprintf(buf,"%s.points",path);
points=info->GetInt(buf);
AllocatePoints(points+DEF_PTS);
for(int i=0;i<points;i++)
{
sprintf(buf,"%s.point%d.x",path,i);
p[i].x=info->GetFloat(buf);
sprintf(buf,"%s.point%d.y",path,i);
p[i].y=info->GetFloat(buf);
sprintf(buf,"%s.point%d.type",path,i);
p[i].type=info->GetInt(buf);
}
return TRUE;
}
bool QCurve::Save(QInfo *info,cstring path)
{
char buf[128];
sprintf(buf,"%s.xname",path);
info->SetString(buf,xName);
sprintf(buf,"%s.yname",path);
info->SetString(buf,yName);
sprintf(buf,"%s.xsteps",path);
info->SetInt(buf,xSteps);
sprintf(buf,"%s.ysteps",path);
info->SetInt(buf,ySteps);
// Min/max
sprintf(buf,"%s.xmin",path);
info->SetInt(buf,xMin);
sprintf(buf,"%s.ymin",path);
info->SetInt(buf,yMin);
sprintf(buf,"%s.xmax",path);
info->SetInt(buf,xMax);
sprintf(buf,"%s.ymax",path);
info->SetInt(buf,yMax);
// The points
sprintf(buf,"%s.points",path);
info->SetInt(buf,points);
for(int i=0;i<points;i++)
{
sprintf(buf,"%s.point%d.x",path,i);
info->SetFloat(buf,p[i].x);
sprintf(buf,"%s.point%d.y",path,i);
info->SetFloat(buf,p[i].y);
if(p[i].type!=QCurvePoint::T_LINEAR)
{
sprintf(buf,"%s.point%d.type",path,i);
info->SetInt(buf,p[i].type);
}
}
// Flush
info->Write();
return TRUE;
}