Module: qcurve.cpp

class QCurve
.h

constructorQCurve()
destructor~QCurve()
AllocatePointsvoid AllocatePoints(int n)
Resetvoid Reset()
GetPointQCurvePoint *GetPoint(int n)

Returns point structure #n

FindRightPointint 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

AddPointint AddPoint(qcfloat x,qcfloat y,int type)

Add a point to the curve; insert where necessary
Returns point index where it was inserted

ModifyPointvoid ModifyPoint(int n,qcfloat x,qcfloat y)

Rethink the x/y location

RemovePointvoid RemovePoint(int n)
SetPointTypevoid SetPointType(int n,int type)
GetValueqcfloat GetValue(qcfloat x)

For a given x, approximate the y

GetPointTypeint GetPointType(int n)
Loadbool Load(QInfo *info,cstring path)
Savebool 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;
}