1 #ifndef _ScatterDraw_ScatterDraw_h
2 #define _ScatterDraw_ScatterDraw_h
3 
4 #include <Draw/Draw.h>
5 #include <Painter/Painter.h>
6 #include "DataSource.h"
7 #include "Equation.h"
8 #include "DrawingFunctions.h"
9 #include "SeriesPlot.h"
10 #include "MarkPlot.h"
11 
12 namespace Upp {
13 
14 Color GetOpaqueColor(const Color &color, const Color &background, double opacity);
15 
16 void debug_h();			// Dummy function used to debug .h files
17 
18 class DashStyle {
19 public:
Register(const String & name,const String & style)20 	static int Register(const String& name, const String& style) {
21 		return map().FindAdd(name, style);
22 		return map().FindAdd(name, style);
23 	}
Unregister(const String & name)24 	static void Unregister(const String& name) {
25 		int id = TypeIndex(name);
26 		ASSERT(id >= 0);
27 		map().Remove(id);
28 	}
UnregisterFrom(int id)29 	static void UnregisterFrom(int id) {
30 		for (int i = GetCount() - 1; i >= id; --i)
31 			map().Remove(i);
32 	}
TypeName(int i)33 	static String         TypeName(int i)         		{return map().GetKey(i);}
Style(int i)34 	static String         Style(int i)         			{return map()[i];}
TypeIndex(const String & name)35 	static int            TypeIndex(const String& name) {return map().Find(name);}
StyleIndex(const String & style)36 	static int            StyleIndex(const String& style) {
37 		for (int i = 0; i < GetCount(); ++i) {
38 			if (map()[i] == style)
39 				return i;
40 		}
41 		return -1;
42 	}
GetCount()43 	static int            GetCount()   		{return map().GetCount();}
44 
45 protected:
map()46 	static VectorMap<String, String>& map()	{static VectorMap<String, String> map; 	 return map;}
47 };
48 
49 enum RAINBOW {BLUE_YELLOW_RED, RED_YELLOW_BLUE, GREEN_YELLOW_RED, RED_YELLOW_GREEN,
50 			  BLUE_WHITE_RED, RED_WHITE_BLUE, WHITE_BLACK, BLACK_WHITE};
51 
52 Color GetRainbowColor(double frac, RAINBOW rainbow, int numScales);
53 Color GetRainbowColor(double frac, const Color &from, const Color &to, int numScales);
54 Color GetRainbowColor(double frac, const Color &col0, const Color &col1, const Color &col2, int numScales);
55 
56 class ScatterDraw {
57 public:
58 	ScatterDraw();
~ScatterDraw()59 	virtual ~ScatterDraw() noexcept {}
60 
61 	enum Formats {
62 		EXP,
63 		MON,
64 		DY,
65 		CUSTOM
66 	};
67 	enum {
68 		MD_DRAW		   = -1,
69 		MD_ANTIALIASED = MODE_ANTIALIASED,
70 		MD_NOAA        = MODE_NOAA,
71 		MD_SUBPIXEL    = MODE_SUBPIXEL
72 	};
73 
74 	#define LINE_SOLID 		  ""
75 	#define LINE_DOTTED_FINER "2 10"
76 	#define LINE_DOTTED_FINE  "2 6"
77 	#define LINE_DOTTED 	  "4 10"
78 	#define LINE_DOTTED_SEP	  "4 20"
79 	#define LINE_DASHED 	  "12 12"
80 	#define LINE_DASH_DOT 	  "12 8 3 8"	// Reduced. Previous was too long
81 	#define LINE_BEGIN_END	  "-"
82 
83 protected:
84 	class ScatterBasicSeries {
85 	public:
86 		ScatterBasicSeries();
87 		void Init(int index);
88 
89 		bool primaryY;
90 		bool sequential;
91 
92 		One<SeriesPlot> seriesPlot;
93 		double thickness;
94 		Color color;
95 		String dash;
96 
97 		One<MarkPlot> markPlot;
98 		double markWidth;
99 		Color markColor;
100 		double markBorderWidth;
101 		Color markBorderColor;
102 
103 		Color fillColor;
104 
105 		String legend;
106 		String unitsX, unitsY;
107 
108 		double opacity;
109 
110 		double barWidth;
111 		bool isClosed;
112 
113 		Vector<String> *labels;
114 		Font labelsFont;
115 		Color labelsColor;
116 		int labelsDx, labelsDy;
117 		Alignment labelsAlign;
118 
119 		bool showLegend;
120 		bool legendLine; // show line in legend even if series is NoPlot
121 
122 		int id;
123 
124 	private:
125 		template <class T>
Ize(T & io)126 		void Ize(T& io) {
127 			int seriesP = Null;
128 			int markP = Null;
129 			if (io.IsStoring()) {
130 				if (markPlot)
131 					markP = markPlot->GetType();
132 				if (seriesPlot)
133 					seriesP = seriesPlot->GetType();
134 			}
135 			io
136 				("primaryY", primaryY)
137 				("sequential", sequential)
138 				("thickness", thickness)
139 				("color", color)
140 				("dash", dash)
141 				("markWidth", markWidth)
142 				("markColor", markColor)
143 				("markBorderWidth", markBorderWidth)
144 				("markBorderColor", markBorderColor)
145 				("fillColor", fillColor)
146 				("markBorderColor", markBorderColor)
147 				("legend", legend)
148 				("unitsX", unitsX)
149 				("unitsY", unitsY)
150 				("opacity", opacity)
151 				("id", id)
152 				("seriesP", seriesP)
153 				("markPlot", markP)
154 				("seriesPlot", seriesP)
155 				("barWidth", barWidth)
156 				("isClosed", isClosed)
157 				("showLegend", showLegend)
158 				("legendLine", legendLine)
159 			;
160 			if (io.IsLoading()) {
161 				if (!IsNull(markP))
162 					markPlot = MarkPlot::Create(markP);
163 				else
164 					markPlot = 0;
165 				if (!IsNull(seriesP))
166 					seriesPlot = SeriesPlot::Create(seriesP);
167 				else
168 					seriesPlot = 0;
169 			}
170 		}
171 
172 	public:
Xmlize(XmlIO & xml)173 		void Xmlize(XmlIO& xml) 	{Ize(xml);}
Jsonize(JsonIO & json)174 		void Jsonize(JsonIO& json) 	{Ize(json);}
175 
Serialize(Stream & s)176 		void Serialize(Stream& s) {
177 			int seriesP = Null;
178 			int markP = Null;
179 			if (s.IsStoring()) {
180 				if (markPlot)
181 					markP = markPlot->GetType();
182 				if (seriesPlot)
183 					seriesP = seriesPlot->GetType();
184 			}
185 			s	% primaryY
186 				% sequential
187 				% thickness
188 				% color
189 				% dash
190 				% markWidth
191 				% markColor
192 				% markBorderWidth
193 				% markBorderColor
194 				% fillColor
195 				% markBorderColor
196 				% legend
197 				% unitsX
198 				% unitsY
199 				% opacity
200 				% id
201 				% seriesP
202 				% markP
203 				% seriesP
204 				% barWidth
205 				% isClosed
206 				% showLegend
207 				% legendLine
208 			;
209 			if (s.IsLoading()) {
210 				if (!IsNull(markP))
211 					markPlot = MarkPlot::Create(markP);
212 				else
213 					markPlot = 0;
214 				if (!IsNull(seriesP))
215 					seriesPlot = SeriesPlot::Create(seriesP);
216 				else
217 					seriesPlot = 0;
218 			}
219 		}
220 	};
221 
222 	class ScatterSeries : public Moveable<ScatterSeries>, public ScatterBasicSeries {
223 	public:
ScatterSeries()224 		ScatterSeries()	: owns(false), serializeData(false) {dataS.Init(&data);}
225 		void SetDataSource(DataSource *pointsData, bool ownsData = true) {
226 			DeletePD();
227 			pD = pointsData;
228 			owns = ownsData;
229 		}
SetDataSourceInternal()230 		void SetDataSourceInternal() {
231 			CopyInternal();
232 			DeletePD();
233 			pD = &dataS;
234 			serializeData = true;
235 			owns = false;
236 		}
Data()237 		DataSource &Data()		 				{return *(~pD);}
Data()238 		const DataSource &Data() const	 		{return *(~pD);}
IsDeleted()239 		bool IsDeleted() const {
240 			if (~pD == nullptr)
241 				return true;
242 			bool ismagic = (~pD)->IsMagic();
243 			ASSERT(ismagic);
244 			return !ismagic;
245 		}
~ScatterSeries()246 		virtual ~ScatterSeries() noexcept		{DeletePD();}
247 		void SerializeData(bool ser = true) 	{serializeData = ser;}
248 		void SerializeFormat(bool ser = false) 	{serializeFormat = ser;}
Xmlize(XmlIO & xio)249 		void Xmlize(XmlIO& xio) 				{XmlizeByJsonize(xio, *this);}
Jsonize(JsonIO & json)250 		void Jsonize(JsonIO& json) {
251 			ScatterBasicSeries::Jsonize(json);
252 			if (json.IsStoring() && pD)
253 				CopyInternal();
254 			json("data", data);
255 			if (json.IsLoading()) {
256 				if (!data.IsEmpty()) {
257 					pD = &dataS;
258 					serializeData = true;
259 				}
260 			}
261 		}
Serialize(Stream & s)262 		void Serialize(Stream& s) {
263 			ScatterBasicSeries::Serialize(s);
264 			if (s.IsStoring() && pD)
265 				CopyInternal();
266 			s % data;
267 			if (s.IsLoading()) {
268 				if (!data.IsEmpty()) {
269 					pD = &dataS;
270 					serializeData = true;
271 				}
272 			}
273 		}
274 
275 	private:
276 		Ptr<DataSource> pD;
277 		bool owns;
278 		Vector<Pointf> data;
279 		VectorPointf dataS;
280 		bool serializeData, serializeFormat;
281 
CopyInternal()282 		void CopyInternal() {
283 			int64 sz = pD->GetCount();
284 			if (IsNull(sz) || sz == 0)
285 				return;
286 			data.SetCount(int(sz));
287 			for (int64 i = 0; i < sz; ++i) {
288 				data[int(i)].x = pD->x(i);
289 				data[int(i)].y = pD->y(i);
290 			}
291 		}
DeletePD()292 		void DeletePD() {
293 			if(pD && owns) {
294 				delete pD;
295 				pD = 0;
296 			}
297 		}
298 	};
299 
300 	static Color GetNewColor(int index, int version = 1);
301 	static String GetNewDash(int index);
302 	static MarkPlot *GetNewMarkPlot(int index);
303 
WhenPaint(Painter & w)304 	void WhenPaint(Painter &w)	{WhenPainter(w);}
WhenPaint(Draw & w)305 	void WhenPaint(Draw &w) 	{WhenDraw(w);}
306 
307 public:
308 	template<class T>
309 	void SetDrawing(T& w, bool ctrl = false);
310 
311 	Function<void(String&, int, double)> cbModifFormatX;
312 	Function<void(String&, int, double)> cbModifFormatXGridUnits;
313 	Function<void(String&, int, double)> cbModifFormatDeltaX;
314 	Function<void(String&, int, double)> cbModifFormatY;
315 	Function<void(String&, int, double)> cbModifFormatYGridUnits;
316 	Function<void(String&, int, double)> cbModifFormatDeltaY;
317 	Function<void(String&, int, double)> cbModifFormatY2;
318 	Function<void(String&, int, double)> cbModifFormatY2GridUnits;
319 	Function<void(String&, int, double)> cbModifFormatDeltaY2;
320 
321 	Function<void(Vector<double>&)> SetGridLinesX;
322 	Function<void(Vector<double>&)> SetGridLinesY;
323 
324 	Function<void()> WhenZoomScroll;
325 	Function<void()> WhenSetRange;
326 	Function<void()> WhenSetXYMin;
327 	Function<void(Painter&)> WhenPainter;
328 	Function<void(Draw&)> WhenDraw;
329 	Function<void()> WhenZoomToFit;
330 
331 	Function <bool(int)> WhenRemoveSeries;
332 	Function <bool(int, int)> WhenSwapSeries;
333 
SetSize(const Size & sz)334 	ScatterDraw& SetSize(const Size &sz) {
335 		size = sz;
336 		plotScaleX   = responsive ? responsivenessFactor*size.cx/600. : 1;
337 		plotScaleY   = responsive ? responsivenessFactor*size.cy/400. : 1;
338 		plotScaleAvg = responsive ? (plotScaleX + plotScaleY)/2. : 1;
339 		return *this;
340 	};
GetSize()341 	Size GetSize() const				{return size;};
342 	ScatterDraw& Responsive(bool _responsive = true, double factor = 1) {
343 		this->responsive = _responsive;
344 		responsivenessFactor = factor;
345 		plotScaleX   = _responsive ? responsivenessFactor*size.cx/600. : 1;
346 		plotScaleY   = _responsive ? responsivenessFactor*size.cy/400. : 1;
347 		plotScaleAvg = _responsive ? (plotScaleX + plotScaleY)/2. : 1;
348 		return *this;
349 	}
IsResponsive()350 	bool IsResponsive()		{return responsive;}
GetResponsivenessFactor()351 	double GetResponsivenessFactor() {return responsivenessFactor;}
GetPlotScaleX()352 	double GetPlotScaleX()	{return plotScaleX;}
GetPlotScaleY()353 	double GetPlotScaleY()	{return plotScaleY;}
GetPlotScaleAvg()354 	double GetPlotScaleAvg(){return plotScaleAvg;}
355 
356 	ScatterDraw& SetColor(const Color& _color);
357 	ScatterDraw& SetTitle(const String& _title);
358 	const String& GetTitle();
359 	ScatterDraw& SetTitleFont(const Upp::Font& fontTitle);
GetTitleFont()360 	Upp::Font& GetTitleFont() {return titleFont;};
361 	ScatterDraw& SetTitleColor(const Color& colorTitle);
GetTitleColor()362 	Upp::Color& GetTitleColor() {return titleColor;};
363 
364 	ScatterDraw& SetLabels(const String& _xLabel, const String& _yLabel, const String& _yLabel2 = "");
365 	ScatterDraw& SetLabelX(const String& _xLabel);
GetLabelX()366 	const String &GetLabelX()	{return xLabel_base;}
367 	ScatterDraw& SetLabelY(const String& _yLabel);
GetLabelY()368 	const String &GetLabelY()	{return yLabel_base;}
369 	ScatterDraw& SetLabelY2(const String& _yLabel);
GetLabelY2()370 	const String &GetLabelY2()	{return yLabel2_base;}
371 	ScatterDraw& SetLabelsFont(const Upp::Font& fontLabels);
GetLabelsFont()372 	Upp::Font GetLabelsFont() 	{return labelsFont;};
373 	ScatterDraw& SetLabelsColor(const Color& colorLabels);
GetLabelsColor()374 	Upp::Color GetLabelsColor() {return labelsColor;};
375 
376 	ScatterDraw& SetPlotAreaMargin(int hLeft, int hRight, int vTop, int vBottom);
377 	ScatterDraw& SetPlotAreaLeftMargin(int margin);
GetPlotAreaLeftMargin()378 	int GetPlotAreaLeftMargin()						{return hPlotLeft;}
379 	ScatterDraw& SetPlotAreaRightMargin(int margin);
GetPlotAreaRightMargin()380 	int GetPlotAreaRightMargin()					{return hPlotRight;}
381 	ScatterDraw& SetPlotAreaTopMargin(int margin);
GetPlotAreaTopMargin()382 	int GetPlotAreaTopMargin()						{return vPlotTop;}
383 	ScatterDraw& SetPlotAreaBottomMargin(int margin);
GetPlotAreaBottomMargin()384 	int GetPlotAreaBottomMargin()					{return vPlotBottom;}
385 
386 	ScatterDraw& SetPlotAreaColor(const Color& p_a_color);
GetPlotAreaColor()387 	Color& GetPlotAreaColor()						{return plotAreaColor;}
388 
389 	ScatterDraw& SetAxisColor(const Color& axis_color);
390 	ScatterDraw& SetAxisWidth(double axis_width);
GetAxisWidth()391 	double GetAxisWidth()							{return axisWidth;}
392 
SetGridColor(const Color & grid_color)393 	ScatterDraw& SetGridColor(const Color& grid_color){gridColor = grid_color;	return *this;}
GetGridColor()394 	Color &GetGridColor() 							{return gridColor;}
SetGridWidth(double grid_width)395 	ScatterDraw& SetGridWidth(double grid_width)	{gridWidth = grid_width;	return *this;}
GetGridWidth()396 	double GetGridWidth() 							{return gridWidth;}
SetGridDash(const char * dash)397 	ScatterDraw& SetGridDash(const char *dash)		{gridDash = dash;			return *this;}
GetGridDash()398 	const char *GetGridDash()						{return gridDash;}
399 
400 	ScatterDraw& ShowVGrid(bool show);
401 	ScatterDraw& ShowHGrid(bool show);
402 
403 	ScatterDraw& ShowLegend(bool show = true) 		{showLegend = show;		return *this;}
GetShowLegend()404 	bool GetShowLegend()							{return showLegend;}
SetLegendPos(const Point & pos)405 	ScatterDraw& SetLegendPos(const Point &pos) 	{legendPos = pos;		return *this;}
SetLegendPosX(int x)406 	ScatterDraw& SetLegendPosX(int x) 				{legendPos.x = x;		return *this;}
SetLegendPosY(int y)407 	ScatterDraw& SetLegendPosY(int y) 				{legendPos.y = y;		return *this;}
GetLegendPos()408 	Point& GetLegendPos() 							{return legendPos;}
SetLegendFont(const Font & fnt)409 	ScatterDraw& SetLegendFont(const Font &fnt) 	{legendFont = fnt;		return *this;}
GetLegendFont()410 	Font &GetLegendFont()							{return legendFont;}
SetLegendNumCols(int num)411 	ScatterDraw& SetLegendNumCols(int num) 			{legendNumCols = num;	return *this;}
GetLegendNumCols()412 	int GetLegendNumCols() 							{return legendNumCols;}
SetLegendRowSpacing(int num)413 	ScatterDraw& SetLegendRowSpacing(int num) 		{legendRowSpacing = num;return *this;}
GetLegendRowSpacing()414 	int GetLegendRowSpacing() 						{return legendRowSpacing;}
415 	enum LEGEND_POS {
416 		TOP,
417 		LEFT_TOP,
418 		RIGHT_TOP,
419 		LEFT_BOTTOM,
420 		RIGHT_BOTTOM
421 	};
SetLegendAnchor(LEGEND_POS anchor)422 	ScatterDraw& SetLegendAnchor(LEGEND_POS anchor) 		{legendAnchor = anchor;	return *this;}
GetLegendAnchor()423 	LEGEND_POS GetLegendAnchor() 							{return legendAnchor;}
SetLegendFillColor(const Color & color)424 	ScatterDraw& SetLegendFillColor(const Color &color) 	{legendFillColor = color;	return *this;}
SetLegendBorderColor(const Color & color)425 	ScatterDraw& SetLegendBorderColor(const Color &color) 	{legendBorderColor = color;	return *this;}
GetLegendFillColor()426 	Color& GetLegendFillColor() 							{return legendFillColor;}
GetLegendBorderColor()427 	Color& GetLegendBorderColor() 							{return legendBorderColor;}
428 
429 	ScatterDraw& SetMode(int _mode = MD_ANTIALIASED)		{this->mode = _mode; Refresh(); return *this;};
GetMode()430 	int GetMode()											{return mode;};
431 
432 	ScatterDraw &ZoomToFit(bool horizontal = true, bool vertical = false, double factor = 0);
433 	//ScatterDraw &ZoomToFit(bool horizontal, double minx, double maxx, bool vertical, double minxy, double maxy,
434 	//				bool vertical2, double miny2, double maxy2, double factor);
435 	//ScatterDraw &ZoomToFitSmart(bool horizontal, double minx, double maxx, bool vertical, double minxy, double maxy,
436 	//				bool vertical2, double miny2, double maxy2, double factor);
437 	void Zoom(double scale, bool hor = true, bool ver = true);
438 	void Scroll(double factorX, double factorY);
439 
440 	enum ZoomStyle {TO_CENTER, FROM_BASE};
441 	ScatterDraw &SetZoomStyleX(ZoomStyle style = TO_CENTER) {zoomStyleX = style; return *this;}
442 	ScatterDraw &SetZoomStyleY(ZoomStyle style = TO_CENTER) {zoomStyleY = style; return *this;}
443 
444 	ScatterDraw& SetRange(double rx, double ry = Null, double ry2 = Null);
445 	ScatterDraw& SetRangeLinked(double rx, double ry, double ry2 = 100);
GetXRange()446 	double GetXRange()const 	{return xRange;}
GetYRange()447 	double GetYRange()const 	{return yRange;}
GetY2Range()448 	double GetY2Range()const 	{return yRange2;}
449 	ScatterDraw &SetMajorUnits(double ux, double uy = Null);
450 	ScatterDraw &SetMajorUnitsNum(int nx, int ny = Null);
GetMajorUnitsX()451 	double GetMajorUnitsX() 	{return xMajorUnit;}
GetMajorUnitsY()452 	double GetMajorUnitsY() 	{return yMajorUnit;}
GetMajorUnitsY2()453 	double GetMajorUnitsY2() 	{return yMajorUnit2;}
454 	ScatterDraw& SetMinUnits(double ux, double uy = Null);
GetXMinUnit()455 	double GetXMinUnit() const  {return xMinUnit;}
GetYMinUnit()456 	double GetYMinUnit() const  {return yMinUnit;}
GetYMinUnit2()457 	double GetYMinUnit2() const {return yMinUnit2;}
458 
459 	ScatterDraw& SetXYMin(double xmin, double ymin = Null, double ymin2 = Null);
460 	ScatterDraw& SetXYMinLinked(double xmin, double ymin = Null, double ymin2 = Null);
GetXMin()461 	double GetXMin() const 		{return xMin;}
GetYMin()462 	double GetYMin() const 		{return yMin;}
GetYMin2()463 	double GetYMin2() const 	{return yMin2;}
GetY2Min()464 	double GetY2Min() const 	{return yMin2;}
GetXMax()465 	double GetXMax() const 		{return xMin + xRange;}
GetYMax()466 	double GetYMax() const 		{return yMin + yRange;}
GetY2Max()467 	double GetY2Max() const 	{return yMin2 + yRange2;}
468 
469 	ScatterDraw &Graduation_FormatX(Formats fi);
470 	ScatterDraw &Graduation_FormatY(Formats fi);
471 	ScatterDraw &Graduation_FormatY2(Formats fi);
472 
473 	//ScatterDraw &SetPolar(bool polar = true)			{isPolar = polar; 	return *this;};
474 
AddSeries(double * yData,int numData,double x0,double deltaX)475 	ScatterDraw &AddSeries(double *yData, int numData, double x0, double deltaX)
476 														{return AddSeries<CArray>(yData, numData, x0, deltaX);}
AddSeries(double * xData,double * yData,int numData)477 	ScatterDraw &AddSeries(double *xData, double *yData, int numData)
478 														{return AddSeries<CArray>(yData, xData, numData);}
AddSeries(Eigen::VectorXd & yData,double x0,double deltaX)479 	ScatterDraw &AddSeries(Eigen::VectorXd &yData, double x0, double deltaX)
480 														{return AddSeries<EigenVector>(yData, x0, deltaX);}
AddSeries(Eigen::VectorXd & xData,Eigen::VectorXd & yData)481 	ScatterDraw &AddSeries(Eigen::VectorXd &xData, Eigen::VectorXd &yData)
482 														{return AddSeries<EigenVector>(xData, yData);}
AddSeries(Vector<double> & xData,Vector<double> & yData)483 	ScatterDraw &AddSeries(Vector<double> &xData, Vector<double> &yData)
484 														{return AddSeries<VectorXY>(xData, yData);}
AddSeries(Upp::Array<double> & xData,Upp::Array<double> & yData)485 	ScatterDraw &AddSeries(Upp::Array<double> &xData, Upp::Array<double> &yData)
486 														{return AddSeries<ArrayXY>(xData, yData);}
AddSeries(Vector<Pointf> & points)487 	ScatterDraw &AddSeries(Vector<Pointf> &points)		{return AddSeries<VectorPointf>(points);}
AddSeries(Upp::Array<Pointf> & points)488 	ScatterDraw &AddSeries(Upp::Array<Pointf> &points)	{return AddSeries<ArrayPointf>(points);}
489 	template <class Y>
490 	ScatterDraw &AddSeries(Vector<Vector <Y> > &data, int idx, int idy,
491 		Vector<int> &idsx, Vector<int> &idsy, Vector<int> &idsFixed, bool useCols = true, int beginData = 0, int numData = Null) {
492 		return AddSeries<VectorVectorY<Y> >(data, idx, idy, idsx, idsy, idsFixed, useCols, beginData, numData);
493 	}
AddSeries(Function<double (double)> function)494 	ScatterDraw &AddSeries(Function <double(double)> function)	{return AddSeries<FuncSource>(function);}
AddSeries(double (* function)(double))495 	ScatterDraw &AddSeries(double (*function)(double))			{return AddSeries<FuncSource>(function);}
AddSeries(void (* function)(double &,double))496 	ScatterDraw &AddSeries(void (*function)(double&, double))
497 														{return AddSeries<FuncSourceV>(function);}
498 	ScatterDraw &AddSeries(Pointf (*function)(double), int np, double from = 0, double to = 1)
499 														{return AddSeries<FuncSourcePara>(function, np, from, to);}
AddSeries(PlotExplicFunc function)500 	ScatterDraw &AddSeries(PlotExplicFunc function)		{return AddSeries<PlotExplicFuncSource>(function);}
501 	ScatterDraw &AddSeries(PlotParamFunc function, int np, double from = 0, double to = 1)
502 														{return AddSeries<PlotParamFuncSource>(function, np, from, to);}
503 
504 	ScatterDraw &AddSeries(DataSource &data);
505 
506 	template <class C>
AddSeries()507 	ScatterDraw &AddSeries() 	{return _AddSeries(new C());}
508 	template <class C, class T1>
AddSeries(T1 & arg1)509 	ScatterDraw &AddSeries(T1 &arg1)
510 								{return _AddSeries(new C(arg1));}
511 	template <class C, class T1, class T2>
AddSeries(T1 & arg1,T2 & arg2)512 	ScatterDraw &AddSeries(T1 &arg1, T2 &arg2)
513 								{return _AddSeries(new C(arg1, arg2));}
514 	template <class C, class T1, class T2, class T3>
AddSeries(T1 & arg1,T2 & arg2,T3 & arg3)515 	ScatterDraw &AddSeries(T1 &arg1, T2 &arg2, T3 &arg3)
516 								{return _AddSeries(new C(arg1, arg2, arg3));}
517 	template <class C, class T1, class T2, class T3, class T4>
AddSeries(T1 & arg1,T2 & arg2,T3 & arg3,T4 & arg4)518 	ScatterDraw &AddSeries(T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4)
519 								{return _AddSeries(new C(arg1, arg2, arg3, arg4));}
520 	template <class C, class T1, class T2, class T3, class T4, class T5>
AddSeries(T1 & arg1,T2 & arg2,T3 & arg3,T4 & arg4,T5 & arg5)521 	ScatterDraw &AddSeries(T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4, T5 &arg5)
522 								{return _AddSeries(new C(arg1, arg2, arg3, arg4, arg5));}
523 	template <class C, class T1, class T2, class T3, class T4, class T5, class T6>
AddSeries(T1 & arg1,T2 & arg2,T3 & arg3,T4 & arg4,T5 & arg5,T6 & arg6)524 	ScatterDraw &AddSeries(T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4, T5 &arg5, T6 &arg6)
525 								{return _AddSeries(new C(arg1, arg2, arg3, arg4, arg5, arg6));}
526 	template <class C, class T1, class T2, class T3, class T4, class T5, class T6, class T7>
AddSeries(T1 & arg1,T2 & arg2,T3 & arg3,T4 & arg4,T5 & arg5,T6 & arg6,T7 & arg7)527 	ScatterDraw &AddSeries(T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4, T5 &arg5, T6 &arg6, T7 &arg7)
528 								{return _AddSeries(new C(arg1, arg2, arg3, arg4, arg5, arg6, arg7));}
529 	template <class C, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
AddSeries(T1 & arg1,T2 & arg2,T3 & arg3,T4 & arg4,T5 & arg5,T6 & arg6,T7 & arg7,T8 & arg8)530 	ScatterDraw &AddSeries(T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4, T5 &arg5, T6 &arg6, T7 &arg7, T8 &arg8)
531 								{return _AddSeries(new C(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8));}
532 	template <class C, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9>
AddSeries(T1 & arg1,T2 & arg2,T3 & arg3,T4 & arg4,T5 & arg5,T6 & arg6,T7 & arg7,T8 & arg8,T9 & arg9)533 	ScatterDraw &AddSeries(T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4, T5 &arg5, T6 &arg6, T7 &arg7, T8 &arg8, T9 &arg9)
534 								{return _AddSeries(new C(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9));}
535 
536 	template <class Y>
AddSeries(Vector<Y> & yData,double x0,double deltaX)537 	ScatterDraw &AddSeries(Vector<Y> &yData, double x0, double deltaX)		{return _AddSeries(new VectorY<Y>(yData, x0, deltaX));}
538 	template <class Y>
AddSeries(Upp::Array<Y> & yData,double x0,double deltaX)539 	ScatterDraw &AddSeries(Upp::Array<Y> &yData, double x0, double deltaX)	{return _AddSeries(new ArrayY<Y>(yData, x0, deltaX));}
540 	template <class X, class Y>
AddSeries(VectorMap<X,Y> & data)541 	ScatterDraw &AddSeries(VectorMap<X, Y> &data)	{return _AddSeries(new VectorMapXY<X, Y>(data));}
542 	template <class X, class Y>
AddSeries(ArrayMap<X,Y> & data)543 	ScatterDraw &AddSeries(ArrayMap<X, Y> &data)	{return _AddSeries(new ArrayMapXY<X, Y>(data));}
544 
GetDataSource(int index)545 	DataSource &GetDataSource(int index) 	{ASSERT(IsValid(index));ASSERT(!series[index].IsDeleted());	return series[index].Data();}
IsDeletedDataSource(int index)546 	bool IsDeletedDataSource(int index) 	{return series[index].IsDeleted();}
547 
548 	ScatterDraw &InsertSeries(int index, double *yData, int numData, double x0 = 0, double deltaX = 1);
549 	ScatterDraw &InsertSeries(int index, double *xData, double *yData, int numData);
550 	ScatterDraw &InsertSeries(int index, Vector<double> &xData, Vector<double> &yData);
551 	ScatterDraw &InsertSeries(int index, Upp::Array<double> &xData, Upp::Array<double> &yData);
552 	ScatterDraw &InsertSeries(int index, Vector<Pointf> &points);
553 	ScatterDraw &InsertSeries(int index, Upp::Array<Pointf> &points);
554 	ScatterDraw &InsertSeries(int index, double (*function)(double));
555 	ScatterDraw &InsertSeries(int index, Pointf (*function)(double), int np, double from = 0, double to = 1);
556 	ScatterDraw &InsertSeries(int index, PlotExplicFunc &function);
557 	ScatterDraw &InsertSeries(int index, PlotParamFunc function, int np, double from = 0, double to = 1);
558 	ScatterDraw &_InsertSeries(int index, DataSource *data);
559 
560 	template <class C>
InsertSeries(int index)561 	ScatterDraw &InsertSeries(int index) 	{return _InsertSeries(index, new C());}
562 	template <class C, class T1>
InsertSeries(int index,T1 & arg1)563 	ScatterDraw &InsertSeries(int index, T1 &arg1)
564 									{return _InsertSeries(index, new C(arg1));}
565 	template <class C, class T1, class T2>
InsertSeries(int index,T1 & arg1,T2 & arg2)566 	ScatterDraw &InsertSeries(int index, T1 &arg1, T2 &arg2)
567 									{return _InsertSeries(index, new C(arg1, arg2));}
568 	template <class C, class T1, class T2, class T3>
InsertSeries(int index,T1 & arg1,T2 & arg2,T3 & arg3)569 	ScatterDraw &InsertSeries(int index, T1 &arg1, T2 &arg2, T3 &arg3)
570 									{return _InsertSeries(index, new C(arg1, arg2, arg3));}
571 	template <class C, class T1, class T2, class T3, class T4>
InsertSeries(int index,T1 & arg1,T2 & arg2,T3 & arg3,T4 & arg4)572 	ScatterDraw &InsertSeries(int index, T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4)
573 									{return _InsertSeries(index, new C(arg1, arg2, arg3, arg4));}
574 	template <class C, class T1, class T2, class T3, class T4, class T5>
InsertSeries(int index,T1 & arg1,T2 & arg2,T3 & arg3,T4 & arg4,T5 & arg5)575 	ScatterDraw &InsertSeries(int index, T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4, T5 &arg5)
576 									{return _InsertSeries(index, new C(arg1, arg2, arg3, arg4, arg5));}
577 	template <class C, class T1, class T2, class T3, class T4, class T5, class T6>
InsertSeries(int index,T1 & arg1,T2 & arg2,T3 & arg3,T4 & arg4,T5 & arg5,T6 & arg6)578 	ScatterDraw &InsertSeries(int index, T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4, T5 &arg5, T6 &arg6)
579 									{return _InsertSeries(index, new C(arg1, arg2, arg3, arg4, arg5, arg6));}
580 
581 	template <class Y>
InsertSeries(int index,Vector<Y> & yData,double x0,double deltaX)582 	ScatterDraw &InsertSeries(int index, Vector<Y> &yData, double x0, double deltaX)		{return _InsertSeries(index, new VectorY<Y>(yData, x0, deltaX));}
583 	template <class Y>
InsertSeries(int index,Upp::Array<Y> & yData,double x0,double deltaX)584 	ScatterDraw &InsertSeries(int index, Upp::Array<Y> &yData, double x0, double deltaX)	{return _InsertSeries(index, new ArrayY<Y>(yData, x0, deltaX));}
585 	template <class X, class Y>
InsertSeries(int index,VectorMap<X,Y> & data)586 	ScatterDraw &InsertSeries(int index, VectorMap<X, Y> &data)	{return _InsertSeries(index, new VectorMapXY<X, Y>(data));}
587 	template <class X, class Y>
InsertSeries(int index,ArrayMap<X,Y> & data)588 	ScatterDraw &InsertSeries(int index, ArrayMap<X, Y> &data)	{return _InsertSeries(index, new ArrayMapXY<X, Y>(data));}
589 
590 	int64 GetCount(int index);
591 	void GetValues(int index, int64 idata, double &x, double &y);
592 	double GetValueX(int index, int64 idata);
593 	Value GetStringX(int index, int64 idata);
594 	double GetValueY(int index, int64 idata);
595 	Value GetStringY(int index, int64 idata);
596 
597 	ScatterDraw &SetNoPlot(int index);
598 
PlotStyle()599 	ScatterDraw &PlotStyle()								{return PlotStyle(0);};
600 	template <class C>
PlotStyle()601 	ScatterDraw &PlotStyle()								{return PlotStyle(new C());}
602 	template <class C, class T1>
PlotStyle(T1 arg1)603 	ScatterDraw &PlotStyle(T1 arg1)							{return PlotStyle(new C(arg1));}
604 	template <class C, class T1, class T2>
PlotStyle(T1 arg1,T2 arg2)605 	ScatterDraw &PlotStyle(T1 arg1, T2 arg2)				{return PlotStyle(new C(arg1, arg2));}
606 	template <class C, class T1, class T2, class T3>
PlotStyle(T1 arg1,T2 arg2,T3 arg3)607 	ScatterDraw &PlotStyle(T1 arg1, T2 arg2, T3 arg3)		{return PlotStyle(new C(arg1, arg2, arg3));}
608 
609 	ScatterDraw &PlotStyle(int index, SeriesPlot *data);
PlotStyle(SeriesPlot * data)610 	ScatterDraw &PlotStyle(SeriesPlot *data)				{return PlotStyle(series.GetCount() - 1, data);}
611 	ScatterDraw &PlotStyle(int index, const String name);
PlotStyle(const String name)612 	ScatterDraw &PlotStyle(const String name)				{return PlotStyle(series.GetCount() - 1, name);}
613 	const String GetPlotStyleName(int index);
614 
NoPlot()615 	ScatterDraw &NoPlot()	{return PlotStyle();};
616 
617 	ScatterDraw &Stacked(bool _stacked = true)				{stacked = _stacked; return *this;}
618 
MarkStyle()619 	ScatterDraw &MarkStyle()								{return MarkStyle(0);}
620 	template <class C>
MarkStyle()621 	ScatterDraw &MarkStyle()								{return MarkStyle(new C());}
622 	template <class C, class T1>
MarkStyle(T1 arg1)623 	ScatterDraw &MarkStyle(T1 arg1)							{return MarkStyle(new C(arg1));}
624 	template <class C, class T1, class T2>
MarkStyle(T1 arg1,T2 arg2)625 	ScatterDraw &MarkStyle(T1 arg1, T2 arg2)				{return MarkStyle(new C(arg1, arg2));}
626 	template <class C, class T1, class T2, class T3>
MarkStyle(T1 arg1,T2 arg2,T3 arg3)627 	ScatterDraw &MarkStyle(T1 arg1, T2 arg2, T3 arg3)		{return MarkStyle(new C(arg1, arg2, arg3));}
628 
629 	ScatterDraw &MarkStyle(int index, MarkPlot *data);
MarkStyle(MarkPlot * data)630 	ScatterDraw &MarkStyle(MarkPlot *data)					{return MarkStyle(series.GetCount() - 1, data);}
631 	ScatterDraw &MarkStyle(int index, const String name);
632 	ScatterDraw &MarkStyle(int index, int typeidx);
MarkStyle(const String name)633 	ScatterDraw &MarkStyle(const String name)				{return MarkStyle(series.GetCount() - 1, name);}
634 	const String GetMarkStyleName(int index);
635 	ScatterDraw &SetMarkStyleType(int index, int type);
SetMarkStyleType(int type)636 	ScatterDraw &SetMarkStyleType(int type)					{return SetMarkStyleType(series.GetCount() - 1, type);}
637 	int GetMarkStyleType(int index);
638 
NoMark()639 	ScatterDraw &NoMark()	{return MarkStyle();};
640 
641 	ScatterDraw &Stroke(int index, double thickness, Color color);
642 	ScatterDraw &Stroke(double thickness, Color color = Null)   {return Stroke(series.GetCount() - 1, thickness, color);}
643 	ScatterDraw &SetLineColor(int index, Color color);
644 	void GetStroke(int index, double &thickness, Color &color);
645 	ScatterDraw &Closed(int index, bool closed);
Closed(bool closed)646 	ScatterDraw &Closed(bool closed)							{return Closed(series.GetCount() - 1, closed);}
647 	bool IsClosed(int index);
648 	ScatterDraw &BarWidth(int index, double width);
BarWidth(double width)649 	ScatterDraw &BarWidth(double width)							{return BarWidth(series.GetCount() - 1, width);}
650 	double GetBarWidth(int index);
651 	ScatterDraw &Dash(const char *dash);
652 	ScatterDraw &Dash(int index, const char *dash);
653 	ScatterDraw &NoDash();
654 	ScatterDraw &NoDash(int index);
655 	const String GetDash(int index);
656 	ScatterDraw &Fill(Color color = Null);
657 	ScatterDraw &MarkColor(Color color = Null);
658 	ScatterDraw &MarkBorderColor(Color color = Null);
659 	ScatterDraw &MarkWidth(double markWidth = 8);
660 	ScatterDraw &MarkBorderWidth(double markWidth = 1);
Hide()661 	ScatterDraw &Hide() {series[series.GetCount() - 1].opacity = 0;	return *this;}
662 
663 	ScatterDraw &ShowSeriesLegend(int index, bool show = false);
664 	ScatterDraw &ShowSeriesLegend(bool show = false)	{return ShowSeriesLegend(series.GetCount() - 1, show);}
GetShowSeriesLegend(int index)665 	bool GetShowSeriesLegend(int index)					{ASSERT(IsValid(index));ASSERT(!series[index].IsDeleted());return series[index].showLegend;}
NoSeriesLegend(int index)666 	ScatterDraw &NoSeriesLegend(int index)				{return ShowSeriesLegend(index, false);}
NoSeriesLegend()667 	ScatterDraw &NoSeriesLegend()						{return ShowSeriesLegend(false);}
668 
669 	ScatterDraw &Opacity(double opacity = 1) {series[series.GetCount() - 1].opacity = opacity;	return *this;}
670 	ScatterDraw &Legend(const String legend);
671 	ScatterDraw &Legend(int index, const String legend);
672 	const String &GetLegend(int index);
673 	ScatterDraw &Units(const String unitsY, const String unitsX = "");
674 	ScatterDraw &Units(int index, const String unitsY, const String unitsX = "");
675 	const String GetUnitsX(int index);
676 	const String GetUnitsY(int index);
677 
678 	ScatterDraw &LegendLine(bool b = true)              { series.Top().legendLine = b; return *this; }
679 
IsValid(int index)680 	inline bool IsValid(int index) const {return (index >= 0 && index < series.GetCount());}
681 
682 	ScatterDraw &SetDrawXReticle(bool set = true)  	{drawXReticle = set;	return *this;}
683 	ScatterDraw &SetDrawYReticle(bool set = true)  	{drawYReticle = set;	return *this;}
684 	ScatterDraw &SetDrawY2Reticle(bool set = true) 	{drawY2Reticle = set;	return *this;}
GetDrawXReticle()685 	bool GetDrawXReticle()							{return drawXReticle;}
GetDrawYReticle()686 	bool GetDrawYReticle()							{return drawYReticle;}
GetDrawY2Reticle()687 	bool GetDrawY2Reticle()							{return drawY2Reticle;}
688 	ScatterDraw &SetDrawXReticleNumbers(bool set = true) {drawXReticleNumbers = set;	return *this;}
689 	ScatterDraw &SetDrawYReticleNumbers(bool set = true) {drawYReticleNumbers = set;	return *this;}
690 	ScatterDraw &SetDrawY2ReticleNumbers(bool set = true){drawY2ReticleNumbers = set;	return *this;}
GetDrawXReticleNumbers()691 	bool GetDrawXReticleNumbers()					{return drawXReticleNumbers;}
GetDrawYReticleNumbers()692 	bool GetDrawYReticleNumbers()					{return drawYReticleNumbers;}
GetDrawY2ReticleNumbers()693 	bool GetDrawY2ReticleNumbers()					{return drawY2ReticleNumbers;}
SetReticleFont(const Font & fnt)694 	ScatterDraw &SetReticleFont(const Font &fnt)	{reticleFont = fnt;		return *this;}
GetReticleFont()695 	Font &GetReticleFont()							{return reticleFont;}
SetReticleColor(const Color & col)696 	ScatterDraw &SetReticleColor(const Color &col)	{reticleColor = col;	return *this;}
GetReticleColor()697 	Color &GetReticleColor()						{return reticleColor;}
698 
699 	ScatterDraw &SetFillColor(int index, const Color& color);
SetFillColor(const Color & color)700 	ScatterDraw &SetFillColor(const Color& color) {return SetFillColor(series.GetCount() - 1, color);}
701 	Color GetFillColor(int index) const;
702 
703 	ScatterDraw &SetMarkWidth(int index, double width);
SetMarkWidth(double width)704 	ScatterDraw &SetMarkWidth(double width) {return SetMarkWidth(series.GetCount() - 1, width);}
705 	double GetMarkWidth(int index);
706 	ScatterDraw &SetMarkColor(int index, const Color& pcolor);
SetMarkColor(const Color & pcolor)707 	ScatterDraw &SetMarkColor(const Color& pcolor) {return SetMarkColor(series.GetCount() - 1, pcolor);}
708 	Color GetMarkColor(int index) const;
709 	ScatterDraw &SetMarkBorderWidth(int index, double width);
710 	double GetMarkBorderWidth(int index);
711 	ScatterDraw &SetMarkBorderColor(int index, const Color& pcolor);
712 	Color GetMarkBorderColor(int index) const;
713 	void NoMark(int index);
714 	bool IsShowMark(int index);
715 
716 	void SetDataPrimaryY(int index, bool primary = true);
717 	ScatterDraw &SetDataPrimaryY(bool primary = true);
718 	void SetDataSecondaryY(int index, bool secondary = true);
719 	ScatterDraw &SetDataSecondaryY(bool secondary = true);
SetRightY(int index)720 	void SetRightY(int index)		{SetDataSecondaryY(index);}
SetRightY()721 	ScatterDraw &SetRightY()		{return SetDataSecondaryY();}
722 	bool IsDataPrimaryY(int index);
723 	bool ThereAreSecondaryY();
724 
725 	void SetSequentialX(int index, bool sequential);
726 	ScatterDraw &SetSequentialX(bool sequential = true);
727 	ScatterDraw &SetSequentialXAll(bool sequential = true);
728 	bool GetSequentialX(int index);
729 	bool GetSequentialX();
730 
731 	void Show(int index, bool show = true);
732 	bool IsVisible(int index);
733 	ScatterDraw &ShowAll(bool show = true);
734 
735 	bool RemoveSeries(int index);
736 	void RemoveAllSeries();
737 
738 	bool SwapSeries(int i1, int i2);
739 
740 	ScatterDraw& Id(int id);
741 	ScatterDraw& Id(int index, int id);
742 	int GetId(int index);
743 
744 	Drawing GetDrawing();
745 	Image GetImage();
746 
747 	#ifdef PLATFORM_WIN32
748 	void SaveAsMetafile(const char* file) const;
749 	#endif
750 
751 	ScatterDraw& SetMinZoom(double x, double y = -1) 	{return SetMinRange(x, y);}
752 	ScatterDraw& SetMaxZoom(double x, double y = -1) 	{return SetMaxRange(x, y);}
753 	ScatterDraw& SetMinRange(double x, double y = -1) 	{minXRange = x; minYRange = y; return *this;}
754 	ScatterDraw& SetMaxRange(double x, double y = -1) 	{maxXRange = x; maxYRange = y; return *this;}
SetMinXmin(double val)755 	ScatterDraw& SetMinXmin(double val)					{minXmin = val; return *this;}
SetMinYmin(double val)756 	ScatterDraw& SetMinYmin(double val)					{minYmin = val; return *this;}
SetMaxXmax(double val)757 	ScatterDraw& SetMaxXmax(double val)					{maxXmax = val; return *this;}
SetMaxYmax(double val)758 	ScatterDraw& SetMaxYmax(double val)					{maxYmax = val; return *this;}
759 
760 	ScatterDraw& SetFastViewX(bool set = true) 			{fastViewX = set;	return *this;}
GetFastViewX()761 	bool GetFastViewX() 								{return fastViewX;}
762 
763 	double GetXByPoint(double x);
764 	double GetYByPoint(double y);
765 	double GetY2ByPoint(double y);
766 	double GetXPointByValue(double x);
767 	double GetYPointByValue(double y);
768 
GetCount()769 	int GetCount() 	{return series.GetCount();}
IsEmpty()770 	bool IsEmpty()	{return series.IsEmpty();}
771 
772 	ScatterDraw& LinkedWith(ScatterDraw& ctrl);
773 	void Unlinked();
774 
GetMinX()775 	double GetMinX()			{return xMin;}
GetPlotWidth()776 	int GetPlotWidth()			{return plotW;}
GetPlotHeight()777 	int GetPlotHeight()			{return plotH;}
GetPosX(double x)778 	double GetPosX(double x)	{return plotW*(x - xMin)/xRange;}
GetSizeX(double cx)779 	double GetSizeX(double cx) 	{return plotW*cx/xRange;}
GetPosY(double y)780 	double GetPosY(double y)	{return plotH - plotH*(y - yMin)/yRange;}
GetSizeY(double cy)781 	double GetSizeY(double cy) 	{return plotH*cy/yRange;}
GetPosY2(double y)782 	double GetPosY2(double y)	{return plotH - plotH*(y - yMin2)/yRange2;}
GetSizeY2(double cy)783 	double GetSizeY2(double cy) {return plotH*cy/yRange2;}
784 
GetRealPosX(double x)785 	double GetRealPosX(double x) 	{return xMin + (x - hPlotLeft*plotScaleX)*xRange/plotW;}
GetRealPosY(double y)786 	double GetRealPosY(double y)	{return yMin + yRange - (y - plotScaleY*vPlotTop - titleHeight)*yRange/plotH;}
GetRealPosY2(double y)787 	double GetRealPosY2(double y)	{return yMin2 + yRange2 - (y - plotScaleY*vPlotTop - titleHeight)*yRange2/plotH;}
788 
GetScatterPosX(double x)789 	double GetScatterPosX(double x) {return (x - xMin)*plotW/xRange + hPlotLeft*plotScaleX;}
GetScatterPosY(double y)790 	double GetScatterPosY(double y) {return (yMin + yRange - y)*plotH/yRange + plotScaleY*vPlotTop + titleHeight;}
GetScatterPosY2(double y)791 	double GetScatterPosY2(double y){return (yMin2 + yRange2 - y)*plotH/yRange2 + plotScaleY*vPlotTop + titleHeight;}
GetScatterDistance(double dx,double dy)792 	double GetScatterDistance(double dx, double dy)  {return sqrt(sqr(GetScatterPosX(dx)) + sqr(GetScatterPosY(dy)));}
GetScatterDistance2(double dx,double dy)793 	double GetScatterDistance2(double dx, double dy) {return sqrt(sqr(GetScatterPosX(dx)) + sqr(GetScatterPosY2(dy)));}
794 
GetPixelThickX()795 	double GetPixelThickX()		{return xRange/plotW;}
GetPixelThickY()796 	double GetPixelThickY()		{return yRange/plotH;}
797 
798 	ScatterDraw& SetMouseHandling(bool valx = true, bool valy = false);
799 	ScatterDraw& SetMouseHandlingLinked(bool valx = true, bool valy = false);
GetMouseHandlingX()800 	bool GetMouseHandlingX()	{return mouseHandlingX;}
GetMouseHandlingY()801 	bool GetMouseHandlingY()	{return mouseHandlingY;}
802 
803 	ScatterDraw& AddSurf(DataSourceSurf &surf);
RemoveSurf()804 	ScatterDraw& RemoveSurf()					{surf = nullptr;	return *this;}
SetSurfMinZ(double val)805 	ScatterDraw& SetSurfMinZ(double val)		{surfMinZ = val;	return *this;}
GetSurfMinZ()806 	double GetSurfMinZ() const					{return surfMinZ;}
SetSurfMaxZ(double val)807 	ScatterDraw& SetSurfMaxZ(double val)		{surfMaxZ = val;	return *this;}
GetSurfMaxZ()808 	double GetSurfMaxZ() const					{return surfMaxZ;}
ZoomToFitZ()809 	ScatterDraw& ZoomToFitZ()					{surfMinZ = surf->MinZ();	surfMaxZ = surf->MaxZ(); return *this;}
810 
SurfNumColor(int num,bool cont)811 	ScatterDraw& SurfNumColor(int num, bool cont){surfNumColor = num; continuousColor = cont; return *this;}
SurfRainbow(RAINBOW val)812 	ScatterDraw& SurfRainbow(RAINBOW val)		{surfRainbow = val;  return *this;}
SurfRainbow()813 	RAINBOW SurfRainbow()						{return surfRainbow;}
814 
SurfUnits(const String & units)815 	ScatterDraw& SurfUnits(const String &units)	{surfUnits = units;	 return *this;}
816 	enum SURF_UNITS_POS {
817 		UNITS_TOP,
818 		UNITS_BOTTOM,
819 		UNITS_LEFT,
820 		UNITS_RIGHT
821 	};
SurfUnitsPos(SURF_UNITS_POS pos)822 	ScatterDraw& SurfUnitsPos(SURF_UNITS_POS pos)			{surfUnitsPos = pos;	return *this;}
823 	enum SURF_LEGEND_POS {
824 		LEGEND_LEFT,
825 		LEGEND_RIGHT
826 	};
SurfLegendPos(SURF_LEGEND_POS pos)827 	ScatterDraw& SurfLegendPos(SURF_LEGEND_POS pos)			{surfLegendPos = pos;	return *this;}
828 
829 	ScatterDraw& ShowRainbowPalette(bool show = true)		{showRainbow = show;	return *this;}
GetShowRainbowPalette()830 	bool GetShowRainbowPalette()							{return showRainbow;}
SetRainbowPalettePos(const Point & p)831 	ScatterDraw& SetRainbowPalettePos(const Point &p) 		{rainbowPos = p;		return *this;}
GetRainbowPalettePos()832 	Point& GetRainbowPalettePos() 							{return rainbowPos;}
SetRainbowPaletteSize(const Size & sz)833 	ScatterDraw& SetRainbowPaletteSize(const Size &sz) 		{rainbowSize = sz;		return *this;}
GetRainbowPaletteSize()834 	Size& GetRainbowPaletteSize() 							{return rainbowSize;}
SetRainbowPaletteAnchor(LEGEND_POS anchor)835 	ScatterDraw& SetRainbowPaletteAnchor(LEGEND_POS anchor) {rainbowAnchor = anchor;return *this;}
GetRainbowPaletteAnchor()836 	LEGEND_POS GetRainbowPaletteAnchor() 					{return rainbowAnchor;}
SetRainbowPaletteBorderColor(const Color & color)837 	ScatterDraw& SetRainbowPaletteBorderColor(const Color &color) 	{rainbowBorderColor = color;return *this;}
GetRainbowPaletteBorderColor()838 	Color& GetRainbowPaletteBorderColor() 					{return rainbowBorderColor;}
SetRainbowPaletteFont(const Font & fnt)839 	ScatterDraw& SetRainbowPaletteFont(const Font &fnt) 	{rainbowPaletteFont = fnt;return *this;}
GetRainbowPaletteFont()840 	Font& GetRainbowPaletteFont() 							{return rainbowPaletteFont;}
SetRainbowPaletteTextColor(const Color & color)841 	ScatterDraw& SetRainbowPaletteTextColor(const Color &color) 	{rainbowPaletteTextColor = color;return *this;}
GetRainbowPaletteTextColor()842 	Color& GetRainbowPaletteTextColor() 					{return rainbowPaletteTextColor;}
843 
844 	ScatterDraw &AddLabelSeries(Vector<String> &labels, int dx = 0, int dy = 0, Font font = StdFont(),
845 					Alignment align = ALIGN_CENTER, Color color = Black()) {
846 		int index = series.GetCount() - 1;
847 
848 		return AddLabelSeries(index, labels, dx, dy, font, align, color);
849 	}
850 	ScatterDraw& AddLabelSeries(int index, Vector<String> &labels, int dx = 0, int dy = 0, Font font = StdFont(),
851 					Alignment align = ALIGN_CENTER, Color color = Black()) {
852 		ASSERT(IsValid(index));
853 		ASSERT(!series[index].IsDeleted());
854 
855 		series[index].labels = &labels;
856 		series[index].labelsDx = dx;
857 		series[index].labelsDy = dy;
858 		series[index].labelsFont = font;
859 		series[index].labelsAlign = align;
860 		series[index].labelsColor = color;
861 		return *this;
862 	}
863 
SetDataSourceInternal()864 	ScatterDraw& SetDataSourceInternal() {
865 		for (int i = 0; i < series.GetCount(); ++i) {
866 			ScatterSeries &serie = series[i];
867 			if (serie.IsDeleted())
868 				continue;
869 			serie.SetDataSourceInternal();
870 		}
871 		return *this;
872 	}
873 	ScatterDraw& SerializeData(bool ser = true) {
874 		for (int i = 0; i < series.GetCount(); ++i) {
875 			ScatterSeries &serie = series[i];
876 			if (serie.IsDeleted())
877 				continue;
878 			serie.SerializeData(ser);
879 		}
880 		return *this;
881 	}
882 	ScatterDraw& SerializeFormat(bool ser = true) {
883 		for (int i = 0; i < series.GetCount(); ++i) {
884 			ScatterSeries &serie = series[i];
885 			if (serie.IsDeleted())
886 				continue;
887 			serie.SerializeFormat(ser);
888 		}
889 		serializeFormat = ser;
890 		return *this;
891 	}
892 
893 	template <class T>
Ize(T & io)894 	void Ize(T& io) {
895 		if (serializeFormat) {
896 			int intlegendAnchor = 0, intrainbowAnchor = 0, intsurfRainbow = 0, intsurfUnitsPos = 0, intsurfLegendPos = 0;
897 			if (io.IsStoring()) {
898 				intlegendAnchor = legendAnchor;
899 				intrainbowAnchor = rainbowAnchor;
900 				intsurfRainbow = surfRainbow;
901 				intsurfUnitsPos = surfUnitsPos;
902 				intsurfLegendPos = surfLegendPos;
903 			}
904 			io
905 				("title", title)
906 				("titleFont", titleFont)
907 				("titleColor", titleColor)
908 				("titleHeight", titleHeight)
909 				("xLabel_base", xLabel_base)
910 				("yLabel_base", yLabel_base)
911 				("yLabel2_base", yLabel2_base)
912 				("labelsFont", labelsFont)
913 				("labelsColor", labelsColor)
914 				("xRange", xRange)
915 				("yRange", yRange)
916 				("yRange2", yRange2)
917 				("xMin", xMin)
918 				("yMin", yMin)
919 				("yMin2", yMin2)
920 				("xMajorUnit", xMajorUnit)
921 				("yMajorUnit", yMajorUnit)
922 				("yMajorUnit2", yMajorUnit2)
923 				("xMinUnit", xMinUnit)
924 				("yMinUnit", yMinUnit)
925 				("yMinUnit2", yMinUnit2)
926 				("minXRange", minXRange)
927 				("maxXRange", maxXRange)
928 				("minYRange", minYRange)
929 				("maxYRange", maxYRange)
930 				("minXmin", minXmin)
931 				("minYmin", minYmin)
932 				("maxXmax", maxXmax)
933 				("maxYmax", maxYmax)
934 				("hPlotLeft", hPlotLeft)
935 				("hPlotRight", hPlotRight)
936 				("vPlotTop", vPlotTop)
937 				("vPlotBottom", vPlotBottom)
938 				("size", size)
939 				("responsive", responsive)
940 				("legendAnchor", intlegendAnchor)
941 				("legendPos", legendPos)
942 				("legendFillColor", legendFillColor)
943 				("legendBorderColor", legendBorderColor)
944 				("legendFont", legendFont)
945 				("legendNumCols", legendNumCols)
946 				("legendRowSpacing", legendRowSpacing)
947 				("series", series)
948 				("mouseHandlingX", mouseHandlingX)
949 				("mouseHandlingY", mouseHandlingY)
950 				("plotAreaColor", plotAreaColor)
951 				("drawXReticle", drawXReticle)
952 				("drawYReticle", drawYReticle)
953 				("drawY2Reticle", drawY2Reticle)
954 				("drawXReticleNumbers", drawXReticleNumbers)
955 				("drawYReticleNumbers", drawYReticleNumbers)
956 				("drawY2ReticleNumbers", drawY2ReticleNumbers)
957 				("axisWidth", axisWidth)
958 				("reticleFont", reticleFont)
959 				("reticleColor", reticleColor)
960 				("gridColor", gridColor)
961 				("gridWidth", gridWidth)
962 				("gridDash",  gridDash)
963 				("drawVGrid", drawVGrid)
964 				//("drawVGrid2", drawVGrid2)
965 				("drawHGrid", drawHGrid)
966 				//("drawHGrid2", drawHGrid2)
967 				//("freqGrid2", freqGrid2)
968 				("showRainbow", showRainbow)
969 				("rainbowPos", rainbowPos)
970 				("rainbowSize", rainbowSize)
971 				("rainbowAnchor", intrainbowAnchor)
972 				("rainbowBorderColor", rainbowBorderColor)
973 				("rainbowPaletteFont", rainbowPaletteFont)
974 				("rainbowPaletteTextColor", rainbowPaletteTextColor)
975 				("surfRainbow", intsurfRainbow)
976 				("surfNumColor", surfNumColor)
977 				("continuousColor", continuousColor)
978 				("surfMinZ", surfMinZ)
979 				("surfMaxZ", surfMaxZ)
980 				("surfUnits", surfUnits)
981 				("surfUnitsPos", intsurfUnitsPos)
982 				("surfLegendPos", intsurfLegendPos)
983 			;
984 			if (io.IsLoading()) {
985 				labelsChanged = true;
986 				legendAnchor = static_cast<LEGEND_POS>(intlegendAnchor);
987 				rainbowAnchor = static_cast<LEGEND_POS>(intrainbowAnchor);
988 				surfRainbow = static_cast<RAINBOW>(intsurfRainbow);
989 				surfUnitsPos = static_cast<SURF_UNITS_POS>(intsurfUnitsPos);
990 				surfLegendPos = static_cast<SURF_LEGEND_POS>(intsurfLegendPos);
991 			}
992 		} else
993 			io("series", series);
994 	}
995 
Xmlize(XmlIO & xml)996 	void Xmlize(XmlIO& xml) 	{Ize(xml);}
Jsonize(JsonIO & json)997 	void Jsonize(JsonIO& json) 	{Ize(json);}
998 
Serialize(Stream & s)999 	void Serialize(Stream& s) {
1000 		if (serializeFormat) {
1001 			int intlegendAnchor = 0, intrainbowAnchor = 0, intsurfRainbow = 0, intsurfUnitsPos = 0, intsurfLegendPos = 0;
1002 			if (s.IsStoring()) {
1003 				intlegendAnchor = legendAnchor;
1004 				intrainbowAnchor = rainbowAnchor;
1005 				intsurfRainbow = surfRainbow;
1006 				intsurfUnitsPos = surfUnitsPos;
1007 				intsurfLegendPos = surfLegendPos;
1008 			}
1009 			s 	% title
1010 				% titleFont
1011 				% titleColor
1012 				% titleHeight
1013 				% xLabel_base
1014 				% yLabel_base
1015 				% yLabel2_base
1016 				% labelsFont
1017 				% labelsColor
1018 				% xRange
1019 				% yRange
1020 				% yRange2
1021 				% xMin
1022 				% yMin
1023 				% yMin2
1024 				% xMajorUnit
1025 				% yMajorUnit
1026 				% yMajorUnit2
1027 				% xMinUnit
1028 				% yMinUnit
1029 				% yMinUnit2
1030 				% minXRange
1031 				% maxXRange
1032 				% minYRange
1033 				% maxYRange
1034 				% minXmin
1035 				% minYmin
1036 				% maxXmax
1037 				% maxYmax
1038 				% hPlotLeft
1039 				% hPlotRight
1040 				% vPlotTop
1041 				% vPlotBottom
1042 				% size
1043 				% intlegendAnchor
1044 				% legendPos
1045 				% legendFillColor
1046 				% legendBorderColor
1047 				% legendFont
1048 				% series
1049 				% mouseHandlingX
1050 				% mouseHandlingY
1051 				% plotAreaColor
1052 				% drawXReticle
1053 				% drawYReticle
1054 				% drawY2Reticle
1055 				% reticleFont
1056 				% reticleColor
1057 				% responsive
1058 				% showRainbow
1059 				% rainbowPos
1060 				% rainbowSize
1061 				% intrainbowAnchor
1062 				% rainbowBorderColor
1063 				% rainbowPaletteFont
1064 				% rainbowPaletteTextColor
1065 				% intsurfRainbow
1066 				% surfNumColor
1067 				% continuousColor
1068 				% surfMinZ
1069 				% surfMaxZ
1070 				% surfUnits
1071 				% intsurfUnitsPos
1072 				% intsurfLegendPos
1073 				% drawXReticleNumbers
1074 				% drawYReticleNumbers
1075 				% drawY2ReticleNumbers
1076 				% axisWidth
1077 			;
1078 			if (s.IsLoading()) {
1079 				labelsChanged = true;
1080 				legendAnchor = static_cast<LEGEND_POS>(intlegendAnchor);
1081 				rainbowAnchor = static_cast<LEGEND_POS>(intrainbowAnchor);
1082 				surfRainbow = static_cast<RAINBOW>(intsurfRainbow);
1083 				surfUnitsPos = static_cast<SURF_UNITS_POS>(intsurfUnitsPos);
1084 				surfLegendPos = static_cast<SURF_LEGEND_POS>(intsurfLegendPos);
1085 			}
1086 		} else
1087 			s % series;
1088 	}
1089 
VariableFormatX(double d)1090 	String VariableFormatX(double d) const  {return VariableFormat(xRange, d);}
VariableFormatY(double d)1091 	String VariableFormatY(double d) const  {return VariableFormat(yRange, d);}
VariableFormatY2(double d)1092 	String VariableFormatY2(double d) const {return VariableFormat(yRange2, d);}
VariableFormatZ(double d)1093 	String VariableFormatZ(double d) const  {return VariableFormat(GetSurfMaxZ()-GetSurfMinZ(), d);}
1094 
1095 protected:
1096 	ScatterDraw &_AddSeries(DataSource *data);
Refresh()1097 	virtual void Refresh() {};
1098 
1099 	int mode{MD_ANTIALIASED};
1100 	Color graphColor = White();
1101 	String title;
1102 	Upp::Font titleFont = Arial(20);
1103 	Color titleColor = SColorText();
1104 	int titleHeight;
1105 
1106 	String xLabel, yLabel, yLabel2;
1107 	String xLabel_base, yLabel_base, yLabel2_base;
1108 	Upp::Font labelsFont = GetStdFont();
1109 	Color labelsColor = SColorText();
1110 
1111 	int   hPlotLeft = 30, hPlotRight = 30,
1112 		  vPlotTop = 30, vPlotBottom = 30;
1113 	Color plotAreaColor = White();
1114 
1115 	bool fastViewX = false, sequentialXAll = false;
1116 
1117 	Color axisColor = SColorText();
1118 	double axisWidth = 0.5;
1119 
1120 	double xRange = 100., yRange = 100., yRange2 = 100.;
1121 	double xMin = 0, yMin = 0, yMin2 = 0;
1122 	double xMajorUnit = 10, yMajorUnit = 10, yMajorUnit2 = 10;
1123 	double xMajorUnitNum = 5, yMajorUnitNum = 5;
1124 	double xMinUnit = 0, yMinUnit = 0, yMinUnit2 = 0;
1125 	double xMinUnit0 = 0, yMinUnit0 = 0, yMinUnit20 = 0;
1126 	double minXRange = -1, maxXRange = -1, minYRange = -1, maxYRange = -1;
1127 	double minXmin = Null, minYmin = Null, maxXmax = Null, maxYmax = Null;
1128 	double lastxRange, lastyRange;
1129 	bool drawXReticle = true, drawYReticle = true, drawY2Reticle = false;
1130 	bool drawXReticleNumbers = true, drawYReticleNumbers = true, drawY2ReticleNumbers = false;
1131 	Font reticleFont = GetStdFont();
1132 	Color reticleColor = Black;
1133 
1134 	Color gridColor = SColorDkShadow();
1135 	double gridWidth = 0.5;
1136 	String gridDash = LINE_DOTTED_FINE;
1137 	bool drawVGrid = true, drawHGrid = true;
1138 
1139 	bool drawVGrid2, drawHGrid2;
1140 
1141 	int butDownX, butDownY;
1142 	bool isScrolling, isLabelPopUp;
1143 	ZoomStyle zoomStyleX = TO_CENTER,
1144 			  zoomStyleY = TO_CENTER;
1145 
1146 	Upp::Array<ScatterSeries> series;
1147 
1148 	bool showLegend = true;
1149 
1150 	bool isPolar = false;
1151 
1152 	int lastRefresh_sign;
1153 	int highlight_0 = Null;
1154 
1155 	Point legendPos = Point(5, 5);
1156 	int legendNumCols = 1;
1157 	LEGEND_POS legendAnchor = RIGHT_TOP;
1158 	int legendRowSpacing = 5;
1159 	Color legendFillColor = White();
1160 	Color legendBorderColor = Black();
1161 	Font legendFont = GetStdFont();
1162 
1163 	void DrawLegend(Draw& w) const;
1164 
1165 	void Scrolling(bool down, Point &pt, bool isOut = false);
1166 
ExpFormat(String & s,int,double d)1167 	static void ExpFormat(String& s, int , double d)	{s = FormatDoubleExp(d, 1);}
MonFormat(String & s,int,double d)1168 	static void MonFormat(String& s, int , double d)	{s = Format("%Mon", int(d));}
DyFormat(String & s,int,double d)1169 	static void DyFormat(String& s, int , double d)		{s = Format("%Dy", int(d));}
1170 
1171 	static String VariableFormat(double range, double d);
1172 
1173 	template<class T>
1174 	void Plot(T& w);
1175 	template<class T>
1176 	bool PlotTexts(T& w, bool boldX = false, bool boldY = false);
1177 
1178 	void AdjustMinUnitX();
1179 	void AdjustMinUnitY();
1180 	void AdjustMinUnitY2();
1181 
1182 	void AdjustMajorUnitX();
1183 	void AdjustMajorUnitY();
1184 	void AdjustMajorUnitY2();
1185 
1186 	bool PointInPlot(Point &pt);
1187 	bool PointInBorder(Point &pt);
1188 	bool PointInLegend(Point &pt);
1189 
1190 	Upp::Index<ScatterDraw *> linkedCtrls;
1191 	ScatterDraw *linkedMaster = nullptr;
1192 
ChangeMouseHandlingX()1193 	void ChangeMouseHandlingX()					{mouseHandlingX = !mouseHandlingX;}
ChangeMouseHandlingY()1194 	void ChangeMouseHandlingY()					{mouseHandlingY = !mouseHandlingY;}
1195 
1196 	bool mouseHandlingX = true, mouseHandlingY = true;
1197 
1198 	DataSourceSurf *surf = nullptr;
1199 	RAINBOW surfRainbow = BLUE_YELLOW_RED;
1200 	int surfNumColor = 4;
1201 	bool continuousColor = true;
1202 	double surfMinZ = Null, surfMaxZ = Null;
1203 	String surfUnits;
1204 	SURF_UNITS_POS surfUnitsPos = UNITS_TOP;
1205 	SURF_LEGEND_POS surfLegendPos = LEGEND_RIGHT;
1206 	//Vector<Pointf> isolines;
1207 	//int isolinesId;
1208 
1209 	bool showRainbow = true;
1210 	Point rainbowPos = Point(5, 5);
1211 	Size rainbowSize = Size(10, 50);
1212 	LEGEND_POS rainbowAnchor = RIGHT_BOTTOM;
1213 	Color rainbowBorderColor = Black;
1214 	Font rainbowPaletteFont = StdFont();
1215 	Color rainbowPaletteTextColor = Black;
1216 
1217 	void DrawRainbowPalette(Draw& w) const;
1218 
1219 private:
1220 	Size size{Size(800, 400)};		// Size to be used for all but screen painting
1221 	double plotScaleX = 1, plotScaleY = 1, plotScaleAvg = 1;
1222 	bool responsive = false;
1223 	double responsivenessFactor = 1;
1224 
1225 	static void ParseTextMultiline(const String &text, Upp::Font &fnt,
1226 								   Upp::Vector <String> &texts, Upp::Vector <Size> &sizes);
1227 
1228 	ScatterDraw &DoFitToData(bool horizontal, bool vertical, double factor);
1229 	//ScatterDraw &DoFitToData(bool horizontal, double minx, double maxx, bool vertical, double minxy, double maxy,
1230 	//				bool vertical2, double miny2, double maxy2, double factor = 0);
1231 	//ScatterDraw &DoFitToDataSmart(bool horizontal, double minx, double maxx, bool vertical, double minxy, double maxy,
1232 	//				bool vertical2, double miny2, double maxy2, double factor = 0);
1233 	void DoZoom(double scale, bool hor, bool ver);
1234 	void DoScroll(double factorX, double factorY);
1235 
1236 	void SetXYMinLinkedEach(double xmin, double xmin0, double ymin, double ymin0, double ymin2, double ymin20);
1237 	void SetRangeLinkedEach(double rx, double rx0, double ry, double ry0, double ry2, double ry20);
1238 
1239 	int NumSeriesLegend() const;
1240 
1241 	int plotW = Null, plotH = Null;
1242 	bool labelsChanged = false;
1243 	bool stacked = false;
1244 	bool serializeFormat = true;
1245 };
1246 
1247 template <class T>
SetDrawing(T & w,bool ctrl)1248 void ScatterDraw::SetDrawing(T& w, bool ctrl) {
1249 	w.DrawRect(size, graphColor);
1250 
1251 	titleHeight = !title.IsEmpty() ? fround(min(plotScaleX, plotScaleY)*(titleFont.GetHeight()+titleFont.GetDescent())) : 0;
1252 
1253 	plotW = size.cx - fround((hPlotLeft + hPlotRight)*plotScaleX);
1254 	plotH = size.cy - fround((vPlotTop + vPlotBottom)*plotScaleY) - titleHeight;
1255 
1256 	Plot(w);
1257 
1258 	if (!ctrl) {
1259 		if (!PlotTexts(w))
1260 			return;
1261 	}
1262 }
1263 
1264 template <class T>
PlotTexts(T & w,const bool boldX,bool boldY)1265 bool ScatterDraw::PlotTexts(T& w, const bool boldX, bool boldY) {
1266 	if(titleHeight > 0) {
1267 		Upp::Font fontTitle6;
1268 		fontTitle6 = titleFont;
1269 		fontTitle6.Height(titleHeight);
1270 		Size sz = GetTextSizeSpace(title, fontTitle6);
1271 		if (sz.cx > size.cx*0.95) {
1272 			fontTitle6.Height(fround((fontTitle6.GetHeight()+fontTitle6.GetDescent())*size.cx*(0.95/sz.cx)));
1273 			sz = GetTextSizeSpace(title, fontTitle6);
1274 		}
1275 		DrawText(w, fround((size.cx - sz.cx)/2.), plotScaleY*2, 0, title, fontTitle6, titleColor);
1276 	}
1277 	if(showLegend)
1278 		DrawLegend(w);
1279 
1280 	if (surf && showRainbow)
1281 		DrawRainbowPalette(w);
1282 
1283 	if (plotW < 0 || plotH < 0)
1284 		return false;
1285 
1286 	w.Offset(Point(fround(plotScaleX*hPlotLeft), fround(plotScaleY*vPlotTop + titleHeight)));
1287 
1288 	Upp::Font fontLabel = labelsFont;
1289 	fontLabel.Height(fround(min(plotScaleX, plotScaleY)*(labelsFont.GetHeight()+labelsFont.GetDescent())));
1290 	Upp::Font fontX = fontLabel;
1291 	if (boldX)
1292 		fontX.Bold();
1293 	Upp::Font fontY = fontLabel;
1294 	if (boldY)
1295 		fontY.Bold();
1296 	Upp::Font fontY2 = fontY;
1297 	fontY2.Italic();
1298 
1299 	if (labelsChanged) {
1300 		xLabel = xLabel_base;
1301 		yLabel = yLabel_base;
1302 		yLabel2 = yLabel2_base;
1303 		String yLabelLegends, yLabelLegends2;
1304 		Upp::Index<String> xUnits, yUnits, yUnits2;
1305 		for (int i = 0; i < series.GetCount(); ++i) {
1306 			const ScatterSeries &serie = series[i];
1307 			if (serie.IsDeleted() || serie.opacity == 0)
1308 				continue;
1309 			if (serie.primaryY) {
1310 				if (yLabel.IsEmpty()) {
1311 					if (!yLabelLegends.IsEmpty())
1312 						yLabelLegends << ";";
1313 					yLabelLegends << serie.legend;
1314 				}
1315 			} else {
1316 				if (yLabel2.IsEmpty()) {
1317 					if (!yLabelLegends2.IsEmpty())
1318 						yLabelLegends2 << ";";
1319 					yLabelLegends2 << serie.legend;
1320 				}
1321 			}
1322 			if (!serie.unitsX.IsEmpty())
1323 				xUnits.FindAdd(serie.unitsX);
1324 			if (!serie.unitsY.IsEmpty()) {
1325 				if (serie.primaryY)
1326 					yUnits.FindAdd(serie.unitsY);
1327 				else
1328 					yUnits2.FindAdd(serie.unitsY);
1329 			}
1330 		}
1331 		yLabel << yLabelLegends;
1332 		yLabel2 << yLabelLegends2;
1333 		if (xLabel.Find('[') < 0 && !xUnits.IsEmpty()) {
1334 			xLabel += " ";
1335 			for (int i = 0; i < xUnits.GetCount(); ++i)
1336 				xLabel += "[" + xUnits[i] + "]";
1337 		}
1338 		if (yLabel.Find('[') < 0 && !yUnits.IsEmpty()) {
1339 			yLabel += " ";
1340 			for (int i = 0; i < yUnits.GetCount(); ++i)
1341 				yLabel += "[" + yUnits[i] + "]";
1342 		}
1343 		if (yLabel2.Find('[') < 0 && !yUnits2.IsEmpty()) {
1344 			yLabel2 += " ";
1345 			for (int i = 0; i < yUnits2.GetCount(); ++i)
1346 				yLabel2 += "[" + yUnits2[i] + "]";
1347 		}
1348 		labelsChanged = false;
1349 	}
1350 	Size lx  = GetTextSizeSpace(xLabel, 	fontX);
1351 	Size ly  = GetTextSizeSpace(yLabel, 	fontY);
1352 	Size ly2 = GetTextSizeSpace(yLabel2, fontY2);
1353 	DrawText(w, (plotW - lx.cx)/2., plotH + plotScaleY*(vPlotBottom - 2) - lx.cy, 0, xLabel, fontX, labelsColor);
1354 	DrawText(w, plotScaleX*(2 - hPlotLeft), (plotH + ly.cx)/2., 900, yLabel,  fontY, labelsColor);
1355 	DrawText(w, size.cx - plotScaleX*(2 + hPlotLeft) - ly2.cy, (plotH + ly2.cx)/2., 900, yLabel2, fontY2, labelsColor);
1356 
1357 	drawXReticle  &= (xRange != 0  && xMajorUnit != 0);
1358 	drawYReticle  &= (yRange != 0  && yMajorUnit != 0);
1359 	drawY2Reticle &= (yRange2 != 0 && yMajorUnit != 0);
1360 	drawXReticleNumbers  &= (xRange != 0  && xMajorUnit != 0);
1361 	drawYReticleNumbers  &= (yRange != 0  && yMajorUnit != 0);
1362 	drawY2ReticleNumbers &= (yRange2 != 0 && yMajorUnit != 0);
1363 
1364 	Upp::Font standard6 = reticleFont;
1365 	standard6.Height(fround(min(plotScaleX, plotScaleY)*(standard6.GetHeight()+standard6.GetDescent())));
1366 	Upp::Font fontXNum = standard6;
1367 	if (boldX)
1368 		fontXNum.Bold();
1369 	Upp::Font fontYNum = standard6;
1370 	if (boldY)
1371 		fontYNum.Bold();
1372 	Upp::Font fontY2Num = fontYNum;
1373 	fontY2Num.Italic();
1374 
1375 	if (drawXReticle || drawXReticleNumbers) {
1376 		Vector<double> unitsX;
1377 		if (SetGridLinesX)
1378 			SetGridLinesX(unitsX);
1379 		else {
1380 			for(int i = 0; xMinUnit + i*xMajorUnit <= xRange; i++)
1381 				unitsX << xMinUnit + i*xMajorUnit;
1382 		}
1383 		double factorX = plotW/xRange;
1384 		for(int i = 0; i < unitsX.GetCount(); ++i) {
1385 			double reticleX = factorX*unitsX[i];
1386 			if (reticleX >=0 && reticleX <= plotW+0.001) {
1387 				double gridX = xMin + unitsX[i];
1388 				String gridLabelX;
1389 				if (cbModifFormatXGridUnits)
1390 					cbModifFormatXGridUnits(gridLabelX, i, gridX);
1391 				else if (cbModifFormatX)
1392 					cbModifFormatX(gridLabelX, i, gridX);
1393 				else
1394 					gridLabelX = VariableFormatX(gridX);
1395 
1396 				if (!gridLabelX.IsEmpty()) {
1397 					if (drawXReticleNumbers) {
1398 						Upp::Vector <String> texts;
1399 						Upp::Vector <Size> sizes;
1400 						ParseTextMultiline(gridLabelX, fontXNum, texts, sizes);
1401 						for (int ii = 0; ii < texts.GetCount(); ++ii) {
1402 							int cy = ii == 0 ? 0 : sizes[ii - 1].cy;
1403 							DrawText(w, reticleX - sizes[ii].cx/2.,
1404 										plotH + (4 + ii*cy), 0, texts[ii], fontXNum, reticleColor);
1405 						}
1406 					}
1407 					if (drawXReticle)
1408 						DrawLineOpa(w, reticleX, plotH, reticleX, plotH + plotScaleY*4, plotScaleAvg, 1, axisWidth, axisColor, LINE_SOLID);
1409 				}
1410 			}
1411 		}
1412 	}
1413 	if (drawYReticle || drawYReticleNumbers || drawY2ReticleNumbers) {
1414 		Vector<double> unitsY;
1415 		if (SetGridLinesY)
1416 			SetGridLinesY(unitsY);
1417 		else {
1418 			for(int i = 0; yMinUnit + i*yMajorUnit <= yRange; i++)
1419 				unitsY << yMinUnit + i*yMajorUnit;
1420 		}
1421 		double factorY = plotH/yRange;
1422 		for(int i = 0; i < unitsY.GetCount(); ++i) {
1423 			double reticleY = plotH - factorY*unitsY[i];
1424 			if (drawYReticle)
1425 				DrawLineOpa(w, -plotScaleX*4, reticleY, 0, reticleY, plotScaleAvg, 1, axisWidth, axisColor, LINE_SOLID);
1426 			if (drawY2Reticle)
1427 				DrawLineOpa(w, plotW+plotScaleX*4, reticleY, plotW, reticleY, plotScaleAvg, 1, axisWidth, axisColor, LINE_SOLID);
1428 			double gridY = yMin + unitsY[i];
1429 			if (drawYReticleNumbers) {
1430 				String gridLabelY;
1431 				if (cbModifFormatYGridUnits)
1432 					cbModifFormatYGridUnits(gridLabelY, i, gridY);
1433 				else if (cbModifFormatY)
1434 					cbModifFormatY(gridLabelY, i, gridY);
1435 				else
1436 					gridLabelY = VariableFormatY(gridY);
1437 				Size sz = GetTextSizeSpace(gridLabelY, fontYNum);
1438 				DrawText(w, -sz.cx - plotScaleX*6, reticleY - sz.cy/2, 0, gridLabelY, fontYNum, axisColor);
1439 			}
1440 			if (drawY2ReticleNumbers) {
1441 				double gridY2 = (gridY - yMin)/yRange*yRange2 + yMin2;
1442 				String gridLabelY2;
1443 				if (cbModifFormatY2GridUnits)
1444 					cbModifFormatY2GridUnits(gridLabelY2, i, gridY2);
1445 				else if (cbModifFormatY2)
1446 					cbModifFormatY2(gridLabelY2, i, gridY2);
1447 				else
1448 					gridLabelY2 = VariableFormatY2(gridY2);
1449 				Size sz = GetTextSizeSpace(gridLabelY2, fontY2Num);
1450 				DrawText(w, plotW + plotScaleX*10, reticleY - sz.cy/2, 0, gridLabelY2, fontY2Num, axisColor);
1451 			}
1452 		}
1453 	}
1454 	int borderWidth = fround(gridWidth*plotScaleAvg);
1455 #ifdef flagGUI		// Control highlight
1456 	if (!IsNull(highlight_0)) {
1457 		double delayFactor = 4*(1000. - (GetTickCount() - highlight_0))/1000.;
1458 		if (delayFactor < 1) {
1459 			delayFactor = 1;
1460 			highlight_0 = Null;
1461 		}
1462 		borderWidth = fround(delayFactor*borderWidth);
1463 	}
1464 #endif
1465 	DrawRectangle(w, 0, 0, plotW, plotH, 1, borderWidth, Black);
1466 
1467 	w.End();
1468 
1469 	return true;
1470 }
1471 
1472 template <class T>
Plot(T & w)1473 void ScatterDraw::Plot(T& w) {
1474 	if (plotW < 0 || plotH < 0)
1475 		return;
1476 
1477 	w.Offset(Point(fround(plotScaleX*hPlotLeft), fround(plotScaleY*vPlotTop + titleHeight)));
1478 	Clip(w, 0, 0, plotW, plotH);
1479 
1480 	double factorX = plotW/xRange;
1481 	double factorY = plotH/yRange;
1482 
1483 	double left, top, d = min(plotW, plotH);//, r = d/2.;
1484 	if (!isPolar) {
1485 		if (!surf)
1486 			w.DrawRect(0, 0, plotW, plotH, plotAreaColor);
1487 		else {
1488 			ImageBuffer out_image(plotW, plotH);
1489 			Upp::Fill(~out_image, plotAreaColor, out_image.GetLength());
1490 
1491 			double deltaz = surfMaxZ - surfMinZ;
1492 			if (deltaz == 0)
1493 				Upp::Fill(~out_image, GetRainbowColor(0, surfRainbow, 0), out_image.GetLength());
1494 			else {
1495 				CoWork co;
1496 				for (int ix = 0; ix < plotW; ++ix) {
1497 					co & [=, &out_image] {
1498 						for (int iy = 0; iy < plotH; ++iy) {
1499 							double x = xMin + (ix + 0.5)/factorX;
1500 							double y = yMin + (iy + 0.5)/factorY;
1501 							double z = surf->z(x, y);
1502 							if (!IsNull(z))
1503 								out_image[plotH - iy - 1][ix] = GetRainbowColor((z - surfMinZ)/deltaz,
1504 										surfRainbow, continuousColor ? 0 : surfNumColor);
1505 						}
1506 					};
1507 				}
1508 			}
1509 			w.DrawImage(0, 0, out_image);
1510 		}
1511 	} else {
1512 		if (plotW > plotH) {
1513 			left = (plotW - d)/2.;
1514 			top = 0;
1515 		} else {
1516 			left = 0;
1517 			top = (plotH - d)/2.;
1518 		}
1519 		w.DrawEllipse(fround(left), fround(top), fround(d), fround(d), plotAreaColor);
1520 	}
1521 
1522 	if (drawVGrid) {
1523 		if (!isPolar) {
1524 			Vector<double> unitsX;
1525 			if (SetGridLinesX)
1526 				SetGridLinesX(unitsX);
1527 			else {
1528 				if (xMajorUnit > 0) {
1529 					for(int i = 0; xMinUnit + i*xMajorUnit <= xRange; i++)
1530 						unitsX << xMinUnit + i*xMajorUnit;
1531 				}
1532 			}
1533 			if (unitsX.GetCount() > 0) {
1534 				for(int i = 0; i < unitsX.GetCount(); i++) {
1535 					double reticleX = factorX*unitsX[i];
1536 					if (reticleX >=0 && reticleX <= plotW) {
1537 						if (gridDash.GetCount() == 1 && gridDash[0] == '-') {
1538 							DrawLineOpa(w, reticleX, 0, reticleX, 8*plotScaleAvg, plotScaleAvg, 1, gridWidth, gridColor, LINE_SOLID);
1539 							DrawLineOpa(w, reticleX, plotH-8*plotScaleAvg, reticleX, plotH, plotScaleAvg, 1, gridWidth, gridColor, LINE_SOLID);
1540 						} else
1541 							DrawLineOpa(w, reticleX, 0, reticleX, plotH, plotScaleAvg, 1, gridWidth, gridColor, gridDash);
1542 					}
1543 				}
1544 			}
1545 		} /*else {
1546 			double ang0 = 2*M_PI*xMinUnit/xRange;
1547 			for(double i = 0; xMinUnit + i*xMajorUnit < xRange; i++) {
1548 				double ang = ang0 + i*2*M_PI*xMajorUnit/xRange;
1549 				DrawLineOpa(w, x_c, y_c, x_c + r*cos(ang), y_c + r*sin(ang), plotScaleAvg, 1, gridWidth*plotScaleAvg, gridColor, gridDash);
1550 			}
1551 		}*/
1552 	}
1553 	if (drawHGrid) {
1554 		if (!isPolar) {
1555 			Vector<double> unitsY;
1556 			if (SetGridLinesY)
1557 				SetGridLinesY(unitsY);
1558 			else {
1559 				if (yMajorUnit > 0) {
1560 					for(int i = 0; yMinUnit + i*yMajorUnit <= yRange; i++)
1561 						unitsY << yMinUnit + i*yMajorUnit;
1562 				}
1563 			}
1564 			if (unitsY.GetCount() > 0) {
1565 				for(int i = 0; i < unitsY.GetCount(); i++) {
1566 					double reticleY = plotH - factorY*unitsY[i];
1567 					if (reticleY > 2*gridWidth*plotScaleAvg && reticleY < plotH - 2*gridWidth*plotScaleAvg) {
1568 						if (gridDash.GetCount() == 1 && gridDash[0] == '-') {
1569 							DrawLineOpa(w, 0, reticleY, 8*plotScaleAvg, reticleY, plotScaleAvg, 1, gridWidth, gridColor, LINE_SOLID);
1570 							DrawLineOpa(w, plotW-8*plotScaleAvg, reticleY, plotW, reticleY, plotScaleAvg, 1, gridWidth, gridColor, LINE_SOLID);
1571 						} else
1572 							DrawLineOpa(w, 0, reticleY, plotW, reticleY, plotScaleAvg, 1, gridWidth, gridColor, gridDash);
1573 					}
1574 				}
1575 			}
1576 		} /*else {
1577 			double y0 = -plotH*yMinUnit/r + plotH;
1578 			for(double i = 0; yMinUnit + i*yMajorUnit < yRange; i++) {
1579 				double reticleY = y0 + i*r*yRange/yMajorUnit;
1580 				DrawCircleOpa(w, plotW/2, plotH/2, reticleY, 1, 1, gridWidth, gridColor, gridDash);
1581 			}
1582 		}*/
1583 	}
1584 
1585 	try {
1586 		for (int j = 0; j < series.GetCount(); j++) {
1587 			ScatterSeries &serie = series[j];
1588 			if (serie.IsDeleted())
1589 				continue;
1590 			DataSource &data = serie.Data();
1591 			if (serie.opacity == 0 || (!serie.seriesPlot && !serie.markPlot))
1592 				continue;
1593 			if (!data.IsExplicit() && data.GetCount() == 0)
1594 				continue;
1595 			if (data.IsExplicit() && IsNull(data.GetCount()))
1596 				continue;
1597 			Vector<Pointf> points;
1598 			if (data.IsParam()) {
1599 				double xmin = 0;
1600 				double xmax = double(data.GetCount());
1601 				for (double x = xmin; x <= xmax; x++) {
1602 					double xx = data.x(x);
1603 					double yy = data.y(x);
1604 					if (IsNull(xx) || IsNull(yy))
1605 						points << Null;
1606 					else {
1607 						int ix = fround(plotW*(xx - xMin)/xRange);
1608 						int iy;
1609 						if (serie.primaryY)
1610 							iy = fround(plotH*(yy - yMin)/yRange);
1611 						else
1612 							iy = fround(plotH*(yy - yMin2)/yRange2);
1613 						points << Point(ix, plotH - iy);
1614 					}
1615 				}
1616 			} else if (data.IsExplicit()) {
1617 				double xmin = xMin - 1;
1618 				double xmax = xMin + xRange + 1;
1619 				double dx = double(xmax - xmin)/plotW;
1620 				for (double xx = xmin; xx < xmax; xx += dx) {
1621 					double yy = data.f(xx);
1622 					if (IsNull(yy))
1623 						points << Null;
1624 					else {
1625 						int ix = fround(plotW*(xx - xMin)/xRange);
1626 						int iy;
1627 						if (serie.primaryY)
1628 							iy = fround(plotH*(yy - yMin)/yRange);
1629 						else
1630 							iy = fround(plotH*(yy - yMin2)/yRange2);
1631 						points << Point(ix, plotH - iy);
1632 					}
1633 				}
1634 			} else {
1635 				int64 imin, imax;
1636 				if (serie.sequential) {
1637 					imin = imax = Null;
1638 					for (int64 i = 0; i < data.GetCount(); ++i) {
1639 						double xx = data.x(i);
1640 						if (!IsNull(xx)) {
1641 							if (IsNull(imin)) {
1642 								if (xx >= xMin)
1643 									imin = i;
1644 							}
1645 							if (IsNull(imax)) {
1646 								if (xx >= xMin + xRange)
1647 									imax = i;
1648 							}
1649 						}
1650 					}
1651 					if (IsNull(imin))
1652 					    imin = 0;
1653 					if (IsNull(imax))
1654 					    imax = data.GetCount() - 1;
1655 				} else {
1656 					imin = 0;
1657 					imax = data.GetCount() - 1;
1658 				}
1659 				if (fastViewX) {
1660 					double dxpix = (data.x(imax) - data.x(imin))/plotW;
1661 					int npix = 1;
1662 					for (int64 i = imin; i <= imax; ) {
1663 						double yy = data.y(i);
1664 						if (IsNull(yy)) {
1665 							++i;
1666 							continue;
1667 						}
1668 						int64 ii;
1669 						double maxv = data.x(imin) + dxpix*npix;
1670 						double maxY = yy, minY = yy;
1671 						for (ii = 1; i + ii < imax && data.x(i + ii) < maxv; ++ii) {
1672 							double dd = data.y(i + ii);
1673 							if (IsNull(dd))
1674 								continue;
1675 							maxY = max(maxY, dd);
1676 							minY = min(minY, dd);
1677 						}
1678 						double xx = data.x(i);
1679 						if (IsNull(xx)) {
1680 							++i;
1681 							continue;
1682 						}
1683 						i += ii;
1684 						npix++;
1685 						int ix = fround(plotW*(xx - xMin)/xRange);
1686 						int iMax, iMin;
1687 						if (serie.primaryY) {
1688 							iMax = fround(plotH*(maxY - yMin)/yRange);
1689 							iMin = fround(plotH*(minY - yMin)/yRange);
1690 						} else {
1691 							iMax = fround(plotH*(maxY - yMin2)/yRange2);
1692 							iMin = fround(plotH*(minY - yMin2)/yRange2);
1693 						}
1694 						points << Point(ix, plotH - iMax);
1695 						if (iMax != iMin)
1696 							points << Point(ix, plotH - iMin);
1697 					}
1698 				} else {
1699 					for (int64 i = imin; i <= imax; ) {
1700 						double xx = data.x(i);
1701 						double yy = data.y(i);
1702 						++i;
1703 						if (IsNull(xx) || IsNull(yy))
1704 							points << Null;
1705 						else {
1706 							int ix = fround(plotW*(xx - xMin)/xRange);
1707 							int iy;
1708 							if (serie.primaryY)
1709 								iy = fround(plotH*(yy - yMin)/yRange);
1710 							else
1711 								iy = fround(plotH*(yy - yMin2)/yRange2);
1712 							points << Point(ix, plotH - iy);
1713 						}
1714 					}
1715 				}
1716 			}
1717 			if (!points.IsEmpty() && serie.seriesPlot && serie.thickness > 0)
1718 				serie.seriesPlot->Paint(w, points, plotScaleAvg, serie.opacity,
1719 											serie.thickness, serie.color,
1720 											serie.dash, plotAreaColor, serie.fillColor, plotW/xRange, plotH/yRange,
1721 											plotH*(1 + yMin/yRange), serie.barWidth,
1722 											serie.isClosed);
1723 
1724 			if (serie.markWidth >= 1 && serie.markPlot) {
1725 				if (!serie.markPlot->IsMultiPlot()) {
1726 					for (int i = 0; i < points.GetCount(); i++)
1727 						serie.markPlot->Paint(w, plotScaleAvg, points[i],
1728 							serie.markWidth, serie.markColor,
1729 							serie.markBorderWidth, serie.markBorderColor);
1730 				} else {
1731 					for (int64 i = 0; i < data.GetCount(); ++i) {
1732 						int ix = fround(plotW*(data.x(i) - xMin)/xRange);
1733 						int iy;
1734 						if (serie.primaryY)
1735 							iy = plotH - fround(plotH*(data.y(i) - yMin)/yRange);
1736 						else
1737 							iy = plotH - fround(plotH*(data.y(i) - yMin2)/yRange2);
1738 						Vector<int> dataX, dataY;
1739 						Vector<double> dataFixed;
1740 						for (int ii = 0; ii < data.GetznxCount(i); ++ii)
1741 							dataX << fround(plotW*(data.znx(ii, i) - xMin)/xRange);
1742 						if (serie.primaryY) {
1743 							for (int ii = 0; ii < data.GetznyCount(i); ++ii)
1744 								dataY << (plotH - fround(plotH*(data.zny(ii, i) - yMin)/yRange));
1745 						} else {
1746 							for (int ii = 0; ii < data.GetznyCount(i); ++ii)
1747 								dataY << (plotH - fround(plotH*(data.zny(ii, i) - yMin2)/yRange2));
1748 						}
1749 						for (int ii = 0; ii < data.GetznFixedCount(); ++ii)
1750 							dataFixed << data.znFixed(ii, i);
1751 						serie.markPlot->Paint(w, plotScaleAvg, ix, iy, dataX, dataY, dataFixed,
1752 							serie.markWidth, serie.markColor,
1753 							serie.markBorderWidth, serie.markBorderColor);
1754 					}
1755 				}
1756 			}
1757 			if (serie.labels) {
1758 				int dx = int(serie.labelsDx*plotScaleX);
1759 				int dy = int(serie.labelsDy*plotScaleY);
1760 				Font fnt = serie.labelsFont;
1761 				fnt.Height(int((fnt.GetHeight() + fnt.GetDescent())*min(plotScaleX, plotScaleY)));
1762 				for (int i = 0; i < points.GetCount() && i < serie.labels->GetCount(); i++) {
1763 					String txt = (*(serie.labels))[i];
1764 					Size sz = GetTextSizeSpace(txt, fnt);
1765 					int ddy = static_cast<int>(-sz.cy/2.);
1766 					int ddx = 0;
1767 					switch (serie.labelsAlign) {
1768 					case ALIGN_LEFT:	ddx = 0;		break;
1769 					case ALIGN_CENTER:	ddx = -sz.cx/2;	break;
1770 					case ALIGN_RIGHT:	ddx = -sz.cx;	break;
1771 					default: 			NEVER();
1772 					}
1773 					double x = points[i].x + dx + ddx;
1774 					double y = points[i].y + dy + ddy;
1775 					DrawText(w, x, y, 0, txt, fnt, serie.labelsColor);
1776 				}
1777 			}
1778 		}
1779 	} catch(ValueTypeError error) {
1780 		ASSERT_(true, error);
1781 	}
1782 
1783 	WhenPaint(w);
1784 	ClipEnd(w);
1785 	w.End();
1786 }
1787 
1788 }
1789 
1790 #endif
1791 
1792