1626 lines
46 KiB
C++
Executable File
1626 lines
46 KiB
C++
Executable File
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <string.h>
|
|
|
|
#include "iupPlot.h"
|
|
|
|
|
|
static inline bool iPlotCheckInsideBox(double x, double y, double boxMinX, double boxMaxX, double boxMinY, double boxMaxY)
|
|
{
|
|
if (x > boxMaxX || x < boxMinX || y > boxMaxY || y < boxMinY)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/************************************************************************************************/
|
|
|
|
|
|
bool iupPlotDataReal::CalculateRange(double &outMin, double &outMax) const
|
|
{
|
|
int theCount = iupArrayCount(mArray);
|
|
if (theCount > 0)
|
|
{
|
|
double* theData = (double*)iupArrayGetData(mArray);
|
|
outMax = outMin = theData[0];
|
|
for (int i = 1; i < theCount; i++)
|
|
{
|
|
if (theData[i] > outMax)
|
|
outMax = theData[i];
|
|
if (theData[i] < outMin)
|
|
outMin = theData[i];
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
iupPlotDataString::~iupPlotDataString()
|
|
{
|
|
for (int i = 0; i < mCount; i++)
|
|
free(mData[i]);
|
|
}
|
|
|
|
bool iupPlotDataString::CalculateRange(double &outMin, double &outMax) const
|
|
{
|
|
if (mCount > 0)
|
|
{
|
|
outMin = 0;
|
|
outMax = mCount - 1;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool iupPlotDataBool::CalculateRange(double &outMin, double &outMax) const
|
|
{
|
|
if (mCount > 0)
|
|
{
|
|
outMin = 0;
|
|
outMax = mCount - 1;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
/************************************************************************************************/
|
|
|
|
|
|
iupPlotDataSet::iupPlotDataSet(bool strXdata)
|
|
: mColor(CD_BLACK), mLineStyle(CD_CONTINUOUS), mLineWidth(1), mAreaTransparency(255), mMarkStyle(CD_X), mMarkSize(7),
|
|
mMultibarIndex(-1), mMultibarCount(0), mBarOutlineColor(0), mBarShowOutline(false), mBarSpacingPercent(10),
|
|
mPieStartAngle(0), mPieRadius(0.95), mPieContour(false), mPieHole(0), mPieSliceLabelPos(0.95),
|
|
mHighlightedSample(-1), mHighlightedCurve(false), mBarMulticolor(false), mOrderedX(false), mSelectedCurve(false),
|
|
mPieSliceLabel(IUP_PLOT_NONE), mMode(IUP_PLOT_LINE), mName(NULL), mHasSelected(false), mUserData(0)
|
|
{
|
|
if (strXdata)
|
|
mDataX = (iupPlotData*)(new iupPlotDataString());
|
|
else
|
|
mDataX = (iupPlotData*)(new iupPlotDataReal());
|
|
|
|
mDataY = (iupPlotData*)new iupPlotDataReal();
|
|
|
|
mSelection = new iupPlotDataBool();
|
|
mSegment = NULL;
|
|
mExtra = NULL;
|
|
}
|
|
|
|
iupPlotDataSet::~iupPlotDataSet()
|
|
{
|
|
SetName(NULL);
|
|
|
|
delete mDataX;
|
|
delete mDataY;
|
|
delete mSelection;
|
|
if (mSegment)
|
|
delete mSegment;
|
|
if (mExtra)
|
|
delete mExtra;
|
|
}
|
|
|
|
bool iupPlotDataSet::FindSample(iupPlotTrafo *inTrafoX, iupPlotTrafo *inTrafoY, double inScreenX, double inScreenY, double inScreenTolerance,
|
|
int &outSampleIndex, double &outX, double &outY) const
|
|
{
|
|
switch (mMode)
|
|
{
|
|
case IUP_PLOT_MULTIBAR:
|
|
return this->FindMultipleBarSample(inTrafoX, inTrafoY, inScreenX, inScreenY, outSampleIndex, outX, outY);
|
|
case IUP_PLOT_BAR:
|
|
return this->FindBarSample(inTrafoX, inTrafoY, inScreenX, inScreenY, outSampleIndex, outX, outY);
|
|
case IUP_PLOT_HORIZONTALBAR:
|
|
return this->FindHorizontalBarSample(inTrafoX, inTrafoY, inScreenX, inScreenY, outSampleIndex, outX, outY);
|
|
case IUP_PLOT_PIE:
|
|
return this->FindPieSample(inTrafoX, inTrafoY, inScreenX, inScreenY, outSampleIndex, outX, outY);
|
|
default:
|
|
return this->FindPointSample(inTrafoX, inTrafoY, inScreenX, inScreenY, inScreenTolerance, outSampleIndex, outX, outY);
|
|
}
|
|
}
|
|
|
|
bool iupPlotDataSet::FindPointSample(iupPlotTrafo *inTrafoX, iupPlotTrafo *inTrafoY, double inScreenX, double inScreenY, double inScreenTolerance,
|
|
int &outSampleIndex, double &outX, double &outY) const
|
|
{
|
|
double theX, theY, theScreenX, theScreenY;
|
|
double thePrevScreenX = 0;
|
|
|
|
int theCount = mDataX->GetCount();
|
|
|
|
for (int i = 0; i < theCount; i++)
|
|
{
|
|
theX = mDataX->GetSample(i);
|
|
theY = mDataY->GetSample(i);
|
|
theScreenX = inTrafoX->Transform(theX);
|
|
theScreenY = inTrafoY->Transform(theY);
|
|
|
|
// optimization when X values are ordered
|
|
if (mOrderedX && i > 0 && (inScreenX < thePrevScreenX - inScreenTolerance || inScreenX > theScreenX + inScreenTolerance))
|
|
{
|
|
if (inScreenX < thePrevScreenX - inScreenTolerance)
|
|
break;
|
|
|
|
thePrevScreenX = theScreenX;
|
|
continue;
|
|
}
|
|
|
|
if (fabs(theScreenX - inScreenX) < inScreenTolerance &&
|
|
fabs(theScreenY - inScreenY) < inScreenTolerance)
|
|
{
|
|
outX = theX;
|
|
outY = theY;
|
|
outSampleIndex = i;
|
|
return true;
|
|
}
|
|
|
|
thePrevScreenX = theScreenX;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool iupPlotDataSet::FindMultipleBarSample(iupPlotTrafo *inTrafoX, iupPlotTrafo *inTrafoY, double inScreenX, double inScreenY,
|
|
int &outSampleIndex, double &outX, double &outY) const
|
|
{
|
|
double theX, theY, theScreenX, theScreenY;
|
|
|
|
int theCount = mDataX->GetCount();
|
|
|
|
double theScreenY0 = inTrafoY->Transform(0);
|
|
|
|
double theMinX = mDataX->GetSample(0);
|
|
double theScreenMinX = inTrafoX->Transform(theMinX);
|
|
double theMaxX = mDataX->GetSample(theCount - 1);
|
|
double theScreenMaxX = inTrafoX->Transform(theMaxX);
|
|
|
|
double theTotalBarWidth = (theScreenMaxX - theScreenMinX) / (theCount - 1);
|
|
theTotalBarWidth *= 1 - (double)mBarSpacingPercent / 100.0;
|
|
double theBarWidth = theTotalBarWidth / mMultibarCount;
|
|
|
|
for (int i = 0; i < theCount; i++)
|
|
{
|
|
theX = mDataX->GetSample(i);
|
|
theY = mDataY->GetSample(i);
|
|
theScreenX = inTrafoX->Transform(theX);
|
|
theScreenY = inTrafoY->Transform(theY);
|
|
|
|
double theBarX = (theScreenX - theTotalBarWidth / 2) + (mMultibarIndex*theBarWidth);
|
|
double theBarHeight = theScreenY - theScreenY0;
|
|
|
|
if (iPlotCheckInsideBox(inScreenX, inScreenY, theBarX, theBarX + theBarWidth, theScreenY0, theScreenY0 + theBarHeight))
|
|
{
|
|
outX = theX;
|
|
outY = theY;
|
|
outSampleIndex = i;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool iupPlotDataSet::FindBarSample(iupPlotTrafo *inTrafoX, iupPlotTrafo *inTrafoY, double inScreenX, double inScreenY,
|
|
int &outSampleIndex, double &outX, double &outY) const
|
|
{
|
|
double theX, theY, theScreenX, theScreenY;
|
|
|
|
int theCount = mDataX->GetCount();
|
|
|
|
double theScreenY0 = inTrafoY->Transform(0);
|
|
|
|
double theMinX = mDataX->GetSample(0);
|
|
double theScreenMinX = inTrafoX->Transform(theMinX);
|
|
double theMaxX = mDataX->GetSample(theCount - 1);
|
|
double theScreenMaxX = inTrafoX->Transform(theMaxX);
|
|
|
|
double theBarWidth = (theScreenMaxX - theScreenMinX) / (theCount - 1);
|
|
theBarWidth *= 1 - (double)mBarSpacingPercent / 100.0;
|
|
|
|
for (int i = 0; i < theCount; i++)
|
|
{
|
|
theX = mDataX->GetSample(i);
|
|
theY = mDataY->GetSample(i);
|
|
theScreenX = inTrafoX->Transform(theX);
|
|
theScreenY = inTrafoY->Transform(theY);
|
|
|
|
double theBarX = theScreenX - theBarWidth / 2;
|
|
double theBarHeight = theScreenY - theScreenY0;
|
|
|
|
if (iPlotCheckInsideBox(inScreenX, inScreenY, theBarX, theBarX + theBarWidth, theScreenY0, theScreenY0 + theBarHeight))
|
|
{
|
|
outX = theX;
|
|
outY = theY;
|
|
outSampleIndex = i;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool iupPlotDataSet::FindHorizontalBarSample(iupPlotTrafo *inTrafoX, iupPlotTrafo *inTrafoY, double inScreenX, double inScreenY,
|
|
int &outSampleIndex, double &outX, double &outY) const
|
|
{
|
|
double theX, theY, theScreenX, theScreenY;
|
|
|
|
int theCount = mDataX->GetCount();
|
|
|
|
double theScreenX0 = inTrafoX->Transform(0);
|
|
|
|
double theMinY = mDataY->GetSample(0);
|
|
double theScreenMinY = inTrafoY->Transform(theMinY);
|
|
double theMaxY = mDataY->GetSample(theCount - 1);
|
|
double theScreenMaxY = inTrafoY->Transform(theMaxY);
|
|
|
|
double theBarHeight = (theScreenMaxY - theScreenMinY) / (theCount - 1);
|
|
theBarHeight *= 1 - (double)mBarSpacingPercent / 100.0;
|
|
|
|
for (int i = 0; i < theCount; i++)
|
|
{
|
|
theX = mDataX->GetSample(i);
|
|
theY = mDataY->GetSample(i);
|
|
theScreenX = inTrafoX->Transform(theX);
|
|
theScreenY = inTrafoY->Transform(theY);
|
|
|
|
double theBarY = theScreenY - theBarHeight / 2;
|
|
double theBarWidth = theScreenX - theScreenX0;
|
|
|
|
if (iPlotCheckInsideBox(inScreenX, inScreenY, theScreenX0, theScreenX0 + theBarWidth, theBarY, theBarY + theBarHeight))
|
|
{
|
|
outX = theX;
|
|
outY = theY;
|
|
outSampleIndex = i;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool iupPlotDataSet::FindPieSample(iupPlotTrafo *inTrafoX, iupPlotTrafo *inTrafoY, double inScreenX, double inScreenY, int &outSampleIndex, double &outX, double &outY) const
|
|
{
|
|
double theX, theY;
|
|
|
|
int theCount = mDataX->GetCount();
|
|
double sum = 0;
|
|
|
|
for (int i = 0; i < theCount; i++)
|
|
{
|
|
theY = mDataY->GetSample(i);
|
|
|
|
if (theY <= 0)
|
|
continue;
|
|
|
|
sum += theY;
|
|
}
|
|
|
|
double inX = inTrafoX->TransformBack(inScreenX);
|
|
double inY = inTrafoY->TransformBack(inScreenY);
|
|
|
|
double inRadius = sqrt(inX*inX + inY*inY);
|
|
|
|
double holeRadius = mPieHole * mPieRadius;
|
|
|
|
double inAngle = atan2(inY, inX);
|
|
|
|
inAngle = CD_RAD2DEG*inAngle;
|
|
|
|
if (inAngle < 0)
|
|
inAngle += 360.;
|
|
|
|
if (inRadius < holeRadius || inRadius > mPieRadius)
|
|
return false;
|
|
|
|
double startAngle = mPieStartAngle;
|
|
|
|
for (int i = 0; i < theCount; i++)
|
|
{
|
|
theX = mDataX->GetSample(i);
|
|
theY = mDataY->GetSample(i);
|
|
|
|
if (theY <= 0)
|
|
continue;
|
|
|
|
double angle = (theY*360.) / sum;
|
|
|
|
if (inAngle > startAngle &&
|
|
inAngle < startAngle + angle)
|
|
{
|
|
outX = theX;
|
|
outY = theY;
|
|
outSampleIndex = i;
|
|
return true;
|
|
}
|
|
|
|
startAngle += angle;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool iPlotCheckInsideBoxTolerance(double x1, double y1, double x2, double y2, double inX, double inY, double inTolerance)
|
|
{
|
|
if (x1 > x2)
|
|
{
|
|
double tmp = x1;
|
|
x1 = x2;
|
|
x2 = tmp;
|
|
}
|
|
|
|
if (y1 > y2)
|
|
{
|
|
double tmp = y1;
|
|
y1 = y2;
|
|
y2 = tmp;
|
|
}
|
|
|
|
x1 -= inTolerance;
|
|
x2 += inTolerance;
|
|
|
|
y1 -= inTolerance;
|
|
y2 += inTolerance;
|
|
|
|
if (inX < x1 || inX > x2)
|
|
return false;
|
|
|
|
if (inY < y1 || inY > y2)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool iupPlotDataSet::FindSegment(iupPlotTrafo *mTrafoX, iupPlotTrafo *mTrafoY, double inScreenX, double inScreenY, double inScreenTolerance,
|
|
int &outSampleIndex1, int &outSampleIndex2, double &outX1, double &outY1, double &outX2, double &outY2) const
|
|
{
|
|
if (!mTrafoX || !mTrafoY)
|
|
return false;
|
|
|
|
double lowestDist = 0;
|
|
int found_Id = -1;
|
|
double found_x1 = 0, found_y1 = 0, found_x2 = 0, found_y2 = 0;
|
|
bool found = false;
|
|
|
|
double theX1 = mDataX->GetSample(0);
|
|
double theY1 = mDataY->GetSample(0);
|
|
double theScreenX1 = mTrafoX->Transform(theX1);
|
|
double theScreenY1 = mTrafoY->Transform(theY1);
|
|
|
|
int theCount = mDataX->GetCount();
|
|
for (int i = 0; i < theCount - 1; i++)
|
|
{
|
|
double theX2 = mDataX->GetSample(i + 1);
|
|
double theY2 = mDataY->GetSample(i + 1);
|
|
double theScreenX2 = mTrafoX->Transform(theX2);
|
|
double theScreenY2 = mTrafoY->Transform(theY2);
|
|
|
|
// optimization when X values are ordered
|
|
if (mOrderedX && (inScreenX < theScreenX1 || inScreenX > theScreenX2))
|
|
{
|
|
if (inScreenX < theScreenX1)
|
|
break;
|
|
|
|
theX1 = theX2;
|
|
theY1 = theY2;
|
|
theScreenX1 = theScreenX2;
|
|
theScreenY1 = theScreenY2;
|
|
continue;
|
|
}
|
|
|
|
// inX,inY must be inside box theScreenX1,theScreenY1 - theScreenX2,theScreenY2
|
|
if (!iPlotCheckInsideBoxTolerance(theScreenX1, theScreenY1, theScreenX2, theScreenY2, inScreenX, inScreenY, inScreenTolerance))
|
|
{
|
|
theX1 = theX2;
|
|
theY1 = theY2;
|
|
theScreenX1 = theScreenX2;
|
|
theScreenY1 = theScreenY2;
|
|
continue;
|
|
}
|
|
|
|
double v1x = theScreenX2 - theScreenX1;
|
|
double v1y = theScreenY2 - theScreenY1;
|
|
|
|
double v1 = v1x*v1x + v1y*v1y;
|
|
|
|
double v2x = inScreenX - theScreenX1;
|
|
double v2y = inScreenY - theScreenY1;
|
|
|
|
double prod = v1x*v2x + v1y*v2y;
|
|
|
|
if (v1 == 0.)
|
|
{
|
|
theX1 = theX2;
|
|
theY1 = theY2;
|
|
theScreenX1 = theScreenX2;
|
|
theScreenY1 = theScreenY2;
|
|
continue;
|
|
}
|
|
|
|
double p1 = prod / v1;
|
|
|
|
if (p1<0. || p1>1.)
|
|
{
|
|
theX1 = theX2;
|
|
theY1 = theY2;
|
|
theScreenX1 = theScreenX2;
|
|
theScreenY1 = theScreenY2;
|
|
continue;
|
|
}
|
|
|
|
double px = theScreenX1 + (theScreenX2 - theScreenX1)*p1;
|
|
double py = theScreenY1 + (theScreenY2 - theScreenY1)*p1;
|
|
|
|
double d = sqrt((inScreenX - px)*(inScreenX - px) + (inScreenY - py)*(inScreenY - py));
|
|
|
|
if (!found || fabs(d) < lowestDist)
|
|
{
|
|
lowestDist = fabs(d);
|
|
found_Id = i;
|
|
found_x1 = theX1;
|
|
found_x2 = theX2;
|
|
found_y1 = theY1;
|
|
found_y2 = theY2;
|
|
found = true;
|
|
}
|
|
|
|
theX1 = theX2;
|
|
theY1 = theY2;
|
|
theScreenX1 = theScreenX2;
|
|
theScreenY1 = theScreenY2;
|
|
}
|
|
|
|
if (found && lowestDist < inScreenTolerance)
|
|
{
|
|
outSampleIndex1 = found_Id;
|
|
outSampleIndex2 = found_Id + 1;
|
|
outX1 = found_x1;
|
|
outY1 = found_y1;
|
|
outX2 = found_x2;
|
|
outY2 = found_y2;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool iupPlotDataSet::SelectSamples(double inMinX, double inMaxX, double inMinY, double inMaxY, const iupPlotSampleNotify* inNotify)
|
|
{
|
|
bool theChanged = false;
|
|
mHasSelected = false;
|
|
|
|
int theCount = mDataX->GetCount();
|
|
for (int i = 0; i < theCount; i++)
|
|
{
|
|
double theX = mDataX->GetSample(i);
|
|
double theY = mDataY->GetSample(i);
|
|
bool theSelected = mSelection->GetSampleBool(i);
|
|
|
|
if (theX >= inMinX && theX <= inMaxX &&
|
|
theY >= inMinY && theY <= inMaxY)
|
|
{
|
|
mHasSelected = true;
|
|
|
|
if (!theSelected)
|
|
{
|
|
if (inNotify->cb)
|
|
{
|
|
int ret = inNotify->cb(inNotify->ih, inNotify->ds, i, theX, theY, (int)theSelected);
|
|
if (ret == IUP_IGNORE)
|
|
continue;
|
|
}
|
|
|
|
theChanged = true;
|
|
mSelection->SetSampleBool(i, true);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (theSelected)
|
|
{
|
|
if (inNotify->cb)
|
|
{
|
|
int ret = inNotify->cb(inNotify->ih, inNotify->ds, i, theX, theY, (int)theSelected);
|
|
if (ret == IUP_IGNORE)
|
|
continue;
|
|
}
|
|
|
|
theChanged = true;
|
|
mSelection->SetSampleBool(i, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
return theChanged;
|
|
}
|
|
|
|
bool iupPlotDataSet::ClearSelection(const iupPlotSampleNotify* inNotify)
|
|
{
|
|
bool theChanged = false;
|
|
|
|
if (!mHasSelected)
|
|
return theChanged;
|
|
|
|
mHasSelected = false;
|
|
|
|
int theCount = mDataX->GetCount();
|
|
for (int i = 0; i < theCount; i++)
|
|
{
|
|
bool theSelected = mSelection->GetSampleBool(i);
|
|
if (theSelected)
|
|
{
|
|
if (inNotify->cb)
|
|
{
|
|
double theX = mDataX->GetSample(i);
|
|
double theY = mDataY->GetSample(i);
|
|
int ret = inNotify->cb(inNotify->ih, inNotify->ds, i, theX, theY, (int)theSelected);
|
|
if (ret == IUP_IGNORE)
|
|
continue;
|
|
}
|
|
|
|
theChanged = true;
|
|
mSelection->SetSampleBool(i, false);
|
|
}
|
|
}
|
|
|
|
return theChanged;
|
|
}
|
|
|
|
bool iupPlotDataSet::DeleteSelectedSamples(const iupPlotSampleNotify* inNotify)
|
|
{
|
|
bool theChanged = false;
|
|
|
|
if (!mHasSelected)
|
|
return theChanged;
|
|
|
|
mHasSelected = false;
|
|
|
|
int theCount = mDataX->GetCount();
|
|
for (int i = theCount - 1; i >= 0; i--)
|
|
{
|
|
bool theSelected = mSelection->GetSampleBool(i);
|
|
if (theSelected)
|
|
{
|
|
if (inNotify->cb)
|
|
{
|
|
double theX = mDataX->GetSample(i);
|
|
double theY = mDataY->GetSample(i);
|
|
int ret = inNotify->cb(inNotify->ih, inNotify->ds, i, theX, theY, (int)theSelected);
|
|
if (ret == IUP_IGNORE)
|
|
continue;
|
|
}
|
|
|
|
theChanged = true;
|
|
RemoveSample(i);
|
|
}
|
|
}
|
|
|
|
return theChanged;
|
|
}
|
|
|
|
int iupPlotDataSet::GetCount()
|
|
{
|
|
return mDataX->GetCount();
|
|
}
|
|
|
|
void iupPlotDataSet::AddSample(double inX, double inY)
|
|
{
|
|
iupPlotDataReal *theXData = (iupPlotDataReal*)mDataX;
|
|
iupPlotDataReal *theYData = (iupPlotDataReal*)mDataY;
|
|
|
|
if (theXData->IsString())
|
|
return;
|
|
|
|
theXData->AddSample(inX);
|
|
theYData->AddSample(inY);
|
|
mSelection->AddSample(false);
|
|
if (mSegment)
|
|
mSegment->AddSample(false);
|
|
if (mExtra)
|
|
mExtra->AddSample(0);
|
|
}
|
|
|
|
void iupPlotDataSet::InsertSample(int inSampleIndex, double inX, double inY)
|
|
{
|
|
iupPlotDataReal *theXData = (iupPlotDataReal*)mDataX;
|
|
iupPlotDataReal *theYData = (iupPlotDataReal*)mDataY;
|
|
|
|
if (theXData->IsString())
|
|
return;
|
|
|
|
theXData->InsertSample(inSampleIndex, inX);
|
|
theYData->InsertSample(inSampleIndex, inY);
|
|
mSelection->InsertSample(inSampleIndex, false);
|
|
if (mSegment)
|
|
mSegment->InsertSample(inSampleIndex, false);
|
|
if (mExtra)
|
|
mExtra->InsertSample(inSampleIndex, 0);
|
|
}
|
|
|
|
void iupPlotDataSet::InitSegment()
|
|
{
|
|
mSegment = new iupPlotDataBool();
|
|
|
|
int theCount = mDataX->GetCount();
|
|
for (int i = 0; i < theCount; i++)
|
|
mSegment->AddSample(false);
|
|
}
|
|
|
|
void iupPlotDataSet::InitExtra()
|
|
{
|
|
mExtra = new iupPlotDataReal();
|
|
|
|
int theCount = mDataX->GetCount();
|
|
for (int i = 0; i < theCount; i++)
|
|
mExtra->AddSample(0);
|
|
}
|
|
|
|
void iupPlotDataSet::AddSampleSegment(double inX, double inY, bool inSegment)
|
|
{
|
|
iupPlotDataReal *theXData = (iupPlotDataReal*)mDataX;
|
|
iupPlotDataReal *theYData = (iupPlotDataReal*)mDataY;
|
|
|
|
if (theXData->IsString())
|
|
return;
|
|
|
|
if (!mSegment)
|
|
InitSegment();
|
|
|
|
theXData->AddSample(inX);
|
|
theYData->AddSample(inY);
|
|
mSelection->AddSample(false);
|
|
mSegment->AddSample(inSegment);
|
|
if (mExtra)
|
|
mExtra->AddSample(0);
|
|
}
|
|
|
|
void iupPlotDataSet::InsertSampleSegment(int inSampleIndex, double inX, double inY, bool inSegment)
|
|
{
|
|
iupPlotDataReal *theXData = (iupPlotDataReal*)mDataX;
|
|
iupPlotDataReal *theYData = (iupPlotDataReal*)mDataY;
|
|
|
|
if (theXData->IsString())
|
|
return;
|
|
|
|
if (!mSegment)
|
|
InitSegment();
|
|
|
|
theXData->InsertSample(inSampleIndex, inX);
|
|
theYData->InsertSample(inSampleIndex, inY);
|
|
mSelection->InsertSample(inSampleIndex, false);
|
|
mSegment->InsertSample(inSampleIndex, inSegment);
|
|
if (mExtra)
|
|
mExtra->InsertSample(inSampleIndex, 0);
|
|
}
|
|
|
|
void iupPlotDataSet::AddSample(const char* inX, double inY)
|
|
{
|
|
iupPlotDataString *theXData = (iupPlotDataString*)mDataX;
|
|
iupPlotDataReal *theYData = (iupPlotDataReal*)mDataY;
|
|
|
|
if (!theXData->IsString())
|
|
return;
|
|
|
|
theXData->AddSample(inX);
|
|
theYData->AddSample(inY);
|
|
mSelection->AddSample(false);
|
|
if (mSegment)
|
|
mSegment->AddSample(false);
|
|
if (mExtra)
|
|
mExtra->AddSample(0);
|
|
}
|
|
|
|
void iupPlotDataSet::InsertSample(int inSampleIndex, const char* inX, double inY)
|
|
{
|
|
iupPlotDataString *theXData = (iupPlotDataString*)mDataX;
|
|
iupPlotDataReal *theYData = (iupPlotDataReal*)mDataY;
|
|
|
|
if (!theXData->IsString())
|
|
return;
|
|
|
|
theXData->InsertSample(inSampleIndex, inX);
|
|
theYData->InsertSample(inSampleIndex, inY);
|
|
mSelection->InsertSample(inSampleIndex, false);
|
|
if (mSegment)
|
|
mSegment->InsertSample(inSampleIndex, false);
|
|
if (mExtra)
|
|
mExtra->InsertSample(inSampleIndex, 0);
|
|
}
|
|
|
|
void iupPlotDataSet::RemoveSample(int inSampleIndex)
|
|
{
|
|
mDataX->RemoveSample(inSampleIndex);
|
|
mDataY->RemoveSample(inSampleIndex);
|
|
mSelection->RemoveSample(inSampleIndex);
|
|
if (mSegment)
|
|
mSegment->RemoveSample(inSampleIndex);
|
|
if (mExtra)
|
|
mExtra->RemoveSample(inSampleIndex);
|
|
}
|
|
|
|
void iupPlotDataSet::GetSample(int inSampleIndex, double *inX, double *inY)
|
|
{
|
|
iupPlotDataReal *theXData = (iupPlotDataReal*)mDataX;
|
|
iupPlotDataReal *theYData = (iupPlotDataReal*)mDataY;
|
|
|
|
if (theXData->IsString())
|
|
return;
|
|
|
|
int theCount = theXData->GetCount();
|
|
if (inSampleIndex < 0 || inSampleIndex >= theCount)
|
|
return;
|
|
|
|
if (inX) *inX = theXData->GetSample(inSampleIndex);
|
|
if (inY) *inY = theYData->GetSample(inSampleIndex);
|
|
}
|
|
|
|
void iupPlotDataSet::GetSample(int inSampleIndex, const char* *inX, double *inY)
|
|
{
|
|
iupPlotDataString *theXData = (iupPlotDataString*)mDataX;
|
|
iupPlotDataReal *theYData = (iupPlotDataReal*)mDataY;
|
|
|
|
if (!theXData->IsString())
|
|
return;
|
|
|
|
int theCount = theXData->GetCount();
|
|
if (inSampleIndex < 0 || inSampleIndex >= theCount)
|
|
return;
|
|
|
|
if (inX) *inX = theXData->GetSampleString(inSampleIndex);
|
|
if (inY) *inY = theYData->GetSample(inSampleIndex);
|
|
}
|
|
|
|
bool iupPlotDataSet::GetSampleSelection(int inSampleIndex)
|
|
{
|
|
int theCount = mDataX->GetCount();
|
|
if (inSampleIndex < 0 || inSampleIndex >= theCount)
|
|
return false;
|
|
|
|
return mSelection->GetSampleBool(inSampleIndex);
|
|
}
|
|
|
|
double iupPlotDataSet::GetSampleExtra(int inSampleIndex)
|
|
{
|
|
int theCount = mDataX->GetCount();
|
|
if (inSampleIndex < 0 || inSampleIndex >= theCount || !mExtra)
|
|
return 0;
|
|
|
|
return mExtra->GetSample(inSampleIndex);
|
|
}
|
|
|
|
void iupPlotDataSet::SetSample(int inSampleIndex, double inX, double inY)
|
|
{
|
|
iupPlotDataReal *theXData = (iupPlotDataReal*)mDataX;
|
|
iupPlotDataReal *theYData = (iupPlotDataReal*)mDataY;
|
|
|
|
if (theXData->IsString())
|
|
return;
|
|
|
|
int theCount = theXData->GetCount();
|
|
if (inSampleIndex < 0 || inSampleIndex >= theCount)
|
|
return;
|
|
|
|
theXData->SetSample(inSampleIndex, inX);
|
|
theYData->SetSample(inSampleIndex, inY);
|
|
}
|
|
|
|
void iupPlotDataSet::SetSample(int inSampleIndex, const char* inX, double inY)
|
|
{
|
|
iupPlotDataString *theXData = (iupPlotDataString*)mDataX;
|
|
iupPlotDataReal *theYData = (iupPlotDataReal*)mDataY;
|
|
|
|
if (!theXData->IsString())
|
|
return;
|
|
|
|
int theCount = theXData->GetCount();
|
|
if (inSampleIndex < 0 || inSampleIndex >= theCount)
|
|
return;
|
|
|
|
theXData->SetSampleString(inSampleIndex, inX);
|
|
theYData->SetSample(inSampleIndex, inY);
|
|
}
|
|
|
|
void iupPlotDataSet::SetSampleSelection(int inSampleIndex, bool inSelected)
|
|
{
|
|
int theCount = mDataX->GetCount();
|
|
if (inSampleIndex < 0 || inSampleIndex >= theCount)
|
|
return;
|
|
|
|
mSelection->SetSampleBool(inSampleIndex, inSelected);
|
|
}
|
|
|
|
void iupPlotDataSet::SetSampleExtra(int inSampleIndex, double inExtra)
|
|
{
|
|
int theCount = mDataX->GetCount();
|
|
if (inSampleIndex < 0 || inSampleIndex >= theCount)
|
|
return;
|
|
|
|
if (!mExtra)
|
|
InitExtra();
|
|
|
|
mExtra->SetSample(inSampleIndex, inExtra);
|
|
}
|
|
|
|
|
|
/************************************************************************************/
|
|
|
|
|
|
#define HIGHLIGHT_ALPHA 64
|
|
#define HIGHLIGHT_OFFSET 12
|
|
#define SELECT_ALPHA 128
|
|
#define SELECT_OFFSET 8
|
|
|
|
|
|
static void iPlotDrawHighlightedBar(cdCanvas *canvas, double x, double y, double barWidth, double barHeight)
|
|
{
|
|
int foreground = cdCanvasForeground(canvas, CD_QUERY);
|
|
long color = cdEncodeAlpha(foreground, HIGHLIGHT_ALPHA);
|
|
int width = cdCanvasLineWidth(canvas, CD_QUERY);
|
|
int style = cdCanvasLineStyle(canvas, CD_QUERY);
|
|
|
|
cdCanvasLineStyle(canvas, CD_CONTINUOUS);
|
|
cdCanvasLineWidth(canvas, width + HIGHLIGHT_OFFSET);
|
|
cdCanvasSetForeground(canvas, color);
|
|
|
|
iupPlotDrawRect(canvas, x, y, barWidth, barHeight);
|
|
|
|
cdCanvasLineStyle(canvas, style);
|
|
cdCanvasLineWidth(canvas, width);
|
|
cdCanvasSetForeground(canvas, foreground);
|
|
}
|
|
|
|
static void iPlotDrawHighlightedStem(cdCanvas *canvas, double x1, double y1, double x2, double y2)
|
|
{
|
|
int foreground = cdCanvasForeground(canvas, CD_QUERY);
|
|
long color = cdEncodeAlpha(foreground, HIGHLIGHT_ALPHA);
|
|
int width = cdCanvasLineWidth(canvas, CD_QUERY);
|
|
int style = cdCanvasLineStyle(canvas, CD_QUERY);
|
|
int size = cdCanvasMarkSize(canvas, CD_QUERY);
|
|
int type = cdCanvasMarkType(canvas, CD_QUERY);
|
|
|
|
cdCanvasLineStyle(canvas, CD_CONTINUOUS);
|
|
cdCanvasLineWidth(canvas, width + HIGHLIGHT_OFFSET);
|
|
cdCanvasMarkSize(canvas, size + HIGHLIGHT_OFFSET);
|
|
cdCanvasMarkType(canvas, CD_CIRCLE);
|
|
cdCanvasSetForeground(canvas, color);
|
|
|
|
cdfCanvasLine(canvas, x1, y1, x2, y2);
|
|
cdfCanvasMark(canvas, x2, y2);
|
|
|
|
cdCanvasSetForeground(canvas, foreground);
|
|
cdCanvasLineStyle(canvas, style);
|
|
cdCanvasLineWidth(canvas, width);
|
|
cdCanvasMarkSize(canvas, size);
|
|
cdCanvasMarkType(canvas, type);
|
|
}
|
|
|
|
static void iPlotDrawHighlightedMark(cdCanvas *canvas, double x, double y)
|
|
{
|
|
int foreground = cdCanvasForeground(canvas, CD_QUERY);
|
|
long color = cdEncodeAlpha(foreground, HIGHLIGHT_ALPHA);
|
|
int size = cdCanvasMarkSize(canvas, CD_QUERY);
|
|
int type = cdCanvasMarkType(canvas, CD_QUERY);
|
|
|
|
cdCanvasMarkSize(canvas, size + HIGHLIGHT_OFFSET);
|
|
cdCanvasMarkType(canvas, CD_CIRCLE);
|
|
cdCanvasSetForeground(canvas, color);
|
|
|
|
cdfCanvasMark(canvas, x, y);
|
|
|
|
cdCanvasSetForeground(canvas, foreground);
|
|
cdCanvasMarkSize(canvas, size);
|
|
cdCanvasMarkType(canvas, type);
|
|
}
|
|
|
|
static void iPlotDrawHighlightedArc(cdCanvas *canvas, double xc, double yc, double w, double h, double startAngle, double endAngle)
|
|
{
|
|
int foreground = cdCanvasForeground(canvas, CD_QUERY);
|
|
long color = cdEncodeAlpha(foreground, HIGHLIGHT_ALPHA);
|
|
int width = cdCanvasLineWidth(canvas, CD_QUERY);
|
|
int style = cdCanvasLineStyle(canvas, CD_QUERY);
|
|
|
|
cdCanvasLineStyle(canvas, CD_CONTINUOUS);
|
|
cdCanvasLineWidth(canvas, width + HIGHLIGHT_OFFSET);
|
|
cdCanvasSetForeground(canvas, color);
|
|
|
|
cdfCanvasArc(canvas, xc, yc, w, h, startAngle, endAngle);
|
|
|
|
cdCanvasLineStyle(canvas, style);
|
|
cdCanvasLineWidth(canvas, width);
|
|
cdCanvasSetForeground(canvas, foreground);
|
|
}
|
|
|
|
static void iPlotDrawHighlightedCurve(cdCanvas *canvas, int inCount, const iupPlotData* inDataX, const iupPlotData* inDataY, const iupPlotDataBool* inSegment,
|
|
const iupPlotTrafo *inTrafoX, const iupPlotTrafo *inTrafoY, bool inConnectPreviousX, bool inSelected = false)
|
|
{
|
|
int foreground = cdCanvasForeground(canvas, CD_QUERY);
|
|
long color = cdEncodeAlpha(foreground, inSelected? SELECT_ALPHA: HIGHLIGHT_ALPHA);
|
|
int width = cdCanvasLineWidth(canvas, CD_QUERY);
|
|
int style = cdCanvasLineStyle(canvas, CD_QUERY);
|
|
double thePreviousScreenX = 0.;
|
|
|
|
cdCanvasLineStyle(canvas, CD_CONTINUOUS);
|
|
cdCanvasLineWidth(canvas, width + (inSelected ? SELECT_OFFSET: HIGHLIGHT_OFFSET));
|
|
cdCanvasSetForeground(canvas, color);
|
|
|
|
cdCanvasBegin(canvas, CD_OPEN_LINES);
|
|
|
|
for (int i = 0; i < inCount; i++)
|
|
{
|
|
double theX = inDataX->GetSample(i);
|
|
double theY = inDataY->GetSample(i);
|
|
double theScreenX = inTrafoX->Transform(theX);
|
|
double theScreenY = inTrafoY->Transform(theY);
|
|
|
|
if (i > 0 && inSegment && inSegment->GetSampleBool(i))
|
|
{
|
|
cdCanvasEnd(canvas);
|
|
cdCanvasBegin(canvas, CD_OPEN_LINES);
|
|
}
|
|
|
|
if (inConnectPreviousX && i > 0)
|
|
cdfCanvasVertex(canvas, thePreviousScreenX, theScreenY);
|
|
|
|
cdfCanvasVertex(canvas, theScreenX, theScreenY);
|
|
|
|
thePreviousScreenX = theScreenX;
|
|
}
|
|
|
|
cdCanvasEnd(canvas);
|
|
|
|
cdCanvasSetForeground(canvas, foreground);
|
|
cdCanvasLineStyle(canvas, style);
|
|
cdCanvasLineWidth(canvas, width);
|
|
}
|
|
|
|
void iupPlotDataSet::DrawDataLine(const iupPlotTrafo *inTrafoX, const iupPlotTrafo *inTrafoY, cdCanvas* canvas, const iupPlotSampleNotify* inNotify, bool inShowMark, bool inErrorBar) const
|
|
{
|
|
int theCount = mDataX->GetCount();
|
|
cdCanvasBegin(canvas, CD_OPEN_LINES);
|
|
|
|
for (int i = 0; i < theCount; i++)
|
|
{
|
|
double theX = mDataX->GetSample(i);
|
|
double theY = mDataY->GetSample(i);
|
|
double theScreenX = inTrafoX->Transform(theX);
|
|
double theScreenY = inTrafoY->Transform(theY);
|
|
|
|
if (inNotify->cb)
|
|
inNotify->cb(inNotify->ih, inNotify->ds, i, theX, theY, (int)mSelection->GetSampleBool(i));
|
|
|
|
if (inShowMark)
|
|
{
|
|
if (mExtra)
|
|
{
|
|
if (inErrorBar)
|
|
DrawErrorBar(inTrafoY, canvas, i, theY, theScreenX);
|
|
else
|
|
SetSampleExtraMarkSize(inTrafoY, canvas, i);
|
|
}
|
|
|
|
// No problem that will be drawn before the polygon, they both should have the same color
|
|
cdfCanvasMark(canvas, theScreenX, theScreenY);
|
|
}
|
|
|
|
if (i == mHighlightedSample)
|
|
iPlotDrawHighlightedMark(canvas, theScreenX, theScreenY);
|
|
|
|
if (i > 0 && mSegment && mSegment->GetSampleBool(i))
|
|
{
|
|
cdCanvasEnd(canvas);
|
|
cdCanvasBegin(canvas, CD_OPEN_LINES);
|
|
}
|
|
|
|
cdfCanvasVertex(canvas, theScreenX, theScreenY);
|
|
}
|
|
|
|
cdCanvasEnd(canvas);
|
|
|
|
if (mHighlightedCurve)
|
|
iPlotDrawHighlightedCurve(canvas, theCount, mDataX, mDataY, mSegment, inTrafoX, inTrafoY, false);
|
|
else if (mSelectedCurve)
|
|
iPlotDrawHighlightedCurve(canvas, theCount, mDataX, mDataY, mSegment, inTrafoX, inTrafoY, false, true);
|
|
}
|
|
|
|
void iupPlotDataSet::DrawErrorBar(const iupPlotTrafo *inTrafoY, cdCanvas* canvas, int index, double theY, double theScreenX) const
|
|
{
|
|
double theError = mExtra->GetSample(index);
|
|
double theScreenErrorY1 = inTrafoY->Transform(theY - theError);
|
|
double theScreenErrorY2 = inTrafoY->Transform(theY + theError);
|
|
|
|
double theBarWidth = (double)mMarkSize; /* fixed size in screen coordinates */
|
|
|
|
cdfCanvasLine(canvas, theScreenX, theScreenErrorY1, theScreenX, theScreenErrorY2);
|
|
cdfCanvasLine(canvas, theScreenX - theBarWidth, theScreenErrorY1, theScreenX + theBarWidth, theScreenErrorY1);
|
|
cdfCanvasLine(canvas, theScreenX - theBarWidth, theScreenErrorY2, theScreenX + theBarWidth, theScreenErrorY2);
|
|
}
|
|
|
|
void iupPlotDataSet::SetSampleExtraMarkSize(const iupPlotTrafo *inTrafoY, cdCanvas* canvas, int inSampleIndex) const
|
|
{
|
|
double theMarkSize = mExtra->GetSample(inSampleIndex);
|
|
int theScreenSize = 1;
|
|
if (theMarkSize != 0)
|
|
theScreenSize = iupPlotRound(inTrafoY->Transform(theMarkSize));
|
|
if (theScreenSize < 1) theScreenSize = 1;
|
|
|
|
cdCanvasMarkSize(canvas, theScreenSize);
|
|
}
|
|
|
|
void iupPlotDataSet::DrawDataMark(const iupPlotTrafo *inTrafoX, const iupPlotTrafo *inTrafoY, cdCanvas* canvas, const iupPlotSampleNotify* inNotify) const
|
|
{
|
|
int theCount = mDataX->GetCount();
|
|
for (int i = 0; i < theCount; i++)
|
|
{
|
|
double theX = mDataX->GetSample(i);
|
|
double theY = mDataY->GetSample(i);
|
|
double theScreenX = inTrafoX->Transform(theX);
|
|
double theScreenY = inTrafoY->Transform(theY);
|
|
|
|
if (inNotify->cb)
|
|
inNotify->cb(inNotify->ih, inNotify->ds, i, theX, theY, (int)mSelection->GetSampleBool(i));
|
|
|
|
if (mExtra)
|
|
SetSampleExtraMarkSize(inTrafoY, canvas, i);
|
|
|
|
cdfCanvasMark(canvas, theScreenX, theScreenY);
|
|
|
|
if (i == mHighlightedSample)
|
|
iPlotDrawHighlightedMark(canvas, theScreenX, theScreenY);
|
|
}
|
|
}
|
|
|
|
void iupPlotDataSet::DrawDataStem(const iupPlotTrafo *inTrafoX, const iupPlotTrafo *inTrafoY, cdCanvas* canvas, const iupPlotSampleNotify* inNotify, bool inShowMark) const
|
|
{
|
|
double theScreenY0 = inTrafoY->Transform(0);
|
|
|
|
int theCount = mDataX->GetCount();
|
|
for (int i = 0; i < theCount; i++)
|
|
{
|
|
double theX = mDataX->GetSample(i);
|
|
double theY = mDataY->GetSample(i);
|
|
double theScreenX = inTrafoX->Transform(theX);
|
|
double theScreenY = inTrafoY->Transform(theY);
|
|
|
|
if (inNotify->cb)
|
|
inNotify->cb(inNotify->ih, inNotify->ds, i, theX, theY, (int)mSelection->GetSampleBool(i));
|
|
|
|
if (inShowMark)
|
|
{
|
|
if (mExtra)
|
|
SetSampleExtraMarkSize(inTrafoY, canvas, i);
|
|
|
|
cdfCanvasMark(canvas, theScreenX, theScreenY);
|
|
}
|
|
|
|
cdfCanvasLine(canvas, theScreenX, theScreenY0, theScreenX, theScreenY);
|
|
|
|
if (i == mHighlightedSample)
|
|
iPlotDrawHighlightedStem(canvas, theScreenX, theScreenY0, theScreenX, theScreenY);
|
|
}
|
|
}
|
|
|
|
void iupPlotDataSet::DrawDataArea(const iupPlotTrafo *inTrafoX, const iupPlotTrafo *inTrafoY, cdCanvas* canvas, const iupPlotSampleNotify* inNotify) const
|
|
{
|
|
int theCount = mDataX->GetCount();
|
|
cdCanvasBegin(canvas, CD_FILL);
|
|
|
|
double theScreenY0 = inTrafoY->Transform(0);
|
|
double theLastScreenX = 0;
|
|
|
|
if (mAreaTransparency != 255)
|
|
cdCanvasSetForeground(canvas, cdEncodeAlpha(mColor, mAreaTransparency));
|
|
|
|
for (int i = 0; i < theCount; i++)
|
|
{
|
|
double theX = mDataX->GetSample(i);
|
|
double theY = mDataY->GetSample(i);
|
|
double theScreenX = inTrafoX->Transform(theX);
|
|
double theScreenY = inTrafoY->Transform(theY);
|
|
|
|
if (inNotify->cb)
|
|
inNotify->cb(inNotify->ih, inNotify->ds, i, theX, theY, (int)mSelection->GetSampleBool(i));
|
|
|
|
if (i == 0)
|
|
cdfCanvasVertex(canvas, theScreenX, theScreenY0);
|
|
|
|
if (i > 0 && mSegment && mSegment->GetSampleBool(i))
|
|
{
|
|
cdfCanvasVertex(canvas, theLastScreenX, theScreenY0);
|
|
cdfCanvasVertex(canvas, theScreenX, theScreenY0);
|
|
}
|
|
|
|
cdfCanvasVertex(canvas, theScreenX, theScreenY);
|
|
|
|
if (i == mHighlightedSample)
|
|
iPlotDrawHighlightedMark(canvas, theScreenX, theScreenY);
|
|
|
|
if (i == theCount - 1)
|
|
cdfCanvasVertex(canvas, theScreenX, theScreenY0);
|
|
|
|
theLastScreenX = theScreenX;
|
|
}
|
|
|
|
cdCanvasEnd(canvas);
|
|
|
|
if (mAreaTransparency != 255)
|
|
{
|
|
cdCanvasSetForeground(canvas, mColor);
|
|
|
|
cdCanvasBegin(canvas, CD_OPEN_LINES);
|
|
|
|
for (int i = 0; i < theCount; i++)
|
|
{
|
|
double theX = mDataX->GetSample(i);
|
|
double theY = mDataY->GetSample(i);
|
|
double theScreenX = inTrafoX->Transform(theX);
|
|
double theScreenY = inTrafoY->Transform(theY);
|
|
|
|
if (i > 0 && mSegment && mSegment->GetSampleBool(i))
|
|
{
|
|
cdCanvasEnd(canvas);
|
|
cdCanvasBegin(canvas, CD_OPEN_LINES);
|
|
}
|
|
|
|
cdfCanvasVertex(canvas, theScreenX, theScreenY);
|
|
}
|
|
|
|
cdCanvasEnd(canvas);
|
|
}
|
|
|
|
if (mHighlightedCurve)
|
|
iPlotDrawHighlightedCurve(canvas, theCount, mDataX, mDataY, mSegment, inTrafoX, inTrafoY, false);
|
|
else if (mSelectedCurve)
|
|
iPlotDrawHighlightedCurve(canvas, theCount, mDataX, mDataY, mSegment, inTrafoX, inTrafoY, false, true);
|
|
}
|
|
|
|
void iupPlotDataSet::DrawDataBar(const iupPlotTrafo *inTrafoX, const iupPlotTrafo *inTrafoY, cdCanvas* canvas, const iupPlotSampleNotify* inNotify) const
|
|
{
|
|
int theCount = mDataX->GetCount();
|
|
double theScreenY0 = inTrafoY->Transform(0);
|
|
|
|
double theMinX = mDataX->GetSample(0);
|
|
double theScreenMinX = inTrafoX->Transform(theMinX);
|
|
double theMaxX = mDataX->GetSample(theCount - 1);
|
|
double theScreenMaxX = inTrafoX->Transform(theMaxX);
|
|
|
|
double theBarWidth = (theScreenMaxX - theScreenMinX) / (theCount - 1);
|
|
theBarWidth *= 1 - (double)mBarSpacingPercent / 100.0;
|
|
|
|
for (int i = 0; i < theCount; i++)
|
|
{
|
|
double theX = mDataX->GetSample(i);
|
|
double theY = mDataY->GetSample(i);
|
|
double theScreenX = inTrafoX->Transform(theX);
|
|
double theScreenY = inTrafoY->Transform(theY);
|
|
|
|
double theBarX = theScreenX - theBarWidth / 2;
|
|
double theBarHeight = theScreenY - theScreenY0;
|
|
|
|
if (inNotify->cb)
|
|
inNotify->cb(inNotify->ih, inNotify->ds, i, theX, theY, (int)mSelection->GetSampleBool(i));
|
|
|
|
if (theBarHeight == 0)
|
|
continue;
|
|
|
|
if (mBarMulticolor)
|
|
cdCanvasSetForeground(canvas, iupPlotDrawGetSampleColorTable(inNotify->ih, i));
|
|
|
|
iupPlotDrawBox(canvas, theBarX, theScreenY0, theBarWidth, theBarHeight);
|
|
|
|
if (mBarShowOutline)
|
|
{
|
|
cdCanvasSetForeground(canvas, mBarOutlineColor);
|
|
iupPlotDrawRect(canvas, theBarX, theScreenY0, theBarWidth, theBarHeight);
|
|
}
|
|
|
|
if (i == mHighlightedSample)
|
|
iPlotDrawHighlightedBar(canvas, theBarX, theScreenY0, theBarWidth, theBarHeight);
|
|
|
|
if (mBarShowOutline && !mBarMulticolor)
|
|
cdCanvasSetForeground(canvas, mColor); // restore curve color
|
|
}
|
|
}
|
|
|
|
void iupPlotDataSet::DrawDataHorizontalBar(const iupPlotTrafo *inTrafoX, const iupPlotTrafo *inTrafoY, cdCanvas* canvas, const iupPlotSampleNotify* inNotify) const
|
|
{
|
|
int theCount = mDataX->GetCount();
|
|
double theScreenX0 = inTrafoX->Transform(0);
|
|
|
|
|
|
double theMinY = mDataY->GetSample(0);
|
|
double theScreenMinY = inTrafoY->Transform(theMinY);
|
|
double theMaxY = mDataY->GetSample(theCount - 1);
|
|
double theScreenMaxY = inTrafoY->Transform(theMaxY);
|
|
|
|
double theBarHeight = (theScreenMaxY - theScreenMinY) / (theCount - 1);
|
|
theBarHeight *= 1 - (double)mBarSpacingPercent / 100.0;
|
|
|
|
for (int i = 0; i < theCount; i++)
|
|
{
|
|
double theX = mDataX->GetSample(i);
|
|
double theY = mDataY->GetSample(i);
|
|
double theScreenX = inTrafoX->Transform(theX);
|
|
double theScreenY = inTrafoY->Transform(theY);
|
|
|
|
double theBarY = theScreenY - theBarHeight / 2;
|
|
double theBarWidth = theScreenX - theScreenX0;
|
|
|
|
if (inNotify->cb)
|
|
inNotify->cb(inNotify->ih, inNotify->ds, i, theX, theY, (int)mSelection->GetSampleBool(i));
|
|
|
|
if (theBarWidth == 0)
|
|
continue;
|
|
|
|
if (mBarMulticolor)
|
|
cdCanvasSetForeground(canvas, iupPlotDrawGetSampleColorTable(inNotify->ih, i));
|
|
|
|
iupPlotDrawBox(canvas, theScreenX0, theBarY, theBarWidth, theBarHeight);
|
|
|
|
if (mBarShowOutline)
|
|
{
|
|
cdCanvasSetForeground(canvas, mBarOutlineColor);
|
|
iupPlotDrawRect(canvas, theScreenX0, theBarY, theBarWidth, theBarHeight);
|
|
}
|
|
|
|
if (i == mHighlightedSample)
|
|
iPlotDrawHighlightedBar(canvas, theScreenX0, theBarY, theBarWidth, theBarHeight);
|
|
|
|
if (mBarShowOutline && !mBarMulticolor)
|
|
cdCanvasSetForeground(canvas, mColor); // restore curve color
|
|
}
|
|
}
|
|
|
|
void iupPlotDataSet::DrawDataMultiBar(const iupPlotTrafo *inTrafoX, const iupPlotTrafo *inTrafoY, cdCanvas* canvas, const iupPlotSampleNotify* inNotify) const
|
|
{
|
|
int theCount = mDataX->GetCount();
|
|
double theScreenY0 = inTrafoY->Transform(0);
|
|
|
|
double theMinX = mDataX->GetSample(0);
|
|
double theScreenMinX = inTrafoX->Transform(theMinX);
|
|
double theMaxX = mDataX->GetSample(theCount - 1);
|
|
double theScreenMaxX = inTrafoX->Transform(theMaxX);
|
|
|
|
double theTotalBarWidth = (theScreenMaxX - theScreenMinX) / (theCount - 1);
|
|
theTotalBarWidth *= 1 - (double)mBarSpacingPercent / 100.0;
|
|
double theBarWidth = theTotalBarWidth / mMultibarCount;
|
|
|
|
for (int i = 0; i < theCount; i++)
|
|
{
|
|
double theX = mDataX->GetSample(i);
|
|
double theY = mDataY->GetSample(i);
|
|
double theScreenX = inTrafoX->Transform(theX);
|
|
double theScreenY = inTrafoY->Transform(theY);
|
|
|
|
double theBarX = (theScreenX - theTotalBarWidth / 2) + (mMultibarIndex*theBarWidth);
|
|
double theBarHeight = theScreenY - theScreenY0;
|
|
|
|
if (inNotify->cb)
|
|
inNotify->cb(inNotify->ih, inNotify->ds, i, theX, theY, (int)mSelection->GetSampleBool(i));
|
|
|
|
if (theBarHeight == 0)
|
|
continue;
|
|
|
|
iupPlotDrawBox(canvas, theBarX, theScreenY0, theBarWidth, theBarHeight);
|
|
|
|
if (mBarShowOutline)
|
|
{
|
|
cdCanvasSetForeground(canvas, mBarOutlineColor);
|
|
iupPlotDrawRect(canvas, theBarX, theScreenY0, theBarWidth, theBarHeight);
|
|
}
|
|
|
|
if (i == mHighlightedSample)
|
|
iPlotDrawHighlightedBar(canvas, theBarX, theScreenY0, theBarWidth, theBarHeight);
|
|
|
|
if (mBarShowOutline)
|
|
cdCanvasSetForeground(canvas, mColor); // restore curve color
|
|
}
|
|
}
|
|
|
|
void iupPlotDataSet::DrawDataStep(const iupPlotTrafo *inTrafoX, const iupPlotTrafo *inTrafoY, cdCanvas* canvas, const iupPlotSampleNotify* inNotify) const
|
|
{
|
|
int theCount = mDataX->GetCount();
|
|
cdCanvasBegin(canvas, CD_OPEN_LINES);
|
|
double theLastScreenX = 0.;
|
|
|
|
for (int i = 0; i < theCount; i++)
|
|
{
|
|
double theX = mDataX->GetSample(i);
|
|
double theY = mDataY->GetSample(i);
|
|
double theScreenX = inTrafoX->Transform(theX);
|
|
double theScreenY = inTrafoY->Transform(theY);
|
|
|
|
if (inNotify->cb)
|
|
inNotify->cb(inNotify->ih, inNotify->ds, i, theX, theY, (int)mSelection->GetSampleBool(i));
|
|
|
|
if (i > 0 && mSegment && mSegment->GetSampleBool(i))
|
|
{
|
|
cdCanvasEnd(canvas);
|
|
cdCanvasBegin(canvas, CD_OPEN_LINES);
|
|
}
|
|
|
|
if (i > 0)
|
|
cdfCanvasVertex(canvas, theLastScreenX, theScreenY);
|
|
|
|
cdfCanvasVertex(canvas, theScreenX, theScreenY);
|
|
|
|
if (i == mHighlightedSample)
|
|
iPlotDrawHighlightedMark(canvas, theScreenX, theScreenY);
|
|
|
|
theLastScreenX = theScreenX;
|
|
}
|
|
|
|
cdCanvasEnd(canvas);
|
|
|
|
|
|
if (mHighlightedCurve)
|
|
iPlotDrawHighlightedCurve(canvas, theCount, mDataX, mDataY, mSegment, inTrafoX, inTrafoY, true);
|
|
else if (mSelectedCurve)
|
|
iPlotDrawHighlightedCurve(canvas, theCount, mDataX, mDataY, mSegment, inTrafoX, inTrafoY, true, true);
|
|
}
|
|
|
|
static int iPlotGetPieTextAligment(double bisectrix, double inPieSliceLabelPos)
|
|
{
|
|
if (inPieSliceLabelPos < 0)
|
|
bisectrix += 180;
|
|
|
|
bisectrix = fmod(bisectrix, 360);
|
|
|
|
if (bisectrix < 22.5)
|
|
return CD_EAST;
|
|
else if (bisectrix < 67.5)
|
|
return CD_NORTH_EAST;
|
|
else if (bisectrix < 112.5)
|
|
return CD_NORTH;
|
|
else if (bisectrix < 157.5)
|
|
return CD_NORTH_WEST;
|
|
else if (bisectrix < 202.5)
|
|
return CD_WEST;
|
|
else if (bisectrix < 247.5)
|
|
return CD_SOUTH_WEST;
|
|
else if (bisectrix < 292.5)
|
|
return CD_SOUTH;
|
|
else if (bisectrix < 337.5)
|
|
return CD_SOUTH_EAST;
|
|
else
|
|
return CD_EAST;
|
|
}
|
|
|
|
void iupPlotDataSet::DrawDataPie(const iupPlotTrafo *inTrafoX, const iupPlotTrafo *inTrafoY, cdCanvas* canvas, const iupPlotSampleNotify* inNotify, const iupPlotAxis& inAxisY, long inBackColor) const
|
|
{
|
|
int theXCount = mDataX->GetCount();
|
|
int theYCount = mDataY->GetCount();
|
|
|
|
if ((theXCount == 0) || (theYCount == 0))
|
|
return;
|
|
|
|
if (theXCount != theYCount)
|
|
return;
|
|
|
|
double xc, yc, w, h;
|
|
|
|
int theCount = mDataX->GetCount();
|
|
double sum = 0;
|
|
|
|
for (int i = 0; i < theCount; i++)
|
|
{
|
|
double theY = mDataY->GetSample(i);
|
|
|
|
if (theY <= 0)
|
|
continue;
|
|
|
|
sum += theY;
|
|
}
|
|
|
|
xc = 0;
|
|
yc = 0;
|
|
xc = inTrafoX->Transform(xc);
|
|
yc = inTrafoY->Transform(yc);
|
|
|
|
w = 2.0 * mPieRadius;
|
|
h = 2.0 * mPieRadius;
|
|
w *= ((iupPlotTrafoLinear *)inTrafoX)->mSlope;
|
|
h *= ((iupPlotTrafoLinear *)inTrafoY)->mSlope;
|
|
|
|
double w1 = 2.0 * (mPieRadius*1.01);
|
|
double h1 = 2.0 * (mPieRadius*1.01);
|
|
w1 *= ((iupPlotTrafoLinear *)inTrafoX)->mSlope;
|
|
h1 *= ((iupPlotTrafoLinear *)inTrafoY)->mSlope;
|
|
|
|
double startAngle = mPieStartAngle;
|
|
|
|
if (mPieContour)
|
|
iupPlotDrawSetLineStyle(canvas, mLineStyle, mLineWidth);
|
|
|
|
if (mPieSliceLabel != IUP_PLOT_NONE)
|
|
inAxisY.SetFont(canvas, inAxisY.mFontStyle, inAxisY.mFontSize);
|
|
|
|
for (int i = 0; i < theCount; i++)
|
|
{
|
|
double theX = mDataX->GetSample(i);
|
|
double theY = mDataY->GetSample(i);
|
|
|
|
if (theY <= 0)
|
|
continue;
|
|
|
|
double angle = (theY*360.) / sum;
|
|
|
|
if (inNotify->cb)
|
|
inNotify->cb(inNotify->ih, inNotify->ds, i, theX, theY, (int)mSelection->GetSampleBool(i));
|
|
|
|
cdCanvasSetForeground(canvas, iupPlotDrawGetSampleColorTable(inNotify->ih, i));
|
|
|
|
cdfCanvasSector(canvas, xc, yc, w, h, startAngle, startAngle + angle);
|
|
|
|
if (mPieContour)
|
|
{
|
|
int foreground = cdCanvasForeground(canvas, mColor);
|
|
|
|
cdCanvasInteriorStyle(canvas, CD_HOLLOW);
|
|
cdfCanvasSector(canvas, xc, yc, w, h, startAngle, startAngle + angle);
|
|
cdCanvasInteriorStyle(canvas, CD_SOLID);
|
|
|
|
cdCanvasForeground(canvas, foreground);
|
|
}
|
|
|
|
if (i == mHighlightedSample)
|
|
iPlotDrawHighlightedArc(canvas, xc, yc, w1, h1, startAngle, startAngle + angle);
|
|
|
|
if (mPieSliceLabel != IUP_PLOT_NONE)
|
|
{
|
|
double bisectrix = (startAngle + startAngle + angle) / 2;
|
|
|
|
int text_alignment = iPlotGetPieTextAligment(bisectrix, mPieSliceLabelPos);
|
|
|
|
double px = xc + (((w / 2.)*fabs(mPieSliceLabelPos)) * cos(bisectrix * CD_DEG2RAD));
|
|
double py = yc + (((h / 2.)*fabs(mPieSliceLabelPos)) * sin(bisectrix * CD_DEG2RAD));
|
|
|
|
cdCanvasSetForeground(canvas, inAxisY.mColor);
|
|
|
|
char theBuf[128];
|
|
switch (mPieSliceLabel)
|
|
{
|
|
case IUP_PLOT_X:
|
|
if (mDataX->IsString())
|
|
iupPlotDrawText(canvas, px, py, text_alignment, ((iupPlotDataString *)mDataX)->GetSampleString(i));
|
|
else
|
|
{
|
|
sprintf(theBuf, "%d", i);
|
|
iupPlotDrawText(canvas, px, py, text_alignment, theBuf);
|
|
}
|
|
break;
|
|
case IUP_PLOT_Y:
|
|
iupStrPrintfDoubleLocale(theBuf, inAxisY.mTick.mFormatString, theY, IupGetGlobal("DEFAULTDECIMALSYMBOL"));
|
|
iupPlotDrawText(canvas, px, py, text_alignment, theBuf);
|
|
break;
|
|
case IUP_PLOT_PERCENT:
|
|
{
|
|
double percent = (theY*100.) / sum;
|
|
iupStrPrintfDoubleLocale(theBuf, inAxisY.mTick.mFormatString, percent, IupGetGlobal("DEFAULTDECIMALSYMBOL"));
|
|
strcat(theBuf, " %");
|
|
iupPlotDrawText(canvas, px, py, text_alignment, theBuf);
|
|
break;
|
|
}
|
|
default: /* IUP_PLOT_NONE */
|
|
break;
|
|
}
|
|
}
|
|
|
|
startAngle += angle;
|
|
}
|
|
|
|
if (mPieHole > 0)
|
|
{
|
|
double hw = mPieHole * 2.0 * mPieRadius;
|
|
double hh = mPieHole * 2.0 * mPieRadius;
|
|
hw *= ((iupPlotTrafoLinear *)inTrafoX)->mSlope;
|
|
hh *= ((iupPlotTrafoLinear *)inTrafoY)->mSlope;
|
|
|
|
cdCanvasSetForeground(canvas, inBackColor);
|
|
|
|
cdfCanvasSector(canvas, xc, yc, hw, hh, 0., 360.);
|
|
|
|
if (mPieContour)
|
|
{
|
|
cdCanvasSetForeground(canvas, mColor);
|
|
|
|
cdCanvasInteriorStyle(canvas, CD_HOLLOW);
|
|
cdfCanvasSector(canvas, xc, yc, hw, hh, 0., 360.);
|
|
cdCanvasInteriorStyle(canvas, CD_SOLID);
|
|
}
|
|
}
|
|
}
|
|
|
|
void iupPlotDataSet::DrawSelection(const iupPlotTrafo *inTrafoX, const iupPlotTrafo *inTrafoY, cdCanvas* canvas, const iupPlotSampleNotify* inNotify) const
|
|
{
|
|
int theCount = mDataX->GetCount();
|
|
|
|
cdCanvasMarkSize(canvas, 7);
|
|
|
|
for (int i = 0; i < theCount; i++)
|
|
{
|
|
if (mSelection->GetSampleBool(i))
|
|
{
|
|
double theX = mDataX->GetSample(i);
|
|
double theY = mDataY->GetSample(i);
|
|
double theScreenX = inTrafoX->Transform(theX);
|
|
double theScreenY = inTrafoY->Transform(theY);
|
|
|
|
if (inNotify->cb)
|
|
{
|
|
int ret = inNotify->cb(inNotify->ih, inNotify->ds, i, theX, theY, (int)mSelection->GetSampleBool(i));
|
|
if (ret == IUP_IGNORE)
|
|
continue;
|
|
}
|
|
|
|
cdCanvasMarkType(canvas, CD_BOX);
|
|
cdCanvasSetForeground(canvas, cdEncodeAlpha(CD_GRAY, 128));
|
|
cdfCanvasMark(canvas, theScreenX, theScreenY);
|
|
|
|
cdCanvasMarkType(canvas, CD_HOLLOW_BOX);
|
|
cdCanvasSetForeground(canvas, cdEncodeAlpha(CD_BLACK, 128));
|
|
cdfCanvasMark(canvas, theScreenX, theScreenY);
|
|
}
|
|
}
|
|
}
|
|
|
|
void iupPlotDataSet::DrawData(const iupPlotTrafo *inTrafoX, const iupPlotTrafo *inTrafoY, cdCanvas* canvas, const iupPlotSampleNotify* inNotify) const
|
|
{
|
|
int theXCount = mDataX->GetCount();
|
|
int theYCount = mDataY->GetCount();
|
|
|
|
if ((theXCount == 0) || (theYCount == 0))
|
|
return;
|
|
|
|
if (theXCount != theYCount)
|
|
return;
|
|
|
|
cdCanvasSetForeground(canvas, mColor);
|
|
iupPlotDrawSetLineStyle(canvas, mLineStyle, mLineWidth);
|
|
iPlotSetMark(canvas, mMarkStyle, mMarkSize);
|
|
|
|
switch (mMode)
|
|
{
|
|
case IUP_PLOT_LINE:
|
|
DrawDataLine(inTrafoX, inTrafoY, canvas, inNotify, false, false);
|
|
break;
|
|
case IUP_PLOT_MARK:
|
|
DrawDataMark(inTrafoX, inTrafoY, canvas, inNotify);
|
|
break;
|
|
case IUP_PLOT_STEM:
|
|
DrawDataStem(inTrafoX, inTrafoY, canvas, inNotify, false);
|
|
break;
|
|
case IUP_PLOT_MARKSTEM:
|
|
DrawDataStem(inTrafoX, inTrafoY, canvas, inNotify, true);
|
|
break;
|
|
case IUP_PLOT_MARKLINE:
|
|
DrawDataLine(inTrafoX, inTrafoY, canvas, inNotify, true, false);
|
|
break;
|
|
case IUP_PLOT_AREA:
|
|
DrawDataArea(inTrafoX, inTrafoY, canvas, inNotify);
|
|
break;
|
|
case IUP_PLOT_BAR:
|
|
DrawDataBar(inTrafoX, inTrafoY, canvas, inNotify);
|
|
break;
|
|
case IUP_PLOT_PIE: /* handled outside DrawData */
|
|
break;
|
|
case IUP_PLOT_HORIZONTALBAR:
|
|
DrawDataHorizontalBar(inTrafoX, inTrafoY, canvas, inNotify);
|
|
break;
|
|
case IUP_PLOT_MULTIBAR:
|
|
DrawDataMultiBar(inTrafoX, inTrafoY, canvas, inNotify);
|
|
break;
|
|
case IUP_PLOT_ERRORBAR:
|
|
DrawDataLine(inTrafoX, inTrafoY, canvas, inNotify, true, true);
|
|
break;
|
|
case IUP_PLOT_STEP:
|
|
DrawDataStep(inTrafoX, inTrafoY, canvas, inNotify);
|
|
break;
|
|
}
|
|
|
|
if (mHasSelected)
|
|
DrawSelection(inTrafoX, inTrafoY, canvas, inNotify);
|
|
}
|
|
|