19 #include "graphpainter.h"
24 #define GRAPH_UI_DELAY 10
27 const XGraph::SFloat XGraph::SFLOAT_MAX = FLT_MAX;
28 const XGraph::GFloat XGraph::GFLOAT_MAX = FLT_MAX;
29 const XGraph::VFloat XGraph::VFLOAT_MAX = DBL_MAX;
31 #define SFLOAT_EXP expf
32 #define GFLOAT_EXP expf
33 #define VFLOAT_EXP exp
35 #define SFLOAT_POW powf
36 #define GFLOAT_POW powf
37 #define VFLOAT_POW pow
39 #define SFLOAT_LOG logf
40 #define GFLOAT_LOG logf
41 #define VFLOAT_LOG log
43 #define SFLOAT_LOG10 log10f
44 #define GFLOAT_LOG10 log10f
45 #define VFLOAT_LOG10 log10
47 #define SFLOAT_LRINT lrintf
48 #define GFLOAT_LRINT lrintf
49 #define VFLOAT_LRINT lrint
51 #define VFLOAT_RINT lrint
53 #define AxisToLabel 0.09
54 #define AxisToTicLabel 0.015
55 #define UNZOOM_ABIT 0.95
57 #define PLOT_POINT_SIZE 5.0
59 #define PLOT_POINT_INTENS 0.5
60 #define PLOT_LINE_INTENS 0.7
61 #define PLOT_BAR_INTENS 0.4
63 XGraph::XGraph(
const char *name,
bool runtime) :
67 m_plots(create<
XPlotList>(
"Plots", true)),
68 m_backGround(create<
XHexNode>(
"BackGround", true)),
69 m_titleColor(create<
XHexNode>(
"TitleColor", true)),
70 m_drawLegends(create<
XBoolNode>(
"DrawLegends", true)),
71 m_persistence(create<
XDoubleNode>(
"Persistence", true)) {
74 m_lsnPropertyChanged = tr[ *label()].onValueChanged().connect(*
this,
75 &XGraph::onPropertyChanged);
76 tr[ *backGround()].onValueChanged().connect(lsnPropertyChanged());
77 tr[ *titleColor()].onValueChanged().connect(lsnPropertyChanged());
78 tr[ *drawLegends()].onValueChanged().connect(lsnPropertyChanged());
79 tr[ *persistence()].onValueChanged().connect(lsnPropertyChanged());
80 tr[ *backGround()] = clWhite;
81 tr[ *titleColor()] = clBlack;
82 tr[ *drawLegends()] =
true;
86 auto xaxis = axes()->create<
XAxis>(tr,
"XAxis",
true, XAxis::DirAxisX
87 ,
false, ref(tr), static_pointer_cast<
XGraph>(shared_from_this()));
88 tr[ *xaxis->label()] = i18n(
"X Axis");
89 auto yaxis = axes()->create<
XAxis>(tr,
"YAxis",
true, XAxis::DirAxisY
90 ,
false, ref(tr), static_pointer_cast<
XGraph>(shared_from_this()));
91 tr[ *yaxis->label()] = i18n(
"Y Axis");
98 shot_this.talk(shot_this[ *
this].onUpdate(),
this);
104 if(shot.size(axes())) {
106 for(
auto it = axes_list.begin(); it != axes_list.end(); ++it) {
107 auto axis = static_pointer_cast<
XAxis>( *it);
108 axis->
startAutoscale(shot, resolution, shot[ *axis->autoScale()]);
111 if(shot.size(plots())) {
113 for(
auto it = plots_list.begin(); it != plots_list.end(); ++it) {
114 auto plot = static_pointer_cast<
XPlot>( *it);
115 if(plot->fixScales(tr)) {
117 plot->validateAutoScale(shot);
121 if(shot.size(axes())) {
123 for(
auto it = axes_list.begin(); it != axes_list.end(); ++it) {
124 auto axis = static_pointer_cast<
XAxis>( *it);
125 if(shot[ *axis->autoScale()])
126 axis->zoom(
true,
true, UNZOOM_ABIT);
127 axis->fixScale(tr, resolution,
true);
133 XGraph::zoomAxes(
Transaction &tr,
float resolution,
136 if(shot.size(axes())) {
138 for(
auto it = axes_list.begin(); it != axes_list.end(); ++it) {
139 auto axis = static_pointer_cast<
XAxis>( *it);
144 if(shot.size(axes())) {
146 for(
auto it = axes_list.begin(); it != axes_list.end(); ++it) {
147 auto axis = static_pointer_cast<
XAxis>( *it);
148 axis->zoom(
true,
true, scale, axis->screenToAxis(shot, center));
149 axis->fixScale(tr, resolution);
154 XPlot::XPlot(
const char *name,
bool runtime,
Transaction &tr_graph,
const shared_ptr<XGraph> &graph)
155 :
XNode(name, runtime),
158 m_maxCount(create<
XUIntNode>(
"MaxCount", true)),
159 m_displayMajorGrid(create<
XBoolNode>(
"DisplayMajorGrid", true)),
160 m_displayMinorGrid(create<
XBoolNode>(
"DisplayMinorGrid", true)),
161 m_drawLines(create<
XBoolNode>(
"DrawLines", true)),
162 m_drawBars(create<
XBoolNode>(
"DrawBars", true)),
163 m_drawPoints(create<
XBoolNode>(
"DrawPoints", true)),
164 m_colorPlot(create<
XBoolNode>(
"ColorPlot", true)),
165 m_majorGridColor(create<
XHexNode>(
"MajorGridColor", true)),
166 m_minorGridColor(create<
XHexNode>(
"MinorGridColor", true)),
167 m_pointColor(create<
XHexNode>(
"PointColor", true)),
168 m_lineColor(create<
XHexNode>(
"LineColor", true)),
169 m_barColor(create<
XHexNode>(
"BarColor", true)),
170 m_colorPlotColorHigh(create<
XHexNode>(
"ColorPlotColorHigh", true)),
171 m_colorPlotColorLow(create<
XHexNode>(
"ColorPlotColorLow", true)),
179 m_intensity(create<
XDoubleNode>(
"Intensity", true)) {
183 tr[ *drawLines()] =
true;
184 tr[ *drawBars()] =
false;
185 tr[ *drawPoints()] =
true;
186 tr[ *majorGridColor()] = clAqua;
187 tr[ *minorGridColor()] = clLime;
188 tr[ *lineColor()] = clRed;
189 tr[ *pointColor()] = clRed;
190 tr[ *barColor()] = clRed;
191 tr[ *displayMajorGrid()] =
true;
192 tr[ *displayMinorGrid()] =
false;
193 intensity()->setFormat(
"%.2f");
194 tr[ *intensity()] = 1.0;
195 tr[ *colorPlot()] =
false;
196 tr[ *colorPlotColorHigh()] = clRed;
197 tr[ *colorPlotColorLow()] = clBlue;
199 m_lsnClearPoints = tr[ *clearPoints()].onTouch().connect(
200 *
this, &XPlot::onClearPoints);
202 tr[ *drawLines()].onValueChanged().connect(graph->lsnPropertyChanged());
203 tr[ *drawBars()].onValueChanged().connect(graph->lsnPropertyChanged());
204 tr[ *drawPoints()].onValueChanged().connect(graph->lsnPropertyChanged());
205 tr[ *majorGridColor()].onValueChanged().connect(graph->lsnPropertyChanged());
206 tr[ *minorGridColor()].onValueChanged().connect(graph->lsnPropertyChanged());
207 tr[ *pointColor()].onValueChanged().connect(graph->lsnPropertyChanged());
208 tr[ *lineColor()].onValueChanged().connect(graph->lsnPropertyChanged());
209 tr[ *barColor()].onValueChanged().connect(graph->lsnPropertyChanged());
210 tr[ *displayMajorGrid()].onValueChanged().connect(graph->lsnPropertyChanged());
211 tr[ *displayMinorGrid()].onValueChanged().connect(graph->lsnPropertyChanged());
212 tr[ *intensity()].onValueChanged().connect(graph->lsnPropertyChanged());
213 tr[ *colorPlot()].onValueChanged().connect(graph->lsnPropertyChanged());
214 tr[ *colorPlotColorHigh()].onValueChanged().connect(graph->lsnPropertyChanged());
215 tr[ *colorPlotColorLow()].onValueChanged().connect(graph->lsnPropertyChanged());
217 tr[ *zwoAxisZ()] = 0.15;
223 shared_ptr<XAxis> axisx = shot[ *axisX()];
224 shared_ptr<XAxis> axisy = shot[ *axisY()];
225 shared_ptr<XAxis> axisz = shot[ *axisZ()];
226 shared_ptr<XAxis> axisw = shot[ *axisW()];
227 if( !axisx || !axisy) {
234 m_scr0.x = shot[ *m_curAxisX->x()];
235 m_scr0.y = shot[ *m_curAxisY->y()];
236 m_len.x = shot[ *m_curAxisX->length()];
237 m_len.y = shot[ *m_curAxisY->length()];
240 m_len.z = (XGraph::SFloat)0.0;
243 m_scr0.z = shot[ *m_curAxisZ->z()];
244 m_len.z = shot[ *m_curAxisZ->length()];
251 shared_ptr<XAxis> axisx = shot[ *axisX()];
252 shared_ptr<XAxis> axisy = shot[ *axisY()];
253 shared_ptr<XAxis> axisz = shot[ *axisZ()];
255 g->z = (XGraph::GFloat)0.0;
257 g->z = (pt.z - shot[ *axisz->z()]) / shot[ *axisz->length()];
258 g->x = (pt.x - shot[ *axisx->x()]) / shot[ *axisx->length()];
259 g->y = (pt.y - shot[ *axisy->y()]) / shot[ *axisy->length()];
264 val->x = m_curAxisX->axisToVal(pt.x);
265 val->y = m_curAxisY->axisToVal(pt.y);
267 val->z = m_curAxisZ->axisToVal(pt.z);
269 val->z = (XGraph::VFloat)0.0;
275 val->x = m_curAxisX->axisToVal(m_curAxisX->screenToAxis(shot, scr), scr_prec / m_len.x);
276 val->y = m_curAxisY->axisToVal(m_curAxisY->screenToAxis(shot, scr), scr_prec / m_len.y);
277 val->z = (m_curAxisZ) ? m_curAxisZ->axisToVal(
278 m_curAxisZ->screenToAxis(shot, scr), scr_prec / m_len.z) : (XGraph::GFloat)0.0;
286 graphToScreenFast(pt, scr);
291 scr->x = m_scr0.x + m_len.x * pt.x;
292 scr->y = m_scr0.y + m_len.y * pt.y;
293 scr->z = m_scr0.z + m_len.z * pt.z;
294 scr->w = std::min(std::max(pt.w, (XGraph::GFloat)0.0), (XGraph::GFloat)1.0);
298 gr->x = m_curAxisX->valToAxis(pt.x);
299 gr->y = m_curAxisY->valToAxis(pt.y);
301 gr->z = m_curAxisZ->valToAxis(pt.z);
305 gr->w = m_curAxisW->valToAxis(pt.w);
313 for(
unsigned int i = start; i < m_ptsSnapped.size(); i++) {
317 valToGraphFast(v, &g2);
318 if(g2.
distance2(gmin, gmax) < width*width) {
330 m_graph.lock()->iterate_commit([=](
Transaction &tr){
336 XPlot::drawGrid(
const Snapshot &shot,
XQGraphPainter *painter, shared_ptr<XAxis> &axis1, shared_ptr<XAxis> &axis2) {
337 int len = SFLOAT_LRINT(1.0/painter->
resScreen());
338 painter->beginLine(1.0);
339 bool disp_major = shot[ *displayMajorGrid()];
340 bool disp_minor = shot[ *displayMinorGrid()];
341 if(disp_major || disp_minor) {
343 unsigned int major_color = shot[ *majorGridColor()];
344 unsigned int minor_color = shot[ *minorGridColor()];
345 double intens = shot[ *intensity()];
346 for(
int i = 0; i < len; i++) {
347 XGraph::GFloat x = (XGraph::GFloat)i/len;
349 (axis1 == m_curAxisY) ? x : 0.0, (axis1 == m_curAxisZ) ? x : 0.0), &s1);
351 (axis1 == m_curAxisX) ? x : ((axis2 == m_curAxisX) ? 1.0 : 0.0),
352 (axis1 == m_curAxisY) ? x : ((axis2 == m_curAxisY) ? 1.0 : 0.0),
353 (axis1 == m_curAxisZ) ? x : ((axis2 == m_curAxisZ) ? 1.0 : 0.0)),
355 XGraph::VFloat tempx;
356 switch(axis1->queryTic(len, i, &tempx)) {
357 case XAxis::MajorTic:
360 max(0.0, min(intens * 0.7, 0.5)) );
361 painter->setVertex(s1);
362 painter->setVertex(s2);
365 case XAxis::MinorTic:
368 max(0.0, min(intens * 0.5, 0.5)) );
369 painter->setVertex(s1);
370 painter->setVertex(s2);
383 drawGrid(shot, painter, m_curAxisX, m_curAxisY);
384 drawGrid(shot, painter, m_curAxisY, m_curAxisX);
385 if(m_curAxisZ && drawzaxis) {
386 drawGrid(shot, painter, m_curAxisX, m_curAxisZ);
387 drawGrid(shot, painter, m_curAxisZ, m_curAxisX);
388 drawGrid(shot, painter, m_curAxisY, m_curAxisZ);
389 drawGrid(shot, painter, m_curAxisZ, m_curAxisY);
396 bool colorplot = shot[ *colorPlot()];
397 bool hasweight = !!m_curAxisW;
398 unsigned int colorhigh = shot[ *colorPlotColorHigh()];
399 unsigned int colorlow = shot[ *colorPlotColorLow()];
400 float alpha1 = hasweight ? 0.2 : 1.0;
402 if(shot[ *drawBars()]) {
403 float alpha = max(0.0f, min((
float)(shot[ *intensity()] * PLOT_BAR_INTENS), 1.0f));
404 painter->beginLine(1.0);
410 painter->
setColor(shot[ *barColor()], alpha1*alpha);
411 if(colorplot) painter->
setColor(colorhigh, alpha1*alpha);
412 painter->setVertex(s1);
413 painter->
setColor(shot[ *barColor()], alpha2*alpha);
414 if(colorplot) painter->
setColor(colorlow, alpha2*alpha);
415 painter->setVertex(s2);
418 if(shot[ *drawLines()]) {
419 float alpha = max(0.0f, min((
float)(shot[ *intensity()] * PLOT_LINE_INTENS), 1.0f));
420 painter->beginLine(1.0);
426 painter->
setColor(shot[ *lineColor()], alpha1*alpha);
427 if(colorplot) painter->
setColor(colorhigh, alpha1*alpha);
428 painter->setVertex(s1);
429 painter->
setColor(shot[ *lineColor()], alpha2*alpha);
430 if(colorplot) painter->
setColor(colorlow, alpha2*alpha);
431 painter->setVertex(s2);
434 if(shot[ *drawPoints()]) {
435 float alpha = max(0.0f, min((
float)(shot[ *intensity()] * PLOT_POINT_INTENS), 1.0f));
436 painter->
setColor(shot[ *pointColor()], alpha );
437 painter->beginPoint(PLOT_POINT_SIZE);
440 painter->setVertex(spt);
443 painter->setVertex(spt);
455 bool colorplot = shot[ *colorPlot()];
456 bool hasweight = !!m_curAxisW;
457 int cnt = m_ptsSnapped.size();
458 m_canvasPtsSnapped.resize(cnt);
463 unsigned int colorhigh = shot[ *colorPlotColorHigh()];
464 unsigned int colorlow = shot[ *colorPlotColorLow()];
465 unsigned int linecolor = shot[ *lineColor()];
466 cpt = &m_canvasPtsSnapped[0];
467 for(
int i = 0; i < cnt; ++i) {
469 valToGraphFast(pt, &g1);
470 graphToScreenFast(g1, &s1);
473 cpt->insidecube = isPtIncluded(g1);
475 cpt->color = blendColor(colorlow, colorhigh,
476 hasweight ? cpt->graph.w : cpt->graph.z);
479 cpt->color = linecolor;
484 if(shot[ *drawBars()]) {
487 double g0y = m_curAxisY->valToAxis(0.0);
488 m_curAxisY->axisToScreen(shot, g0y, &s2);
490 float alpha = max(0.0f, min((
float)(shot[ *intensity()] * PLOT_BAR_INTENS), 1.0f));
491 painter->
setColor(shot[ *barColor()], alpha );
492 painter->beginLine(1.0);
493 cpt = &m_canvasPtsSnapped[0];
494 for(
int i = 0; i < cnt; ++i) {
498 pt2.insidecube = isPtIncluded(pt2.graph);
499 if(clipLine( *cpt, pt2, &s1, &s2,
false, NULL, NULL, NULL, NULL)) {
500 if(colorplot || hasweight) painter->
setColor(cpt->color, alpha * cpt->scr.w);
501 painter->setVertex(s1);
502 painter->setVertex(s2);
508 if(shot[ *drawLines()]) {
509 float alpha = max(0.0f, min((
float)(shot[ *intensity()] * PLOT_LINE_INTENS), 1.0f));
510 painter->
setColor(shot[ *lineColor()], alpha );
511 painter->beginLine(1.0);
513 cpt = &m_canvasPtsSnapped[0];
514 unsigned int color1, color2;
515 float alpha1, alpha2;
516 for(
int i = 1; i < cnt; ++i) {
517 if(clipLine( *cpt, *(cpt + 1), &s1, &s2, colorplot || hasweight,
518 &color1, &color2, &alpha1, &alpha2)) {
519 if(colorplot || hasweight) painter->
setColor(color1, alpha*alpha1);
520 painter->setVertex(s1);
521 if(colorplot || hasweight) painter->
setColor(color2, alpha*alpha2);
522 painter->setVertex(s2);
528 if(shot[ *drawPoints()]) {
529 float alpha = max(0.0f, min((
float)(shot[ *intensity()] * PLOT_POINT_INTENS), 1.0f));
530 painter->
setColor(shot[ *pointColor()], alpha );
531 painter->beginPoint(PLOT_POINT_SIZE);
532 unsigned int pointcolor = shot[ *pointColor()];
533 cpt = &m_canvasPtsSnapped[0];
534 for(
int i = 0; i < cnt; ++i) {
535 if(cpt->insidecube) {
537 painter->
setColor(cpt->color, alpha * cpt->scr.w);
540 painter->
setColor(pointcolor, alpha * cpt->scr.w);
541 painter->setVertex(cpt->scr);
553 XPlot::blendColor(
unsigned int c1,
unsigned int c2,
float t) {
554 unsigned char c1red = qRed((QRgb)c1);
555 unsigned char c1green = qGreen((QRgb)c1);
556 unsigned char c1blue = qBlue((QRgb)c1);
557 unsigned char c2red = qRed((QRgb)c2);
558 unsigned char c2green = qGreen((QRgb)c2);
559 unsigned char c2blue = qBlue((QRgb)c2);
560 return (
unsigned int)qRgb(
561 lrintf(c2red * t + c1red * (1.0f - t)),
562 lrintf(c2green * t + c1green * (1.0f - t)),
563 lrintf(c2blue * t + c1blue * (1.0f - t)));
568 return (pt.x >= 0) && (pt.x <= 1) &&
569 (pt.y >= 0) && (pt.y <= 1) &&
570 (pt.z >= 0) && (pt.z <= 1);
574 XPlot::clipLine(
const tCanvasPoint &c1,
const tCanvasPoint &c2,
576 unsigned int *color1,
unsigned int *color2,
float *alpha1,
float *alpha2) {
577 if(c1.insidecube && c2.insidecube) {
578 *s1 = c1.scr; *s2 = c2.scr;
590 XGraph::GFloat idx = 1.0 / (g1.x - g2.x);
591 XGraph::GFloat tx0 = -g2.x * idx;
592 XGraph::GFloat tx1 = (1.0 - g2.x) * idx;
593 XGraph::GFloat txmin = min(tx0, tx1);
594 XGraph::GFloat txmax = max(tx0, tx1);
596 XGraph::GFloat idy = 1.0 / (g1.y - g2.y);
597 XGraph::GFloat ty0 = -g2.y * idy;
598 XGraph::GFloat ty1 = (1.0 - g2.y) * idy;
599 XGraph::GFloat tymin = min(ty0, ty1);
600 XGraph::GFloat tymax = max(ty0, ty1);
602 XGraph::GFloat tmin = max(txmin, tymin);
603 XGraph::GFloat tmax = min(txmax, tymax);
606 if(tmin >= tmax)
return false;
607 XGraph::GFloat idz = 1.0 / (g1.z - g2.z);
608 XGraph::GFloat tz0 = -g2.z * idz;
609 XGraph::GFloat tz1 = (1.0 - g2.z) * idz;
610 XGraph::GFloat tzmin = min(tz0, tz1);
611 XGraph::GFloat tzmax = max(tz0, tz1);
612 tmin = max(tmin, tzmin);
613 tmax = min(tmax, tzmax);
616 if(tmin >= tmax)
return false;
617 if(tmin >= 1.0)
return false;
618 if(tmax <= 0.0)
return false;
622 tmin * g1.x + (1.0 - tmin) * g2.x,
623 tmin * g1.y + (1.0 - tmin) * g2.y,
624 tmin * g1.z + (1.0 - tmin) * g2.z)
627 *color2 = blendColor(c2.color, c1.color, tmin);
628 *alpha2 = tmin * c1.scr.w + (1.0 - tmin) * c2.scr.w;
640 tmax * g1.x + (1.0 - tmax) * g2.x,
641 tmax * g1.y + (1.0 - tmax) * g2.y,
642 tmax * g1.z + (1.0 - tmax) * g2.z)
645 *color2 = blendColor(c2.color, c1.color, tmax);
646 *alpha2 = tmax * c1.scr.w + (1.0 - tmax) * c2.scr.w;
661 bool autoscale_x = shot[ *m_curAxisX->autoScale()];
662 bool autoscale_y = shot[ *m_curAxisY->autoScale()];
663 bool autoscale_z = m_curAxisZ ? shot[ *m_curAxisZ->autoScale()] :
false;
664 bool autoscale_w = m_curAxisW ? shot[ *m_curAxisW->autoScale()] :
false;
665 for(
unsigned int i = 0; i < m_ptsSnapped.size(); ++i) {
667 bool included =
true;
668 included = included && (autoscale_x || m_curAxisX->isIncluded(pt.x));
669 included = included && (autoscale_y || m_curAxisY->isIncluded(pt.y));
671 included = included && (autoscale_z || m_curAxisZ->isIncluded(pt.z));
673 included = included && (autoscale_w || m_curAxisW->isIncluded(pt.w));
675 included = included && (pt.w > (XGraph::VFloat)1e-20);
677 m_curAxisX->tryInclude(pt.x);
678 m_curAxisY->tryInclude(pt.y);
680 m_curAxisZ->tryInclude(pt.z);
682 m_curAxisW->tryInclude(pt.w);
691 tr[ *
this].points().clear();
694 tr[ *
this].m_startPos = 0;
695 shared_ptr<XGraph> graph(m_graph.lock());
696 tr.mark(shot[ *graph].onUpdate(), graph.get());
701 const auto &points(shot[ *
this].points());
702 int offset = shot[ *
this].m_startPos;
703 int cnt = (int)points.size();
704 m_ptsSnapped.resize(cnt);
706 for(
int i = 0; i < cnt; ++i) {
707 m_ptsSnapped[i] = points[j % cnt];
713 XGraph::VFloat x, XGraph::VFloat y, XGraph::VFloat z, XGraph::VFloat w) {
716 shared_ptr<XGraph> graph(m_graph.lock());
719 auto &points(tr[ *
this].points());
720 unsigned int offset = shot[ *
this].m_startPos;
721 unsigned int maxcount = shot[ *maxCount()];
722 if((offset && (points.size() < maxcount)) || (points.size() > maxcount)) {
726 if(points.size() > maxcount) {
728 j += points.size() - maxcount;
729 j = j % points.size();
730 points.resize(maxcount);
732 for(
int i = 0; i < points.size(); ++i) {
733 points[i] = buf[j % buf.size()];
737 tr[ *
this].m_startPos = 0;
741 if(points.size() == maxcount) {
742 unsigned int startpos = offset + 1;
743 if(startpos >= points.size())
745 tr[ *
this].m_startPos = startpos;
747 points[offset] = npt;
750 points.push_back(npt);
752 tr.mark(shot[ *graph].onUpdate(), graph.get());
755 XAxis::XAxis(
const char *name,
bool runtime,
756 AxisDirection dir,
bool rightOrTop,
Transaction &tr_graph,
const shared_ptr<XGraph> &graph) :
757 XNode(name, runtime),
759 m_dirVector( (dir == DirAxisX) ? 1.0 : 0.0,
760 (dir == DirAxisY) ? 1.0 : 0.0, (dir == DirAxisZ) ? 1.0 : 0.0),
767 m_majorTicScale(create<
XDoubleNode>(
"MajorTicScale", true)),
768 m_minorTicScale(create<
XDoubleNode>(
"MinorTicScale", true)),
769 m_displayMajorTics(create<
XBoolNode>(
"DisplayMajorTics", true)),
770 m_displayMinorTics(create<
XBoolNode>(
"DisplayMinorTics", true)),
773 m_rightOrTopSided(create<
XBoolNode>(
"RightOrTopSided", true)),
774 m_ticLabelFormat(create<
XStringNode>(
"TicLabelFormat", true)),
775 m_displayLabel(create<
XBoolNode>(
"DisplayLabel", true)),
776 m_displayTicLabels(create<
XBoolNode>(
"DisplayTicLabels", true)),
777 m_ticColor(create<
XHexNode>(
"TicColor", true)),
778 m_labelColor(create<
XHexNode>(
"LabelColor", true)),
779 m_ticLabelColor(create<
XHexNode>(
"TicLabelColor", true)),
780 m_autoFreq(create<
XBoolNode>(
"AutoFreq", true)),
781 m_autoScale(create<
XBoolNode>(
"AutoScale", true)),
782 m_logScale(create<
XBoolNode>(
"LogScale", true)) {
783 m_ticLabelFormat->setValidator(&formatDoubleValidator);
789 tr[ *length()] = 0.7;
790 tr[ *maxValue()] = 0;
791 tr[ *minValue()] = 0;
792 tr[ *ticLabelFormat()] =
"";
793 tr[ *logScale()] =
false;
794 tr[ *displayLabel()] =
true;
795 tr[ *displayTicLabels()] =
true;
796 tr[ *displayMajorTics()] =
true;
797 tr[ *displayMinorTics()] =
true;
798 tr[ *autoFreq()] =
true;
799 tr[ *autoScale()] =
true;
800 tr[ *rightOrTopSided()] = rightOrTop;
801 tr[ *majorTicScale()] = 10;
802 tr[ *minorTicScale()] = 1;
803 tr[ *labelColor()] = clBlack;
804 tr[ *ticColor()] = clBlack;
805 tr[ *ticLabelColor()] = clBlack;
808 if(dir == DirAxisY) tr[ *x()] = 1.0- tr[ *x()];
809 if(dir == DirAxisX) tr[ *y()] = 1.0- tr[ *y()];
812 startAutoscale_(tr,
true);
814 tr[ *maxValue()].onValueChanged().connect(graph->lsnPropertyChanged());
815 tr[ *minValue()].onValueChanged().connect(graph->lsnPropertyChanged());
816 tr[ *label()].onValueChanged().connect(graph->lsnPropertyChanged());
817 tr[ *logScale()].onValueChanged().connect(graph->lsnPropertyChanged());
818 tr[ *autoScale()].onValueChanged().connect(graph->lsnPropertyChanged());
819 tr[ *x()].onValueChanged().connect(graph->lsnPropertyChanged());
820 tr[ *y()].onValueChanged().connect(graph->lsnPropertyChanged());
821 tr[ *z()].onValueChanged().connect(graph->lsnPropertyChanged());
822 tr[ *length()].onValueChanged().connect(graph->lsnPropertyChanged());
823 tr[ *ticLabelFormat()].onValueChanged().connect(graph->lsnPropertyChanged());
824 tr[ *displayLabel()].onValueChanged().connect(graph->lsnPropertyChanged());
825 tr[ *displayTicLabels()].onValueChanged().connect(graph->lsnPropertyChanged());
826 tr[ *displayMajorTics()].onValueChanged().connect(graph->lsnPropertyChanged());
827 tr[ *displayMinorTics()].onValueChanged().connect(graph->lsnPropertyChanged());
828 tr[ *autoFreq()].onValueChanged().connect(graph->lsnPropertyChanged());
829 tr[ *rightOrTopSided()].onValueChanged().connect(graph->lsnPropertyChanged());
830 tr[ *majorTicScale()].onValueChanged().connect(graph->lsnPropertyChanged());
831 tr[ *minorTicScale()].onValueChanged().connect(graph->lsnPropertyChanged());
832 tr[ *labelColor()].onValueChanged().connect(graph->lsnPropertyChanged());
833 tr[ *ticColor()].onValueChanged().connect(graph->lsnPropertyChanged());
834 tr[ *ticLabelColor()].onValueChanged().connect(graph->lsnPropertyChanged());
840 XAxis::startAutoscale_(
const Snapshot &shot,
bool clearscale) {
841 m_bLogscaleFixed = shot[ *logScale()];
842 m_bAutoscaleFixed = shot[ *autoScale()];
844 m_minFixed = XGraph::VFLOAT_MAX;
845 m_maxFixed = m_bLogscaleFixed ? 0 : - XGraph::VFLOAT_MAX;
848 m_minFixed = m_bLogscaleFixed ?
849 max((XGraph::VFloat)shot[ *minValue()], (XGraph::VFloat)0.0) :
850 (
XGraph::VFloat)shot[ *minValue()];
851 m_maxFixed = shot[ *maxValue()];
853 m_invMaxMinusMinFixed = -1;
854 m_invLogMaxOverMinFixed = -1;
858 startAutoscale_(shot, clearscale);
863 shared_ptr<XGraph> graph(m_graph.lock());
864 if(m_minFixed == m_maxFixed) {
865 XGraph::VFloat x = m_minFixed;
866 m_maxFixed = x ? std::max(x * 1.01, x * 0.99) : 0.01;
867 m_minFixed = x ? std::min(x * 1.01, x * 0.99) : -0.01;
869 XGraph::VFloat min_tmp = m_bLogscaleFixed ?
870 max((XGraph::VFloat)shot[ *minValue()], (XGraph::VFloat)0.0) :
871 (XGraph::VFloat)shot[ *minValue()];
872 if(m_minFixed != min_tmp) {
873 minValue()->setFormat(shot[ *ticLabelFormat()].to_str().c_str());
874 tr[ *minValue()] = m_minFixed;
876 if(m_maxFixed != shot[ *maxValue()]) {
877 maxValue()->setFormat(shot[ *ticLabelFormat()].to_str().c_str());
878 tr[ *maxValue()] = m_maxFixed;
881 tr.unmark(graph->lsnPropertyChanged());
883 performAutoFreq(shot, resolution);
886 XAxis::performAutoFreq(
const Snapshot &shot,
float resolution) {
887 if(shot[ *autoFreq()] &&
888 ( !m_bLogscaleFixed || (m_minFixed >= 0)) &&
889 (m_minFixed < m_maxFixed)) {
890 float fac = max(0.8f, log10f(2e-3 / resolution) );
891 m_majorFixed = (VFLOAT_POW((XGraph::VFloat)10.0,
892 VFLOAT_RINT(VFLOAT_LOG10(m_maxFixed - m_minFixed) - fac)));
893 m_minorFixed = m_majorFixed / (XGraph::VFloat)2.0;
896 m_majorFixed = shot[ *majorTicScale()];
897 m_minorFixed = shot[ *minorTicScale()];
902 XAxis::isIncluded(XGraph::VFloat x) {
903 return (x >= m_minFixed)
904 && ((m_direction == AxisWeight) || (x <= m_maxFixed));
907 XAxis::tryInclude(XGraph::VFloat x) {
909 if( !(m_bLogscaleFixed && (x <= 0))) {
910 if(m_bAutoscaleFixed) {
913 m_invMaxMinusMinFixed = -1;
914 m_invLogMaxOverMinFixed = -1;
918 m_invMaxMinusMinFixed = -1;
919 m_invLogMaxOverMinFixed = -1;
926 XAxis::zoom(
bool minchange,
bool maxchange, XGraph::GFloat prop, XGraph::GFloat center) {
927 if(direction() == AxisWeight)
return;
930 m_maxFixed =
axisToVal(center + (XGraph::GFloat)0.5 / prop);
933 m_minFixed =
axisToVal(center - (XGraph::GFloat)0.5 / prop);
935 m_invMaxMinusMinFixed = -1;
936 m_invLogMaxOverMinFixed = -1;
942 if(m_bLogscaleFixed) {
943 if ((x <= 0) || (m_minFixed <= 0) || (m_maxFixed <= m_minFixed))
944 return - XGraph::GFLOAT_MAX;
945 if(m_invLogMaxOverMinFixed < 0)
946 m_invLogMaxOverMinFixed = 1 / VFLOAT_LOG(m_maxFixed / m_minFixed);
947 pos = VFLOAT_LOG(x / m_minFixed) * m_invLogMaxOverMinFixed;
950 if(m_maxFixed <= m_minFixed)
return -1;
951 if(m_invMaxMinusMinFixed < 0)
952 m_invMaxMinusMinFixed = 1 / (m_maxFixed - m_minFixed);
953 pos = (x - m_minFixed) * m_invMaxMinusMinFixed;
960 XGraph::VFloat x = 0;
962 if(m_bLogscaleFixed) {
963 if((m_minFixed <= 0) || (m_maxFixed < m_minFixed))
return 0;
964 x = m_minFixed * VFLOAT_EXP(VFLOAT_LOG(m_maxFixed / m_minFixed) * pos);
967 if(m_maxFixed < m_minFixed)
return 0;
968 x = m_minFixed + pos *(m_maxFixed - m_minFixed);
974 XGraph::VFloat dx =
axisToVal(pos + axis_prec) - x;
975 return setprec(x, dx);
981 XGraph::SFloat len = shot[ *length()];
983 scr->x = shot[ *x()] + ((m_direction == DirAxisX) ? pos: (XGraph::SFloat) 0.0);
984 scr->y = shot[ *y()] + ((m_direction == DirAxisY) ? pos: (XGraph::SFloat) 0.0);
985 scr->z = shot[ *z()] + ((m_direction == DirAxisZ) ? pos: (XGraph::SFloat) 0.0);
989 XGraph::SFloat _x = scr.x - shot[ *x()];
990 XGraph::SFloat _y = scr.y - shot[ *y()];
991 XGraph::SFloat _z = scr.z - shot[ *z()];
992 XGraph::GFloat pos = ((m_direction == DirAxisX) ? _x :
993 ((m_direction == DirAxisY) ? _y : _z)) / (XGraph::SFloat)shot[ *length()];
1005 XAxis::valToString(XGraph::VFloat val) {
1006 return formatDouble(( **ticLabelFormat())->to_str().c_str(), val);
1011 XGraph::VFloat x, t;
1012 if(m_bLogscaleFixed) {
1013 x =
axisToVal((XGraph::GFloat)pos / len);
1014 if(x <= 0)
return NoTics;
1015 t = VFLOAT_POW((XGraph::VFloat)10.0, VFLOAT_RINT(VFLOAT_LOG10(x)));
1016 if(GFLOAT_LRINT(
valToAxis(t) * len) == pos) {
1022 t = VFLOAT_RINT(x / (XGraph::VFloat)0.1) * (XGraph::VFloat)0.1 * t;
1024 t = VFLOAT_RINT(x) * t;
1025 if(GFLOAT_LRINT(
valToAxis(t) * len) == pos) {
1032 x =
axisToVal((XGraph::GFloat)pos / len);
1033 t = VFLOAT_RINT(x / m_majorFixed) * m_majorFixed;
1034 if(GFLOAT_LRINT(
valToAxis(t) * len) == pos) {
1038 t = VFLOAT_RINT(x / m_minorFixed) * m_minorFixed;
1039 if(GFLOAT_LRINT(
valToAxis(t) * len) == pos) {
1050 if(m_direction == AxisWeight)
return;
1052 const int sizehint = 2;
1053 painter->
setColor(shot[ *labelColor()]);
1059 painter->
posOffAxis(m_dirVector, &s1, AxisToLabel);
1062 if( !painter->
selectFont(shot[ *label()], s1, s2, s3, sizehint)) {
1063 painter->drawText(s1, shot[ *label()]);
1073 if( !painter->
selectFont(shot[ *label()], s1, s2, s3, sizehint)) {
1074 painter->drawText(s1, shot[ *label()]);
1082 painter->
posOffAxis(m_dirVector, &s1, -AxisToLabel);
1085 if( !painter->
selectFont(shot[ *label()], s1, s2, s3, sizehint)) {
1086 painter->drawText(s1, shot[ *label()]);
1094 if(m_direction == AxisWeight)
return -1;
1096 XGraph::SFloat LenMajorTicL = 0.01;
1097 XGraph::SFloat LenMinorTicL = 0.005;
1099 painter->
setColor(shot[ *ticColor()]);
1105 painter->beginLine();
1106 painter->setVertex(s1);
1107 painter->setVertex(s2);
1110 if(shot[ *displayLabel()]) {
1111 drawLabel(shot, painter);
1113 if(m_bLogscaleFixed && (m_minFixed < 0))
return -1;
1114 if(m_maxFixed <= m_minFixed)
return -1;
1116 int len = SFLOAT_LRINT(shot[ *length()] / painter->
resScreen());
1117 painter->defaultFont();
1118 XGraph::GFloat mindx = 2, lastg = -1;
1120 for(
int i = 0; i < len; ++i) {
1122 XGraph::GFloat x = (XGraph::GFloat)i / len;
1123 if(
queryTic(len, i, &z) == MajorTic) {
1124 if(mindx > x - lastg) {
1131 painter->
posOffAxis(m_dirVector, &s1, AxisToTicLabel);
1135 double var = setprec(z, m_bLogscaleFixed ? (XGraph::VFloat)z : m_minorFixed);
1136 painter->
selectFont(valToString(var), s1, s2, s3, 0);
1144 for(
int i = 0; i < len; ++i) {
1146 XGraph::GFloat x = (XGraph::GFloat)i / len;
1149 if(shot[ *displayMajorTics()]) {
1151 painter->
posOffAxis(m_dirVector, &s1, LenMajorTicL);
1153 painter->
posOffAxis(m_dirVector, &s2, -LenMajorTicL);
1154 painter->
setColor(shot[ *ticColor()]);
1155 painter->beginLine(1.0);
1156 painter->setVertex(s1);
1157 painter->setVertex(s2);
1160 if(shot[ *displayTicLabels()]) {
1162 painter->
posOffAxis(m_dirVector, &s1, AxisToTicLabel);
1163 double var = setprec(z, m_bLogscaleFixed ? (XGraph::VFloat)z : m_minorFixed);
1164 painter->drawText(s1, valToString(var));
1168 if(shot[ *displayMinorTics()]) {
1170 painter->
posOffAxis(m_dirVector, &s1, LenMinorTicL);
1172 painter->
posOffAxis(m_dirVector, &s2, -LenMinorTicL);
1173 painter->
setColor(shot[ *ticColor()]);
1174 painter->beginLine(1.0);
1175 painter->setVertex(s1);
1176 painter->setVertex(s2);
1187 XFuncPlot::XFuncPlot(
const char *name,
bool runtime,
Transaction &tr_graph,
const shared_ptr<XGraph> &graph)
1188 :
XPlot(name, runtime, tr_graph, graph) {
1189 trans( *maxCount()) = 300;
1194 unsigned int cnt = (
unsigned int)shot[ *maxCount()];
1195 m_ptsSnapped.resize(cnt);
1196 for(
unsigned int i = 0; i < cnt; ++i) {
1198 pt.x = m_curAxisX->axisToVal((XGraph::GFloat)i / cnt);