1 #include "ScatterDraw.h"
2 
3 namespace Upp {
4 
ScatterDraw()5 ScatterDraw::ScatterDraw() {
6 	lastxRange = xRange;
7 	lastyRange = yRange;
8 }
9 
debug_h()10 void debug_h() {
11 	;			// It does nothing. It just serves to set a breakpoint in templated functions
12 }
13 
SetColor(const Color & _color)14 ScatterDraw& ScatterDraw::SetColor(const Color& _color) {
15 	graphColor = _color;
16 	return *this;
17 }
18 
SetTitle(const String & _title)19 ScatterDraw& ScatterDraw::SetTitle(const String& _title) {
20 	title = _title;
21 	return *this;
22 }
23 
GetTitle()24 const String& ScatterDraw::GetTitle() {
25 	return title;
26 }
27 
SetTitleFont(const Font & fontTitle)28 ScatterDraw& ScatterDraw::SetTitleFont(const Font& fontTitle) {
29 	titleFont = fontTitle;
30 	return *this;
31 }
32 
SetTitleColor(const Color & colorTitle)33 ScatterDraw& ScatterDraw::SetTitleColor(const Color& colorTitle) {
34 	titleColor = colorTitle;
35 	return *this;
36 }
37 
SetLabels(const String & _xLabel,const String & _yLabel,const String & _yLabel2)38 ScatterDraw& ScatterDraw::SetLabels(const String& _xLabel, const String& _yLabel, const String& _yLabel2) {
39 	xLabel_base = _xLabel;
40 	yLabel_base = _yLabel;
41 	yLabel2_base = _yLabel2;
42 	labelsChanged = true;
43 	return *this;
44 }
45 
SetLabelX(const String & _xLabel)46 ScatterDraw& ScatterDraw::SetLabelX(const String& _xLabel) {
47 	xLabel_base = _xLabel;
48 	labelsChanged = true;
49 	return *this;
50 }
51 
SetLabelY(const String & _yLabel)52 ScatterDraw& ScatterDraw::SetLabelY(const String& _yLabel) {
53 	yLabel_base = _yLabel;
54 	labelsChanged = true;
55 	return *this;
56 }
57 
SetLabelY2(const String & _yLabel)58 ScatterDraw& ScatterDraw::SetLabelY2(const String& _yLabel) {
59 	yLabel2_base = _yLabel;
60 	labelsChanged = true;
61 	return *this;
62 }
63 
SetLabelsFont(const Font & fontLabels)64 ScatterDraw& ScatterDraw::SetLabelsFont(const Font& fontLabels) {
65 	labelsFont = fontLabels;
66 	return *this;
67 }
68 
SetLabelsColor(const Color & colorLabels)69 ScatterDraw& ScatterDraw::SetLabelsColor(const Color& colorLabels) {
70 	labelsColor = colorLabels;
71 	return *this;
72 }
73 
SetPlotAreaMargin(int hLeft,int hRight,int vTop,int vBottom)74 ScatterDraw& ScatterDraw::SetPlotAreaMargin(int hLeft, int hRight, int vTop, int vBottom) {
75 	hPlotLeft   = hLeft;
76 	hPlotRight  = hRight;
77 	vPlotTop    = vTop;
78 	vPlotBottom = vBottom;
79 	return *this;
80 }
81 
SetPlotAreaLeftMargin(int margin)82 ScatterDraw& ScatterDraw::SetPlotAreaLeftMargin(int margin) {
83 	hPlotLeft = margin;
84 	return *this;
85 }
86 
SetPlotAreaRightMargin(int margin)87 ScatterDraw& ScatterDraw::SetPlotAreaRightMargin(int margin) {
88 	hPlotRight = margin;
89 	return *this;
90 }
91 
SetPlotAreaTopMargin(int margin)92 ScatterDraw& ScatterDraw::SetPlotAreaTopMargin(int margin) {
93 	vPlotTop = margin;
94 	return *this;
95 }
96 
SetPlotAreaBottomMargin(int margin)97 ScatterDraw& ScatterDraw::SetPlotAreaBottomMargin(int margin) {
98 	vPlotBottom = margin;
99 	return *this;
100 }
101 
SetPlotAreaColor(const Color & p_a_color)102 ScatterDraw& ScatterDraw::SetPlotAreaColor(const Color& p_a_color) {
103 	plotAreaColor = p_a_color;
104 	return *this;
105 }
106 
SetAxisColor(const Color & axis_color)107 ScatterDraw& ScatterDraw::SetAxisColor(const Color& axis_color) {
108 	axisColor = axis_color;
109 	return *this;
110 }
111 
SetAxisWidth(double axis_width)112 ScatterDraw& ScatterDraw::SetAxisWidth(double axis_width) {
113 	axisWidth = axis_width;
114 	return *this;
115 }
116 
ShowHGrid(bool show)117 ScatterDraw& ScatterDraw::ShowHGrid(bool show) {
118 	drawHGrid = show;
119 	return *this;
120 }
121 
122 /*ScatterDraw& ScatterDraw::ShowHGrid2(bool show) {
123 	drawHGrid2 = show;
124 	return *this;
125 }*/
126 
ShowVGrid(bool show)127 ScatterDraw& ScatterDraw::ShowVGrid(bool show) {
128 	drawVGrid = show;
129 	return *this;
130 }
131 
132 /*ScatterDraw& ScatterDraw::ShowVGrid2(bool show) {
133 	drawVGrid2 = show;
134 	return *this;
135 }
136 
137 ScatterDraw& ScatterDraw::FreqGrid2(double freq) {
138 	freqGrid2 = freq;
139 	return *this;
140 }*/
141 
PointInPlot(Point & pt)142 bool ScatterDraw::PointInPlot(Point &pt)
143 {
144 	return 	hPlotLeft*plotScaleX <= pt.x && pt.x <= (GetSize().cx - hPlotRight*plotScaleX) &&
145 		  	(vPlotTop*plotScaleY + titleHeight) <= pt.y && pt.y <= (GetSize().cy - vPlotBottom*plotScaleY);
146 }
147 
PointInBorder(Point & pt)148 bool ScatterDraw::PointInBorder(Point &pt)
149 {
150 	return !PointInPlot(pt);
151 }
152 
PointInLegend(Point &)153 bool ScatterDraw::PointInLegend(Point &)
154 {
155 	return false;
156 }
157 
AdjustMinUnitX()158 void ScatterDraw::AdjustMinUnitX() {
159 	if (SetGridLinesX)
160 		return;
161 	xMinUnit = xMinUnit0;
162 	if (xMajorUnit > 0) {
163 		if (xMinUnit < 0)
164 			xMinUnit += (fabs(floor(xMinUnit/xMajorUnit)))*xMajorUnit;
165 		else if (xMinUnit >= xMajorUnit)
166 			xMinUnit -= (fabs(floor(xMinUnit/xMajorUnit)))*xMajorUnit;
167 	}
168 }
169 
AdjustMinUnitY()170 void ScatterDraw::AdjustMinUnitY() {
171 	if (SetGridLinesY)
172 		return;
173 	yMinUnit = yMinUnit0;
174 	if (yMajorUnit > 0) {
175 		if (yMinUnit < 0)
176 			yMinUnit += (fabs(ceil(yMinUnit/yMajorUnit)) + 1)*yMajorUnit;
177 		else if (yMinUnit >= yMajorUnit)
178 			yMinUnit -= (fabs(floor(yMinUnit/yMajorUnit)))*yMajorUnit;
179 	}
180 }
181 
AdjustMinUnitY2()182 void ScatterDraw::AdjustMinUnitY2() {
183 	if (SetGridLinesY)
184 		return;
185 	yMinUnit2 = yMinUnit20;
186 	if (yMajorUnit2 > 0) {
187 		if (yMinUnit2 < 0)
188 			yMinUnit2 += (fabs(ceil(yMinUnit2/yMajorUnit2)) + 1)*yMajorUnit2;
189 		else if (yMinUnit2 >= yMajorUnit2)
190 			yMinUnit2 -= (fabs(floor(yMinUnit2/yMajorUnit2)))*yMajorUnit2;
191 	}
192 }
193 
AdjustMajorUnitX()194 void ScatterDraw::AdjustMajorUnitX() {
195 	if (xMajorUnit == 0 || IsNull(xMajorUnit))
196 		return;
197 	while (xRange/xMajorUnit > 1.2*xMajorUnitNum)
198 		xMajorUnit *= 2;
199 	while (xRange/xMajorUnit < xMajorUnitNum/1.5)
200 		xMajorUnit /= 2;
201 }
202 
AdjustMajorUnitY()203 void ScatterDraw::AdjustMajorUnitY() {
204 	if (yMajorUnit == 0 || IsNull(yMajorUnit))
205 		return;
206 	while (yRange/yMajorUnit > 1.2*yMajorUnitNum)
207 		yMajorUnit *= 2;
208 	while (yRange/yMajorUnit < yMajorUnitNum/1.5)
209 		yMajorUnit /= 2;
210 }
211 
AdjustMajorUnitY2()212 void ScatterDraw::AdjustMajorUnitY2() {
213 	if (yMajorUnit2 == 0 || IsNull(yMajorUnit2))
214 		return;
215 	while (yRange2/yMajorUnit2 > 1.2*yMajorUnitNum)
216 		yMajorUnit2 *= 2;
217 	while (yRange2/yMajorUnit2 < yMajorUnitNum/1.5)
218 		yMajorUnit2 /= 2;
219 }
220 
SetRange(double rx,double ry,double ry2)221 ScatterDraw &ScatterDraw::SetRange(double rx, double ry, double ry2) {
222 	ASSERT(IsNull(rx) || rx  > 0);
223 	ASSERT(IsNull(ry) || ry  > 0);
224 	ASSERT(IsNull(ry2)|| ry2 > 0);
225 
226 	if (!IsNull(rx)) {
227 		xRange = rx;
228 		AdjustMajorUnitX();
229 		AdjustMinUnitX();
230 	}
231 	if (!IsNull(ry)) {
232 		yRange = ry;
233 		AdjustMajorUnitY();
234 		AdjustMinUnitY();
235 	}
236 	if (!IsNull(ry2)) {
237 		yRange2 = ry2;
238 		AdjustMajorUnitY2();
239 		AdjustMinUnitY2();
240 	}
241 	WhenSetRange();
242 	return *this;
243 }
244 
SetMajorUnits(double ux,double uy)245 ScatterDraw &ScatterDraw::SetMajorUnits(double ux, double uy) {
246 	if (!IsNull(ux)) {
247 		xMajorUnit = ux;
248 		xMajorUnitNum = int(xRange/ux);
249 		AdjustMinUnitX();
250 	}
251 	if (!IsNull(uy)) {
252 		yMajorUnit = uy;
253 		yMajorUnit2 = yMajorUnit*yRange2/yRange;
254 		yMajorUnitNum = int(yRange/uy);
255 		AdjustMinUnitY();
256 		AdjustMinUnitY2();
257 	}
258 	return *this;
259 }
260 
SetMajorUnitsNum(int nx,int ny)261 ScatterDraw &ScatterDraw::SetMajorUnitsNum(int nx, int ny) {
262 	if (!IsNull(nx)) {
263 		xMajorUnitNum = nx;
264 		xMajorUnit = xRange/nx;
265 		AdjustMinUnitX();
266 	}
267 	if (!IsNull(ny)) {
268 		yMajorUnitNum = ny;
269 		yMajorUnit = yRange/ny;
270 		yMajorUnit2 = yMajorUnit*yRange2/yRange;
271 		AdjustMinUnitY();
272 		AdjustMinUnitY2();
273 	}
274 	return *this;
275 }
276 
SetMinUnits(double ux,double uy)277 ScatterDraw &ScatterDraw::SetMinUnits(double ux, double uy) {
278 	if (!IsNull(ux))
279 		xMinUnit = xMinUnit0 = ux;
280 	if (!IsNull(uy)) {
281 		yMinUnit = yMinUnit0 = uy;
282 		yMinUnit2 = yMinUnit20 = yRange2*yMinUnit/yRange;
283 	}
284 	if (!IsNull(ux))
285 		AdjustMinUnitX();
286 	if (!IsNull(uy)) {
287 		AdjustMinUnitY();
288 		AdjustMinUnitY2();
289 	}
290 	return *this;
291 }
292 
SetXYMin(double xmin,double ymin,double ymin2)293 ScatterDraw &ScatterDraw::SetXYMin(double xmin, double ymin, double ymin2) {
294 	if (!IsNull(xmin))
295 		xMin = xmin;
296 	if (!IsNull(ymin))
297 		yMin = ymin;
298 	if (!IsNull(ymin2))
299 		yMin2 = ymin2;
300 	WhenSetXYMin();
301 	return *this;
302 }
303 
ZoomToFit(bool horizontal,bool vertical,double factor)304 ScatterDraw &ScatterDraw::ZoomToFit(bool horizontal, bool vertical, double factor) {
305 	if (linkedMaster) {
306 		linkedMaster->ZoomToFit(horizontal, vertical, factor);
307 		return *this;
308 	}
309 	DoFitToData(horizontal, vertical, factor);
310 	if (!linkedCtrls.IsEmpty()) {
311 		for (int i = 0; i < linkedCtrls.GetCount(); ++i)
312 	    	linkedCtrls[i]->DoFitToData(horizontal, vertical, factor);
313 	}
314 	WhenZoomToFit();
315 	return *this;
316 }
317 
DoFitToData(bool horizontal,bool vertical,double factor)318 ScatterDraw &ScatterDraw::DoFitToData(bool horizontal, bool vertical, double factor) {
319 	double minx, maxx, miny, miny2, maxy, maxy2;
320 	minx = miny = miny2 = -DOUBLE_NULL;
321 	maxx = maxy = maxy2 = DOUBLE_NULL;
322 
323 	try {
324 		if (horizontal) {
325 			for (int j = 0; j < series.GetCount(); j++) {
326 				ScatterSeries &serie = series[j];
327 				if (serie.IsDeleted() || serie.opacity == 0 || serie.Data().IsExplicit())
328 					continue;
329 				double mn = serie.Data().MinX();
330 				if (!IsNull(mn))
331 					minx = min(minx, mn);
332 				double mx = serie.Data().MaxX();
333 				if (!IsNull(mx))
334 					maxx = max(maxx, mx);
335 			}
336 			if (minx != -DOUBLE_NULL) {
337 				double deltaX = (maxx - minx)*factor;
338 				minx -= deltaX;
339 				maxx += deltaX;
340 			}
341 			if (surf) {
342 				minx = min(minx, surf->MinX());
343 				maxx = max(maxx, surf->MaxX());
344 			}
345 		}
346 		if (vertical) {
347 			for (int j = 0; j < series.GetCount(); j++) {
348 				ScatterSeries &serie = series[j];
349 				if (serie.IsDeleted() || serie.opacity == 0 || serie.Data().IsExplicit())
350 					continue;
351 				for (int64 i = 0; i < serie.Data().GetCount(); i++) {
352 					double py = serie.Data().y(i);
353 					if (IsNull(py))
354 						continue;
355 					if (serie.primaryY) {
356 						if (py < miny)
357 							miny = py;
358 						if (py > maxy)
359 							maxy = py;
360 					} else {
361 						if (py < miny2)
362 							miny2 = py;
363 						if (py > maxy2)
364 							maxy2 = py;
365 					}
366 				}
367 			}
368 			if (miny != -DOUBLE_NULL) {
369 				double deltaY = (maxy - miny)*factor;
370 				miny -= deltaY;
371 				maxy += deltaY;
372 			}
373 			if (miny2 != -DOUBLE_NULL) {
374 				double deltaY2 = (maxy2 - miny2)*factor;
375 				miny2 -= deltaY2;
376 				maxy2 += deltaY2;
377 			}
378 			if (surf) {
379 				miny = min(miny, surf->MinY());
380 				maxy = max(maxy, surf->MaxY());
381 			}
382 		}
383 		if (horizontal) {
384 			if (minx != -DOUBLE_NULL) {
385 				if (maxx == minx) {
386 					if (maxx == 0) {
387 						xRange = 2;
388 						xMin = -1;
389 					} else
390 						xRange = 2*maxx;
391 				} else
392 					xRange = maxx - minx;
393 				double deltaX = xMin - minx;
394 				xMin -= deltaX;
395 
396 				AdjustMinUnitX();
397 				AdjustMajorUnitX();
398 			}
399 		}
400 		if (vertical) {
401 			if (miny != -DOUBLE_NULL) {
402 				if (maxy == miny)
403 					yRange = maxy > 0 ? 2*maxy : 1;
404 				else
405 					yRange = maxy - miny;
406 				double deltaY = yMin - miny;
407 				yMin -= deltaY;
408 
409 				AdjustMajorUnitY();
410 				AdjustMinUnitY();
411 			}
412 			if (miny2 != -DOUBLE_NULL) {
413 				if (maxy2 == miny2)
414 					yRange2 = maxy2 > 0 ? 2*maxy2 : 1;
415 				else
416 					yRange2 = maxy2 - miny2;
417 				double deltaY2 = yMin2 - miny2;
418 				yMin2 -= deltaY2;
419 
420 				AdjustMajorUnitY2();
421 				AdjustMinUnitY2();
422 			}
423 		}
424 	} catch (ValueTypeError err) {
425 		ASSERT_(true, err);
426 		return *this;
427 	}
428 	WhenSetRange();
429 	WhenSetXYMin();
430 	Refresh();
431 	return *this;
432 }
433 
Graduation_FormatX(Formats fi)434 ScatterDraw &ScatterDraw::Graduation_FormatX(Formats fi) {
435 	switch (fi) {
436 		case EXP: cbModifFormatX = cbModifFormatXGridUnits = ExpFormat;	break;
437 		case MON: cbModifFormatX = cbModifFormatXGridUnits = MonFormat;	break;
438 		case DY:  cbModifFormatX = cbModifFormatXGridUnits = DyFormat;	break;
439 		default:  break;
440 	}
441 	return *this;
442 }
443 
Graduation_FormatY(Formats fi)444 ScatterDraw &ScatterDraw::Graduation_FormatY(Formats fi) {
445 	switch (fi) {
446 		case EXP: cbModifFormatY = cbModifFormatYGridUnits = ExpFormat;	break;
447 		case MON: cbModifFormatY = cbModifFormatYGridUnits = MonFormat;	break;
448 		case DY:  cbModifFormatY = cbModifFormatYGridUnits = DyFormat;	break;
449 		default:  break;
450 	}
451 	return *this;
452 }
453 
Graduation_FormatY2(Formats fi)454 ScatterDraw &ScatterDraw::Graduation_FormatY2(Formats fi) {
455 	switch (fi) {
456 		case EXP: cbModifFormatY2 = cbModifFormatY2GridUnits = ExpFormat;	break;
457 		case MON: cbModifFormatY2 = cbModifFormatY2GridUnits = MonFormat;	break;
458 		case DY:  cbModifFormatY2 = cbModifFormatY2GridUnits = DyFormat;	break;
459 		default:  break;
460 	}
461 	return *this;
462 }
463 
VariableFormat(double range,double d)464 String ScatterDraw::VariableFormat(double range, double d) {
465 	if (fabs(d) <= 1e-15)
466 		d = 0;
467 	if 		(0.001 <= range && range < 0.01)   return FormatDouble(d, 5);
468 	else if (0.01  <= range && range < 0.1)    return FormatDouble(d, 4);
469 	else if (0.1   <= range && range < 1) 	   return FormatDouble(d, 3);
470 	else if (1	   <= range && range < 10) 	   return FormatDouble(d, 2);
471 	else if (10	   <= range && range < 100)    return FormatDouble(d, 1);
472 	else if (100   <= range && range < 10000000)return FormatDouble(d, 0);
473 	else return FormatDoubleExp(d, 2);
474 }
475 
GetNewColor(int index,int version)476 Color ScatterDraw::GetNewColor(int index, int version) {
477 	Color old[20] = {LtBlue(), LtRed(), LtGreen(), Black(), LtGray(), Brown(), Blue(), Red(), Green(), Gray(),
478 					 LtBlue(), LtRed(), LtGreen(), Black(), LtGray(), Brown(), Blue(), Red(), Green(), Gray()};
479 	// Colours from http://tools.medialab.sciences-po.fr/iwanthue/
480 	Color nwc[20] = {Color(197,127,117), Color(115,214,74), Color(205,80,212), Color(124,193,215), Color(85,82,139),
481 					 Color(109,212,161), Color(207,72,48), Color(209,206,59), Color(194,134,55), Color(63,72,41),
482 					 Color(201,63,109), Color(193,192,158), Color(91,134,56), Color(105,48,38), Color(201,170,200),
483 					 Color(86,117,119), Color(188,91,165), Color(124,120,216), Color(195,208,119), Color(79,46,75)};
484 	if (index < 20) {
485 		if (version == 0)
486 			return old[index];
487 		else
488 			return nwc[index];
489 	} else
490 		return Color(Random(), Random(), Random());
491 }
492 
GetNewDash(int index)493 String ScatterDraw::GetNewDash(int index) {
494 	switch(index) {
495 	case 0:		return LINE_SOLID;
496 	case 1:		return LINE_DOTTED;
497 	case 2:		return LINE_DASHED;
498 	case 3:		return LINE_DASH_DOT;
499 	case 4:		return LINE_SOLID;
500 	case 5:		return LINE_DOTTED;
501 	case 6:		return LINE_DASHED;
502 	case 7:		return LINE_DASH_DOT;
503 	case 8:		return LINE_SOLID;
504 	case 9:		return LINE_DOTTED;
505 	case 10:	return LINE_DASHED;
506 	case 11:	return LINE_DASH_DOT;
507 	}
508 	dword r = Random();
509 	if (r < 8000)
510 		r += 2000;
511 	String ret = FormatInt(r).Right(4);
512 	String space = " ";
513 	return ret.Mid(0, 1) + space + ret.Mid(1, 1) + space + ret.Mid(2, 1) + space + ret.Mid(3, 1);
514 }
515 
GetNewMarkPlot(int index)516 MarkPlot *ScatterDraw::GetNewMarkPlot(int index) {
517 	switch(index) {
518 	case 0:	return new CircleMarkPlot();
519 	case 1:	return new SquareMarkPlot();
520 	case 2:	return new TriangleMarkPlot();
521 	case 3:	return new CrossMarkPlot();
522 	case 4:	return new XMarkPlot();
523 	case 5:	return new RhombMarkPlot();
524 	}
525 	return new CircleMarkPlot();
526 }
527 
GetOpaqueColor(const Color & color,const Color & background,double opacity)528 Color GetOpaqueColor(const Color &color, const Color &background, double opacity) {
529 	if (opacity == 1)
530 		return color;
531 	if (opacity == 0)
532 		return background;
533 	return Color(int(opacity*(color.GetR() - background.GetR()) + background.GetR()),
534 	             int(opacity*(color.GetG() - background.GetG()) + background.GetG()),
535 	             int(opacity*(color.GetB() - background.GetB()) + background.GetB()));
536 }
537 
ScatterBasicSeries()538 ScatterDraw::ScatterBasicSeries::ScatterBasicSeries() {
539 	color = Null;
540 	thickness = 3;
541 	legend = "";
542 	unitsX = "";
543 	unitsY = "";
544 	opacity = 1;
545 	primaryY = true;
546 	sequential = false;
547 	dash = LINE_SOLID;
548 	seriesPlot = new LineSeriesPlot();
549 	markPlot = new CircleMarkPlot();
550 	markWidth = 8;
551 	markColor = Null;
552 	markBorderWidth = 1;
553 	markBorderColor = Null;
554 	fillColor = Null;
555 	labels = 0;
556 	isClosed = false;
557 	barWidth = 10;
558 	labelsFont = StdFont();
559 	labelsColor = Null;
560 	labelsDx = labelsDy = 0;
561 	labelsAlign = ALIGN_CENTER;
562 	showLegend = true;
563 	legendLine = false;
564 }
565 
Init(int index)566 void ScatterDraw::ScatterBasicSeries::Init(int index) {
567 	color = GetNewColor(index);
568 	markColor = Color(max(color.GetR()-30, 0), max(color.GetG()-30, 0), max(color.GetB()-30, 0));
569 
570 	dash = GetNewDash(int(index/6));
571 	markPlot = GetNewMarkPlot(index);
572 }
573 
AddSeries(DataSource & data)574 ScatterDraw &ScatterDraw::AddSeries(DataSource &data) {
575 	ScatterSeries &s = series.Add();
576 	s.Init(series.GetCount()-1);
577 	s.SetDataSource(&data, false);
578 	if (sequentialXAll)
579 		s.sequential = true;
580 	Refresh();
581 	return *this;
582 }
583 
_AddSeries(DataSource * data)584 ScatterDraw &ScatterDraw::_AddSeries(DataSource *data) {
585 	ScatterSeries &s = series.Add();
586 	s.Init(series.GetCount()-1);
587 	s.SetDataSource(data);
588 	Refresh();
589 	return *this;
590 }
591 
InsertSeries(int index,double * yData,int numData,double x0,double deltaX)592 ScatterDraw &ScatterDraw::InsertSeries(int index, double *yData, int numData, double x0, double deltaX) {
593 	return InsertSeries<CArray>(index, yData, numData, x0, deltaX);
594 }
595 
InsertSeries(int index,double * xData,double * yData,int numData)596 ScatterDraw &ScatterDraw::InsertSeries(int index, double *xData, double *yData, int numData) {
597 	return InsertSeries<CArray>(index, xData, yData, numData);
598 }
599 
InsertSeries(int index,Vector<double> & xData,Vector<double> & yData)600 ScatterDraw &ScatterDraw::InsertSeries(int index, Vector<double> &xData, Vector<double> &yData) {
601 	return InsertSeries<VectorXY>(index, xData, yData);
602 }
603 
InsertSeries(int index,Upp::Array<double> & xData,Upp::Array<double> & yData)604 ScatterDraw &ScatterDraw::InsertSeries(int index, Upp::Array<double> &xData, Upp::Array<double> &yData) {
605 	return InsertSeries<ArrayXY>(index, xData, yData);
606 }
607 
InsertSeries(int index,Vector<Pointf> & points)608 ScatterDraw &ScatterDraw::InsertSeries(int index, Vector<Pointf> &points) {
609 	return InsertSeries<VectorPointf>(index, points);
610 }
611 
InsertSeries(int index,Upp::Array<Pointf> & points)612 ScatterDraw &ScatterDraw::InsertSeries(int index, Upp::Array<Pointf> &points) {
613 	return InsertSeries<ArrayPointf>(index, points);
614 }
615 
InsertSeries(int index,double (* function)(double))616 ScatterDraw &ScatterDraw::InsertSeries(int index, double (*function)(double))	 {
617 	return InsertSeries<FuncSource>(index, function);
618 }
619 
InsertSeries(int index,Pointf (* function)(double),int np,double from,double to)620 ScatterDraw &ScatterDraw::InsertSeries(int index, Pointf (*function)(double), int np, double from, double to)	 {
621 	return InsertSeries<FuncSourcePara>(index, function, np, from, to);
622 }
623 
InsertSeries(int index,PlotExplicFunc & function)624 ScatterDraw &ScatterDraw::InsertSeries(int index, PlotExplicFunc &function)	 {
625 	return InsertSeries<PlotExplicFuncSource>(index, function);
626 }
627 
InsertSeries(int index,PlotParamFunc function,int np,double from,double to)628 ScatterDraw &ScatterDraw::InsertSeries(int index, PlotParamFunc function, int np, double from, double to)	 {
629 	return InsertSeries<PlotParamFuncSource>(index, function, np, from, to);
630 }
631 
_InsertSeries(int index,DataSource * data)632 ScatterDraw &ScatterDraw::_InsertSeries(int index, DataSource *data) {
633 	ASSERT(IsValid(index));
634 
635 	ScatterSeries &s = series.Insert(index);
636 	s.Init(index);
637 	s.SetDataSource(data);
638 	Refresh();
639 	return *this;
640 }
641 
GetCount(int index)642 int64 ScatterDraw::GetCount(int index) {
643 	ASSERT(IsValid(index));
644 	ASSERT(!series[index].IsDeleted());
645 
646 	return series[index].Data().GetCount();
647 }
648 
GetValues(int index,int64 idata,double & x,double & y)649 void ScatterDraw::GetValues(int index, int64 idata, double &x, double &y) {
650 	ASSERT(IsValid(index) && !IsNull(GetCount(index)));
651 	ASSERT(!series[index].IsDeleted());
652 	ASSERT(idata >= 0 && idata < series[index].Data().GetCount());
653 
654 	try {
655 		x = series[index].Data().x(idata);
656 		y = series[index].Data().y(idata);
657 	} catch(ValueTypeError error) {
658 		ASSERT_(true, error);
659 		x = y = Null;
660 	}
661 }
662 
GetValueX(int index,int64 idata)663 double ScatterDraw::GetValueX(int index, int64 idata) {
664 	ASSERT(IsValid(index) && !IsNull(GetCount(index)));
665 	ASSERT(!series[index].IsDeleted());
666 	ASSERT(idata >= 0 && idata < series[index].Data().GetCount());
667 
668 	try {
669 		return series[index].Data().x(idata);
670 	} catch(ValueTypeError error) {
671 		ASSERT_(true, error);
672 		return Null;
673 	}
674 }
675 
GetStringX(int index,int64 idata)676 Value ScatterDraw::GetStringX(int index, int64 idata) {
677 	double ret = GetValueX(index, idata);
678 	if (IsNull(ret))
679 		return Null;
680 	if (cbModifFormatX) {
681 		String sret;
682 		cbModifFormatX(sret, int(idata), ret);
683 		return sret;
684 	} else
685 		return ret;
686 }
687 
688 
GetValueY(int index,int64 idata)689 double ScatterDraw::GetValueY(int index, int64 idata) {
690 	ASSERT(IsValid(index) && !IsNull(GetCount(index)));
691 	ASSERT(!series[index].IsDeleted());
692 	ASSERT(idata >= 0 && idata < series[index].Data().GetCount());
693 
694 	try {
695 		return series[index].Data().y(idata);
696 	} catch(ValueTypeError error) {
697 		ASSERT_(true, error);
698 		return Null;
699 	}
700 }
701 
GetStringY(int index,int64 idata)702 Value ScatterDraw::GetStringY(int index, int64 idata) {
703 	double ret = GetValueY(index, idata);
704 	if (IsNull(ret))
705 		return Null;
706 	if (cbModifFormatY) {
707 		String sret;
708 		cbModifFormatY(sret, int(idata), ret);
709 		return sret;
710 	} else
711 		return ret;
712 }
713 
SetNoPlot(int index)714 ScatterDraw &ScatterDraw::SetNoPlot(int index) {
715  	ASSERT(IsValid(index));
716  	ASSERT(!series[index].IsDeleted());
717 
718  	series[index].seriesPlot = NULL;
719  	return *this;
720 }
721 
PlotStyle(int index,SeriesPlot * data)722 ScatterDraw &ScatterDraw::PlotStyle(int index, SeriesPlot *data) {
723 	ASSERT(IsValid(index));
724 	ASSERT(!series[index].IsDeleted());
725 
726 	series[index].seriesPlot = data;
727 	return *this;
728 }
729 
MarkStyle(int index,MarkPlot * data)730 ScatterDraw &ScatterDraw::MarkStyle(int index, MarkPlot *data) {
731 	ASSERT(IsValid(index));
732 	ASSERT(!series[index].IsDeleted());
733 
734 	series[index].markPlot = data;
735 	return *this;
736 }
737 
MarkStyle(int index,const String name)738 ScatterDraw &ScatterDraw::MarkStyle(int index, const String name) {
739 	ASSERT(IsValid(index));
740 	ASSERT(!series[index].IsDeleted());
741 
742 	int typeidx = MarkPlot::TypeIndex(name);
743 
744 	if (typeidx >= 0)
745 		series[index].markPlot = MarkPlot::Create(typeidx);
746 	else
747 		series[index].markPlot = 0;
748 	return *this;
749 }
750 
GetMarkStyleName(int index)751 const String ScatterDraw::GetMarkStyleName(int index) {
752 	ASSERT(IsValid(index));
753 	ASSERT(!series[index].IsDeleted());
754 
755 	if (series[index].markPlot)
756 		return MarkPlot::TypeName(series[index].markPlot->GetType());
757 	else
758 		return t_("No mark");
759 }
760 
GetMarkStyleType(int index)761 int ScatterDraw::GetMarkStyleType(int index) {
762 	ASSERT(IsValid(index));
763 	ASSERT(!series[index].IsDeleted());
764 
765 	if (series[index].markPlot)
766 		return series[index].markPlot->GetTypeType();
767 	else
768 		return -1;
769 }
770 
SetMarkStyleType(int index,int type)771 ScatterDraw &ScatterDraw::SetMarkStyleType(int index, int type) {
772 	ASSERT(IsValid(index));
773 	ASSERT(!series[index].IsDeleted());
774 
775 	if (series[index].markPlot)
776 		series[index].markPlot->SetTypeType(type);
777 
778 	return *this;
779 }
780 
Stroke(int index,double thickness,Color color)781 ScatterDraw &ScatterDraw::Stroke(int index, double thickness, Color color) {
782 	ASSERT(IsValid(index));
783 	ASSERT(!series[index].IsDeleted());
784 
785 	if (IsNull(color))
786 		color = GetNewColor(index);
787 	series[index].color = color;
788 	series[index].thickness = thickness;
789 	//series[index].dash = GetNewDash(index);
790 
791 	Refresh();
792 	return *this;
793 }
794 
GetStroke(int index,double & thickness,Color & color)795 void ScatterDraw::GetStroke(int index, double &thickness, Color &color) {
796 	ASSERT(IsValid(index));
797 	ASSERT(!series[index].IsDeleted());
798 
799 	color = series[index].color;
800 	thickness  = series[index].thickness;
801 }
802 
Fill(Color color)803 ScatterDraw &ScatterDraw::Fill(Color color) {
804 	int index = series.GetCount() - 1;
805 
806 	if (IsNull(color)) {
807 		color = GetNewColor(index);
808 		color = Color(min(color.GetR()+30, 255), min(color.GetG()+30, 255), min(color.GetB()+30, 255));
809 	}
810 	series[index].fillColor = color;
811 
812 	Refresh();
813 	return *this;
814 }
815 
MarkColor(Color color)816 ScatterDraw &ScatterDraw::MarkColor(Color color) {
817 	int index = series.GetCount() - 1;
818 
819 	if (IsNull(color)) {
820 		color = GetNewColor(index);
821 		color = Color(max(color.GetR()-30, 0), max(color.GetG()-30, 0), max(color.GetB()-30, 0));
822 	}
823 	series[index].markColor = color;
824 
825 	Refresh();
826 	return *this;
827 }
828 
MarkBorderColor(Color color)829 ScatterDraw &ScatterDraw::MarkBorderColor(Color color) {
830 	int index = series.GetCount() - 1;
831 
832 	if (IsNull(color)) {
833 		color = GetNewColor(index + 1);
834 		color = Color(max(color.GetR()-30, 0), max(color.GetG()-30, 0), max(color.GetB()-30, 0));
835 	}
836 	series[index].markBorderColor = color;
837 
838 	Refresh();
839 	return *this;
840 }
841 
MarkWidth(double markWidth)842 ScatterDraw &ScatterDraw::MarkWidth(double markWidth) {
843 	int index = series.GetCount() - 1;
844 
845 	series[index].markWidth = markWidth;
846 
847 	Refresh();
848 	return *this;
849 }
850 
MarkBorderWidth(double markWidth)851 ScatterDraw &ScatterDraw::MarkBorderWidth(double markWidth) {
852 	int index = series.GetCount() - 1;
853 
854 	series[index].markBorderWidth = markWidth;
855 
856 	Refresh();
857 	return *this;
858 }
859 
ShowSeriesLegend(int index,bool show)860 ScatterDraw &ScatterDraw::ShowSeriesLegend(int index, bool show) {
861 	ASSERT(IsValid(index));
862 	ASSERT(!series[index].IsDeleted());
863 
864 	series[index].showLegend = show;
865 
866 	Refresh();
867 	return *this;
868 }
869 
Closed(int index,bool closed)870 ScatterDraw &ScatterDraw::Closed(int index, bool closed) {
871 	ASSERT(IsValid(index));
872 	ASSERT(!series[index].IsDeleted());
873 
874 	series[index].isClosed = closed;
875 	Refresh();
876 	return *this;
877 }
878 
IsClosed(int index)879 bool ScatterDraw::IsClosed(int index) {
880 	ASSERT(IsValid(index));
881 	ASSERT(!series[index].IsDeleted());
882 
883 	return series[index].isClosed;
884 }
885 
BarWidth(int index,double width)886 ScatterDraw &ScatterDraw::BarWidth(int index, double width) {
887 	ASSERT(IsValid(index));
888 	ASSERT(!series[index].IsDeleted());
889 
890 	series[index].barWidth = width;
891 	Refresh();
892 	return *this;
893 }
894 
Dash(const char * dash)895 ScatterDraw &ScatterDraw::Dash(const char *dash) {
896 	int index = series.GetCount() - 1;
897 
898 	return Dash(index, dash);
899 }
900 
Dash(int index,const char * dash)901 ScatterDraw &ScatterDraw::Dash(int index, const char *dash) {
902 	ASSERT(IsValid(index));
903 	ASSERT(!series[index].IsDeleted());
904 
905 	series[index].dash = dash;
906 	Refresh();
907 	return *this;
908 }
909 
NoDash()910 ScatterDraw &ScatterDraw::NoDash() {
911 	int index = series.GetCount() - 1;
912 
913 	return NoDash(index);
914 }
915 
NoDash(int index)916 ScatterDraw &ScatterDraw::NoDash(int index) {
917 	ASSERT(IsValid(index));
918 	ASSERT(!series[index].IsDeleted());
919 
920 	series[index].dash = LINE_SOLID;
921 	Refresh();
922 	return *this;
923 }
924 
GetDash(int index)925 const String ScatterDraw::GetDash(int index) {
926 	ASSERT(IsValid(index));
927 	ASSERT(!series[index].IsDeleted());
928 
929 	return series[index].dash;
930 }
931 
Legend(const String legend)932 ScatterDraw &ScatterDraw::Legend(const String legend) {
933 	int index = series.GetCount() - 1;
934 
935 	return Legend(index, legend);
936 }
937 
Legend(int index,const String legend)938 ScatterDraw& ScatterDraw::Legend(int index, const String legend) {
939 	ASSERT(IsValid(index));
940 	ASSERT(!series[index].IsDeleted());
941 
942 	series[index].legend = legend;
943 	return *this;
944 }
945 
GetLegend(int index)946 const String& ScatterDraw::GetLegend(int index) {
947 	ASSERT(IsValid(index));
948 	ASSERT(!series[index].IsDeleted());
949 
950 	return series[index].legend;
951 }
952 
Units(const String unitsY,const String unitsX)953 ScatterDraw &ScatterDraw::Units(const String unitsY, const String unitsX) {
954 	int index = series.GetCount() - 1;
955 
956 	return Units(index, unitsY, unitsX);
957 }
958 
Units(int index,const String unitsY,const String unitsX)959 ScatterDraw& ScatterDraw::Units(int index, const String unitsY, const String unitsX) {
960 	ASSERT(IsValid(index));
961 	ASSERT(!series[index].IsDeleted());
962 
963 	series[index].unitsX = unitsX;
964 	series[index].unitsY = unitsY;
965 	labelsChanged = true;
966 
967 	return *this;
968 }
969 
GetUnitsX(int index)970 const String ScatterDraw::GetUnitsX(int index) {
971 	ASSERT(IsValid(index));
972 	ASSERT(!series[index].IsDeleted());
973 
974 	return series[index].unitsX;
975 }
976 
GetUnitsY(int index)977 const String ScatterDraw::GetUnitsY(int index) {
978 	ASSERT(IsValid(index));
979 	ASSERT(!series[index].IsDeleted());
980 
981 	return series[index].unitsY;
982 }
983 
SetFillColor(int index,const Color & color)984 ScatterDraw& ScatterDraw::SetFillColor(int index, const Color& color) {
985 	ASSERT(IsValid(index));
986 	ASSERT(!series[index].IsDeleted());
987 
988 	series[index].fillColor = color;
989 	Refresh();
990 	return *this;
991 }
992 
GetFillColor(int index) const993 Color ScatterDraw::GetFillColor(int index) const {
994 	ASSERT(IsValid(index));
995 	ASSERT(!series[index].IsDeleted());
996 
997 	return series[index].fillColor;
998 }
999 
SetMarkBorderWidth(int index,double width)1000 ScatterDraw &ScatterDraw::SetMarkBorderWidth(int index, double width) {
1001 	ASSERT(IsValid(index));
1002 	ASSERT(!series[index].IsDeleted());
1003 
1004 	series[index].markBorderWidth = width;
1005 	Refresh();
1006 	return *this;
1007 }
1008 
GetMarkBorderWidth(int index)1009 double ScatterDraw::GetMarkBorderWidth(int index) {
1010  	ASSERT(IsValid(index));
1011 	ASSERT(!series[index].IsDeleted());
1012 
1013  	return series[index].markBorderWidth;
1014 }
1015 
SetMarkWidth(int index,double markWidth)1016 ScatterDraw &ScatterDraw::SetMarkWidth(int index, double markWidth) {
1017 	ASSERT(IsValid(index));
1018 	ASSERT(!series[index].IsDeleted());
1019 
1020 	series[index].markWidth = markWidth;
1021 	Refresh();
1022 	return *this;
1023 }
1024 
GetMarkWidth(int index)1025 double ScatterDraw::GetMarkWidth(int index) {
1026 	ASSERT(IsValid(index));
1027 	ASSERT(!series[index].IsDeleted());
1028 
1029 	return series[index].markWidth;
1030 }
1031 
SetMarkColor(int index,const Color & color)1032 ScatterDraw &ScatterDraw::SetMarkColor(int index, const Color& color) {
1033 	ASSERT(IsValid(index));
1034 	ASSERT(!series[index].IsDeleted());
1035 
1036 	series[index].markColor = color;
1037 	Refresh();
1038 	return *this;
1039 }
1040 
GetMarkColor(int index) const1041 Color ScatterDraw::GetMarkColor(int index) const {
1042 	ASSERT(IsValid(index));
1043 	ASSERT(!series[index].IsDeleted());
1044 
1045 	return series[index].markColor;
1046 }
1047 
SetMarkBorderColor(int index,const Color & color)1048 ScatterDraw &ScatterDraw::SetMarkBorderColor(int index, const Color& color) {
1049 	ASSERT(IsValid(index));
1050 	ASSERT(!series[index].IsDeleted());
1051 
1052 	series[index].markBorderColor = color;
1053 	Refresh();
1054 	return *this;
1055 }
1056 
GetMarkBorderColor(int index) const1057 Color ScatterDraw::GetMarkBorderColor(int index) const {
1058 	ASSERT(IsValid(index));
1059 	ASSERT(!series[index].IsDeleted());
1060 
1061 	return series[index].markBorderColor;
1062 }
1063 
NoMark(int index)1064 void ScatterDraw::NoMark(int index) {
1065 	ASSERT(IsValid(index));
1066 	ASSERT(!series[index].IsDeleted());
1067 
1068 	series[index].markWidth = 0;
1069 }
1070 
SetDataPrimaryY(int index,bool primary)1071 void ScatterDraw::SetDataPrimaryY(int index, bool primary) {
1072 	ASSERT(IsValid(index));
1073 	ASSERT(!series[index].IsDeleted());
1074 
1075 	series[index].primaryY = primary;
1076 	if (!primary)
1077 		SetDrawY2Reticle(true);
1078 	Refresh();
1079 }
1080 
SetDataPrimaryY(bool primary)1081 ScatterDraw &ScatterDraw::SetDataPrimaryY(bool primary) {
1082 	SetDataPrimaryY(series.GetCount()-1, primary);
1083 	return *this;
1084 }
1085 
SetDataSecondaryY(int index,bool secondary)1086 void ScatterDraw::SetDataSecondaryY(int index, bool secondary) {
1087 	ASSERT(IsValid(index));
1088 	ASSERT(!series[index].IsDeleted());
1089 
1090 	series[index].primaryY = !secondary;
1091 	if (secondary)
1092 		SetDrawY2Reticle().SetDrawY2ReticleNumbers();
1093 	Refresh();
1094 }
1095 
SetDataSecondaryY(bool secondary)1096 ScatterDraw &ScatterDraw::SetDataSecondaryY(bool secondary) {
1097 	SetDataSecondaryY(series.GetCount()-1, secondary);
1098 	return *this;
1099 }
1100 
IsDataPrimaryY(int index)1101 bool ScatterDraw::IsDataPrimaryY(int index) {
1102 	ASSERT(IsValid(index));
1103 	ASSERT(!series[index].IsDeleted());
1104 
1105 	return series[index].primaryY;
1106 }
1107 /*
1108 void ScatterDraw::SetDataSourceInternal() {
1109 	for (int i = 0; i < series.GetCount(); ++i)
1110 		series[i].SetDataSource_Internal(true);
1111 }*/
1112 
ThereAreSecondaryY()1113 bool ScatterDraw::ThereAreSecondaryY() {
1114 	for (int i = 0; i < series.GetCount(); ++i)
1115 		if (!series[i].primaryY)
1116 			return true;
1117 	return false;
1118 }
1119 
SetSequentialX(int index,bool sequential)1120 void ScatterDraw::SetSequentialX(int index, bool sequential) {
1121 	ASSERT(IsValid(index));
1122 	ASSERT(!series[index].IsDeleted());
1123 
1124 	series[index].sequential = sequential;
1125 	Refresh();
1126 }
1127 
SetSequentialX(bool sequential)1128 ScatterDraw &ScatterDraw::SetSequentialX(bool sequential) {
1129 	SetSequentialX(series.GetCount()-1, sequential);
1130 	return *this;
1131 }
1132 
GetSequentialX(int index)1133 bool ScatterDraw::GetSequentialX(int index) {
1134 	ASSERT(IsValid(index));
1135 	ASSERT(!series[index].IsDeleted());
1136 
1137 	return series[index].sequential;
1138 }
1139 
GetSequentialX()1140 bool ScatterDraw::GetSequentialX() {
1141 	return GetSequentialX(series.GetCount()-1);
1142 }
1143 
SetSequentialXAll(bool sequential)1144 ScatterDraw &ScatterDraw::SetSequentialXAll(bool sequential) {
1145 	for (int i = 0; i < series.GetCount(); ++i) {
1146 		const ScatterSeries &serie = series[i];
1147 		if (serie.IsDeleted())
1148 			continue;
1149 		SetSequentialX(i, sequential);
1150 	}
1151 	sequentialXAll = sequential;
1152 	return *this;
1153 }
1154 
Show(int index,bool show)1155 void ScatterDraw::Show(int index, bool show) {
1156 	ASSERT(IsValid(index));
1157 	ASSERT(!series[index].IsDeleted());
1158 
1159 	series[index].opacity = show ? 1 : 0;
1160 	labelsChanged = true;
1161 	Refresh();
1162 }
1163 
IsVisible(int index)1164 bool ScatterDraw::IsVisible(int index) {
1165 	ASSERT(IsValid(index));
1166 	ASSERT(!series[index].IsDeleted());
1167 
1168 	return series[index].opacity > 0;
1169 }
1170 
ShowAll(bool)1171 ScatterDraw &ScatterDraw::ShowAll(bool ) {
1172 	for (int i = 0; i < series.GetCount(); ++i) {
1173 		ScatterSeries &serie = series[i];
1174 		if (serie.IsDeleted())
1175 			continue;
1176 		serie.opacity = 1;
1177 	}
1178 	return *this;
1179 }
1180 
Id(int id)1181 ScatterDraw& ScatterDraw::Id(int id) {
1182 	return Id(series.GetCount()-1, id);
1183 }
1184 
Id(int index,int id)1185 ScatterDraw& ScatterDraw::Id(int index, int id) {
1186 	ASSERT(IsValid(index));
1187 	ASSERT(!series[index].IsDeleted());
1188 
1189 	series[index].id = id;
1190 	return *this;
1191 }
1192 
GetId(int index)1193 int ScatterDraw::GetId(int index) {
1194 	ASSERT(IsValid(index));
1195 	ASSERT(!series[index].IsDeleted());
1196 
1197 	return series[index].id;
1198 }
1199 
RemoveSeries(int index)1200 bool ScatterDraw::RemoveSeries(int index) {
1201 	ASSERT(IsValid(index));
1202 	ASSERT(!series[index].IsDeleted());
1203 
1204 	if (WhenRemoveSeries)
1205 		if (!WhenRemoveSeries(index))
1206 			return false;
1207 	series.Remove(index);
1208 	Refresh();
1209 	return true;
1210 }
1211 
RemoveAllSeries()1212 void ScatterDraw::RemoveAllSeries() {
1213 	series.Clear();
1214 	Refresh();
1215 }
1216 
SwapSeries(int i1,int i2)1217 bool ScatterDraw::SwapSeries(int i1, int i2) {
1218 	ASSERT(IsValid(i1));
1219 	ASSERT(!series[i1].IsDeleted());
1220 	ASSERT(IsValid(i2));
1221 	ASSERT(!series[i2].IsDeleted());
1222 
1223 	if (WhenSwapSeries)
1224 		if (!WhenSwapSeries(i1, i2))
1225 			return false;
1226 	series.Swap(i1, i2);
1227 	Refresh();
1228 	return true;
1229 }
1230 
GetDrawing()1231 Drawing ScatterDraw::GetDrawing() {
1232 	DrawingDraw ddw(size);
1233 
1234 	SetDrawing<DrawingDraw>(ddw, true);
1235 	PlotTexts(ddw);
1236 
1237 	return ddw;
1238 }
1239 
GetImage()1240 Image ScatterDraw::GetImage() {
1241 #ifndef flagGUI
1242 	ASSERT(mode != MD_DRAW);
1243 #endif
1244 	ImageBuffer ib(size);
1245 	BufferPainter bp(ib, mode);
1246 
1247 	bp.LineCap(LINECAP_SQUARE);
1248 	bp.LineJoin(LINEJOIN_MITER);
1249 	SetDrawing(bp, false);
1250 
1251 	return ib;
1252 }
1253 
1254 
GetXByPoint(double x)1255 double ScatterDraw::GetXByPoint(double x) {
1256 	return (x - hPlotLeft)*GetXRange()/(GetSize().cx - (hPlotLeft + hPlotRight) - 1) + GetXMin();
1257 }
1258 
GetYByPoint(double y)1259 double ScatterDraw::GetYByPoint(double y) {
1260 	return (GetSize().cy - vPlotTop - y - 1)*GetYRange()/(GetSize().cy - (vPlotTop + vPlotBottom) - GetTitleFont().GetHeight() - GetTitleFont().GetDescent() - 1) + GetYMin();
1261 }
1262 
GetY2ByPoint(double y)1263 double ScatterDraw::GetY2ByPoint(double y) {
1264 	return (GetSize().cy - vPlotTop - y - 1)*GetY2Range()/(GetSize().cy - (vPlotTop + vPlotBottom) - GetTitleFont().GetHeight() - GetTitleFont().GetDescent() - 1) + GetYMin2();
1265 }
1266 
GetXPointByValue(double x)1267 double ScatterDraw::GetXPointByValue(double x) {
1268 	return (x - GetXMin())/GetXRange()*(GetSize().cx - (hPlotLeft + hPlotRight) - 1) + hPlotLeft;
1269 }
1270 
GetYPointByValue(double y)1271 double ScatterDraw::GetYPointByValue(double y) {
1272 	return (GetSize().cy - vPlotTop - 1) - (y - GetYMin())/GetYRange()*(GetSize().cy - (vPlotTop + vPlotBottom) - GetTitleFont().GetHeight() - GetTitleFont().GetDescent() - 1);
1273 }
1274 
SetRangeLinked(double rx,double ry,double ry2)1275 ScatterDraw &ScatterDraw::SetRangeLinked(double rx, double ry, double ry2) {
1276 	if (linkedMaster) {
1277 		linkedMaster->SetRangeLinked(rx, ry, ry2);
1278 		linkedMaster->Refresh();
1279 		return *this;
1280 	}
1281 	SetRange(rx, ry, ry2);
1282 	if (!linkedCtrls.IsEmpty()) {
1283 		for (int i = 0; i < linkedCtrls.GetCount(); ++i) {
1284 	    	linkedCtrls[i]->SetRange(rx, ry, ry2);
1285 	    	linkedCtrls[i]->Refresh();
1286 		}
1287 	}
1288 	return *this;
1289 }
1290 
SetXYMinLinked(double xmin,double ymin,double ymin2)1291 ScatterDraw &ScatterDraw::SetXYMinLinked(double xmin, double ymin, double ymin2) {
1292 	if (linkedMaster) {
1293 		linkedMaster->SetXYMinLinked(xmin, ymin, ymin2);
1294 		linkedMaster->Refresh();
1295 		return *this;
1296 	}
1297 	SetXYMin(xmin, ymin, ymin2);
1298 	if (!linkedCtrls.IsEmpty()) {
1299 		for (int i = 0; i < linkedCtrls.GetCount(); ++i) {
1300 	    	linkedCtrls[i]->SetXYMin(xmin, ymin, ymin2);
1301 	    	linkedCtrls[i]->Refresh();
1302 		}
1303 	}
1304 	return *this;
1305 }
1306 
Zoom(double scale,bool mouseX,bool mouseY)1307 void ScatterDraw::Zoom(double scale, bool mouseX, bool mouseY) {
1308 	if (linkedMaster) {
1309 		linkedMaster->Zoom(scale, mouseX, mouseY);
1310 		return;
1311 	}
1312 	DoZoom(scale, mouseX, mouseY);
1313 	if (!linkedCtrls.IsEmpty()) {
1314 		for (int i = 0; i < linkedCtrls.GetCount(); ++i)
1315 	    	linkedCtrls[i]->DoZoom(scale, mouseX, mouseY);
1316 	}
1317 }
1318 
DoZoom(double scale,bool mouseX,bool mouseY)1319 void ScatterDraw::DoZoom(double scale, bool mouseX, bool mouseY) {
1320 	if (scale == 1)
1321 		return;
1322 	lastRefresh_sign = (scale >= 0) ? 1 : -1;
1323 
1324 	if (scale > 1) {
1325 		if (maxXRange > 0) {
1326 			if (xRange*scale > maxXRange) {
1327 				highlight_0 = GetTickCount();
1328 				if (xRange == maxXRange) {
1329 					Refresh();
1330 					return;
1331 				} else
1332 					scale = maxXRange/xRange;
1333 			}
1334 		}
1335 		if (maxYRange > 0) {
1336 			if (yRange*scale > maxYRange) {
1337 				highlight_0 = GetTickCount();
1338 				if (yRange == maxYRange) {
1339 					Refresh();
1340 					return;
1341 				} else
1342 					scale = maxYRange/xRange;
1343 			}
1344 		}
1345 	} else {
1346 		if (maxXRange > 0) {
1347 			if (xRange*scale < minXRange) {
1348 				highlight_0 = GetTickCount();
1349 				if (xRange == minXRange) {
1350 					Refresh();
1351 					return;
1352 				} else
1353 					scale = minXRange/xRange;
1354 			}
1355 		}
1356 		if (maxYRange > 0) {
1357 			if (yRange*scale < minYRange) {
1358 				highlight_0 = GetTickCount();
1359 				if (yRange == minYRange) {
1360 					Refresh();
1361 					return;
1362 				} else
1363 					scale = minYRange/xRange;
1364 			}
1365 		}
1366 	}
1367 
1368 	if (mouseX) {
1369 		if (zoomStyleX == TO_CENTER) {
1370 			if (!IsNull(minXmin) && xMin + xRange*(1-scale)/2. <= minXmin) {
1371 				highlight_0 = GetTickCount();
1372 				Refresh();
1373 				return;
1374 			}
1375 			if (!IsNull(maxXmax) && xMin + xRange*scale + xRange*(1-scale)/2. >= maxXmax) {
1376 				highlight_0 = GetTickCount();
1377 				Refresh();
1378 				return;
1379 			}
1380 			double oldXMin = xMin;
1381 			xMin += xRange*(1-scale)/2.;
1382 			xMinUnit = oldXMin + xMinUnit - xMin;
1383 			AdjustMinUnitX();
1384 		}
1385 		xRange *= scale;
1386 
1387 		AdjustMajorUnitX();
1388 		AdjustMinUnitX();
1389 		lastxRange = xRange;
1390 	}
1391 	if (mouseY) {
1392 		if (zoomStyleY == TO_CENTER) {
1393 			if (!IsNull(minYmin) && yMin + yRange*(1-scale)/2. <= minYmin) {
1394 				highlight_0 = GetTickCount();
1395 				Refresh();
1396 				return;
1397 			}
1398 			if (!IsNull(maxYmax) && yMin + yRange*scale + yRange*(1-scale)/2. >= maxYmax) {
1399 				highlight_0 = GetTickCount();
1400 				Refresh();
1401 				return;
1402 			}
1403 			double oldYMin = yMin;
1404 			yMin += yRange*(1 - scale)/2.;
1405 			yMinUnit = oldYMin + yMinUnit - yMin;
1406 			AdjustMinUnitY();
1407 			double oldYMin2 = yMin2;
1408 			yMin2 += yRange2*(1-scale)/2.;
1409 			yMinUnit2 = oldYMin2 + yMinUnit2 - yMin2;
1410 			AdjustMinUnitY2();
1411 		}
1412 		yRange *= scale;
1413 		yRange2 *= scale;
1414 
1415 		AdjustMajorUnitY();
1416 		AdjustMinUnitY();
1417 		lastyRange = yRange;
1418 	}
1419 	if (mouseX || mouseY) {
1420 		WhenSetRange();
1421 		if (zoomStyleX == TO_CENTER || zoomStyleY == TO_CENTER)
1422 			WhenSetXYMin();
1423 		Refresh();
1424 		WhenZoomScroll();
1425 	}
1426 }
1427 
Scroll(double factorX,double factorY)1428 void ScatterDraw::Scroll(double factorX, double factorY) {
1429 	if (linkedMaster) {
1430 		linkedMaster->Scroll(factorX, factorY);
1431 		return;
1432 	}
1433 	DoScroll(factorX, factorY);
1434 	if (!linkedCtrls.IsEmpty()) {
1435 		for (int i = 0; i < linkedCtrls.GetCount(); ++i)
1436 	    	linkedCtrls[i]->DoScroll(factorX, factorY);
1437 	}
1438 }
1439 
DoScroll(double factorX,double factorY)1440 void ScatterDraw::DoScroll(double factorX, double factorY) {
1441 	if (factorX != 0) {
1442 		double deltaX = factorX*xRange;
1443 		if (!IsNull(minXmin) && factorX > 0) {
1444 			if (xMin > minXmin) {
1445 				if (xMin - deltaX < minXmin) {
1446 					highlight_0 = GetTickCount();
1447 					deltaX = xMin - minXmin;
1448 				}
1449 			} else {
1450 				factorX = Null;
1451 				highlight_0 = GetTickCount();
1452 			}
1453 		}
1454 		if (!IsNull(maxXmax) && factorX < 0) {
1455 			if (xMin + xRange < maxXmax) {
1456 				if (xMin + xRange - deltaX > maxXmax) {
1457 					highlight_0 = GetTickCount();
1458 					deltaX = xMin + xRange - maxXmax;
1459 				}
1460 			} else {
1461 				factorX = Null;
1462 				highlight_0 = GetTickCount();
1463 			}
1464 		}
1465 		if (factorX != 0 && !IsNull(factorX)) {
1466 			xMin -= deltaX;
1467 			xMinUnit += deltaX;
1468 			AdjustMinUnitX();
1469 		}
1470 	}
1471 	if (factorY != 0) {
1472 		double deltaY = factorY*yRange;
1473 		if (!IsNull(minYmin) && factorY > 0) {
1474 			if (yMin > minYmin) {
1475 				if (yMin - deltaY < minYmin) {
1476 					highlight_0 = GetTickCount();
1477 					deltaY = yMin - minYmin;
1478 				}
1479 			} else {
1480 				factorY = Null;
1481 				highlight_0 = GetTickCount();
1482 			}
1483 		}
1484 		if (!IsNull(maxYmax) && factorY < 0) {
1485 			if (yMin + yRange < maxYmax) {
1486 				if (yMin + yRange - deltaY > maxYmax) {
1487 					highlight_0 = GetTickCount();
1488 					deltaY = yMin + yRange - maxYmax;
1489 				}
1490 			} else {
1491 				factorY = Null;
1492 				highlight_0 = GetTickCount();
1493 			}
1494 		}
1495 		if (factorY != 0 && !IsNull(factorY)) {
1496 			yMin -= deltaY;
1497 			yMinUnit += deltaY;
1498 			AdjustMinUnitY();
1499 			if (drawY2Reticle) {
1500 				double deltaY2 = factorY*yRange2;
1501 				yMin2 -= deltaY2;
1502 				yMinUnit2 += deltaY2;
1503 				AdjustMinUnitY2();
1504 			}
1505 		}
1506 	}
1507 	if (IsNull(factorX) || IsNull(factorY))
1508 		Refresh();
1509 	else if (factorX != 0 || factorY != 0) {
1510 		WhenSetXYMin();
1511 		Refresh();
1512 		WhenZoomScroll();
1513 	}
1514 }
1515 
LinkedWith(ScatterDraw & ctrl)1516 ScatterDraw &ScatterDraw::LinkedWith(ScatterDraw &ctrl) {
1517 	Unlinked();
1518 
1519 	if (ctrl.linkedMaster)
1520 		linkedMaster = ctrl.linkedMaster;
1521 	else
1522 		linkedMaster = &ctrl;
1523 
1524 	linkedMaster->linkedCtrls.FindAdd(this);
1525 
1526 	return *this;
1527 }
1528 
Unlinked()1529 void ScatterDraw::Unlinked() {
1530 	if (!linkedMaster) {
1531 		for (int i = 0; i < linkedCtrls.GetCount(); ++i)
1532 			linkedCtrls[i]->linkedMaster = 0;
1533 		linkedCtrls.Clear();
1534 	} else {
1535 		linkedMaster->linkedCtrls.RemoveKey(this);
1536 		linkedMaster = 0;
1537 	}
1538 }
1539 
SetMouseHandling(bool valx,bool valy)1540 ScatterDraw& ScatterDraw::SetMouseHandling(bool valx, bool valy) {
1541 	mouseHandlingX = valx;
1542 	mouseHandlingY = valy;
1543 	return *this;
1544 }
1545 
SetMouseHandlingLinked(bool valx,bool valy)1546 ScatterDraw& ScatterDraw::SetMouseHandlingLinked(bool valx, bool valy) {
1547 	if (linkedMaster)
1548 		return linkedMaster->SetMouseHandlingLinked(valx, valy);
1549 
1550 	SetMouseHandling(valx, valy);
1551 	if (!linkedCtrls.IsEmpty()) {
1552 		for (int i = 0; i < linkedCtrls.GetCount(); ++i)
1553 	    	linkedCtrls[i]->SetMouseHandling(valx, valy);
1554 	}
1555 	return *this;
1556 }
1557 
1558 
1559 INITBLOCK {
1560 	SeriesPlot::Register<LineSeriesPlot>("Line");
1561 	SeriesPlot::Register<StaggeredSeriesPlot>("Staggered");
1562 	SeriesPlot::Register<BarSeriesPlot>("Bar");
1563 
1564 	MarkPlot::Register<CircleMarkPlot>("Circle");
1565 	MarkPlot::Register<SquareMarkPlot>("Square");
1566 	MarkPlot::Register<TriangleMarkPlot>("Triangle");
1567 	MarkPlot::Register<CrossMarkPlot>("Cross");
1568 	MarkPlot::Register<XMarkPlot>("X");
1569 	MarkPlot::Register<RhombMarkPlot>("Rhomb");
1570 	MarkPlot::Register<RangePlot>("Range");
1571 	MarkPlot::Register<BubblePlot>("Bubble");
1572 
1573 	DashStyle::Register("LINE_SOLID", LINE_SOLID);
1574 	DashStyle::Register("LINE_DOTTED_FINER", LINE_DOTTED_FINER);
1575 	DashStyle::Register("LINE_DOTTED_FINE", LINE_DOTTED_FINE);
1576 	DashStyle::Register("LINE_DOTTED", LINE_DOTTED);
1577 	DashStyle::Register("LINE_DOTTED_SEP", LINE_DOTTED_SEP);
1578 	DashStyle::Register("LINE_DASHED", LINE_DASHED);
1579 	DashStyle::Register("LINE_DASH_DOT", LINE_DASH_DOT);
1580 	DashStyle::Register("-    -", LINE_BEGIN_END);
1581 }
1582 
1583 }