From 5ea40301dca0583b1af2691272b5d7a2db407562 Mon Sep 17 00:00:00 2001 From: cxl Date: Tue, 1 May 2012 18:20:38 +0000 Subject: [PATCH] *ScatterDraw: Fixed to compile git-svn-id: svn://ultimatepp.org/upp/trunk@4897 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- uppsrc/ScatterDraw/DataSource.cpp | 33 + uppsrc/ScatterDraw/DataSource.h | 234 +++ uppsrc/ScatterDraw/ScatterDraw.cpp | 2813 ++++++++++++++-------------- uppsrc/ScatterDraw/ScatterDraw.h | 1297 +++++++------ uppsrc/ScatterDraw/ScatterDraw.upp | 5 +- uppsrc/ScatterDraw/init | 1 - 6 files changed, 2324 insertions(+), 2059 deletions(-) create mode 100644 uppsrc/ScatterDraw/DataSource.cpp create mode 100644 uppsrc/ScatterDraw/DataSource.h diff --git a/uppsrc/ScatterDraw/DataSource.cpp b/uppsrc/ScatterDraw/DataSource.cpp new file mode 100644 index 000000000..d1440e9c7 --- /dev/null +++ b/uppsrc/ScatterDraw/DataSource.cpp @@ -0,0 +1,33 @@ +#include "ScatterDraw.h" + +NAMESPACE_UPP + +#define Membercall(fun) (this->*fun) + +double DataSource::Min(Getdatafun getdata) +{ + double minVal = -DOUBLE_NULL; + for (int i = 0; i < GetCount(); ++i) + if (minVal > Membercall(getdata)(i)) + minVal = Membercall(getdata)(i); + return minVal; +} + +double DataSource::Max(Getdatafun getdata) +{ + double maxVal = DOUBLE_NULL; + for (int i = 0; i < GetCount(); ++i) + if (maxVal < Membercall(getdata)(i)) + maxVal = Membercall(getdata)(i); + return maxVal; +} + +double DataSource::Avg(Getdatafun getdata) +{ + double ret = 0; + for (int i = 0; i < GetCount(); ++i) + ret += Membercall(getdata)(i); + return ret/GetCount(); +} + +END_UPP_NAMESPACE \ No newline at end of file diff --git a/uppsrc/ScatterDraw/DataSource.h b/uppsrc/ScatterDraw/DataSource.h new file mode 100644 index 000000000..dbf1fce33 --- /dev/null +++ b/uppsrc/ScatterDraw/DataSource.h @@ -0,0 +1,234 @@ +#ifndef _DataSource_DataSource_h_ +#define _DataSource_DataSource_h_ + +class DataSource { +public: + typedef double (DataSource::*Getdatafun)(int id); + + DataSource() : isParam(false) {} + virtual ~DataSource() {}; + virtual double z(int id){return Null;}; + virtual double y(int id){return Null;}; + virtual double x(int id){return Null;}; + virtual int GetCount() {return Null;}; + bool IsParam() {return isParam;}; + + virtual double MinX() {return Min(&DataSource::x);} + virtual double MinY() {return Min(&DataSource::y);} + virtual double MinZ() {return Min(&DataSource::z);} + + virtual double MaxX() {return Max(&DataSource::x);} + virtual double MaxY() {return Max(&DataSource::y);} + virtual double MaxZ() {return Max(&DataSource::z);} + + virtual double AvgX() {return Avg(&DataSource::x);} + virtual double AvgY() {return Avg(&DataSource::y);} + virtual double AvgZ() {return Avg(&DataSource::z);} + +protected: + bool isParam; + + virtual double Min(Getdatafun getdata); + virtual double Max(Getdatafun getdata); + virtual double Avg(Getdatafun getdata); +}; + +class CArray : public DataSource { +private: + double *xData, *yData, *zData; + int numData; + double x0, deltaX; + +public: + CArray(double *yData, int numData, double x0, double deltaX) : yData(yData), numData(numData), x0(x0), deltaX(deltaX) { xData = NULL; }; + CArray(double *xData, double *yData, int numData) : xData(xData), yData(yData), numData(numData) { zData = NULL; x0 = deltaX = 0; }; + CArray(double *xData, double *yData, double *zData, int numData) : xData(xData), yData(yData), zData(zData), numData(numData) { x0 = deltaX = 0; }; + virtual inline double z(int id) {ASSERT(zData); return zData[id];}; + virtual inline double y(int id) {return yData[id];}; + virtual inline double x(int id) {return xData ? xData[id] : id*deltaX + x0;}; + virtual inline int GetCount() {return numData;}; +}; + +template +class VectorY : public DataSource { +private: + Vector *yData; + +public: + VectorY(Vector &yData) : yData(&yData) {}; + virtual inline double y(int id) {return (*yData)[id];}; + virtual inline double x(int id) {return id;}; + virtual inline int GetCount() {return yData->GetCount();}; +}; + +template +class ArrayY : public DataSource { +private: + Upp::Array *yData; + +public: + ArrayY(Upp::Array &yData) : yData(&yData) {}; + virtual inline double y(int id) {return (*yData)[id];}; + virtual inline double x(int id) {return id;}; + virtual inline int GetCount() {return yData->GetCount();}; +}; + +class VectorDouble : public DataSource { +private: + const Vector *xData, *yData; + +public: + VectorDouble(const Vector &xData, Vector &yData) : xData(&xData), yData(&yData) {}; + virtual inline double y(int id) {return (*yData)[id];}; + virtual inline double x(int id) {return (*xData)[id];}; + virtual inline int GetCount() {return xData->GetCount();}; +}; + +class ArrayDouble : public DataSource { +private: + const Upp::Array *xData, *yData; + +public: + ArrayDouble(const Upp::Array &xData, Upp::Array &yData) : xData(&xData), yData(&yData) {}; + virtual inline double y(int id) {return (*yData)[id];}; + virtual inline double x(int id) {return (*xData)[id];}; + virtual inline int GetCount() {return xData->GetCount();}; +}; + +class VectorPointf : public DataSource { +private: + const Vector *data; + +public: + VectorPointf(const Vector &data) : data(&data) {}; + VectorPointf(Vector *data) : data(data) {}; + virtual inline double y(int id) {return (*data)[id].y;}; + virtual inline double x(int id) {return (*data)[id].x;}; + virtual inline int GetCount() {return data->GetCount();}; +}; + +class ArrayPointf : public DataSource { +private: + Upp::Array *data; + +public: + ArrayPointf(Upp::Array &data) : data(&data) {}; + virtual inline double y(int id) {return (*data)[id].y;}; + virtual inline double x(int id) {return (*data)[id].x;}; + virtual inline int GetCount() {return data->GetCount();}; +}; + +template +class VectorMapXY : public DataSource { +private: + VectorMap *data; + +public: + VectorMapXY(VectorMap &data) : data(&data) {}; + virtual inline double y(int id) {return (*data)[id];}; + virtual inline double x(int id) {return (*data).GetKey(id);}; + virtual inline int GetCount() {return data->GetCount();}; +}; + +template +class ArrayMapXY : public DataSource { +private: + ArrayMap *data; + +public: + ArrayMapXY(ArrayMap &data) : data(&data) {}; + virtual inline double y(int id) {return (*data)[id];}; + virtual inline double x(int id) {return (*data).GetKey(id);}; + virtual inline int GetCount() {return data->GetCount();}; +}; + +class FuncSource : public DataSource { +private: + double (*function)(double); + +public: + FuncSource(double (*function)(double)) : function(function) {}; + virtual inline double y(int t) {return function(t);}; + virtual inline double x(int t) {return t;}; + virtual inline int GetCount() {return Null;}; +}; + +class FuncSourcePara : public DataSource { +private: + Pointf (*function)(double); + Pointf lastPointf; + double lastT; + int numPoints; + double minT, maxT; + +public: + FuncSourcePara(Pointf (*function)(double), int np, double from, double to) : + function(function), numPoints(np), minT(from), maxT(to) { + lastT = Null; + isParam = true; + } + virtual inline double y(int t) { + if (IsNull(lastT) || t != lastT) { + lastPointf = function(minT + t*(maxT-minT)/numPoints); + lastT = t; + } + return lastPointf.y; + } + virtual inline double x(int t) { + if (IsNull(lastT) || t != lastT) { + lastPointf = function(minT + t*(maxT-minT)/numPoints); + lastT = t; + } + return lastPointf.x; + } + virtual inline int GetCount() {return numPoints;}; +}; + +typedef Callback2 PlotFunc; +typedef Callback2 PlotParamFunc; + +class PlotFuncSource : public DataSource { +private: + PlotFunc function; + +public: + PlotFuncSource() {}; + PlotFuncSource(PlotFunc &function) : function(function) {}; + virtual inline double y(int t) {double y; function(y, t); return y;}; + virtual inline double x(int t) {return t;}; + virtual inline int GetCount() {return Null;}; +}; + +class PlotParamFuncSource : public DataSource { +private: + PlotParamFunc function; + Pointf lastPointf; + double lastT; + int numPoints; + double minT, maxT; + +public: + PlotParamFuncSource(PlotParamFunc function, int np, double from, double to) : + function(function), numPoints(np), minT(from), maxT(to) { + lastT = Null; + isParam = true; + } + inline double y(int t) { + if (IsNull(lastT) || t != lastT) { + function(lastPointf, minT + t*(maxT-minT)/numPoints); + lastT = t; + } + return lastPointf.y; + } + + inline double x(int t) { + if (IsNull(lastT) || t != lastT) { + function(lastPointf, minT + t*(maxT-minT)/numPoints); + lastT = t; + } + return lastPointf.x; + } + virtual inline int GetCount() {return numPoints;}; +}; + +#endif diff --git a/uppsrc/ScatterDraw/ScatterDraw.cpp b/uppsrc/ScatterDraw/ScatterDraw.cpp index 9bb97aa70..f52382449 100644 --- a/uppsrc/ScatterDraw/ScatterDraw.cpp +++ b/uppsrc/ScatterDraw/ScatterDraw.cpp @@ -1,1407 +1,1406 @@ -#include "ScatterDraw.h" - -ScatterDraw& ScatterDraw::SetColor(const Color& _color) -{ - graphColor = _color; - return *this; -} - -ScatterDraw& ScatterDraw::SetTitle(const String& _title) -{ - title = _title; - return *this; -} - -ScatterDraw& ScatterDraw::SetTitleFont(const Font& fontTitle) -{ - titleFont = fontTitle; - return *this; -} - -ScatterDraw& ScatterDraw::SetTitleColor(const Color& colorTitle) -{ - titleColor = colorTitle; - return *this; -} - -void ScatterDraw::SetLabels(const String& _xLabel, const String& _yLabel, const String& _yLabel2) -{ - xLabel = _xLabel; - yLabel = _yLabel; - yLabel2 = _yLabel2; -} - -ScatterDraw& ScatterDraw::SetLabelX(const String& _xLabel) -{ - xLabel = _xLabel; - return *this; -} - -ScatterDraw& ScatterDraw::SetLabelY(const String& _yLabel) -{ - yLabel = _yLabel; - return *this; -} - -ScatterDraw& ScatterDraw::SetLabelY2(const String& _yLabel) -{ - yLabel2 = _yLabel; - return *this; -} - -ScatterDraw& ScatterDraw::SetLabelsFont(const Font& fontLabels) -{ - labelsFont = fontLabels; - return *this; -} - -ScatterDraw& ScatterDraw::SetLabelsColor(const Color& colorLabels) -{ - labelsColor = colorLabels; - return *this; -} - -ScatterDraw& ScatterDraw::SetPlotAreaMargin(const int hLeft, const int hRight, const int vTop, const int vBottom) -{ - hPlotLeft = hLeft; - hPlotRight = hRight; - vPlotTop = vTop; - vPlotBottom = vBottom; - return *this; -} - -ScatterDraw& ScatterDraw::SetPlotAreaLeftMargin(const int margin) { - hPlotLeft = margin; - return *this; -} - -ScatterDraw& ScatterDraw::SetPlotAreaRightMargin(const int margin) { - hPlotRight = margin; - return *this; -} - -ScatterDraw& ScatterDraw::SetPlotAreaTopMargin(const int margin) { - vPlotTop = margin; - return *this; -} - -ScatterDraw& ScatterDraw::SetPlotAreaBottomMargin(const int margin) { - vPlotBottom = margin; - return *this; -} - -ScatterDraw& ScatterDraw::SetPlotAreaColor(const Color& p_a_color) -{ - plotAreaColor = p_a_color; - return *this; -} - -ScatterDraw& ScatterDraw::SetAxisColor(const Color& axis_color) -{ - axisColor = axis_color; - return *this; -} - -ScatterDraw& ScatterDraw::SetAxisWidth(const int& axis_width) -{ - axisWidth = axis_width; - return *this; -} - -ScatterDraw& ScatterDraw::SetGridColor(const Color& grid_color) -{ - gridColor = grid_color; - return *this; -} - -ScatterDraw& ScatterDraw::SetGridWidth(const int& grid_width) -{ - gridWidth = grid_width; - return *this; -} - -ScatterDraw& ScatterDraw::ShowHGrid(const bool& show) -{ - drawHGrid = show; - return *this; -} - -ScatterDraw& ScatterDraw::ShowVGrid(const bool& show) -{ - drawVGrid = show; - return *this; -} - -ScatterDraw& ScatterDraw::ShowLegend(const bool& show) -{ - showLegend = show; - return *this; -} - -ScatterDraw& ScatterDraw::SetLegendWeight(const int& weight) -{ - legendWeight = weight; - return *this; -} - -ScatterDraw &ScatterDraw::SetDrawXReticle(bool set) -{ - drawXReticle = set; - return *this; -} - -ScatterDraw &ScatterDraw::SetDrawYReticle(bool set) -{ - drawYReticle = set; - return *this; -} - -ScatterDraw &ScatterDraw::SetDrawY2Reticle(bool set) -{ - drawY2Reticle = set; - return *this; -} - -void ScatterDraw::DrawLegend(Draw& w, const int& scale) const -{ - int nmr = fround((GetSize().cx - 2*(hPlotLeft + hPlotRight))/legendWeight); //max number of labels per row - if (nmr <= 0) - return; - int nLab = series.GetCount(); //number of labels - int Nc; //number of complete rows - int LCR; //number of labels on complete row - int R; //number of remaining labels on incomplete row - if(nmr > nLab) { - Nc = 0; LCR = 0; R = nLab; - } else if (nmr == nLab) { - Nc = 1; LCR = nLab; R = 0; - } else { - Nc = nLab/nmr; LCR = nmr; R = nLab%nmr; - } - for(int j = 0; j <= Nc; j++) { - int start = nLab - (j+1)*LCR; - int end = nLab - j*LCR; - if (j == Nc) { - start = 0; - end = R; - } - for(int i = start; i < end; i++) { - Vector vp; - vp << Point(scale*(i-start)*legendWeight, scale*(4-12*(j+1))) << - Point(scale*(i-start)*legendWeight+scale*23, scale*(4-12*(j+1))); - if (series[i].opacity > 0 && series[i].seriesPlot) - DrawPolylineOpa(w, vp, scale, 1, scale*series[i].thickness, series[i].color, series[i].dash); - Point p(scale*((i-start)*legendWeight+7),scale*(4-12*(j+1))/*+scale*Thick.At(i)/12*/); - if (series[i].markWidth >= 1 && series[i].markPlot) - series[i].markPlot->Paint(w, scale, p, series[i].markWidth, series[i].markColor); - Font scaledFont; - scaledFont.Height(scale*StdFont().GetHeight()); - DrawText(w, scale*(i-start)*legendWeight+scale*25, scale*(-2-12*(j+1)), 0, - series[i].legend, scaledFont, series[i].color); - } - } -} - -void ScatterDraw::AdjustMinUnitX() -{ - if (xMajorUnit > 0) { - while (xMinUnit < 0) - xMinUnit += xMajorUnit; - while (xMinUnit > xMajorUnit) - xMinUnit -= xMajorUnit; - } -} -/* -void ScatterDraw::AdjustMinUnitY() -{ - if (yMajorUnit > 0) { - while (yMinUnit < 0) - yMinUnit += yMajorUnit; - while (yMinUnit > yMajorUnit) - yMinUnit -= yMajorUnit; - } -} - -void ScatterDraw::AdjustMinUnitY2() -{ - if (yMajorUnit2 > 0) { - while (yMinUnit2 < 0) - yMinUnit2 += yMajorUnit2; - while (yMinUnit2 > yMajorUnit2) - yMinUnit2 -= yMajorUnit2; - } -} -*/ - -void ScatterDraw::AdjustMinUnitY() -{ - if (yMajorUnit > 0) { - if (fabs(yMinUnit/yMajorUnit) > 10000000000) - yMinUnit = yMajorUnit; - else { - while (yMinUnit < 0) - yMinUnit += yMajorUnit; - } - if (fabs(yMinUnit/yMajorUnit) > 10000000000) - yMinUnit = yMajorUnit; - else { - while (yMinUnit > yMajorUnit) - yMinUnit -= yMajorUnit; - } - } -} - -void ScatterDraw::AdjustMinUnitY2() -{ - if (yMajorUnit2 > 0) { - if (fabs(yMinUnit2/yMajorUnit2) > 10000000000) - yMinUnit2 = yMajorUnit2; - else { - while (yMinUnit2 < 0) - yMinUnit2 += yMajorUnit2; - } - if (fabs(yMinUnit2/yMajorUnit2) > 10000000000) - yMinUnit2 = yMajorUnit2; - else { - while (yMinUnit2 > yMajorUnit2) - yMinUnit2 -= yMajorUnit2; - } - } -} - -ScatterDraw &ScatterDraw::SetRange(double rx, double ry, double ry2) -{ - ASSERT(!(rx <= 0 || ry <= 0 || ry2 <= 0)); - xRange = rx; - yRange = ry; - yRange2 = ry2; - xMajorUnit = xRange/10; - AdjustMinUnitX(); - yMajorUnit = yRange/10; - AdjustMinUnitY(); - yMajorUnit2 = yRange2/10; - AdjustMinUnitY2(); - WhenSetRange(); - return *this; -} - -ScatterDraw &ScatterDraw::SetMajorUnits(double ux, double uy) -{ - if (!IsNull(ux)) { - xMajorUnit = ux; - AdjustMinUnitX(); - } - if (!IsNull(uy)) { - yMajorUnit = uy; - yMajorUnit2 = yMajorUnit*yRange2/yRange; - AdjustMinUnitY(); - AdjustMinUnitY2(); - } - return *this; -} - -ScatterDraw &ScatterDraw::SetMajorUnitsNum(int nx, int ny) -{ - if (!IsNull(nx)) { - xMajorUnit = xRange/nx; - AdjustMinUnitX(); - } - if (!IsNull(ny)) { - yMajorUnit = yRange/ny; - yMajorUnit2 = yMajorUnit*yRange2/yRange; - AdjustMinUnitY(); - AdjustMinUnitY2(); - } - return *this; -} - -ScatterDraw &ScatterDraw::SetMinUnits(double ux, double uy) -{ - xMinUnit = ux; - yMinUnit = uy; - yMinUnit2 = yRange2*yMinUnit/yRange; - AdjustMinUnitX(); - AdjustMinUnitY(); - AdjustMinUnitY2(); - return *this; -} - -ScatterDraw &ScatterDraw::SetXYMin(double xmin, double ymin, double ymin2) -{ - xMin = xmin; - yMin = ymin; - yMin2 = ymin2; - WhenSetXYMin(); - return *this; -} - -void ScatterDraw::FitToData(bool vertical) { - double minx, maxx, miny, miny2, maxy, maxy2; - minx = miny = miny2 = -DOUBLE_NULL; - maxx = maxy = maxy2 = DOUBLE_NULL; - - for (int j = 0; j < series.GetCount(); j++) { - if (series[j].opacity == 0) - continue; - for (int i = 0; i < series[j].PointsData()->GetCount(); i++) { - if (series[j].PointsData()->x(i) < minx) - minx = series[j].PointsData()->x(i); - if (series[j].PointsData()->x(i) > maxx) - maxx = series[j].PointsData()->x(i); - } - } - if (vertical) { - for (int j = 0; j < series.GetCount(); j++) { - if (series[j].opacity == 0) - continue; - for (int i = 0; i < series[j].PointsData()->GetCount(); i++) { - if (series[j].primaryY) { - if (series[j].PointsData()->y(i) < miny) - miny = series[j].PointsData()->y(i); - if (series[j].PointsData()->y(i) > maxy) - maxy = series[j].PointsData()->y(i); - } else { - if (series[j].PointsData()->y(i) < miny2) - miny2 = series[j].PointsData()->y(i); - if (series[j].PointsData()->y(i) > maxy2) - maxy2 = series[j].PointsData()->y(i); - } - } - } - } - if (minx != -DOUBLE_NULL) { - double deltaX = xMin - minx; - xMin -= deltaX; - xMinUnit += deltaX; - AdjustMinUnitX(); - xRange = maxx - minx; - } - if (vertical) { - if (miny != -DOUBLE_NULL) { - /* - if (!IsNull(maxy2)) { - miny = min((miny-yMin)/yRange, (miny2-yMin2)/yRange2); - maxy = max((maxy-yMin-yRange)/yRange, (maxy2-yMin2-yRange2)/yRange2); - } else { - miny = (miny-yMin)/yRange; - maxy = (maxy-yMin-yRange)/yRange; - } - - miny = miny*yRange + yMin; - maxy = maxy*yRange + yMin + yRange; - */ - double fact = yRange2/yRange; - double deltaY = yMin - miny; - double deltaY2 = deltaY*fact; - - yMin -= deltaY; - yMinUnit += deltaY; - AdjustMinUnitY(); - yRange = maxy - miny; - - yMin2 -= deltaY2; - yMinUnit2 += deltaY2; - AdjustMinUnitY2(); - yRange2 = yRange*fact; - } - } - WhenSetRange(); - WhenSetXYMin(); - Refresh(); -} - -ScatterDraw &ScatterDraw::Graduation_FormatX(Formats fi) -{ - switch (fi) { - case EXP: cbModifFormatX = THISBACK(ExpFormat); break; - case MON: cbModifFormatX = THISBACK(MonFormat); break; - case DY: cbModifFormatX = THISBACK(DyFormat); break; - default:break; - } - return *this; -} - -ScatterDraw &ScatterDraw::Graduation_FormatY(Formats fi) -{ - switch (fi) { - case EXP: cbModifFormatY = THISBACK(ExpFormat); break; - case MON: cbModifFormatY = THISBACK(MonFormat); break; - case DY: cbModifFormatY = THISBACK(DyFormat); break; - default:break; - } - return *this; -} - -ScatterDraw &ScatterDraw::Graduation_FormatY2(Formats fi) -{ - switch (fi) { - case EXP: cbModifFormatY2 = THISBACK(ExpFormat); break; - case MON: cbModifFormatY2 = THISBACK(MonFormat); break; - case DY: cbModifFormatY2 = THISBACK(DyFormat); break; - default:break; - } - return *this; -} - -Color ScatterDraw::GetNewColor(int id) -{ - switch(id) { - case 0: return LtBlue(); - case 1: return LtRed(); - case 2: return LtGreen(); - case 3: return Black(); - case 4: return LtGray(); - case 5: return Brown(); - case 6: return Blue(); - case 7: return Red(); - case 8: return Green(); - case 9: return Gray(); - case 10: return LtBlue(); - case 11: return LtRed(); - case 12: return LtGreen(); - case 13: return Black(); - case 14: return LtGray(); - case 15: return Brown(); - case 16: return Blue(); - case 17: return Red(); - case 18: return Green(); - case 19: return Gray(); - } - return Color(Random(), Random(), Random()); -} - -String ScatterDraw::GetNewDash(int id) -{ - switch(id) { - case 0: return LINE_SOLID; - case 1: return LINE_DOTTED; - case 2: return LINE_DASHED; - case 3: return LINE_DASH_DOT; - case 4: return LINE_SOLID; - case 5: return LINE_DOTTED; - case 6: return LINE_DASHED; - case 7: return LINE_DASH_DOT; - case 8: return LINE_SOLID; - case 9: return LINE_DOTTED; - case 10: return LINE_DASHED; - case 11: return LINE_DASH_DOT; - } - dword r = Random(); - if (r < 8000) - r += 2000; - String ret = FormatInt(r).Right(4); - String space = " "; - return ret.Mid(0, 1) + space + ret.Mid(1, 1) + space + ret.Mid(2, 1) + space + ret.Mid(3, 1); -} - -MarkPlot *ScatterDraw::GetNewMarkPlot(int id) -{ - switch(id) { - case 0: return new CircleMarkPlot(); - case 1: return new SquareMarkPlot(); - case 2: return new TriangleMarkPlot(); - case 3: return new CrossMarkPlot(); - case 4: return new XMarkPlot(); - case 5: return new RhombMarkPlot(); - } - return new CircleMarkPlot(); -} - -Color GetOpaqueColor(const Color &color, const Color &background, const double opacity) -{ - if (opacity == 1) - return color; - if (opacity == 0) - return background; - return Color(int(opacity*(color.GetR() - background.GetR()) + background.GetR()), - int(opacity*(color.GetG() - background.GetG()) + background.GetG()), - int(opacity*(color.GetB() - background.GetB()) + background.GetB())); -} - -ScatterDraw::ScatterBasicSeries::ScatterBasicSeries() -{ - color = Null; - thickness = 3; - legend = ""; - opacity = 1; - primaryY = true; - sequential = false; - dash = LINE_SOLID; - seriesPlot = new LineSeriesPlot(); - markPlot = new CircleMarkPlot(); - markWidth = 8; - markColor = Null; - fillColor = Null; -} - -void ScatterDraw::ScatterBasicSeries::Init(int id) -{ - color = GetNewColor(id); - markColor = Color(max(color.GetR()-30, 0), max(color.GetG()-30, 0), max(color.GetB()-30, 0)); - - dash = GetNewDash(id); - markPlot = GetNewMarkPlot(id); -} - -ScatterDraw &ScatterDraw::AddSeries(double *yData, int numData, double x0, double deltaX) -{ - return AddSeries(yData, numData, x0, deltaX); -} - -ScatterDraw &ScatterDraw::AddSeries(double *xData, double *yData, int numData) -{ - return AddSeries(xData, yData, numData); -} - -ScatterDraw &ScatterDraw::AddSeries(Vector &xData, Vector &yData) -{ - return AddSeries(xData, yData); -} - -ScatterDraw &ScatterDraw::AddSeries(Array &xData, Array &yData) -{ - return AddSeries(xData, yData); -} - -ScatterDraw &ScatterDraw::AddSeries(Vector &points) -{ - return AddSeries(points); -} - -ScatterDraw &ScatterDraw::AddSeries(Array &points) -{ - return AddSeries(points); -} - -ScatterDraw &ScatterDraw::AddSeries(double (*function)(double)) -{ - return AddSeries(function); -} - -ScatterDraw &ScatterDraw::AddSeries(Pointf (*function)(double), int np, double from, double to) -{ - return AddSeries(function, np, from, to); -} - -ScatterDraw &ScatterDraw::AddSeries(PlotFunc &function) -{ - return AddSeries(function); -} - -ScatterDraw &ScatterDraw::AddSeries(PlotParamFunc function, int np, double from, double to) -{ - return AddSeries(function, np, from, to); -} - -ScatterDraw &ScatterDraw::AddSeries(DataSource &data) -{ - ScatterSeries &s = series.Add(); - s.Init(series.GetCount()-1); - s.SetDataSource(&data, false); - Refresh(); - return *this; -} - -ScatterDraw &ScatterDraw::_AddSeries(DataSource *data) -{ - ScatterSeries &s = series.Add(); - s.Init(series.GetCount()-1); - s.SetDataSource(data); - Refresh(); - return *this; -} - -void ScatterDraw::InsertSeries(int id, double *yData, int numData, double x0, double deltaX) -{ - InsertSeries(id, yData, numData, x0, deltaX); -} - -void ScatterDraw::InsertSeries(int id, double *xData, double *yData, int numData) -{ - InsertSeries(id, xData, yData, numData); -} - -void ScatterDraw::InsertSeries(int id, Vector &xData, Vector &yData) -{ - InsertSeries(id, xData, yData); -} - -void ScatterDraw::InsertSeries(int id, Array &xData, Array &yData) -{ - InsertSeries(id, xData, yData); -} - -void ScatterDraw::InsertSeries(int id, Vector &points) -{ - InsertSeries(id, points); -} - -void ScatterDraw::InsertSeries(int id, Array &points) -{ - InsertSeries(id, points); -} - -void ScatterDraw::InsertSeries(int id, double (*function)(double)) -{ - InsertSeries(id, function); -} - -void ScatterDraw::InsertSeries(int id, Pointf (*function)(double), int np, double from, double to) -{ - InsertSeries(id, function, np, from, to); -} - -void ScatterDraw::InsertSeries(int id, PlotFunc &function) -{ - InsertSeries(id, function); -} - -void ScatterDraw::InsertSeries(int id, PlotParamFunc function, int np, double from, double to) -{ - InsertSeries(id, function, np, from, to); -} - -void ScatterDraw::_InsertSeries(int id, DataSource *data) -{ - ASSERT(IsValid(id)); - ScatterSeries &s = series.Insert(id); - s.Init(id); - s.SetDataSource(data); - Refresh(); -} - -ScatterDraw &ScatterDraw::PlotStyle(SeriesPlot *data) -{ - int id = series.GetCount() - 1; - - series[id].seriesPlot = data; - return *this; -} - -ScatterDraw &ScatterDraw::MarkStyle(MarkPlot *data) -{ - int id = series.GetCount() - 1; - - series[id].markPlot = data; - return *this; -} - -ScatterDraw &ScatterDraw::Stroke(double thickness, Color color) -{ - int id = series.GetCount() - 1; - - if (IsNull(color)) - color = GetNewColor(id); - series[id].color = color; - series[id].thickness = thickness; - //series[id].dash = GetNewDash(id); - - Refresh(); - return *this; -} - -ScatterDraw &ScatterDraw::Fill(Color color) -{ - int id = series.GetCount() - 1; - - if (IsNull(color)) { - color = GetNewColor(id); - color = Color(min(color.GetR()+30, 255), min(color.GetG()+30, 255), min(color.GetB()+30, 255)); - } - series[id].fillColor = color; - - Refresh(); - return *this; -} - -ScatterDraw &ScatterDraw::MarkColor(Color color) -{ - int id = series.GetCount() - 1; - - if (IsNull(color)) { - color = GetNewColor(id); - color = Color(max(color.GetR()-30, 0), max(color.GetG()-30, 0), max(color.GetB()-30, 0)); - } - series[id].markColor = color; - - Refresh(); - return *this; -} - -ScatterDraw &ScatterDraw::MarkWidth(const double& markWidth) -{ - int id = series.GetCount() - 1; - - series[id].markWidth = markWidth; - - Refresh(); - return *this; -} - -ScatterDraw &ScatterDraw::Dash(const char *dash) -{ - int id = series.GetCount() - 1; - - series[id].dash = dash; - Refresh(); - return *this; -} - -ScatterDraw &ScatterDraw::Legend(const String legend) -{ - int id = series.GetCount() - 1; - - series[id].legend = legend; - return *this; -} - -void ScatterDraw::SetDataColor(const int& j, const Color& color) -{ - ASSERT(IsValid(j)); - series[j].color = color; - Refresh(); -} - -Color ScatterDraw::GetDataColor(const int& j) const -{ - ASSERT(IsValid(j)); - return series[j].color; -} - -void ScatterDraw::SetDataThickness(const int& j, const double& thickness) -{ - ASSERT(IsValid(j)); - series[j].thickness = thickness; - Refresh(); -} - -double ScatterDraw::GetDataThickness(const int& j) const -{ - ASSERT(IsValid(j)); - return series[j].thickness; -} - -void ScatterDraw::SetFillColor(const int& j, const ::Color& color) -{ - ASSERT(IsValid(j)); - series[j].fillColor = color; - Refresh(); -} - -Color ScatterDraw::GetFillColor(const int& j) const -{ - ASSERT(IsValid(j)); - return series[j].fillColor; -} - -ScatterDraw &ScatterDraw::SetMarkWidth(const int& j, const double& markWidth) -{ - ASSERT(IsValid(j)); - series[j].markWidth = markWidth; - Refresh(); - return *this; -} - -double ScatterDraw::GetMarkWidth(const int& j) const -{ - ASSERT(IsValid(j)); - return series[j].markWidth; -} - - -void ScatterDraw::SetMarkColor(const int& j, const ::Color& color) -{ - ASSERT(IsValid(j)); - series[j].markColor = color; - Refresh(); -} - -Color ScatterDraw::GetMarkColor(const int& j) const -{ - ASSERT(IsValid(j)); - return series[j].markColor; -} - -void ScatterDraw::NoMark(const int& j) -{ - ASSERT(IsValid(j)); - series[j].markWidth = 0; -} - -bool ScatterDraw::IsShowMark(const int& j) const throw (Exc) -{ - ASSERT(IsValid(j)); - return series[j].markWidth > 0; -} - - -void ScatterDraw::SetDataPrimaryY(const int& j, const bool& primary) -{ - ASSERT(IsValid(j)); - series[j].primaryY = primary; - Refresh(); -} - -ScatterDraw &ScatterDraw::SetDataPrimaryY(const bool& primary) -{ - SetDataPrimaryY(series.GetCount()-1, primary); - return *this; -} - -bool ScatterDraw::IsDataPrimaryY(const int& j) const throw (Exc) -{ - ASSERT(IsValid(j)); - return series[j].primaryY; -} - -void ScatterDraw::SetSequentialX(const int& j, const bool& sequential) -{ - ASSERT(IsValid(j)); - series[j].sequential = sequential; - Refresh(); -} - -ScatterDraw &ScatterDraw::SetSequentialX(const bool& sequential) -{ - SetSequentialX(series.GetCount()-1, sequential); - return *this; -} - -ScatterDraw &ScatterDraw::SetSequentialXAll(const bool& sequential) -{ - for (int i = 0; i < series.GetCount(); ++i) - SetSequentialX(i, sequential); - sequentialXAll = sequential; - return *this; -} - -void ScatterDraw::Show(const int& j, const bool& show) -{ - ASSERT(IsValid(j)); - series[j].opacity = show ? 1 : 0; - Refresh(); -} - -bool ScatterDraw::IsVisible(const int& j) -{ - ASSERT(IsValid(j)); - return series[j].opacity > 0; -} - -ScatterDraw &ScatterDraw::ShowAll(const bool& show) -{ - for (int i = 0; i < series.GetCount(); ++i) - series[i].opacity = 1; - return *this; -} - -ScatterDraw& ScatterDraw::Id(int id) -{ - return Id(series.GetCount()-1, id); -} - -ScatterDraw& ScatterDraw::Id(const int& j, int id) -{ - ASSERT(IsValid(j)); - series[j].id = id; - return *this; -} - -int ScatterDraw::GetId(const int& j) -{ - ASSERT(IsValid(j)); - return series[j].id; -} - -void ScatterDraw::RemoveSeries(const int& j) -{ - ASSERT(IsValid(j)); - series.Remove(j); - Refresh(); -} - -void ScatterDraw::RemoveAllSeries() -{ - series.Clear(); - Refresh(); -} - -Drawing ScatterDraw::GetDrawing() -{ - DrawingDraw ddw(6*GetSize()); - - SetDrawing (ddw, 6); - return ddw; -} - -Image ScatterDraw::GetImage(const int &scale) -{ -#ifndef flagGUI - ASSERT(mode != MD_DRAW); -#endif - - ImageBuffer ib(scale*GetSize()); - BufferPainter bp(ib, mode); - - SetDrawing(bp, scale); - - return ib; -} - -double ScatterDraw::GetXByPoint(const int x) -{ - return (x - hPlotLeft)*GetXRange()/(GetSize().cx - (hPlotLeft + hPlotRight) - 1) + GetXMin(); -} - -double ScatterDraw::GetYByPoint(const int y) -{ - return (GetSize().cy - vPlotTop - y - 1)*GetYRange()/(GetSize().cy - (vPlotTop + vPlotBottom) - GetTitleFont().GetHeight() - 1) + GetYMin(); -} - -double ScatterDraw::GetY2ByPoint(const int y) -{ - return (GetSize().cy - vPlotTop - y - 1)*GetY2Range()/(GetSize().cy - (vPlotTop + vPlotBottom) - GetTitleFont().GetHeight() - 1) + GetYMin2(); -} - -double ScatterDraw::GetXPointByValue(const double x) -{ - return (x - GetXMin())/GetXRange()*(GetSize().cx - (hPlotLeft + hPlotRight) - 1) + hPlotLeft; -} - -double ScatterDraw::GetYPointByValue(const double y) -{ - return (GetSize().cy - vPlotTop - 1) - (y - GetYMin())/GetYRange()*(GetSize().cy - (vPlotTop + vPlotBottom) - GetTitleFont().GetHeight() - 1); -} - -void ScatterDraw::Zoom(double scale, bool mouseX, bool mouseY) -{ - mouseX = mouseX && ((minXZoom > 0 && xRange*scale > minXZoom) || (minXZoom < 0)); - mouseX = mouseX && ((maxXZoom > 0 && xRange*scale < maxXZoom) || (maxXZoom < 0)); - mouseY = mouseY && ((minYZoom > 0 && yRange*scale > minYZoom) || (minYZoom < 0)); - mouseY = mouseY && ((maxYZoom > 0 && yRange*scale < maxYZoom) || (maxYZoom < 0)); - if (mouseX) { - if (zoomStyleX == TO_CENTER) { - double oldXMin = xMin; - xMin += xRange*(1-scale)/2.; - xMinUnit = oldXMin + xMinUnit - xMin; - AdjustMinUnitX(); - } - xRange *= scale; - if (!IsNull(maxMajorUnitsX)) { - if (xRange < xMajorUnit) - xMajorUnit /= 10; - else if (xRange/xMajorUnit > maxMajorUnitsX) - xMajorUnit *= 10; - } - } - if (mouseY) { - if (zoomStyleY == TO_CENTER) { - double oldYMin = yMin; - yMin += yRange*(1-scale)/2.; - yMinUnit = oldYMin + yMinUnit - yMin; - AdjustMinUnitY(); - double oldYMin2 = yMin2; - yMin2 += yRange2*(1-scale)/2.; - yMinUnit2 = oldYMin2 + yMinUnit2 - yMin2; - AdjustMinUnitY2(); - } - yRange *= scale; - yRange2 *= scale; - if (!IsNull(maxMajorUnitsY)) { - if (yRange < yMajorUnit) { - yMajorUnit /= 10; - yMajorUnit2 /= 10; - } else if (yRange/yMajorUnit > maxMajorUnitsY) { - yMajorUnit *= 10; - yMajorUnit2 *= 10; - } - } - } - if (mouseX || mouseY) { - WhenSetRange(); - Refresh(); - WhenZoomScroll(); - } -} - -void ScatterDraw::Scroll(double factorX, double factorY) -{ - if (factorX != 0) { - double deltaX = factorX*xRange; - xMin -= deltaX; - xMinUnit += deltaX; - AdjustMinUnitX(); - } - if (factorY != 0) { - double deltaY = -factorY*yRange; - yMin -= deltaY; - yMinUnit += deltaY; - AdjustMinUnitY(); - if (drawY2Reticle) { - double deltaY2 = -factorY*yRange2; - yMin2 -= deltaY2; - yMinUnit2 += deltaY2; - AdjustMinUnitY2(); - } - } - if (factorX != 0 || factorY != 0) { - Refresh(); - WhenZoomScroll(); - } -} - -Pointf PointAtLen(const Pointf &p0, const Pointf &p1, double len) -{ - Pointf ret; - if (p1.y == p0.y) { - ret.x = p0.x + ((p0.x < p1.x) ? len : -len); - ret.y = p0.y; - } else if (p1.x == p0.x) { - ret.x = p0.x; - ret.y = p0.y + ((p0.y < p1.y) ? len : -len); - } else { - double k = sqr((p1.x-p0.x)/(p1.y-p0.y)); - double deltax = len/sqrt(1/k + 1); - double deltay = len/sqrt(k + 1); - ret.x = p0.x + ((p0.x < p1.x) ? deltax : -deltax); - ret.y = p0.y + ((p0.y < p1.y) ? deltay : -deltay); - } - return ret; -} - -inline bool Even(int val) {return !(val%2);} - -Vector GetLineDash(String dash) -{ - Vector d; - CParser p(dash); - try { - while(!p.IsEof()) - if(!p.Char(':')) - d.Add(p.ReadDouble()); - } - catch(CParser::Error) {} - - if(d.GetCount() & 1) { - Vector dash1; - dash1.Append(d); - dash1.Append(d); - return dash1; - } - return d; -} - -Vector &GetDashedArray(String dash) -{ - static VectorMap > pats; - - int pos = pats.Find(dash); - if (pos < 0) { - pats.Add(dash, GetLineDash(dash)); - pos = pats.GetCount()-1; - } - return pats.GetValues()[pos]; -} - -void ScatterDraw::ParseTextMultiline(const String &text, Font fnt, Upp::Array &texts, Upp::Array &sizes) { - Size ret(0, 0); - int npos = 0; - for (int pos = 0; npos != -1; pos = npos+1) { - npos = text.Find('\n', pos); - String &t = texts.Add(); - if (npos != -1) - t = text.Mid(pos, npos-pos); - else - t = text.Mid(pos); - Size &s = sizes.Add(); - s.cx = GetTextSize(t, fnt).cx; - s.cy = GetTextSize(t, fnt).cy; - } -} - -Size GetTextSizeMultiline(Array &sizes) { - Size ret(0, 0); - for (int i = 0; i < sizes.GetCount(); ++i) { - if (sizes[i].cx > ret.cx) - ret.cx = sizes[i].cx; - ret.cy += sizes[i].cy; - } - return ret; -} - -ScatterDraw::ScatterDraw() -{ - mode = MD_ANTIALIASED; - size = Size(0, 0); - titleColor = SColorText(); - graphColor = White(); - titleFont = Roman(20); - labelsFont = StdFont(); - labelsColor = SColorText(); - plotAreaColor = SColorLtFace(); - axisColor = SColorText(); - axisWidth = 6; - hPlotLeft = hPlotRight = vPlotTop = vPlotBottom = 30; - xRange = yRange = yRange2 = 100.0; - xMin = yMin = yMin2 = xMinUnit = yMinUnit = yMinUnit2 = 0.0; - logX = logY = logY2 = false; - gridColor = SColorDkShadow(); - gridWidth = 1; - drawXReticle = true; drawYReticle = true; - drawY2Reticle = false; - drawVGrid = drawHGrid = showLegend = true; - legendWeight = 80; - minXZoom = maxXZoom = minYZoom = maxYZoom = -1; - fastViewX = false; - sequentialXAll = false; - zoomStyleX = zoomStyleY = TO_CENTER; - maxMajorUnitsX = maxMajorUnitsY = Null; - SetMajorUnitsNum(5, 10); - Color(graphColor); -} - -void DrawLine(Draw &w, double x0, double y0, double x1, double y1, double width, const Color &color) -{ - w.DrawLine(fround(x0), fround(y0), fround(x1), fround(y1), fround(width), color); -} - -void DrawLine(Painter &w, double x0, double y0, double x1, double y1, double width, const Color &color) -{ - w.Move(x0, y0).Line(x0, y0).Line(x1, y1).Stroke(width, color); -} - -void DrawVArrow(Draw &w, double x0, double y0, double x1, double y1, double width, double aWidth, double aHeight, const Color &color) -{ - DrawLine(w, x0, y0, x1, y1, width, color); - if (fabs(y0 - y1) > 2*aHeight) { - if (x0 > x1) - Swap(x0, x1); - if (y0 > y1) - Swap(y0, y1); - Vector arrowU, arrowL; - arrowU << Point(fround(x0), fround(y0)) << Point(fround(x0-aWidth), fround(y0+aHeight)) << Point(fround(x0+aWidth), fround(y0+aHeight)); - w.DrawPolygon(arrowU, SColorHighlight()); - arrowL << Point(fround(x0), fround(y1)) << Point(fround(x0-aWidth), fround(y1-aHeight)) << Point(fround(x0+aWidth), fround(y1-aHeight)); - w.DrawPolygon(arrowL, SColorHighlight()); - } -} - -void DrawVArrow(Painter &w, double x0, double y0, double x1, double y1, double width, double aWidth, double aHeight, const Color &color) -{ - DrawLine(w, x0, y0, x1, y1, width, color); - if (fabs(y0 - y1) > 2*aHeight) { - if (x0 > x1) - Swap(x0, x1); - if (y0 > y1) - Swap(y0, y1); - w.Move(x0, y0).Line(x0-aWidth, y0+aHeight).Line(x0+aWidth, y0+aHeight).Fill(SColorHighlight()); - w.Move(x0, y1).Line(x0-aWidth, y1-aHeight).Line(x0+aWidth, y1-aHeight).Fill(SColorHighlight()); - } -} - -void DrawHArrow(Draw &w, double x0, double y0, double x1, double y1, double width, double aWidth, double aHeight, const Color &color) -{ - DrawLine(w, x0, y0, x1, y1, width, color); - if (fabs(x0 - x1) > 2*aHeight) { - if (x0 > x1) - Swap(x0, x1); - if (y0 > y1) - Swap(y0, y1); - Vector arrowL, arrowR; - arrowL << Point(fround(x0), fround(y0)) << Point(fround(x0+aHeight), fround(y0+aWidth)) << Point(fround(x0+aHeight), fround(y0-aWidth)); - w.DrawPolygon(arrowL, SColorHighlight()); - arrowR << Point(fround(x1), fround(y0)) << Point(fround(x1-aHeight), fround(y0+aWidth)) << Point(fround(x1-aHeight), fround(y0-aWidth)); - w.DrawPolygon(arrowR, SColorHighlight()); - } -} - -void DrawHArrow(Painter &w, double x0, double y0, double x1, double y1, double width, double aWidth, double aHeight, const Color &color) -{ - DrawLine(w, x0, y0, x1, y1, width, color); - if (fabs(x0 - x1) > 2*aHeight) { - if (x0 > x1) - Swap(x0, x1); - if (y0 > y1) - Swap(y0, y1); - w.Move(x0, y0).Line(x0+aHeight, y0+aWidth).Line(x0+aHeight, y0-aWidth).Fill(SColorHighlight()); - w.Move(x1, y0).Line(x1-aHeight, y0+aWidth).Line(x1-aHeight, y0-aWidth).Fill(SColorHighlight()); - } -} - -void DrawText(Draw &w, double x, double y, int angle, const String &text, Font font, Color color) -{ - w.DrawText(fround(x), fround(y), angle, text, font, color); -} - -void DrawText(Painter &w, double x, double y, int angle, const String &text, Font font, Color color) -{ - w.Begin(); - w.Translate(x-0.5, y-0.5).Rotate(-angle*M_PI/1800.); - w.Text(0, 0, text, font).Fill(color); - w.End(); -} - -void Clip(Draw &w, double x, double y, double cx, double cy) -{ - w.Clip(fround(x), fround(y), fround(cx), fround(cy)); -} - -void Clip(Painter &w, double x, double y, double cx, double cy) -{ - w.Rectangle(x, y, cx, cy).Clip(); -} - -void ClipEnd(Draw &w) -{ - w.End(); -} - -void ClipEnd(Painter &w) -{ - ; -} - -void DrawLineOpa(Draw& w, const int x0, const int y0, const int x1, const int y1, const int &scale, - const double opacity, double thick, const Color &_color, String dash, - const Color &background) -{ - Vector p; - p << Point(x0, y0) << Point(x1, y1); - DrawPolylineOpa(w, p, scale, opacity, thick, _color, dash, background); -} - -void DashScaled(Painter& w, const String dash, double scale) -{ - if (!dash.IsEmpty()) { - Vector d; - double start = 0; - CParser p(dash); - try { - while(!p.IsEof()) - if(p.Char(':')) - start = p.ReadDouble(); - else - d.Add(scale*p.ReadDouble()); - } - catch(CParser::Error) {} - w.Dash(d, scale*start); - } -} - -void DrawLineOpa(Painter& w, const int x0, const int y0, const int x1, const int y1, const int &scale, - const double opacity, double thick, const Color &color, String dash, - const Color &background) -{ - w.Move(Pointf(x0, y0)); - w.Line(Pointf(x1, y1)); - DashScaled(w, dash, scale); - w.Opacity(opacity); // Before Stroke() - w.Stroke(thick*scale, color); -} - -void FillRectangleOpa(Draw &w, double x0, double y0, double x1, double y1, const int &scale, - const double opacity, const Color &background, const Color &color) -{ - if (IsNull(color)) - return; - Color opacolor = GetOpaqueColor(color, background, opacity); - if (x0 > x1) - Swap(x0, x1); - if (y0 > y1) - Swap(y0, y1); - w.DrawRect(int(x0), int(y0), abs(int(x1 - x0)), abs(int(y1 - y0)), opacolor); -} - -void FillRectangleOpa(Painter &w, double x0, double y0, double x1, double y1, const int &scale, - const double opacity, const Color &background, const Color &color) -{ - if (IsNull(color)) - return; - w.Rectangle(x0, y0, x1 - x0, y1 - y0).Opacity(opacity).Fill(color); -} - -void DrawPolylineOpa(Draw& w, const Vector &p, const int &scale, const double opacity, - double thick, const Color &_color, String dash, const Color &background) -{ - ASSERT(!p.IsEmpty()); - Color color = GetOpaqueColor(_color, background, opacity) ; - if (dash == LINE_SOLID) - w.DrawPolyline(p, fround(thick), color); - else { - Vector &pat = GetDashedArray(dash); - int iPat = 0; - - double len = pat[0]*scale; // Pixels per bar - Pointf begin, end; - begin = p[0]; - for (int i = 1; i < p.GetCount();) { - double d = Distance(begin, p[i]); - if (d >= len) - end = PointAtLen(begin, p[i], len); - else { - end = p[i]; - len -= d; - ++i; - } - if (Even(iPat)) - w.DrawLine(begin, end, fround(thick), color); - if (d >= len) { - iPat++; - if (iPat == pat.GetCount()) - iPat = 0; - len = pat[iPat]*scale; - } - begin = end; - } - } -} - -void DrawPolylineOpa(Painter& w, const Vector &p, const int &scale, const double opacity, - double thick, const Color &color, String dash, const Color &background) -{ - ASSERT(!p.IsEmpty()); - w.Move(p[0]); - for (int i = 1; i < p.GetCount(); ++i) - w.Line(p[i]); - DashScaled(w, dash, scale); - w.Opacity(opacity); // Before Stroke() - w.Stroke(thick*scale, color); -} - -void FillPolylineOpa(Draw& w, const Vector &p, const int &scale, const double opacity, - const Color &background, const Color &fillColor) -{ - ASSERT(!p.IsEmpty()); - Color opacolor = GetOpaqueColor(fillColor, background, opacity) ; - - w.DrawPolygon(p, opacolor); -} - -void FillPolylineOpa(Painter& w, const Vector &p, const int &scale, const double opacity, - const Color &background, const Color &fillColor) -{ - ASSERT(!p.IsEmpty()); - w.Move(p[0]); - for (int i = 1; i < p.GetCount(); ++i) - w.Line(p[i]); - w.Opacity(opacity); - w.Fill(fillColor); // Before Stroke() -} - -INITBLOCK{ - SeriesPlot::Register("Line"); - SeriesPlot::Register("Staggered"); - SeriesPlot::Register("Bar"); - - MarkPlot::Register("Circle"); - MarkPlot::Register("Square"); - MarkPlot::Register("Triangle"); - MarkPlot::Register("Cross"); - MarkPlot::Register("X"); - MarkPlot::Register("Rhomb"); -} - -void GoBreakpoint() -{ - int kk = 1; -} \ No newline at end of file +#include "ScatterDraw.h" + +NAMESPACE_UPP + +ScatterDraw& ScatterDraw::SetColor(const Color& _color) +{ + graphColor = _color; + return *this; +} + +ScatterDraw& ScatterDraw::SetTitle(const String& _title) +{ + title = _title; + return *this; +} + +ScatterDraw& ScatterDraw::SetTitleFont(const Font& fontTitle) +{ + titleFont = fontTitle; + return *this; +} + +ScatterDraw& ScatterDraw::SetTitleColor(const Color& colorTitle) +{ + titleColor = colorTitle; + return *this; +} + +void ScatterDraw::SetLabels(const String& _xLabel, const String& _yLabel, const String& _yLabel2) +{ + xLabel = _xLabel; + yLabel = _yLabel; + yLabel2 = _yLabel2; +} + +ScatterDraw& ScatterDraw::SetLabelX(const String& _xLabel) +{ + xLabel = _xLabel; + return *this; +} + +ScatterDraw& ScatterDraw::SetLabelY(const String& _yLabel) +{ + yLabel = _yLabel; + return *this; +} + +ScatterDraw& ScatterDraw::SetLabelY2(const String& _yLabel) +{ + yLabel2 = _yLabel; + return *this; +} + +ScatterDraw& ScatterDraw::SetLabelsFont(const Font& fontLabels) +{ + labelsFont = fontLabels; + return *this; +} + +ScatterDraw& ScatterDraw::SetLabelsColor(const Color& colorLabels) +{ + labelsColor = colorLabels; + return *this; +} + +ScatterDraw& ScatterDraw::SetPlotAreaMargin(const int hLeft, const int hRight, const int vTop, const int vBottom) +{ + hPlotLeft = hLeft; + hPlotRight = hRight; + vPlotTop = vTop; + vPlotBottom = vBottom; + return *this; +} + +ScatterDraw& ScatterDraw::SetPlotAreaLeftMargin(const int margin) { + hPlotLeft = margin; + return *this; +} + +ScatterDraw& ScatterDraw::SetPlotAreaRightMargin(const int margin) { + hPlotRight = margin; + return *this; +} + +ScatterDraw& ScatterDraw::SetPlotAreaTopMargin(const int margin) { + vPlotTop = margin; + return *this; +} + +ScatterDraw& ScatterDraw::SetPlotAreaBottomMargin(const int margin) { + vPlotBottom = margin; + return *this; +} + +ScatterDraw& ScatterDraw::SetPlotAreaColor(const Color& p_a_color) +{ + plotAreaColor = p_a_color; + return *this; +} + +ScatterDraw& ScatterDraw::SetAxisColor(const Color& axis_color) +{ + axisColor = axis_color; + return *this; +} + +ScatterDraw& ScatterDraw::SetAxisWidth(const int& axis_width) +{ + axisWidth = axis_width; + return *this; +} + +ScatterDraw& ScatterDraw::SetGridColor(const Color& grid_color) +{ + gridColor = grid_color; + return *this; +} + +ScatterDraw& ScatterDraw::SetGridWidth(const int& grid_width) +{ + gridWidth = grid_width; + return *this; +} + +ScatterDraw& ScatterDraw::ShowHGrid(const bool& show) +{ + drawHGrid = show; + return *this; +} + +ScatterDraw& ScatterDraw::ShowVGrid(const bool& show) +{ + drawVGrid = show; + return *this; +} + +ScatterDraw& ScatterDraw::ShowLegend(const bool& show) +{ + showLegend = show; + return *this; +} + +ScatterDraw& ScatterDraw::SetLegendWeight(const int& weight) +{ + legendWeight = weight; + return *this; +} + +ScatterDraw &ScatterDraw::SetDrawXReticle(bool set) +{ + drawXReticle = set; + return *this; +} + +ScatterDraw &ScatterDraw::SetDrawYReticle(bool set) +{ + drawYReticle = set; + return *this; +} + +ScatterDraw &ScatterDraw::SetDrawY2Reticle(bool set) +{ + drawY2Reticle = set; + return *this; +} + +void ScatterDraw::DrawLegend(Draw& w, const int& scale) const +{ + int nmr = fround((GetSize().cx - 2*(hPlotLeft + hPlotRight))/legendWeight); //max number of labels per row + if (nmr <= 0) + return; + int nLab = series.GetCount(); //number of labels + int Nc; //number of complete rows + int LCR; //number of labels on complete row + int R; //number of remaining labels on incomplete row + if(nmr > nLab) { + Nc = 0; LCR = 0; R = nLab; + } else if (nmr == nLab) { + Nc = 1; LCR = nLab; R = 0; + } else { + Nc = nLab/nmr; LCR = nmr; R = nLab%nmr; + } + for(int j = 0; j <= Nc; j++) { + int start = nLab - (j+1)*LCR; + int end = nLab - j*LCR; + if (j == Nc) { + start = 0; + end = R; + } + for(int i = start; i < end; i++) { + Vector vp; + vp << Point(scale*(i-start)*legendWeight, scale*(4-12*(j+1))) << + Point(scale*(i-start)*legendWeight+scale*23, scale*(4-12*(j+1))); + if (series[i].opacity > 0 && series[i].seriesPlot) + DrawPolylineOpa(w, vp, scale, 1, scale*series[i].thickness, series[i].color, series[i].dash); + Point p(scale*((i-start)*legendWeight+7),scale*(4-12*(j+1))/*+scale*Thick.At(i)/12*/); + if (series[i].markWidth >= 1 && series[i].markPlot) + series[i].markPlot->Paint(w, scale, p, series[i].markWidth, series[i].markColor); + Font scaledFont; + scaledFont.Height(scale*StdFont().GetHeight()); + DrawText(w, scale*(i-start)*legendWeight+scale*25, scale*(-2-12*(j+1)), 0, + series[i].legend, scaledFont, series[i].color); + } + } +} + +void ScatterDraw::AdjustMinUnitX() +{ + if (xMajorUnit > 0) { + while (xMinUnit < 0) + xMinUnit += xMajorUnit; + while (xMinUnit > xMajorUnit) + xMinUnit -= xMajorUnit; + } +} +/* +void ScatterDraw::AdjustMinUnitY() +{ + if (yMajorUnit > 0) { + while (yMinUnit < 0) + yMinUnit += yMajorUnit; + while (yMinUnit > yMajorUnit) + yMinUnit -= yMajorUnit; + } +} + +void ScatterDraw::AdjustMinUnitY2() +{ + if (yMajorUnit2 > 0) { + while (yMinUnit2 < 0) + yMinUnit2 += yMajorUnit2; + while (yMinUnit2 > yMajorUnit2) + yMinUnit2 -= yMajorUnit2; + } +} +*/ + +void ScatterDraw::AdjustMinUnitY() +{ + if (yMajorUnit > 0) { + if (fabs(yMinUnit/yMajorUnit) > 10000000000) + yMinUnit = yMajorUnit; + else { + while (yMinUnit < 0) + yMinUnit += yMajorUnit; + } + if (fabs(yMinUnit/yMajorUnit) > 10000000000) + yMinUnit = yMajorUnit; + else { + while (yMinUnit > yMajorUnit) + yMinUnit -= yMajorUnit; + } + } +} + +void ScatterDraw::AdjustMinUnitY2() +{ + if (yMajorUnit2 > 0) { + if (fabs(yMinUnit2/yMajorUnit2) > 10000000000) + yMinUnit2 = yMajorUnit2; + else { + while (yMinUnit2 < 0) + yMinUnit2 += yMajorUnit2; + } + if (fabs(yMinUnit2/yMajorUnit2) > 10000000000) + yMinUnit2 = yMajorUnit2; + else { + while (yMinUnit2 > yMajorUnit2) + yMinUnit2 -= yMajorUnit2; + } + } +} + +ScatterDraw &ScatterDraw::SetRange(double rx, double ry, double ry2) +{ + ASSERT(!(rx <= 0 || ry <= 0 || ry2 <= 0)); + xRange = rx; + yRange = ry; + yRange2 = ry2; + xMajorUnit = xRange/10; + AdjustMinUnitX(); + yMajorUnit = yRange/10; + AdjustMinUnitY(); + yMajorUnit2 = yRange2/10; + AdjustMinUnitY2(); + WhenSetRange(); + return *this; +} + +ScatterDraw &ScatterDraw::SetMajorUnits(double ux, double uy) +{ + if (!IsNull(ux)) { + xMajorUnit = ux; + AdjustMinUnitX(); + } + if (!IsNull(uy)) { + yMajorUnit = uy; + yMajorUnit2 = yMajorUnit*yRange2/yRange; + AdjustMinUnitY(); + AdjustMinUnitY2(); + } + return *this; +} + +ScatterDraw &ScatterDraw::SetMajorUnitsNum(int nx, int ny) +{ + if (!IsNull(nx)) { + xMajorUnit = xRange/nx; + AdjustMinUnitX(); + } + if (!IsNull(ny)) { + yMajorUnit = yRange/ny; + yMajorUnit2 = yMajorUnit*yRange2/yRange; + AdjustMinUnitY(); + AdjustMinUnitY2(); + } + return *this; +} + +ScatterDraw &ScatterDraw::SetMinUnits(double ux, double uy) +{ + xMinUnit = ux; + yMinUnit = uy; + yMinUnit2 = yRange2*yMinUnit/yRange; + AdjustMinUnitX(); + AdjustMinUnitY(); + AdjustMinUnitY2(); + return *this; +} + +ScatterDraw &ScatterDraw::SetXYMin(double xmin, double ymin, double ymin2) +{ + xMin = xmin; + yMin = ymin; + yMin2 = ymin2; + WhenSetXYMin(); + return *this; +} + +void ScatterDraw::FitToData(bool vertical) { + double minx, maxx, miny, miny2, maxy, maxy2; + minx = miny = miny2 = -DOUBLE_NULL; + maxx = maxy = maxy2 = DOUBLE_NULL; + + for (int j = 0; j < series.GetCount(); j++) { + if (series[j].opacity == 0) + continue; + for (int i = 0; i < series[j].PointsData()->GetCount(); i++) { + if (series[j].PointsData()->x(i) < minx) + minx = series[j].PointsData()->x(i); + if (series[j].PointsData()->x(i) > maxx) + maxx = series[j].PointsData()->x(i); + } + } + if (vertical) { + for (int j = 0; j < series.GetCount(); j++) { + if (series[j].opacity == 0) + continue; + for (int i = 0; i < series[j].PointsData()->GetCount(); i++) { + if (series[j].primaryY) { + if (series[j].PointsData()->y(i) < miny) + miny = series[j].PointsData()->y(i); + if (series[j].PointsData()->y(i) > maxy) + maxy = series[j].PointsData()->y(i); + } else { + if (series[j].PointsData()->y(i) < miny2) + miny2 = series[j].PointsData()->y(i); + if (series[j].PointsData()->y(i) > maxy2) + maxy2 = series[j].PointsData()->y(i); + } + } + } + } + if (minx != -DOUBLE_NULL) { + double deltaX = xMin - minx; + xMin -= deltaX; + xMinUnit += deltaX; + AdjustMinUnitX(); + xRange = maxx - minx; + } + if (vertical) { + if (miny != -DOUBLE_NULL) { + /* + if (!IsNull(maxy2)) { + miny = min((miny-yMin)/yRange, (miny2-yMin2)/yRange2); + maxy = max((maxy-yMin-yRange)/yRange, (maxy2-yMin2-yRange2)/yRange2); + } else { + miny = (miny-yMin)/yRange; + maxy = (maxy-yMin-yRange)/yRange; + } + + miny = miny*yRange + yMin; + maxy = maxy*yRange + yMin + yRange; + */ + double fact = yRange2/yRange; + double deltaY = yMin - miny; + double deltaY2 = deltaY*fact; + + yMin -= deltaY; + yMinUnit += deltaY; + AdjustMinUnitY(); + yRange = maxy - miny; + + yMin2 -= deltaY2; + yMinUnit2 += deltaY2; + AdjustMinUnitY2(); + yRange2 = yRange*fact; + } + } + WhenSetRange(); + WhenSetXYMin(); + Refresh(); +} + +ScatterDraw &ScatterDraw::Graduation_FormatX(Formats fi) +{ + switch (fi) { + case EXP: cbModifFormatX = THISBACK(ExpFormat); break; + case MON: cbModifFormatX = THISBACK(MonFormat); break; + case DY: cbModifFormatX = THISBACK(DyFormat); break; + default:break; + } + return *this; +} + +ScatterDraw &ScatterDraw::Graduation_FormatY(Formats fi) +{ + switch (fi) { + case EXP: cbModifFormatY = THISBACK(ExpFormat); break; + case MON: cbModifFormatY = THISBACK(MonFormat); break; + case DY: cbModifFormatY = THISBACK(DyFormat); break; + default:break; + } + return *this; +} + +ScatterDraw &ScatterDraw::Graduation_FormatY2(Formats fi) +{ + switch (fi) { + case EXP: cbModifFormatY2 = THISBACK(ExpFormat); break; + case MON: cbModifFormatY2 = THISBACK(MonFormat); break; + case DY: cbModifFormatY2 = THISBACK(DyFormat); break; + default:break; + } + return *this; +} + +Color ScatterDraw::GetNewColor(int id) +{ + switch(id) { + case 0: return LtBlue(); + case 1: return LtRed(); + case 2: return LtGreen(); + case 3: return Black(); + case 4: return LtGray(); + case 5: return Brown(); + case 6: return Blue(); + case 7: return Red(); + case 8: return Green(); + case 9: return Gray(); + case 10: return LtBlue(); + case 11: return LtRed(); + case 12: return LtGreen(); + case 13: return Black(); + case 14: return LtGray(); + case 15: return Brown(); + case 16: return Blue(); + case 17: return Red(); + case 18: return Green(); + case 19: return Gray(); + } + return Color(Random(), Random(), Random()); +} + +String ScatterDraw::GetNewDash(int id) +{ + switch(id) { + case 0: return LINE_SOLID; + case 1: return LINE_DOTTED; + case 2: return LINE_DASHED; + case 3: return LINE_DASH_DOT; + case 4: return LINE_SOLID; + case 5: return LINE_DOTTED; + case 6: return LINE_DASHED; + case 7: return LINE_DASH_DOT; + case 8: return LINE_SOLID; + case 9: return LINE_DOTTED; + case 10: return LINE_DASHED; + case 11: return LINE_DASH_DOT; + } + dword r = Random(); + if (r < 8000) + r += 2000; + String ret = FormatInt(r).Right(4); + String space = " "; + return ret.Mid(0, 1) + space + ret.Mid(1, 1) + space + ret.Mid(2, 1) + space + ret.Mid(3, 1); +} + +MarkPlot *ScatterDraw::GetNewMarkPlot(int id) +{ + switch(id) { + case 0: return new CircleMarkPlot(); + case 1: return new SquareMarkPlot(); + case 2: return new TriangleMarkPlot(); + case 3: return new CrossMarkPlot(); + case 4: return new XMarkPlot(); + case 5: return new RhombMarkPlot(); + } + return new CircleMarkPlot(); +} + +Color GetOpaqueColor(const Color &color, const Color &background, const double opacity) +{ + if (opacity == 1) + return color; + if (opacity == 0) + return background; + return Color(int(opacity*(color.GetR() - background.GetR()) + background.GetR()), + int(opacity*(color.GetG() - background.GetG()) + background.GetG()), + int(opacity*(color.GetB() - background.GetB()) + background.GetB())); +} + +ScatterDraw::ScatterBasicSeries::ScatterBasicSeries() +{ + color = Null; + thickness = 3; + legend = ""; + opacity = 1; + primaryY = true; + sequential = false; + dash = LINE_SOLID; + seriesPlot = new LineSeriesPlot(); + markPlot = new CircleMarkPlot(); + markWidth = 8; + markColor = Null; + fillColor = Null; +} + +void ScatterDraw::ScatterBasicSeries::Init(int id) +{ + color = GetNewColor(id); + markColor = Color(max(color.GetR()-30, 0), max(color.GetG()-30, 0), max(color.GetB()-30, 0)); + + dash = GetNewDash(id); + markPlot = GetNewMarkPlot(id); +} + +ScatterDraw &ScatterDraw::AddSeries(double *yData, int numData, double x0, double deltaX) +{ + return AddSeries(yData, numData, x0, deltaX); +} + +ScatterDraw &ScatterDraw::AddSeries(double *xData, double *yData, int numData) +{ + return AddSeries(xData, yData, numData); +} + +ScatterDraw &ScatterDraw::AddSeries(Vector &xData, Vector &yData) +{ + return AddSeries(xData, yData); +} + +ScatterDraw &ScatterDraw::AddSeries(Array &xData, Array &yData) +{ + return AddSeries(xData, yData); +} + +ScatterDraw &ScatterDraw::AddSeries(Vector &points) +{ + return AddSeries(points); +} + +ScatterDraw &ScatterDraw::AddSeries(Array &points) +{ + return AddSeries(points); +} + +ScatterDraw &ScatterDraw::AddSeries(double (*function)(double)) +{ + return AddSeries(function); +} + +ScatterDraw &ScatterDraw::AddSeries(Pointf (*function)(double), int np, double from, double to) +{ + return AddSeries(function, np, from, to); +} + +ScatterDraw &ScatterDraw::AddSeries(PlotFunc &function) +{ + return AddSeries(function); +} + +ScatterDraw &ScatterDraw::AddSeries(PlotParamFunc function, int np, double from, double to) +{ + return AddSeries(function, np, from, to); +} + +ScatterDraw &ScatterDraw::AddSeries(DataSource &data) +{ + ScatterSeries &s = series.Add(); + s.Init(series.GetCount()-1); + s.SetDataSource(&data, false); + Refresh(); + return *this; +} + +ScatterDraw &ScatterDraw::_AddSeries(DataSource *data) +{ + ScatterSeries &s = series.Add(); + s.Init(series.GetCount()-1); + s.SetDataSource(data); + Refresh(); + return *this; +} + +void ScatterDraw::InsertSeries(int id, double *yData, int numData, double x0, double deltaX) +{ + InsertSeries(id, yData, numData, x0, deltaX); +} + +void ScatterDraw::InsertSeries(int id, double *xData, double *yData, int numData) +{ + InsertSeries(id, xData, yData, numData); +} + +void ScatterDraw::InsertSeries(int id, Vector &xData, Vector &yData) +{ + InsertSeries(id, xData, yData); +} + +void ScatterDraw::InsertSeries(int id, Array &xData, Array &yData) +{ + InsertSeries(id, xData, yData); +} + +void ScatterDraw::InsertSeries(int id, Vector &points) +{ + InsertSeries(id, points); +} + +void ScatterDraw::InsertSeries(int id, Array &points) +{ + InsertSeries(id, points); +} + +void ScatterDraw::InsertSeries(int id, double (*function)(double)) +{ + InsertSeries(id, function); +} + +void ScatterDraw::InsertSeries(int id, Pointf (*function)(double), int np, double from, double to) +{ + InsertSeries(id, function, np, from, to); +} + +void ScatterDraw::InsertSeries(int id, PlotFunc &function) +{ + InsertSeries(id, function); +} + +void ScatterDraw::InsertSeries(int id, PlotParamFunc function, int np, double from, double to) +{ + InsertSeries(id, function, np, from, to); +} + +void ScatterDraw::_InsertSeries(int id, DataSource *data) +{ + ASSERT(IsValid(id)); + ScatterSeries &s = series.Insert(id); + s.Init(id); + s.SetDataSource(data); + Refresh(); +} + +ScatterDraw &ScatterDraw::PlotStyle(SeriesPlot *data) +{ + int id = series.GetCount() - 1; + + series[id].seriesPlot = data; + return *this; +} + +ScatterDraw &ScatterDraw::MarkStyle(MarkPlot *data) +{ + int id = series.GetCount() - 1; + + series[id].markPlot = data; + return *this; +} + +ScatterDraw &ScatterDraw::Stroke(double thickness, Color color) +{ + int id = series.GetCount() - 1; + + if (IsNull(color)) + color = GetNewColor(id); + series[id].color = color; + series[id].thickness = thickness; + //series[id].dash = GetNewDash(id); + + Refresh(); + return *this; +} + +ScatterDraw &ScatterDraw::Fill(Color color) +{ + int id = series.GetCount() - 1; + + if (IsNull(color)) { + color = GetNewColor(id); + color = Color(min(color.GetR()+30, 255), min(color.GetG()+30, 255), min(color.GetB()+30, 255)); + } + series[id].fillColor = color; + + Refresh(); + return *this; +} + +ScatterDraw &ScatterDraw::MarkColor(Color color) +{ + int id = series.GetCount() - 1; + + if (IsNull(color)) { + color = GetNewColor(id); + color = Color(max(color.GetR()-30, 0), max(color.GetG()-30, 0), max(color.GetB()-30, 0)); + } + series[id].markColor = color; + + Refresh(); + return *this; +} + +ScatterDraw &ScatterDraw::MarkWidth(const double& markWidth) +{ + int id = series.GetCount() - 1; + + series[id].markWidth = markWidth; + + Refresh(); + return *this; +} + +ScatterDraw &ScatterDraw::Dash(const char *dash) +{ + int id = series.GetCount() - 1; + + series[id].dash = dash; + Refresh(); + return *this; +} + +ScatterDraw &ScatterDraw::Legend(const String legend) +{ + int id = series.GetCount() - 1; + + series[id].legend = legend; + return *this; +} + +void ScatterDraw::SetDataColor(const int& j, const Color& color) +{ + ASSERT(IsValid(j)); + series[j].color = color; + Refresh(); +} + +Color ScatterDraw::GetDataColor(const int& j) const +{ + ASSERT(IsValid(j)); + return series[j].color; +} + +void ScatterDraw::SetDataThickness(const int& j, const double& thickness) +{ + ASSERT(IsValid(j)); + series[j].thickness = thickness; + Refresh(); +} + +double ScatterDraw::GetDataThickness(const int& j) const +{ + ASSERT(IsValid(j)); + return series[j].thickness; +} + +void ScatterDraw::SetFillColor(const int& j, const Color& color) +{ + ASSERT(IsValid(j)); + series[j].fillColor = color; + Refresh(); +} + +Color ScatterDraw::GetFillColor(const int& j) const +{ + ASSERT(IsValid(j)); + return series[j].fillColor; +} + +ScatterDraw &ScatterDraw::SetMarkWidth(const int& j, const double& markWidth) +{ + ASSERT(IsValid(j)); + series[j].markWidth = markWidth; + Refresh(); + return *this; +} + +double ScatterDraw::GetMarkWidth(const int& j) const +{ + ASSERT(IsValid(j)); + return series[j].markWidth; +} + + +void ScatterDraw::SetMarkColor(const int& j, const Color& color) +{ + ASSERT(IsValid(j)); + series[j].markColor = color; + Refresh(); +} + +Color ScatterDraw::GetMarkColor(const int& j) const +{ + ASSERT(IsValid(j)); + return series[j].markColor; +} + +void ScatterDraw::NoMark(const int& j) +{ + ASSERT(IsValid(j)); + series[j].markWidth = 0; +} + +bool ScatterDraw::IsShowMark(const int& j) const throw (Exc) +{ + ASSERT(IsValid(j)); + return series[j].markWidth > 0; +} + + +void ScatterDraw::SetDataPrimaryY(const int& j, const bool& primary) +{ + ASSERT(IsValid(j)); + series[j].primaryY = primary; + Refresh(); +} + +ScatterDraw &ScatterDraw::SetDataPrimaryY(const bool& primary) +{ + SetDataPrimaryY(series.GetCount()-1, primary); + return *this; +} + +bool ScatterDraw::IsDataPrimaryY(const int& j) const throw (Exc) +{ + ASSERT(IsValid(j)); + return series[j].primaryY; +} + +void ScatterDraw::SetSequentialX(const int& j, const bool& sequential) +{ + ASSERT(IsValid(j)); + series[j].sequential = sequential; + Refresh(); +} + +ScatterDraw &ScatterDraw::SetSequentialX(const bool& sequential) +{ + SetSequentialX(series.GetCount()-1, sequential); + return *this; +} + +ScatterDraw &ScatterDraw::SetSequentialXAll(const bool& sequential) +{ + for (int i = 0; i < series.GetCount(); ++i) + SetSequentialX(i, sequential); + sequentialXAll = sequential; + return *this; +} + +void ScatterDraw::Show(const int& j, const bool& show) +{ + ASSERT(IsValid(j)); + series[j].opacity = show ? 1 : 0; + Refresh(); +} + +bool ScatterDraw::IsVisible(const int& j) +{ + ASSERT(IsValid(j)); + return series[j].opacity > 0; +} + +ScatterDraw &ScatterDraw::ShowAll(const bool& show) +{ + for (int i = 0; i < series.GetCount(); ++i) + series[i].opacity = 1; + return *this; +} + +ScatterDraw& ScatterDraw::Id(int id) +{ + return Id(series.GetCount()-1, id); +} + +ScatterDraw& ScatterDraw::Id(const int& j, int id) +{ + ASSERT(IsValid(j)); + series[j].id = id; + return *this; +} + +int ScatterDraw::GetId(const int& j) +{ + ASSERT(IsValid(j)); + return series[j].id; +} + +void ScatterDraw::RemoveSeries(const int& j) +{ + ASSERT(IsValid(j)); + series.Remove(j); + Refresh(); +} + +void ScatterDraw::RemoveAllSeries() +{ + series.Clear(); + Refresh(); +} + +Drawing ScatterDraw::GetDrawing() +{ + DrawingDraw ddw(6*GetSize()); + + SetDrawing (ddw, 6); + return ddw; +} + +Image ScatterDraw::GetImage(const int &scale) +{ +#ifndef flagGUI + ASSERT(mode != MD_DRAW); +#endif + + ImageBuffer ib(scale*GetSize()); + BufferPainter bp(ib, mode); + + SetDrawing(bp, scale); + + return ib; +} + +double ScatterDraw::GetXByPoint(const int x) +{ + return (x - hPlotLeft)*GetXRange()/(GetSize().cx - (hPlotLeft + hPlotRight) - 1) + GetXMin(); +} + +double ScatterDraw::GetYByPoint(const int y) +{ + return (GetSize().cy - vPlotTop - y - 1)*GetYRange()/(GetSize().cy - (vPlotTop + vPlotBottom) - GetTitleFont().GetHeight() - 1) + GetYMin(); +} + +double ScatterDraw::GetY2ByPoint(const int y) +{ + return (GetSize().cy - vPlotTop - y - 1)*GetY2Range()/(GetSize().cy - (vPlotTop + vPlotBottom) - GetTitleFont().GetHeight() - 1) + GetYMin2(); +} + +double ScatterDraw::GetXPointByValue(const double x) +{ + return (x - GetXMin())/GetXRange()*(GetSize().cx - (hPlotLeft + hPlotRight) - 1) + hPlotLeft; +} + +double ScatterDraw::GetYPointByValue(const double y) +{ + return (GetSize().cy - vPlotTop - 1) - (y - GetYMin())/GetYRange()*(GetSize().cy - (vPlotTop + vPlotBottom) - GetTitleFont().GetHeight() - 1); +} + +void ScatterDraw::Zoom(double scale, bool mouseX, bool mouseY) +{ + mouseX = mouseX && ((minXZoom > 0 && xRange*scale > minXZoom) || (minXZoom < 0)); + mouseX = mouseX && ((maxXZoom > 0 && xRange*scale < maxXZoom) || (maxXZoom < 0)); + mouseY = mouseY && ((minYZoom > 0 && yRange*scale > minYZoom) || (minYZoom < 0)); + mouseY = mouseY && ((maxYZoom > 0 && yRange*scale < maxYZoom) || (maxYZoom < 0)); + if (mouseX) { + if (zoomStyleX == TO_CENTER) { + double oldXMin = xMin; + xMin += xRange*(1-scale)/2.; + xMinUnit = oldXMin + xMinUnit - xMin; + AdjustMinUnitX(); + } + xRange *= scale; + if (!IsNull(maxMajorUnitsX)) { + if (xRange < xMajorUnit) + xMajorUnit /= 10; + else if (xRange/xMajorUnit > maxMajorUnitsX) + xMajorUnit *= 10; + } + } + if (mouseY) { + if (zoomStyleY == TO_CENTER) { + double oldYMin = yMin; + yMin += yRange*(1-scale)/2.; + yMinUnit = oldYMin + yMinUnit - yMin; + AdjustMinUnitY(); + double oldYMin2 = yMin2; + yMin2 += yRange2*(1-scale)/2.; + yMinUnit2 = oldYMin2 + yMinUnit2 - yMin2; + AdjustMinUnitY2(); + } + yRange *= scale; + yRange2 *= scale; + if (!IsNull(maxMajorUnitsY)) { + if (yRange < yMajorUnit) { + yMajorUnit /= 10; + yMajorUnit2 /= 10; + } else if (yRange/yMajorUnit > maxMajorUnitsY) { + yMajorUnit *= 10; + yMajorUnit2 *= 10; + } + } + } + if (mouseX || mouseY) { + WhenSetRange(); + Refresh(); + WhenZoomScroll(); + } +} + +void ScatterDraw::Scroll(double factorX, double factorY) +{ + if (factorX != 0) { + double deltaX = factorX*xRange; + xMin -= deltaX; + xMinUnit += deltaX; + AdjustMinUnitX(); + } + if (factorY != 0) { + double deltaY = -factorY*yRange; + yMin -= deltaY; + yMinUnit += deltaY; + AdjustMinUnitY(); + if (drawY2Reticle) { + double deltaY2 = -factorY*yRange2; + yMin2 -= deltaY2; + yMinUnit2 += deltaY2; + AdjustMinUnitY2(); + } + } + if (factorX != 0 || factorY != 0) { + Refresh(); + WhenZoomScroll(); + } +} + +Pointf PointAtLen(const Pointf &p0, const Pointf &p1, double len) +{ + Pointf ret; + if (p1.y == p0.y) { + ret.x = p0.x + ((p0.x < p1.x) ? len : -len); + ret.y = p0.y; + } else if (p1.x == p0.x) { + ret.x = p0.x; + ret.y = p0.y + ((p0.y < p1.y) ? len : -len); + } else { + double k = sqr((p1.x-p0.x)/(p1.y-p0.y)); + double deltax = len/sqrt(1/k + 1); + double deltay = len/sqrt(k + 1); + ret.x = p0.x + ((p0.x < p1.x) ? deltax : -deltax); + ret.y = p0.y + ((p0.y < p1.y) ? deltay : -deltay); + } + return ret; +} + +inline bool Even(int val) {return !(val%2);} + +Vector GetLineDash(String dash) +{ + Vector d; + CParser p(dash); + try { + while(!p.IsEof()) + if(!p.Char(':')) + d.Add(p.ReadDouble()); + } + catch(CParser::Error) {} + + if(d.GetCount() & 1) { + Vector dash1; + dash1.Append(d); + dash1.Append(d); + return dash1; + } + return d; +} + +Vector &GetDashedArray(String dash) +{ + static VectorMap > pats; + + int pos = pats.Find(dash); + if (pos < 0) { + pats.Add(dash, GetLineDash(dash)); + pos = pats.GetCount()-1; + } + return pats.GetValues()[pos]; +} + +void ScatterDraw::ParseTextMultiline(const String &text, Font fnt, Upp::Array &texts, Upp::Array &sizes) { + Size ret(0, 0); + int npos = 0; + for (int pos = 0; npos != -1; pos = npos+1) { + npos = text.Find('\n', pos); + String &t = texts.Add(); + if (npos != -1) + t = text.Mid(pos, npos-pos); + else + t = text.Mid(pos); + Size &s = sizes.Add(); + s.cx = GetTextSize(t, fnt).cx; + s.cy = GetTextSize(t, fnt).cy; + } +} + +Size GetTextSizeMultiline(Array &sizes) { + Size ret(0, 0); + for (int i = 0; i < sizes.GetCount(); ++i) { + if (sizes[i].cx > ret.cx) + ret.cx = sizes[i].cx; + ret.cy += sizes[i].cy; + } + return ret; +} + +ScatterDraw::ScatterDraw() +{ + mode = MD_ANTIALIASED; + size = Size(0, 0); + titleColor = SColorText(); + graphColor = White(); + titleFont = Roman(20); + labelsFont = StdFont(); + labelsColor = SColorText(); + plotAreaColor = SColorLtFace(); + axisColor = SColorText(); + axisWidth = 6; + hPlotLeft = hPlotRight = vPlotTop = vPlotBottom = 30; + xRange = yRange = yRange2 = 100.0; + xMin = yMin = yMin2 = xMinUnit = yMinUnit = yMinUnit2 = 0.0; + logX = logY = logY2 = false; + gridColor = SColorDkShadow(); + gridWidth = 1; + drawXReticle = true; drawYReticle = true; + drawY2Reticle = false; + drawVGrid = drawHGrid = showLegend = true; + legendWeight = 80; + minXZoom = maxXZoom = minYZoom = maxYZoom = -1; + fastViewX = false; + sequentialXAll = false; + zoomStyleX = zoomStyleY = TO_CENTER; + maxMajorUnitsX = maxMajorUnitsY = Null; + SetMajorUnitsNum(5, 10); + Color(graphColor); +} + +void DrawLine(Draw &w, double x0, double y0, double x1, double y1, double width, const Color &color) +{ + w.DrawLine(fround(x0), fround(y0), fround(x1), fround(y1), fround(width), color); +} + +void DrawLine(Painter &w, double x0, double y0, double x1, double y1, double width, const Color &color) +{ + w.Move(x0, y0).Line(x0, y0).Line(x1, y1).Stroke(width, color); +} + +void DrawVArrow(Draw &w, double x0, double y0, double x1, double y1, double width, double aWidth, double aHeight, const Color &color) +{ + DrawLine(w, x0, y0, x1, y1, width, color); + if (fabs(y0 - y1) > 2*aHeight) { + if (x0 > x1) + Swap(x0, x1); + if (y0 > y1) + Swap(y0, y1); + Vector arrowU, arrowL; + arrowU << Point(fround(x0), fround(y0)) << Point(fround(x0-aWidth), fround(y0+aHeight)) << Point(fround(x0+aWidth), fround(y0+aHeight)); + w.DrawPolygon(arrowU, SColorHighlight()); + arrowL << Point(fround(x0), fround(y1)) << Point(fround(x0-aWidth), fround(y1-aHeight)) << Point(fround(x0+aWidth), fround(y1-aHeight)); + w.DrawPolygon(arrowL, SColorHighlight()); + } +} + +void DrawVArrow(Painter &w, double x0, double y0, double x1, double y1, double width, double aWidth, double aHeight, const Color &color) +{ + DrawLine(w, x0, y0, x1, y1, width, color); + if (fabs(y0 - y1) > 2*aHeight) { + if (x0 > x1) + Swap(x0, x1); + if (y0 > y1) + Swap(y0, y1); + w.Move(x0, y0).Line(x0-aWidth, y0+aHeight).Line(x0+aWidth, y0+aHeight).Fill(SColorHighlight()); + w.Move(x0, y1).Line(x0-aWidth, y1-aHeight).Line(x0+aWidth, y1-aHeight).Fill(SColorHighlight()); + } +} + +void DrawHArrow(Draw &w, double x0, double y0, double x1, double y1, double width, double aWidth, double aHeight, const Color &color) +{ + DrawLine(w, x0, y0, x1, y1, width, color); + if (fabs(x0 - x1) > 2*aHeight) { + if (x0 > x1) + Swap(x0, x1); + if (y0 > y1) + Swap(y0, y1); + Vector arrowL, arrowR; + arrowL << Point(fround(x0), fround(y0)) << Point(fround(x0+aHeight), fround(y0+aWidth)) << Point(fround(x0+aHeight), fround(y0-aWidth)); + w.DrawPolygon(arrowL, SColorHighlight()); + arrowR << Point(fround(x1), fround(y0)) << Point(fround(x1-aHeight), fround(y0+aWidth)) << Point(fround(x1-aHeight), fround(y0-aWidth)); + w.DrawPolygon(arrowR, SColorHighlight()); + } +} + +void DrawHArrow(Painter &w, double x0, double y0, double x1, double y1, double width, double aWidth, double aHeight, const Color &color) +{ + DrawLine(w, x0, y0, x1, y1, width, color); + if (fabs(x0 - x1) > 2*aHeight) { + if (x0 > x1) + Swap(x0, x1); + if (y0 > y1) + Swap(y0, y1); + w.Move(x0, y0).Line(x0+aHeight, y0+aWidth).Line(x0+aHeight, y0-aWidth).Fill(SColorHighlight()); + w.Move(x1, y0).Line(x1-aHeight, y0+aWidth).Line(x1-aHeight, y0-aWidth).Fill(SColorHighlight()); + } +} + +void DrawText(Draw &w, double x, double y, int angle, const String &text, Font font, Color color) +{ + w.DrawText(fround(x), fround(y), angle, text, font, color); +} + +void DrawText(Painter &w, double x, double y, int angle, const String &text, Font font, Color color) +{ + w.Begin(); + w.Translate(x-0.5, y-0.5).Rotate(-angle*M_PI/1800.); + w.Text(0, 0, text, font).Fill(color); + w.End(); +} + +void Clip(Draw &w, double x, double y, double cx, double cy) +{ + w.Clip(fround(x), fround(y), fround(cx), fround(cy)); +} + +void Clip(Painter &w, double x, double y, double cx, double cy) +{ + w.Rectangle(x, y, cx, cy).Clip(); +} + +void ClipEnd(Draw &w) +{ + w.End(); +} + +void ClipEnd(Painter &w) +{ + ; +} + +void DrawLineOpa(Draw& w, const int x0, const int y0, const int x1, const int y1, const int &scale, + const double opacity, double thick, const Color &_color, String dash, + const Color &background) +{ + Vector p; + p << Point(x0, y0) << Point(x1, y1); + DrawPolylineOpa(w, p, scale, opacity, thick, _color, dash, background); +} + +void DashScaled(Painter& w, const String dash, double scale) +{ + if (!dash.IsEmpty()) { + Vector d; + double start = 0; + CParser p(dash); + try { + while(!p.IsEof()) + if(p.Char(':')) + start = p.ReadDouble(); + else + d.Add(scale*p.ReadDouble()); + } + catch(CParser::Error) {} + w.Dash(d, scale*start); + } +} + +void DrawLineOpa(Painter& w, const int x0, const int y0, const int x1, const int y1, const int &scale, + const double opacity, double thick, const Color &color, String dash, + const Color &background) +{ + w.Move(Pointf(x0, y0)); + w.Line(Pointf(x1, y1)); + DashScaled(w, dash, scale); + w.Opacity(opacity); // Before Stroke() + w.Stroke(thick*scale, color); +} + +void FillRectangleOpa(Draw &w, double x0, double y0, double x1, double y1, const int &scale, + const double opacity, const Color &background, const Color &color) +{ + if (IsNull(color)) + return; + Color opacolor = GetOpaqueColor(color, background, opacity); + if (x0 > x1) + Swap(x0, x1); + if (y0 > y1) + Swap(y0, y1); + w.DrawRect(int(x0), int(y0), abs(int(x1 - x0)), abs(int(y1 - y0)), opacolor); +} + +void FillRectangleOpa(Painter &w, double x0, double y0, double x1, double y1, const int &scale, + const double opacity, const Color &background, const Color &color) +{ + if (IsNull(color)) + return; + w.Rectangle(x0, y0, x1 - x0, y1 - y0).Opacity(opacity).Fill(color); +} + +void DrawPolylineOpa(Draw& w, const Vector &p, const int &scale, const double opacity, + double thick, const Color &_color, String dash, const Color &background) +{ + ASSERT(!p.IsEmpty()); + Color color = GetOpaqueColor(_color, background, opacity) ; + if (dash == LINE_SOLID) + w.DrawPolyline(p, fround(thick), color); + else { + Vector &pat = GetDashedArray(dash); + int iPat = 0; + + double len = pat[0]*scale; // Pixels per bar + Pointf begin, end; + begin = p[0]; + for (int i = 1; i < p.GetCount();) { + double d = Distance(begin, p[i]); + if (d >= len) + end = PointAtLen(begin, p[i], len); + else { + end = p[i]; + len -= d; + ++i; + } + if (Even(iPat)) + w.DrawLine(begin, end, fround(thick), color); + if (d >= len) { + iPat++; + if (iPat == pat.GetCount()) + iPat = 0; + len = pat[iPat]*scale; + } + begin = end; + } + } +} + +void DrawPolylineOpa(Painter& w, const Vector &p, const int &scale, const double opacity, + double thick, const Color &color, String dash, const Color &background) +{ + ASSERT(!p.IsEmpty()); + w.Move(p[0]); + for (int i = 1; i < p.GetCount(); ++i) + w.Line(p[i]); + DashScaled(w, dash, scale); + w.Opacity(opacity); // Before Stroke() + w.Stroke(thick*scale, color); +} + +void FillPolylineOpa(Draw& w, const Vector &p, const int &scale, const double opacity, + const Color &background, const Color &fillColor) +{ + ASSERT(!p.IsEmpty()); + Color opacolor = GetOpaqueColor(fillColor, background, opacity) ; + + w.DrawPolygon(p, opacolor); +} + +void FillPolylineOpa(Painter& w, const Vector &p, const int &scale, const double opacity, + const Color &background, const Color &fillColor) +{ + ASSERT(!p.IsEmpty()); + w.Move(p[0]); + for (int i = 1; i < p.GetCount(); ++i) + w.Line(p[i]); + w.Opacity(opacity); + w.Fill(fillColor); // Before Stroke() +} + +INITBLOCK{ + SeriesPlot::Register("Line"); + SeriesPlot::Register("Staggered"); + SeriesPlot::Register("Bar"); + + MarkPlot::Register("Circle"); + MarkPlot::Register("Square"); + MarkPlot::Register("Triangle"); + MarkPlot::Register("Cross"); + MarkPlot::Register("X"); + MarkPlot::Register("Rhomb"); +} + +END_UPP_NAMESPACE diff --git a/uppsrc/ScatterDraw/ScatterDraw.h b/uppsrc/ScatterDraw/ScatterDraw.h index 7e87857f3..127f41159 100644 --- a/uppsrc/ScatterDraw/ScatterDraw.h +++ b/uppsrc/ScatterDraw/ScatterDraw.h @@ -1,649 +1,648 @@ -#ifndef _ScatterDraw_ScatterDraw_h -#define _ScatterDraw_ScatterDraw_h - -#include -#include - -#include - -using namespace Upp; - -#include -#include "DrawingFunctions.h" -#include "SeriesPlot.h" -#include "MarkPlot.h" - - -Color GetOpaqueColor(const Color &color, const Color &background, const double opacity); - -class ScatterDraw { -public: - typedef ScatterDraw CLASSNAME; - ScatterDraw(); - - enum Formats { - EXP, - MON, - DY, - CUSTOM - }; - enum { - MD_DRAW = -1, - MD_ANTIALIASED = MODE_ANTIALIASED, - MD_NOAA = MODE_NOAA, - MD_SUBPIXEL = MODE_SUBPIXEL - }; - - #define LINE_DOTTED "4 10" - #define LINE_DOTTED_SEP "4 20" - #define LINE_DASHED "12 12" - #define LINE_DASH_DOT "20 10 5 10" - #define LINE_SOLID "" - -protected: - class ScatterBasicSeries { - public: - ScatterBasicSeries(); - void Init(int id); - - bool primaryY; - bool sequential; - - One seriesPlot; - double thickness; - Color color; - String dash; - - One markPlot; - double markWidth; - Color markColor; - - Color fillColor; - - String legend; - - double opacity; - - int id; - - bool trendLine; - //double trend - }; - - class ScatterSeries : public Moveable, public ScatterBasicSeries { - public: - ScatterSeries() {pD = 0;} - void SetDataSource(DataSource *pointsData, bool ownsData = true) {pD = pointsData; owns = ownsData;} - inline DataSource *PointsData() {return pD;} - ~ScatterSeries() {if(pD && owns) delete pD;} - private: - DataSource *pD; - bool owns; - }; - - static Color GetNewColor(int id); - static String GetNewDash(int id); - static MarkPlot *GetNewMarkPlot(int id); - -public: - Callback3 cbModifFormatX, cbModifFormatDeltaX; - Callback3 cbModifFormatY, cbModifFormatDeltaY; - Callback3 cbModifFormatY2, cbModifFormatDeltaY2; - - Callback WhenZoomScroll; - Callback WhenSetRange; - Callback WhenSetXYMin; - - ScatterDraw& SetSize(Size sz) {size = sz; return *this;}; - virtual Size GetSize() const {return size;}; - - ScatterDraw& SetColor(const Color& _color); - ScatterDraw& SetTitle(const String& _title); - ScatterDraw& SetTitleFont(const Font& fontTitle); - ScatterDraw& SetTitleColor(const Color& colorTitle); - - void SetLabels(const String& _xLabel, const String& _yLabel, const String& _yLabel2 = ""); - ScatterDraw& SetLabelX(const String& _xLabel); - ScatterDraw& SetLabelY(const String& _yLabel); - ScatterDraw& SetLabelY2(const String& _yLabel); - ScatterDraw& SetLabelsFont(const Font& fontLabels); - Font GetLabelsFont() {return labelsFont;}; - ScatterDraw& SetLabelsColor(const Color& colorLabels); - - ScatterDraw& SetPlotAreaMargin(const int hLeft, const int hRight, const int vTop, const int vBottom); - ScatterDraw& SetPlotAreaLeftMargin(const int margin); - ScatterDraw& SetPlotAreaRightMargin(const int margin); - ScatterDraw& SetPlotAreaTopMargin(const int margin); - ScatterDraw& SetPlotAreaBottomMargin(const int margin); - - ScatterDraw& SetPlotAreaColor(const Color& p_a_color); - - ScatterDraw& SetAxisColor(const Color& axis_color); - ScatterDraw& SetAxisWidth(const int& axis_width); - - ScatterDraw& SetGridColor(const Color& grid_color); - ScatterDraw& SetGridWidth(const int& grid_width); - ScatterDraw& ShowVGrid(const bool& show); - ScatterDraw& ShowHGrid(const bool& show); - - ScatterDraw& ShowLegend(const bool& show=true); - ScatterDraw& SetLegendWeight(const int& weight); - - ScatterDraw& SetMode(int _mode = MD_ANTIALIASED) {mode = _mode; Refresh(); return *this;}; - int GetMode() {return mode;}; - - void FitToData(bool Y = false); - void Zoom(double scale, bool hor = true, bool ver = true); - void Scroll(double factorX, double factorY); - - enum ZoomStyle {TO_CENTER, FROM_BASE}; - ScatterDraw &SetZoomStyleX(ZoomStyle style = TO_CENTER) {zoomStyleX = style; return *this;} - ScatterDraw &SetZoomStyleY(ZoomStyle style = TO_CENTER) {zoomStyleY = style; return *this;} - - ScatterDraw& SetRange(double rx, double ry, double ry2 = 100); - double GetXRange()const {return xRange;} - double GetYRange()const {return yRange;} - double GetY2Range()const {return yRange2;} - ScatterDraw &SetMajorUnits(double ux, double uy); - ScatterDraw &SetMajorUnitsNum(int nx, int ny); - ScatterDraw &SetMaxMajorUnitsX(int maxX, int maxY) {maxMajorUnitsX = maxX; maxMajorUnitsY = maxY; return *this;} - double GetMajorUnitsX() {return xMajorUnit;} - double GetMajorUnitsY() {return yMajorUnit;} - ScatterDraw& SetMinUnits(double ux, double uy); - double GetXMinUnit () const {return xMinUnit;} - double GetYMinUnit () const {return yMinUnit;} - - ScatterDraw& SetXYMin(double xmin,double ymin,double ymin2 = 0); - double GetXMin () const {return xMin;} - double GetYMin () const {return yMin;} - double GetYMin2 () const {return yMin2;} - - ScatterDraw &Graduation_FormatX(Formats fi); - ScatterDraw &Graduation_FormatY(Formats fi); - ScatterDraw &Graduation_FormatY2(Formats fi); - - ScatterDraw &AddSeries(double *yData, int numData, double x0 = 0, double deltaX = 1); - ScatterDraw &AddSeries(double *xData, double *yData, int numData); - ScatterDraw &AddSeries(Vector &xData, Vector &yData); - ScatterDraw &AddSeries(Upp::Array &xData, Upp::Array &yData); - ScatterDraw &AddSeries(Vector &points); - ScatterDraw &AddSeries(Upp::Array &points); - ScatterDraw &AddSeries(double (*function)(double)); - ScatterDraw &AddSeries(Pointf (*function)(double), int np, double from = 0, double to = 1); - ScatterDraw &AddSeries(PlotFunc &function); - ScatterDraw &AddSeries(PlotParamFunc function, int np, double from = 0, double to = 1); - ScatterDraw &_AddSeries(DataSource *data); - ScatterDraw &AddSeries(DataSource &data); - - template - ScatterDraw &AddSeries() {return _AddSeries(new C());} - template - ScatterDraw &AddSeries(T1 &arg1) - {return _AddSeries(new C(arg1));} - template - ScatterDraw &AddSeries(T1 &arg1, T2 &arg2) - {return _AddSeries(new C(arg1, arg2));} - template - ScatterDraw &AddSeries(T1 &arg1, T2 &arg2, T3 &arg3) - {return _AddSeries(new C(arg1, arg2, arg3));} - template - ScatterDraw &AddSeries(T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4) - {return _AddSeries(new C(arg1, arg2, arg3, arg4));} - template - ScatterDraw &AddSeries(T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4, T5 &arg5) - {return _AddSeries(new C(arg1, arg2, arg3, arg4, arg5));} - template - ScatterDraw &AddSeries(T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4, T5 &arg5, T6 &arg6) - {return _AddSeries(new C(arg1, arg2, arg3, arg4, arg5, arg6));} - - template - ScatterDraw &AddSeries(Vector &yData) {return _AddSeries(new VectorY(yData));} - template - ScatterDraw &AddSeries(Upp::Array &yData) {return _AddSeries(new ArrayY(yData));} - template - ScatterDraw &AddSeries(VectorMap &data) {return _AddSeries(new VectorMapXY(data));} - template - ScatterDraw &AddSeries(ArrayMap &data) {return _AddSeries(new ArrayMapXY(data));} - - void InsertSeries(int id, double *yData, int numData, double x0 = 0, double deltaX = 1); - void InsertSeries(int id, double *xData, double *yData, int numData); - void InsertSeries(int id, Vector &xData, Vector &yData); - void InsertSeries(int id, Upp::Array &xData, Upp::Array &yData); - void InsertSeries(int id, Vector &points); - void InsertSeries(int id, Upp::Array &points); - void InsertSeries(int id, double (*function)(double)); - void InsertSeries(int id, Pointf (*function)(double), int np, double from = 0, double to = 1); - void InsertSeries(int id, PlotFunc &function); - void InsertSeries(int id, PlotParamFunc function, int np, double from = 0, double to = 1); - void _InsertSeries(int id, DataSource *data); - - template - void InsertSeries(int id) {_InsertSeries(id, new C());} - template - void InsertSeries(int id, T1 &arg1) - {_InsertSeries(id, new C(arg1));} - template - void InsertSeries(int id, T1 &arg1, T2 &arg2) - {_InsertSeries(id, new C(arg1, arg2));} - template - void InsertSeries(int id, T1 &arg1, T2 &arg2, T3 &arg3) - {_InsertSeries(id, new C(arg1, arg2, arg3));} - template - void InsertSeries(int id, T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4) - {_InsertSeries(id, new C(arg1, arg2, arg3, arg4));} - template - void InsertSeries(int id, T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4, T5 &arg5) - {_InsertSeries(id, new C(arg1, arg2, arg3, arg4, arg5));} - template - void InsertSeries(int id, T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4, T5 &arg5, T6 &arg6) - {_InsertSeries(id, new C(arg1, arg2, arg3, arg4, arg5, arg6));} - - template - void InsertSeries(int id, Vector &yData) {_InsertSeries(id, new VectorY(yData));} - template - void InsertSeries(int id, Upp::Array &yData) {_InsertSeries(id, new ArrayY(yData));} - template - void InsertSeries(int id, VectorMap &data){_InsertSeries(id, new VectorMapXY(data));} - template - void InsertSeries(int id, ArrayMap &data) {_InsertSeries(id, new ArrayMapXY(data));} - - ScatterDraw &PlotStyle() {return PlotStyle(0);}; - template - ScatterDraw &PlotStyle() {return PlotStyle(new C());}; - template - ScatterDraw &PlotStyle(T1 &arg1) {return PlotStyle(new C(arg1));}; - template - ScatterDraw &PlotStyle(T1 &arg1, T2 &arg2) {return PlotStyle(new C(arg1, arg2));}; - template - ScatterDraw &PlotStyle(T1 &arg1, T2 &arg2, T3 &arg3) {return PlotStyle(new C(arg1, arg2, arg3));}; - ScatterDraw &PlotStyle(SeriesPlot *data); - - ScatterDraw &NoPlot() {return PlotStyle();}; - - ScatterDraw &MarkStyle() {return MarkStyle(0);}; - template - ScatterDraw &MarkStyle() {return MarkStyle(new C());}; - template - ScatterDraw &MarkStyle(T1 &arg1) {return MarkStyle(new C(arg1));}; - template - ScatterDraw &MarkStyle(T1 &arg1, T2 &arg2) {return MarkStyle(new C(arg1, arg2));}; - template - ScatterDraw &MarkStyle(T1 &arg1, T2 &arg2, T3 &arg3) {return MarkStyle(new C(arg1, arg2, arg3));}; - ScatterDraw &MarkStyle(MarkPlot *data); - - ScatterDraw &NoMark() {return MarkStyle();}; - - ScatterDraw &Stroke(double thickness = 3, Color color = Null); - ScatterDraw &Dash(const char *dash); - ScatterDraw &Fill(Color color = Null); - ScatterDraw &MarkColor(Color color = Null); - ScatterDraw &MarkWidth(const double& markWidth = 8); - ScatterDraw &Hide() {series[series.GetCount() - 1].opacity = 0; return *this;} - - ScatterDraw &Opacity(double opacity = 1) {series[series.GetCount() - 1].opacity = opacity; return *this;} - ScatterDraw &Legend(const String legend); - - inline bool IsValid(const int& j) const {return (j >= 0 && j < series.GetCount());} - - ScatterDraw& SetDrawXReticle(bool set = true); - ScatterDraw& SetDrawYReticle(bool set = true); - ScatterDraw& SetDrawY2Reticle(bool set = true); - - void SetDataColor(const int& j,const Color& pcolor); - Color GetDataColor (const int& j) const; - void SetDataThickness(const int& j, const double& thick); - double GetDataThickness(const int& j) const; - void SetFillColor(const int& j, const Color& color); - Color GetFillColor(const int& j) const; - - ScatterDraw &SetMarkWidth(const int& j, const double& width); - double GetMarkWidth(const int& j) const; - void SetMarkColor(const int& j, const Color& pcolor); - ::Color GetMarkColor (const int& j) const; - void NoMark(const int& j); - bool IsShowMark(const int& j) const throw (Exc); - - void SetDataPrimaryY(const int& j, const bool& primary=true); - ScatterDraw &SetDataPrimaryY(const bool& primary); - bool IsDataPrimaryY(const int& j) const throw (Exc); - - void SetSequentialX(const int& j, const bool& sequential = true); - ScatterDraw &SetSequentialX(const bool& sequential = true); - ScatterDraw &SetSequentialXAll(const bool& sequential = true); - - void Show(const int& j, const bool& show = true); - bool IsVisible(const int& j); - ScatterDraw &ShowAll(const bool& show = true); - - void RemoveSeries(const int& j); - void RemoveAllSeries(); - - ScatterDraw& Id(int id); - ScatterDraw& Id(const int& j, int id); - int GetId(const int& j); - - Drawing GetDrawing(); - Image GetImage(const int& scale = 1); - - #ifdef PLATFORM_WIN32 - void SaveAsMetafile(const char* file) const; - #endif - - ScatterDraw& LogX(const bool& logx=true) {logX=logx; return *this;} - ScatterDraw& LogY(const bool& logy=true) {logY=logy; return *this;} - ScatterDraw& LogY2(const bool& logy=true) {logY2=logy; return *this;} - - ScatterDraw& SetMinZoom(double x, double y = -1) {minXZoom = x; minYZoom = y; return *this;}; - ScatterDraw& SetMaxZoom(double x, double y = -1) {maxXZoom = x; maxYZoom = y; return *this;}; - - ScatterDraw& SetFastViewX(bool set = true) {fastViewX = set; return *this;}; - - Font& GetTitleFont() {return titleFont;}; - - double GetXByPoint(const int x); - double GetYByPoint(const int y); - double GetY2ByPoint(const int y); - double GetXPointByValue(const double x); - double GetYPointByValue(const double y); - - int GetCount() {return series.GetCount();} - bool IsEmpty() {return series.IsEmpty();} - - virtual void Refresh() {}; - -protected: - int mode; - class ::Color graphColor; - String title; - Font titleFont; - Color titleColor; - - String xLabel, yLabel, yLabel2; - Font labelsFont; - Color labelsColor; - - int hPlotLeft, hPlotRight, vPlotTop, vPlotBottom; - class ::Color plotAreaColor; - - bool fastViewX, sequentialXAll; - - Color axisColor; - int axisWidth; - - double xRange, yRange, yRange2; - double xMin, yMin, yMin2; - double xMajorUnit, yMajorUnit, yMajorUnit2; - double xMinUnit, yMinUnit, yMinUnit2; - double minXZoom, maxXZoom, minYZoom, maxYZoom; - bool drawXReticle, drawYReticle, drawY2Reticle; - - int maxMajorUnitsX, maxMajorUnitsY; - - Color gridColor; - int gridWidth; - bool drawVGrid, drawHGrid; - - int butDownX, butDownY; - bool isScrolling, isLabelPopUp; - ZoomStyle zoomStyleX, zoomStyleY; - - Vector series; - - bool showLegend; - int legendWeight; - - void DrawLegend(Draw& w,const int& scale) const; - - void Scrolling(bool down, Point &pt, bool isOut = false); - - void ExpFormat(String& s, int i, double d) {s = FormatDoubleExp(d,1);} - void MonFormat(String& s, int i, double d) {s = Format("%Mon",int(d));} - void DyFormat(String& s, int i, double d) {s = Format("%Dy",int(d));} - - static String VariableFormat(double range, double d) - { - if (fabs(d) <= 1e-15) - d = 0; - if (0.001<=range && range<0.01) return FormatDouble(d,5); - else if (0.01<=range && range<0.1) return FormatDouble(d,4); - else if (0.1<=range && range<1) return FormatDouble(d,3); - else if (1<=range && range<10) return FormatDouble(d,2); - else if (10<=range && range<100) return FormatDouble(d,1); - else if (100<=range && range<100000) return FormatDouble(d,0); - else return FormatDoubleExp(d,2); - - } - String VariableFormatX(const double& d) const {return VariableFormat(xRange, d);} - String VariableFormatY(const double& d) const {return VariableFormat(yRange, d);} - String VariableFormatY2(const double& d) const {return VariableFormat(yRange2, d);} - - template - void SetDrawing(T& w, const int& scale); - template - void Plot(T& w, const int& scale,const int& l,const int& h); - - void AdjustMinUnitX(); - void AdjustMinUnitY(); - void AdjustMinUnitY2(); - - bool logX, logY, logY2; - -private: - Size size; - static void ParseTextMultiline(const String &text, Font fnt, - Upp::Array &texts, Upp::Array &sizes); -}; - -void GoBreakpoint(); - -template -void ScatterDraw::SetDrawing(T& w, const int& scale) -{ - if (GetSize().cx == 0 || GetSize().cy == 0) - return; - - w.DrawRect(scale*GetSize(), graphColor); - - if (typeid(T) == typeid(BufferPainter)) { - Painter &p = (Painter &)w; - p.Translate(0, 0.5); - } - - Size sz(0, 0); - - int titleHeight = !title.IsEmpty() ? scale*titleFont.GetHeight() : 0; - - if(titleHeight > 0) { - Font fontTitle6; - fontTitle6 = titleFont; - fontTitle6.Height(titleHeight); - fontTitle6.Width(scale*titleFont.GetWidth()); - sz = GetTextSize(title, fontTitle6); - DrawText(w, (scale*GetSize().cx - sz.cx)/2., scale*2., 0, title, fontTitle6, titleColor); - } - - w.Offset(Point(scale*hPlotLeft, scale*vPlotTop + titleHeight)); - if(showLegend) - DrawLegend(w, scale); - - int plotW = scale*(GetSize().cx - (hPlotLeft + hPlotRight)); - int plotH = scale*(GetSize().cy - (vPlotTop + vPlotBottom)) - titleHeight; - - Font fontLabel; - fontLabel = labelsFont; - fontLabel.Height(scale*labelsFont.GetHeight()); - - Size lx = GetTextSize(xLabel, fontLabel); - Size ly = GetTextSize(yLabel, fontLabel); - Size ly2 = GetTextSize(yLabel2, fontLabel); - DrawText(w, (plotW - lx.cx)/2., scale*GetSize().cy - lx.cy - 70*scale, 0, xLabel, fontLabel, labelsColor); - DrawText(w, scale*2. - scale*hPlotLeft, (plotH + ly.cx)/2., 900, yLabel, fontLabel, labelsColor); - DrawText(w, scale*GetSize().cx - ly2.cy - 42*scale, (plotH + ly2.cx)/2., 900, yLabel2, fontLabel, labelsColor); - - if (typeid(T) == typeid(BufferPainter)) { - Painter &p = (Painter &)w; - p.Translate(0.5, 0); - } -GoBreakpoint(); - if (drawXReticle) - for(int i = 0; xMinUnit + i*xMajorUnit <= xRange; i++){ - w.DrawLine(fround(plotW*xMinUnit/xRange + i*plotW/(xRange/xMajorUnit)), plotH, - fround(plotW*xMinUnit/xRange + i*plotW/(xRange/xMajorUnit)), plotH + scale*4, - fround(gridWidth*scale), axisColor); - Font standard6; - standard6.Height(scale*StdFont().GetHeight()); - double gridX = xMinUnit + i*xMajorUnit + xMin; - String gridLabelX; - if (cbModifFormatX) - cbModifFormatX(gridLabelX, i, gridX); - else - gridLabelX = VariableFormatX(gridX); - - Array texts; - Array sizes; - ParseTextMultiline(gridLabelX, StdFont(), texts, sizes); - for (int ii = 0; ii < texts.GetCount(); ++ii) { - int cy = ii == 0 ? 0 : sizes[ii - 1].cy; - DrawText(w, plotW*xMinUnit/xRange + i*plotW/(xRange/xMajorUnit) - scale*sizes[ii].cx/2., - plotH + scale*(4 + ii*cy), 0, texts[ii], standard6, axisColor); - } - } -GoBreakpoint(); - if (drawYReticle) - for(int i = 0; yMinUnit + i*yMajorUnit <= yRange; i++){ - w.DrawLine(-(scale*4), fround(-plotH*yMinUnit/yRange + plotH - i*plotH/(yRange/yMajorUnit)), - 0, fround(-plotH*yMinUnit/yRange + plotH - i*plotH/(yRange/yMajorUnit)), - fround(gridWidth*scale), axisColor); - double gridY = yMinUnit + i*yMajorUnit + yMin; - String gridLabelY; - if (cbModifFormatY) - cbModifFormatY(gridLabelY, i, gridY); - else - gridLabelY = VariableFormatY(gridY); - int dx=scale*GetTextSize(gridLabelY,StdFont()).cx; - Font Standard6; - Standard6.Height(scale*StdFont().GetHeight()); - DrawText(w, -dx - scale*6, fround(-plotH*yMinUnit/yRange + plotH - i*plotH/(yRange/yMajorUnit)) - scale*8, - 0, gridLabelY, Standard6, axisColor); - } -GoBreakpoint(); - if (drawY2Reticle) - for(int i = 0; yMinUnit + i*yMajorUnit <= yRange; i++){ - w.DrawLine(plotW + (scale*4), fround(-plotH*yMinUnit2/yRange2 + plotH - i*plotH/(yRange/yMajorUnit)), - plotW, fround(-plotH*yMinUnit2/yRange2 + plotH - i*plotH/(yRange/yMajorUnit)), - fround(gridWidth*scale), axisColor); - double gridY2 = yMinUnit2 + i*yMajorUnit2 + yMin2; - String gridLabelY2; - if (cbModifFormatY2) - cbModifFormatY2(gridLabelY2, i, gridY2); - else - gridLabelY2 = VariableFormatY2(gridY2); - Font standard6; - standard6.Height(scale*StdFont().GetHeight()); - DrawText(w, plotW + scale*10, fround(-plotH*yMinUnit2/yRange2 + plotH - i*plotH/(yRange/yMajorUnit)) - scale*8, 0, - gridLabelY2, standard6, axisColor); - } -GoBreakpoint(); - Plot(w, scale, plotW, plotH); - ClipEnd(w); -} - -template -void ScatterDraw::Plot(T& w, const int& scale, const int& plotW, const int& plotH) -{ - double d1 = xRange/xMajorUnit; - double d2 = yRange/yMajorUnit; - - w.DrawRect(1, 1, plotW - 2, plotH - 1, plotAreaColor); - - if (drawVGrid) - for(int i = 0; xMinUnit + i*xMajorUnit < xRange; i++) - DrawLineOpa(w, fround(plotW*xMinUnit/xRange + i*plotW/d1), 0, fround(plotW*xMinUnit/xRange + i*plotW/d1), plotH, - 1, 1, gridWidth, gridColor, "2 2"); - - if (drawHGrid) - for(int i = 0; yMinUnit + i*yMajorUnit < yRange; i++) - DrawLineOpa(w, 0, fround(-plotH*yMinUnit/yRange + plotH - i*plotH/d2), plotW, fround(-plotH*yMinUnit/yRange + plotH - i*plotH/d2), - 1, 1, gridWidth, gridColor, "2 2"); - - w.DrawLine(0, plotH, plotW, plotH, fround(gridWidth*scale), Black); - w.DrawLine(0, 0, plotW, 0, fround(gridWidth*scale), Black); - w.DrawLine(0, 0, 0, plotH, fround(gridWidth*scale), Black); - w.DrawLine(plotW, 0, plotW, plotH + 1, fround(gridWidth*scale), Black); - - Clip(w, 0, 0, plotW, plotH); -GoBreakpoint(); - if (!series.IsEmpty()) { - for (int j = 0; j < series.GetCount(); j++) { - if (series[j].opacity == 0 || (!series[j].seriesPlot && !series[j].markPlot)) - continue; - Vector p1; - int imin, imax; - if (series[j].sequential) { - imin = imax = Null; - for (int i = 1; i < series[j].PointsData()->GetCount() - 1; ++i) { - if (IsNull(imin)) { - if (series[j].PointsData()->x(i) >= xMin) - imin = i - 1; - } else if (IsNull(imax)) { - if (series[j].PointsData()->x(i) >= xMin + xRange) - imax = i + 1; - } - } - if (IsNull(imin)) - imin = 0; - if (IsNull(imax)) - imax = series[j].PointsData()->GetCount(); - } else if (series[j].PointsData()->IsParam()) { // It is a param function - imin = 0; - imax = series[j].PointsData()->GetCount(); - } else if (IsNull(series[j].PointsData()->GetCount())) { // It is a function - imin = fround(xMin) - 1; - imax = fround(xMin + xRange) + 1; - } else { - imin = 0; - imax = series[j].PointsData()->GetCount(); - } - int numV; - if (fastViewX) - numV = 1 + (imax - imin)/plotW; - else - numV = 1; - for (int i = imin; i < imax; i += numV) { - double xx, yy; - if (fastViewX && numV > 1) { - yy = 0; - int ii; - for (ii = 0; ii < numV && i + ii < imax; ++ii) - yy += series[j].PointsData()->y(i + ii); - yy /= double(ii); - xx = (series[j].PointsData()->x(i) + series[j].PointsData()->x(i + ii - 1))/2; - } else { - xx = series[j].PointsData()->x(i); - yy = series[j].PointsData()->y(i); - } - int ix, iy; - ix = fround(plotW*(xx - xMin)/xRange); - if (series[j].primaryY) - iy = fround(plotH*(yy - yMin)/yRange); - else - iy = fround(plotH*(yy - yMin2)/yRange2); - p1 << Point(ix, plotH - iy); - } - if (!p1.IsEmpty()) - series[j].seriesPlot->Paint(w, p1, scale, series[j].opacity, - fround(series[j].thickness), series[j].color, - series[j].dash, plotAreaColor, series[j].fillColor, plotW/xRange, plotH/yRange, - int(plotH*(1 + yMin/yRange))); - - if (series[j].markWidth >= 1 && series[j].markPlot) { - for (int i = 0; i < (imax - imin)/numV; i++) - series[j].markPlot->Paint(w, scale, p1[i], series[j].markWidth, series[j].markColor); - } - } - } - w.End(); -} - -#endif - +#ifndef _ScatterDraw_ScatterDraw_h +#define _ScatterDraw_ScatterDraw_h + +#include +#include + +#include + +NAMESPACE_UPP + +#include "DataSource.h" +#include "DrawingFunctions.h" +#include "SeriesPlot.h" +#include "MarkPlot.h" + +Color GetOpaqueColor(const Color &color, const Color &background, const double opacity); + +class ScatterDraw { +public: + typedef ScatterDraw CLASSNAME; + ScatterDraw(); + + enum Formats { + EXP, + MON, + DY, + CUSTOM + }; + enum { + MD_DRAW = -1, + MD_ANTIALIASED = MODE_ANTIALIASED, + MD_NOAA = MODE_NOAA, + MD_SUBPIXEL = MODE_SUBPIXEL + }; + + #define LINE_DOTTED "4 10" + #define LINE_DOTTED_SEP "4 20" + #define LINE_DASHED "12 12" + #define LINE_DASH_DOT "20 10 5 10" + #define LINE_SOLID "" + +protected: + class ScatterBasicSeries { + public: + ScatterBasicSeries(); + void Init(int id); + + bool primaryY; + bool sequential; + + One seriesPlot; + double thickness; + Color color; + String dash; + + One markPlot; + double markWidth; + Color markColor; + + Color fillColor; + + String legend; + + double opacity; + + int id; + + bool trendLine; + //double trend + }; + + class ScatterSeries : public Moveable, public ScatterBasicSeries { + public: + ScatterSeries() {pD = 0;} + void SetDataSource(DataSource *pointsData, bool ownsData = true) {pD = pointsData; owns = ownsData;} + inline DataSource *PointsData() {return pD;} + ~ScatterSeries() {if(pD && owns) delete pD;} + private: + DataSource *pD; + bool owns; + }; + + static Color GetNewColor(int id); + static String GetNewDash(int id); + static MarkPlot *GetNewMarkPlot(int id); + +public: + Callback3 cbModifFormatX, cbModifFormatDeltaX; + Callback3 cbModifFormatY, cbModifFormatDeltaY; + Callback3 cbModifFormatY2, cbModifFormatDeltaY2; + + Callback WhenZoomScroll; + Callback WhenSetRange; + Callback WhenSetXYMin; + + ScatterDraw& SetSize(Size sz) {size = sz; return *this;}; + virtual Size GetSize() const {return size;}; + + ScatterDraw& SetColor(const Color& _color); + ScatterDraw& SetTitle(const String& _title); + ScatterDraw& SetTitleFont(const Font& fontTitle); + ScatterDraw& SetTitleColor(const Color& colorTitle); + + void SetLabels(const String& _xLabel, const String& _yLabel, const String& _yLabel2 = ""); + ScatterDraw& SetLabelX(const String& _xLabel); + ScatterDraw& SetLabelY(const String& _yLabel); + ScatterDraw& SetLabelY2(const String& _yLabel); + ScatterDraw& SetLabelsFont(const Font& fontLabels); + Font GetLabelsFont() {return labelsFont;}; + ScatterDraw& SetLabelsColor(const Color& colorLabels); + + ScatterDraw& SetPlotAreaMargin(const int hLeft, const int hRight, const int vTop, const int vBottom); + ScatterDraw& SetPlotAreaLeftMargin(const int margin); + ScatterDraw& SetPlotAreaRightMargin(const int margin); + ScatterDraw& SetPlotAreaTopMargin(const int margin); + ScatterDraw& SetPlotAreaBottomMargin(const int margin); + + ScatterDraw& SetPlotAreaColor(const Color& p_a_color); + + ScatterDraw& SetAxisColor(const Color& axis_color); + ScatterDraw& SetAxisWidth(const int& axis_width); + + ScatterDraw& SetGridColor(const Color& grid_color); + ScatterDraw& SetGridWidth(const int& grid_width); + ScatterDraw& ShowVGrid(const bool& show); + ScatterDraw& ShowHGrid(const bool& show); + + ScatterDraw& ShowLegend(const bool& show=true); + ScatterDraw& SetLegendWeight(const int& weight); + + ScatterDraw& SetMode(int _mode = MD_ANTIALIASED) {mode = _mode; Refresh(); return *this;}; + int GetMode() {return mode;}; + + void FitToData(bool Y = false); + void Zoom(double scale, bool hor = true, bool ver = true); + void Scroll(double factorX, double factorY); + + enum ZoomStyle {TO_CENTER, FROM_BASE}; + ScatterDraw &SetZoomStyleX(ZoomStyle style = TO_CENTER) {zoomStyleX = style; return *this;} + ScatterDraw &SetZoomStyleY(ZoomStyle style = TO_CENTER) {zoomStyleY = style; return *this;} + + ScatterDraw& SetRange(double rx, double ry, double ry2 = 100); + double GetXRange()const {return xRange;} + double GetYRange()const {return yRange;} + double GetY2Range()const {return yRange2;} + ScatterDraw &SetMajorUnits(double ux, double uy); + ScatterDraw &SetMajorUnitsNum(int nx, int ny); + ScatterDraw &SetMaxMajorUnitsX(int maxX, int maxY) {maxMajorUnitsX = maxX; maxMajorUnitsY = maxY; return *this;} + double GetMajorUnitsX() {return xMajorUnit;} + double GetMajorUnitsY() {return yMajorUnit;} + ScatterDraw& SetMinUnits(double ux, double uy); + double GetXMinUnit () const {return xMinUnit;} + double GetYMinUnit () const {return yMinUnit;} + + ScatterDraw& SetXYMin(double xmin,double ymin,double ymin2 = 0); + double GetXMin () const {return xMin;} + double GetYMin () const {return yMin;} + double GetYMin2 () const {return yMin2;} + + ScatterDraw &Graduation_FormatX(Formats fi); + ScatterDraw &Graduation_FormatY(Formats fi); + ScatterDraw &Graduation_FormatY2(Formats fi); + + ScatterDraw &AddSeries(double *yData, int numData, double x0 = 0, double deltaX = 1); + ScatterDraw &AddSeries(double *xData, double *yData, int numData); + ScatterDraw &AddSeries(Vector &xData, Vector &yData); + ScatterDraw &AddSeries(Upp::Array &xData, Upp::Array &yData); + ScatterDraw &AddSeries(Vector &points); + ScatterDraw &AddSeries(Upp::Array &points); + ScatterDraw &AddSeries(double (*function)(double)); + ScatterDraw &AddSeries(Pointf (*function)(double), int np, double from = 0, double to = 1); + ScatterDraw &AddSeries(PlotFunc &function); + ScatterDraw &AddSeries(PlotParamFunc function, int np, double from = 0, double to = 1); + ScatterDraw &_AddSeries(DataSource *data); + ScatterDraw &AddSeries(DataSource &data); + + template + ScatterDraw &AddSeries() {return _AddSeries(new C());} + template + ScatterDraw &AddSeries(T1 &arg1) + {return _AddSeries(new C(arg1));} + template + ScatterDraw &AddSeries(T1 &arg1, T2 &arg2) + {return _AddSeries(new C(arg1, arg2));} + template + ScatterDraw &AddSeries(T1 &arg1, T2 &arg2, T3 &arg3) + {return _AddSeries(new C(arg1, arg2, arg3));} + template + ScatterDraw &AddSeries(T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4) + {return _AddSeries(new C(arg1, arg2, arg3, arg4));} + template + ScatterDraw &AddSeries(T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4, T5 &arg5) + {return _AddSeries(new C(arg1, arg2, arg3, arg4, arg5));} + template + ScatterDraw &AddSeries(T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4, T5 &arg5, T6 &arg6) + {return _AddSeries(new C(arg1, arg2, arg3, arg4, arg5, arg6));} + + template + ScatterDraw &AddSeries(Vector &yData) {return _AddSeries(new VectorY(yData));} + template + ScatterDraw &AddSeries(Upp::Array &yData) {return _AddSeries(new ArrayY(yData));} + template + ScatterDraw &AddSeries(VectorMap &data) {return _AddSeries(new VectorMapXY(data));} + template + ScatterDraw &AddSeries(ArrayMap &data) {return _AddSeries(new ArrayMapXY(data));} + + void InsertSeries(int id, double *yData, int numData, double x0 = 0, double deltaX = 1); + void InsertSeries(int id, double *xData, double *yData, int numData); + void InsertSeries(int id, Vector &xData, Vector &yData); + void InsertSeries(int id, Upp::Array &xData, Upp::Array &yData); + void InsertSeries(int id, Vector &points); + void InsertSeries(int id, Upp::Array &points); + void InsertSeries(int id, double (*function)(double)); + void InsertSeries(int id, Pointf (*function)(double), int np, double from = 0, double to = 1); + void InsertSeries(int id, PlotFunc &function); + void InsertSeries(int id, PlotParamFunc function, int np, double from = 0, double to = 1); + void _InsertSeries(int id, DataSource *data); + + template + void InsertSeries(int id) {_InsertSeries(id, new C());} + template + void InsertSeries(int id, T1 &arg1) + {_InsertSeries(id, new C(arg1));} + template + void InsertSeries(int id, T1 &arg1, T2 &arg2) + {_InsertSeries(id, new C(arg1, arg2));} + template + void InsertSeries(int id, T1 &arg1, T2 &arg2, T3 &arg3) + {_InsertSeries(id, new C(arg1, arg2, arg3));} + template + void InsertSeries(int id, T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4) + {_InsertSeries(id, new C(arg1, arg2, arg3, arg4));} + template + void InsertSeries(int id, T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4, T5 &arg5) + {_InsertSeries(id, new C(arg1, arg2, arg3, arg4, arg5));} + template + void InsertSeries(int id, T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4, T5 &arg5, T6 &arg6) + {_InsertSeries(id, new C(arg1, arg2, arg3, arg4, arg5, arg6));} + + template + void InsertSeries(int id, Vector &yData) {_InsertSeries(id, new VectorY(yData));} + template + void InsertSeries(int id, Upp::Array &yData) {_InsertSeries(id, new ArrayY(yData));} + template + void InsertSeries(int id, VectorMap &data){_InsertSeries(id, new VectorMapXY(data));} + template + void InsertSeries(int id, ArrayMap &data) {_InsertSeries(id, new ArrayMapXY(data));} + + ScatterDraw &PlotStyle() {return PlotStyle(0);}; + template + ScatterDraw &PlotStyle() {return PlotStyle(new C());}; + template + ScatterDraw &PlotStyle(T1 &arg1) {return PlotStyle(new C(arg1));}; + template + ScatterDraw &PlotStyle(T1 &arg1, T2 &arg2) {return PlotStyle(new C(arg1, arg2));}; + template + ScatterDraw &PlotStyle(T1 &arg1, T2 &arg2, T3 &arg3) {return PlotStyle(new C(arg1, arg2, arg3));}; + ScatterDraw &PlotStyle(SeriesPlot *data); + + ScatterDraw &NoPlot() {return PlotStyle();}; + + ScatterDraw &MarkStyle() {return MarkStyle(0);}; + template + ScatterDraw &MarkStyle() {return MarkStyle(new C());}; + template + ScatterDraw &MarkStyle(T1 &arg1) {return MarkStyle(new C(arg1));}; + template + ScatterDraw &MarkStyle(T1 &arg1, T2 &arg2) {return MarkStyle(new C(arg1, arg2));}; + template + ScatterDraw &MarkStyle(T1 &arg1, T2 &arg2, T3 &arg3) {return MarkStyle(new C(arg1, arg2, arg3));}; + ScatterDraw &MarkStyle(MarkPlot *data); + + ScatterDraw &NoMark() {return MarkStyle();}; + + ScatterDraw &Stroke(double thickness = 3, Color color = Null); + ScatterDraw &Dash(const char *dash); + ScatterDraw &Fill(Color color = Null); + ScatterDraw &MarkColor(Color color = Null); + ScatterDraw &MarkWidth(const double& markWidth = 8); + ScatterDraw &Hide() {series[series.GetCount() - 1].opacity = 0; return *this;} + + ScatterDraw &Opacity(double opacity = 1) {series[series.GetCount() - 1].opacity = opacity; return *this;} + ScatterDraw &Legend(const String legend); + + inline bool IsValid(const int& j) const {return (j >= 0 && j < series.GetCount());} + + ScatterDraw& SetDrawXReticle(bool set = true); + ScatterDraw& SetDrawYReticle(bool set = true); + ScatterDraw& SetDrawY2Reticle(bool set = true); + + void SetDataColor(const int& j,const Color& pcolor); + Color GetDataColor (const int& j) const; + void SetDataThickness(const int& j, const double& thick); + double GetDataThickness(const int& j) const; + void SetFillColor(const int& j, const Color& color); + Color GetFillColor(const int& j) const; + + ScatterDraw &SetMarkWidth(const int& j, const double& width); + double GetMarkWidth(const int& j) const; + void SetMarkColor(const int& j, const Color& pcolor); + Color GetMarkColor (const int& j) const; + void NoMark(const int& j); + bool IsShowMark(const int& j) const throw (Exc); + + void SetDataPrimaryY(const int& j, const bool& primary=true); + ScatterDraw &SetDataPrimaryY(const bool& primary); + bool IsDataPrimaryY(const int& j) const throw (Exc); + + void SetSequentialX(const int& j, const bool& sequential = true); + ScatterDraw &SetSequentialX(const bool& sequential = true); + ScatterDraw &SetSequentialXAll(const bool& sequential = true); + + void Show(const int& j, const bool& show = true); + bool IsVisible(const int& j); + ScatterDraw &ShowAll(const bool& show = true); + + void RemoveSeries(const int& j); + void RemoveAllSeries(); + + ScatterDraw& Id(int id); + ScatterDraw& Id(const int& j, int id); + int GetId(const int& j); + + Drawing GetDrawing(); + Image GetImage(const int& scale = 1); + + #ifdef PLATFORM_WIN32 + void SaveAsMetafile(const char* file) const; + #endif + + ScatterDraw& LogX(const bool& logx=true) {logX=logx; return *this;} + ScatterDraw& LogY(const bool& logy=true) {logY=logy; return *this;} + ScatterDraw& LogY2(const bool& logy=true) {logY2=logy; return *this;} + + ScatterDraw& SetMinZoom(double x, double y = -1) {minXZoom = x; minYZoom = y; return *this;}; + ScatterDraw& SetMaxZoom(double x, double y = -1) {maxXZoom = x; maxYZoom = y; return *this;}; + + ScatterDraw& SetFastViewX(bool set = true) {fastViewX = set; return *this;}; + + Font& GetTitleFont() {return titleFont;}; + + double GetXByPoint(const int x); + double GetYByPoint(const int y); + double GetY2ByPoint(const int y); + double GetXPointByValue(const double x); + double GetYPointByValue(const double y); + + int GetCount() {return series.GetCount();} + bool IsEmpty() {return series.IsEmpty();} + + virtual void Refresh() {}; + +protected: + int mode; + Color graphColor; + String title; + Font titleFont; + Color titleColor; + + String xLabel, yLabel, yLabel2; + Font labelsFont; + Color labelsColor; + + int hPlotLeft, hPlotRight, vPlotTop, vPlotBottom; + Color plotAreaColor; + + bool fastViewX, sequentialXAll; + + Color axisColor; + int axisWidth; + + double xRange, yRange, yRange2; + double xMin, yMin, yMin2; + double xMajorUnit, yMajorUnit, yMajorUnit2; + double xMinUnit, yMinUnit, yMinUnit2; + double minXZoom, maxXZoom, minYZoom, maxYZoom; + bool drawXReticle, drawYReticle, drawY2Reticle; + + int maxMajorUnitsX, maxMajorUnitsY; + + Color gridColor; + int gridWidth; + bool drawVGrid, drawHGrid; + + int butDownX, butDownY; + bool isScrolling, isLabelPopUp; + ZoomStyle zoomStyleX, zoomStyleY; + + Vector series; + + bool showLegend; + int legendWeight; + + void DrawLegend(Draw& w,const int& scale) const; + + void Scrolling(bool down, Point &pt, bool isOut = false); + + void ExpFormat(String& s, int i, double d) {s = FormatDoubleExp(d,1);} + void MonFormat(String& s, int i, double d) {s = Format("%Mon",int(d));} + void DyFormat(String& s, int i, double d) {s = Format("%Dy",int(d));} + + static String VariableFormat(double range, double d) + { + if (fabs(d) <= 1e-15) + d = 0; + if (0.001<=range && range<0.01) return FormatDouble(d,5); + else if (0.01<=range && range<0.1) return FormatDouble(d,4); + else if (0.1<=range && range<1) return FormatDouble(d,3); + else if (1<=range && range<10) return FormatDouble(d,2); + else if (10<=range && range<100) return FormatDouble(d,1); + else if (100<=range && range<100000) return FormatDouble(d,0); + else return FormatDoubleExp(d,2); + + } + String VariableFormatX(const double& d) const {return VariableFormat(xRange, d);} + String VariableFormatY(const double& d) const {return VariableFormat(yRange, d);} + String VariableFormatY2(const double& d) const {return VariableFormat(yRange2, d);} + + template + void SetDrawing(T& w, const int& scale); + template + void Plot(T& w, const int& scale,const int& l,const int& h); + + void AdjustMinUnitX(); + void AdjustMinUnitY(); + void AdjustMinUnitY2(); + + bool logX, logY, logY2; + +private: + Size size; + static void ParseTextMultiline(const String &text, Font fnt, + Upp::Array &texts, Upp::Array &sizes); +}; + +template +void ScatterDraw::SetDrawing(T& w, const int& scale) +{ + if (GetSize().cx == 0 || GetSize().cy == 0) + return; + + w.DrawRect(scale*GetSize(), graphColor); + + if (typeid(T) == typeid(BufferPainter)) { + Painter &p = (Painter &)w; + p.Translate(0, 0.5); + } + + Size sz(0, 0); + + int titleHeight = !title.IsEmpty() ? scale*titleFont.GetHeight() : 0; + + if(titleHeight > 0) { + Font fontTitle6; + fontTitle6 = titleFont; + fontTitle6.Height(titleHeight); + fontTitle6.Width(scale*titleFont.GetWidth()); + sz = GetTextSize(title, fontTitle6); + DrawText(w, (scale*GetSize().cx - sz.cx)/2., scale*2., 0, title, fontTitle6, titleColor); + } + + w.Offset(Point(scale*hPlotLeft, scale*vPlotTop + titleHeight)); + if(showLegend) + DrawLegend(w, scale); + + int plotW = scale*(GetSize().cx - (hPlotLeft + hPlotRight)); + int plotH = scale*(GetSize().cy - (vPlotTop + vPlotBottom)) - titleHeight; + + Font fontLabel; + fontLabel = labelsFont; + fontLabel.Height(scale*labelsFont.GetHeight()); + + Size lx = GetTextSize(xLabel, fontLabel); + Size ly = GetTextSize(yLabel, fontLabel); + Size ly2 = GetTextSize(yLabel2, fontLabel); + DrawText(w, (plotW - lx.cx)/2., scale*GetSize().cy - lx.cy - 70*scale, 0, xLabel, fontLabel, labelsColor); + DrawText(w, scale*2. - scale*hPlotLeft, (plotH + ly.cx)/2., 900, yLabel, fontLabel, labelsColor); + DrawText(w, scale*GetSize().cx - ly2.cy - 42*scale, (plotH + ly2.cx)/2., 900, yLabel2, fontLabel, labelsColor); + + if (typeid(T) == typeid(BufferPainter)) { + Painter &p = (Painter &)w; + p.Translate(0.5, 0); + } + + if (drawXReticle) + for(int i = 0; xMinUnit + i*xMajorUnit <= xRange; i++){ + w.DrawLine(fround(plotW*xMinUnit/xRange + i*plotW/(xRange/xMajorUnit)), plotH, + fround(plotW*xMinUnit/xRange + i*plotW/(xRange/xMajorUnit)), plotH + scale*4, + fround(gridWidth*scale), axisColor); + Font standard6; + standard6.Height(scale*StdFont().GetHeight()); + double gridX = xMinUnit + i*xMajorUnit + xMin; + String gridLabelX; + if (cbModifFormatX) + cbModifFormatX(gridLabelX, i, gridX); + else + gridLabelX = VariableFormatX(gridX); + + Array texts; + Array sizes; + ParseTextMultiline(gridLabelX, StdFont(), texts, sizes); + for (int ii = 0; ii < texts.GetCount(); ++ii) { + int cy = ii == 0 ? 0 : sizes[ii - 1].cy; + DrawText(w, plotW*xMinUnit/xRange + i*plotW/(xRange/xMajorUnit) - scale*sizes[ii].cx/2., + plotH + scale*(4 + ii*cy), 0, texts[ii], standard6, axisColor); + } + } + + if (drawYReticle) + for(int i = 0; yMinUnit + i*yMajorUnit <= yRange; i++){ + w.DrawLine(-(scale*4), fround(-plotH*yMinUnit/yRange + plotH - i*plotH/(yRange/yMajorUnit)), + 0, fround(-plotH*yMinUnit/yRange + plotH - i*plotH/(yRange/yMajorUnit)), + fround(gridWidth*scale), axisColor); + double gridY = yMinUnit + i*yMajorUnit + yMin; + String gridLabelY; + if (cbModifFormatY) + cbModifFormatY(gridLabelY, i, gridY); + else + gridLabelY = VariableFormatY(gridY); + int dx=scale*GetTextSize(gridLabelY,StdFont()).cx; + Font Standard6; + Standard6.Height(scale*StdFont().GetHeight()); + DrawText(w, -dx - scale*6, fround(-plotH*yMinUnit/yRange + plotH - i*plotH/(yRange/yMajorUnit)) - scale*8, + 0, gridLabelY, Standard6, axisColor); + } + + if (drawY2Reticle) + for(int i = 0; yMinUnit + i*yMajorUnit <= yRange; i++){ + w.DrawLine(plotW + (scale*4), fround(-plotH*yMinUnit2/yRange2 + plotH - i*plotH/(yRange/yMajorUnit)), + plotW, fround(-plotH*yMinUnit2/yRange2 + plotH - i*plotH/(yRange/yMajorUnit)), + fround(gridWidth*scale), axisColor); + double gridY2 = yMinUnit2 + i*yMajorUnit2 + yMin2; + String gridLabelY2; + if (cbModifFormatY2) + cbModifFormatY2(gridLabelY2, i, gridY2); + else + gridLabelY2 = VariableFormatY2(gridY2); + Font standard6; + standard6.Height(scale*StdFont().GetHeight()); + DrawText(w, plotW + scale*10, fround(-plotH*yMinUnit2/yRange2 + plotH - i*plotH/(yRange/yMajorUnit)) - scale*8, 0, + gridLabelY2, standard6, axisColor); + } + + Plot(w, scale, plotW, plotH); + ClipEnd(w); +} + +template +void ScatterDraw::Plot(T& w, const int& scale, const int& plotW, const int& plotH) +{ + double d1 = xRange/xMajorUnit; + double d2 = yRange/yMajorUnit; + + w.DrawRect(1, 1, plotW - 2, plotH - 1, plotAreaColor); + + if (drawVGrid) + for(int i = 0; xMinUnit + i*xMajorUnit < xRange; i++) + DrawLineOpa(w, fround(plotW*xMinUnit/xRange + i*plotW/d1), 0, fround(plotW*xMinUnit/xRange + i*plotW/d1), plotH, + 1, 1, gridWidth, gridColor, "2 2"); + + if (drawHGrid) + for(int i = 0; yMinUnit + i*yMajorUnit < yRange; i++) + DrawLineOpa(w, 0, fround(-plotH*yMinUnit/yRange + plotH - i*plotH/d2), plotW, fround(-plotH*yMinUnit/yRange + plotH - i*plotH/d2), + 1, 1, gridWidth, gridColor, "2 2"); + + w.DrawLine(0, plotH, plotW, plotH, fround(gridWidth*scale), Black); + w.DrawLine(0, 0, plotW, 0, fround(gridWidth*scale), Black); + w.DrawLine(0, 0, 0, plotH, fround(gridWidth*scale), Black); + w.DrawLine(plotW, 0, plotW, plotH + 1, fround(gridWidth*scale), Black); + + Clip(w, 0, 0, plotW, plotH); + + if (!series.IsEmpty()) { + for (int j = 0; j < series.GetCount(); j++) { + if (series[j].opacity == 0 || (!series[j].seriesPlot && !series[j].markPlot)) + continue; + Vector p1; + int imin, imax; + if (series[j].sequential) { + imin = imax = Null; + for (int i = 1; i < series[j].PointsData()->GetCount() - 1; ++i) { + if (IsNull(imin)) { + if (series[j].PointsData()->x(i) >= xMin) + imin = i - 1; + } else if (IsNull(imax)) { + if (series[j].PointsData()->x(i) >= xMin + xRange) + imax = i + 1; + } + } + if (IsNull(imin)) + imin = 0; + if (IsNull(imax)) + imax = series[j].PointsData()->GetCount(); + } else if (series[j].PointsData()->IsParam()) { // It is a param function + imin = 0; + imax = series[j].PointsData()->GetCount(); + } else if (IsNull(series[j].PointsData()->GetCount())) { // It is a function + imin = fround(xMin) - 1; + imax = fround(xMin + xRange) + 1; + } else { + imin = 0; + imax = series[j].PointsData()->GetCount(); + } + int numV; + if (fastViewX) + numV = 1 + (imax - imin)/plotW; + else + numV = 1; + for (int i = imin; i < imax; i += numV) { + double xx, yy; + if (fastViewX && numV > 1) { + yy = 0; + int ii; + for (ii = 0; ii < numV && i + ii < imax; ++ii) + yy += series[j].PointsData()->y(i + ii); + yy /= double(ii); + xx = (series[j].PointsData()->x(i) + series[j].PointsData()->x(i + ii - 1))/2; + } else { + xx = series[j].PointsData()->x(i); + yy = series[j].PointsData()->y(i); + } + int ix, iy; + ix = fround(plotW*(xx - xMin)/xRange); + if (series[j].primaryY) + iy = fround(plotH*(yy - yMin)/yRange); + else + iy = fround(plotH*(yy - yMin2)/yRange2); + p1 << Point(ix, plotH - iy); + } + if (!p1.IsEmpty()) + series[j].seriesPlot->Paint(w, p1, scale, series[j].opacity, + fround(series[j].thickness), series[j].color, + series[j].dash, plotAreaColor, series[j].fillColor, plotW/xRange, plotH/yRange, + int(plotH*(1 + yMin/yRange))); + + if (series[j].markWidth >= 1 && series[j].markPlot) { + for (int i = 0; i < (imax - imin)/numV; i++) + series[j].markPlot->Paint(w, scale, p1[i], series[j].markWidth, series[j].markColor); + } + } + } + w.End(); +} + +END_UPP_NAMESPACE + +#endif + diff --git a/uppsrc/ScatterDraw/ScatterDraw.upp b/uppsrc/ScatterDraw/ScatterDraw.upp index 4feba6f71..88bba82f8 100644 --- a/uppsrc/ScatterDraw/ScatterDraw.upp +++ b/uppsrc/ScatterDraw/ScatterDraw.upp @@ -1,14 +1,15 @@ description "Scatter control\377"; uses - Painter, - DataSource; + Painter; file ScatterDraw.h, + DataSource.h, DrawingFunctions.h, SeriesPlot.h, MarkPlot.h, + DataSource.cpp, ScatterDraw.cpp, ScatterDraw.t; diff --git a/uppsrc/ScatterDraw/init b/uppsrc/ScatterDraw/init index 025e87d02..ce872b352 100644 --- a/uppsrc/ScatterDraw/init +++ b/uppsrc/ScatterDraw/init @@ -1,5 +1,4 @@ #ifndef _ScatterDraw_icpp_init_stub #define _ScatterDraw_icpp_init_stub #include "Painter/init" -#include "DataSource/init" #endif