graph.cpp
1 /***************************************************************************
2  Copyright (C) 2002-2015 Kentaro Kitagawa
3  kitagawa@phys.s.u-tokyo.ac.jp
4 
5  This program is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License as published by the Free Software Foundation; either
8  version 2 of the License, or (at your option) any later version.
9 
10  You should have received a copy of the GNU Library General
11  Public License and a list of authors along with this program;
12  see the files COPYING and AUTHORS.
13 ***************************************************************************/
14 #include "graph.h"
15 #include "support.h"
16 
17 // \todo Use Payload for scales.
18 
19 #include "graphpainter.h"
20 
21 using std::min;
22 using std::max;
23 
24 #define GRAPH_UI_DELAY 10
25 
26 #include <float.h>
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;
30 
31 #define SFLOAT_EXP expf
32 #define GFLOAT_EXP expf
33 #define VFLOAT_EXP exp
34 
35 #define SFLOAT_POW powf
36 #define GFLOAT_POW powf
37 #define VFLOAT_POW pow
38 
39 #define SFLOAT_LOG logf
40 #define GFLOAT_LOG logf
41 #define VFLOAT_LOG log
42 
43 #define SFLOAT_LOG10 log10f
44 #define GFLOAT_LOG10 log10f
45 #define VFLOAT_LOG10 log10
46 
47 #define SFLOAT_LRINT lrintf
48 #define GFLOAT_LRINT lrintf
49 #define VFLOAT_LRINT lrint
50 
51 #define VFLOAT_RINT lrint
52 
53 #define AxisToLabel 0.09
54 #define AxisToTicLabel 0.015
55 #define UNZOOM_ABIT 0.95
56 
57 #define PLOT_POINT_SIZE 5.0
58 
59 #define PLOT_POINT_INTENS 0.5
60 #define PLOT_LINE_INTENS 0.7
61 #define PLOT_BAR_INTENS 0.4
62 
63 XGraph::XGraph(const char *name, bool runtime) :
64  XNode(name, runtime),
65  m_label(create<XStringNode>("Label", true)),
66  m_axes(create<XAxisList>("Axes", true)),
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)) {
72 
73  iterate_commit([=](Transaction &tr){
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;
83 
84  tr[ *label()] = name;
85 
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");
92  });
93 }
94 
95 void
96 XGraph::onPropertyChanged(const Snapshot &shot, XValueNodeBase *) {
97  Snapshot shot_this( *this);
98  shot_this.talk(shot_this[ *this].onUpdate(), this);
99 }
100 
101 void
102 XGraph::setupRedraw(Transaction &tr, float resolution) {
103  const Snapshot &shot(tr);
104  if(shot.size(axes())) {
105  const XNode::NodeList &axes_list( *shot.list(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()]);
109  }
110  }
111  if(shot.size(plots())) {
112  const XNode::NodeList &plots_list( *shot.list(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)) {
116  plot->snapshot(shot);
117  plot->validateAutoScale(shot);
118  }
119  }
120  }
121  if(shot.size(axes())) {
122  const XNode::NodeList &axes_list( *shot.list(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);
128  }
129  }
130 }
131 
132 void
133 XGraph::zoomAxes(Transaction &tr, float resolution,
134  XGraph::GFloat scale, const XGraph::ScrPoint &center) {
135  const Snapshot &shot(tr);
136  if(shot.size(axes())) {
137  const XNode::NodeList &axes_list( *shot.list(axes()));
138  for(auto it = axes_list.begin(); it != axes_list.end(); ++it) {
139  auto axis = static_pointer_cast<XAxis>( *it);
140  axis->startAutoscale(shot, resolution);
141  }
142  }
143 // validateAutoScale();
144  if(shot.size(axes())) {
145  const XNode::NodeList &axes_list( *shot.list(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);
150  }
151  }
152 }
153 
154 XPlot::XPlot(const char *name, bool runtime, Transaction &tr_graph, const shared_ptr<XGraph> &graph)
155  : XNode(name, runtime),
156  m_graph(graph),
157  m_label(create<XStringNode>("Label", true)),
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)), //, BarInnerColor;
170  m_colorPlotColorHigh(create<XHexNode>("ColorPlotColorHigh", true)),
171  m_colorPlotColorLow(create<XHexNode>("ColorPlotColorLow", true)),
172  m_clearPoints(create<XTouchableNode>("ClearPoints", true)),
173  m_axisX(create<XItemNode<XAxisList, XAxis> >("AxisX", true, ref(tr_graph), graph->axes())),
174  m_axisY(create<XItemNode<XAxisList, XAxis> >("AxisY", true, ref(tr_graph), graph->axes())),
175  m_axisZ(create<XItemNode<XAxisList, XAxis> >("AxisZ", true, ref(tr_graph), graph->axes())),
176  m_axisW(create<XItemNode<XAxisList, XAxis> >("AxisW", true, ref(tr_graph), graph->axes())),
177  //! z value without AxisZ
178  m_zwoAxisZ(create<XDoubleNode>("ZwoAxisZ", true)),
179  m_intensity(create<XDoubleNode>("Intensity", true)) {
180 
181  iterate_commit([=](Transaction &tr){
182  // MaxCount.value(0);
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;
198 
199  m_lsnClearPoints = tr[ *clearPoints()].onTouch().connect(
200  *this, &XPlot::onClearPoints);
201 
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());
216 
217  tr[ *zwoAxisZ()] = 0.15;
218  });
219 }
220 
221 bool
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) {
228  return false;
229  }
230  m_curAxisX = axisx;
231  m_curAxisY = axisy;
232  m_curAxisZ = axisz;
233  m_curAxisW = axisw;
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()];
238  if( !m_curAxisZ) {
239  m_scr0.z = shot[ *zwoAxisZ()];
240  m_len.z = (XGraph::SFloat)0.0;
241  }
242  else {
243  m_scr0.z = shot[ *m_curAxisZ->z()];
244  m_len.z = shot[ *m_curAxisZ->length()];
245  }
246  return true;
247 }
248 
249 void
250 XPlot::screenToGraph(const Snapshot &shot, const XGraph::ScrPoint &pt, XGraph::GPoint *g) {
251  shared_ptr<XAxis> axisx = shot[ *axisX()];
252  shared_ptr<XAxis> axisy = shot[ *axisY()];
253  shared_ptr<XAxis> axisz = shot[ *axisZ()];
254  if( !axisz)
255  g->z = (XGraph::GFloat)0.0;
256  else
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()];
260 }
261 void
262 XPlot::graphToVal(const Snapshot &shot, const XGraph::GPoint &pt, XGraph::ValPoint *val) {
263  if(fixScales(shot)) {
264  val->x = m_curAxisX->axisToVal(pt.x);
265  val->y = m_curAxisY->axisToVal(pt.y);
266  if(m_curAxisZ)
267  val->z = m_curAxisZ->axisToVal(pt.z);
268  else
269  val->z = (XGraph::VFloat)0.0;
270  }
271 }
272 int
273 XPlot::screenToVal(const Snapshot &shot, const XGraph::ScrPoint &scr, XGraph::ValPoint *val, XGraph::SFloat scr_prec) {
274  if(fixScales(shot)) {
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;
279  return 0;
280  }
281  return -1;
282 }
283 void
284 XPlot::graphToScreen(const Snapshot &shot, const XGraph::GPoint &pt, XGraph::ScrPoint *scr) {
285  if(fixScales(shot)) {
286  graphToScreenFast(pt, scr);
287  }
288 }
289 inline void
290 XPlot::graphToScreenFast(const XGraph::GPoint &pt, XGraph::ScrPoint *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);
295 }
296 inline void
297 XPlot::valToGraphFast(const XGraph::ValPoint &pt, XGraph::GPoint *gr) {
298  gr->x = m_curAxisX->valToAxis(pt.x);
299  gr->y = m_curAxisY->valToAxis(pt.y);
300  if(m_curAxisZ)
301  gr->z = m_curAxisZ->valToAxis(pt.z);
302  else
303  gr->z = 0.0;
304  if(m_curAxisW)
305  gr->w = m_curAxisW->valToAxis(pt.w);
306  else
307  gr->w = pt.w;
308 }
309 int
310 XPlot::findPoint(const Snapshot &shot, int start, const XGraph::GPoint &gmin, const XGraph::GPoint &gmax,
311  XGraph::GFloat width, XGraph::ValPoint *val, XGraph::GPoint *g1) {
312  if(fixScales(shot)) {
313  for(unsigned int i = start; i < m_ptsSnapped.size(); i++) {
315  XGraph::GPoint g2;
316  v = m_ptsSnapped[i];
317  valToGraphFast(v, &g2);
318  if(g2.distance2(gmin, gmax) < width*width) {
319  *val = v;
320  *g1 = g2;
321  return i;
322  }
323  }
324  }
325  return -1;
326 }
327 
328 void
329 XPlot::onClearPoints(const Snapshot &, XTouchableNode *) {
330  m_graph.lock()->iterate_commit([=](Transaction &tr){
331  clearAllPoints(tr);
332  });
333 }
334 
335 void
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) {
342  XGraph::ScrPoint s1, s2;
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;
348  graphToScreenFast(XGraph::GPoint((axis1 == m_curAxisX) ? x : 0.0,
349  (axis1 == m_curAxisY) ? x : 0.0, (axis1 == m_curAxisZ) ? x : 0.0), &s1);
350  graphToScreenFast(XGraph::GPoint(
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)),
354  &s2);
355  XGraph::VFloat tempx;
356  switch(axis1->queryTic(len, i, &tempx)) {
357  case XAxis::MajorTic:
358  if(disp_major) {
359  painter->setColor(major_color,
360  max(0.0, min(intens * 0.7, 0.5)) );
361  painter->setVertex(s1);
362  painter->setVertex(s2);
363  }
364  break;
365  case XAxis::MinorTic:
366  if(disp_minor) {
367  painter->setColor(minor_color,
368  max(0.0, min(intens * 0.5, 0.5)) );
369  painter->setVertex(s1);
370  painter->setVertex(s2);
371  }
372  break;
373  default:
374  break;
375  }
376  }
377  }
378  painter->endLine();
379 }
380 void
381 XPlot::drawGrid(const Snapshot &shot, XQGraphPainter *painter, bool drawzaxis) {
382  if(fixScales(shot)) {
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);
390  }
391  }
392 }
393 int
394 XPlot::drawLegend(const Snapshot &shot, XQGraphPainter *painter, const XGraph::ScrPoint &spt, float dx, float dy) {
395  if(fixScales(shot)) {
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;
401  float alpha2 = 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);
405  XGraph::ScrPoint s1, s2;
406  s1 = spt;
407  s1 += XGraph::ScrPoint(0, dy/2, 0);
408  s2 = spt;
409  s2 -= XGraph::ScrPoint(0, dy/2, 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);
416  painter->endLine();
417  }
418  if(shot[ *drawLines()]) {
419  float alpha = max(0.0f, min((float)(shot[ *intensity()] * PLOT_LINE_INTENS), 1.0f));
420  painter->beginLine(1.0);
421  XGraph::ScrPoint s1, s2;
422  s1 = spt;
423  s1 += XGraph::ScrPoint(dx/2, 0, 0);
424  s2 = spt;
425  s2 -= XGraph::ScrPoint(dx/2, 0, 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);
432  painter->endLine();
433  }
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);
438  if(colorplot)
439  painter->setColor(colorhigh);
440  painter->setVertex(spt);
441  if(colorplot) {
442  painter->setColor(colorhigh);
443  painter->setVertex(spt);
444  }
445  painter->endPoint();
446  }
447  return 0;
448  }
449  return -1;
450 }
451 
452 int
453 XPlot::drawPlot(const Snapshot &shot, XQGraphPainter *painter) {
454  if(fixScales(shot)) {
455  bool colorplot = shot[ *colorPlot()];
456  bool hasweight = !!m_curAxisW;
457  int cnt = m_ptsSnapped.size();
458  m_canvasPtsSnapped.resize(cnt);
459  tCanvasPoint *cpt;
460  {
461  XGraph::ScrPoint s1;
462  XGraph::GPoint g1;
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) {
468  XGraph::ValPoint pt = m_ptsSnapped[i];
469  valToGraphFast(pt, &g1);
470  graphToScreenFast(g1, &s1);
471  cpt->scr = s1;
472  cpt->graph = g1;
473  cpt->insidecube = isPtIncluded(g1);
474  if(colorplot) {
475  cpt->color = blendColor(colorlow, colorhigh,
476  hasweight ? cpt->graph.w : cpt->graph.z);
477  }
478  else {
479  cpt->color = linecolor;
480  }
481  cpt++;
482  }
483  }
484  if(shot[ *drawBars()]) {
485  XGraph::ScrPoint s1, s2;
486  tCanvasPoint pt2;
487  double g0y = m_curAxisY->valToAxis(0.0);
488  m_curAxisY->axisToScreen(shot, g0y, &s2);
489  double s0y = s2.y;
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) {
495  pt2 = *cpt;
496  pt2.graph.y = g0y;
497  pt2.scr.y = s0y;
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);
503  }
504  cpt++;
505  }
506  painter->endLine();
507  }
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);
512  XGraph::ScrPoint s1, s2;
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);
523  }
524  cpt++;
525  }
526  painter->endLine();
527  }
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) {
536  if(colorplot)
537  painter->setColor(cpt->color, alpha * cpt->scr.w);
538  else
539  if(hasweight)
540  painter->setColor(pointcolor, alpha * cpt->scr.w);
541  painter->setVertex(cpt->scr);
542  }
543  cpt++;
544  }
545  painter->endPoint();
546  }
547  return 0;
548  }
549  return -1;
550 }
551 
552 inline unsigned int
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)));
564 }
565 
566 inline bool
567 XPlot::isPtIncluded(const XGraph::GPoint &pt) {
568  return (pt.x >= 0) && (pt.x <= 1) &&
569  (pt.y >= 0) && (pt.y <= 1) &&
570  (pt.z >= 0) && (pt.z <= 1);
571 }
572 
573 inline bool
574 XPlot::clipLine(const tCanvasPoint &c1, const tCanvasPoint &c2,
575  XGraph::ScrPoint *s1, XGraph::ScrPoint *s2, bool blendcolor,
576  unsigned int *color1, unsigned int *color2, float *alpha1, float *alpha2) {
577  if(c1.insidecube && c2.insidecube) {
578  *s1 = c1.scr; *s2 = c2.scr;
579  if(blendcolor) {
580  *color1 = c1.color;
581  *color2 = c2.color;
582  *alpha1 = c1.scr.w;
583  *alpha2 = c1.scr.w;
584  }
585  return true;
586  }
587  XGraph::GPoint g1 = c1.graph;
588  XGraph::GPoint g2 = c2.graph;
589 
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);
595 
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);
601 
602  XGraph::GFloat tmin = max(txmin, tymin);
603  XGraph::GFloat tmax = min(txmax, tymax);
604 
605  if(m_curAxisZ) {
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);
614  }
615 
616  if(tmin >= tmax) return false;
617  if(tmin >= 1.0) return false;
618  if(tmax <= 0.0) return false;
619 
620  if(tmin > 0.0) {
621  graphToScreenFast(XGraph::GPoint(
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)
625  , s2);
626  if(blendcolor) {
627  *color2 = blendColor(c2.color, c1.color, tmin);
628  *alpha2 = tmin * c1.scr.w + (1.0 - tmin) * c2.scr.w;
629  }
630  }
631  else {
632  *s2 = c2.scr;
633  if(blendcolor) {
634  *color2 = c2.color;
635  *alpha2 = c2.scr.w;
636  }
637  }
638  if(tmax < 1.0) {
639  graphToScreenFast(XGraph::GPoint(
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)
643  , s1);
644  if(blendcolor) {
645  *color2 = blendColor(c2.color, c1.color, tmax);
646  *alpha2 = tmax * c1.scr.w + (1.0 - tmax) * c2.scr.w;
647  }
648  }
649  else {
650  *s1 = c1.scr;
651  if(blendcolor) {
652  *color1 = c1.color;
653  *alpha1 = c1.scr.w;
654  }
655  }
656  return true;
657 }
658 
659 int
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) {
666  XGraph::ValPoint &pt = m_ptsSnapped[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));
670  if(m_curAxisZ)
671  included = included && (autoscale_z || m_curAxisZ->isIncluded(pt.z));
672  if(m_curAxisW)
673  included = included && (autoscale_w || m_curAxisW->isIncluded(pt.w));
674  else
675  included = included && (pt.w > (XGraph::VFloat)1e-20);
676  if(included) {
677  m_curAxisX->tryInclude(pt.x);
678  m_curAxisY->tryInclude(pt.y);
679  if(m_curAxisZ)
680  m_curAxisZ->tryInclude(pt.z);
681  if(m_curAxisW)
682  m_curAxisW->tryInclude(pt.w);
683  }
684  }
685  return 0;
686 }
687 
688 void
689 XXYPlot::clearAllPoints(Transaction &tr) {
690  const Snapshot &shot(tr);
691  tr[ *this].points().clear();
692 // tr[ *this].points().shrink_to_fit();
693 // tr[ *this].points().reserve(shot[ *maxCount()]);
694  tr[ *this].m_startPos = 0;
695  shared_ptr<XGraph> graph(m_graph.lock());
696  tr.mark(shot[ *graph].onUpdate(), graph.get());
697 }
698 
699 void
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);
705  int j = offset;
706  for(int i = 0; i < cnt; ++i) {
707  m_ptsSnapped[i] = points[j % cnt];
708  ++j;
709  }
710 }
711 void
713  XGraph::VFloat x, XGraph::VFloat y, XGraph::VFloat z, XGraph::VFloat w) {
714  XGraph::ValPoint npt(x, y, z, w);
715 
716  shared_ptr<XGraph> graph(m_graph.lock());
717 
718  const Snapshot &shot(tr);
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)) {
723  //maxcount has changed. reorders.
724  auto buf = points;
725  int j = offset;
726  if(points.size() > maxcount) {
727  //maxcount has decreased.
728  j += points.size() - maxcount;
729  j = j % points.size();
730  points.resize(maxcount);
731  }
732  for(int i = 0; i < points.size(); ++i) {
733  points[i] = buf[j % buf.size()];
734  ++j;
735  }
736  offset = 0;
737  tr[ *this].m_startPos = 0;
738  }
739 
740 
741  if(points.size() == maxcount) {
742  unsigned int startpos = offset + 1;
743  if(startpos >= points.size())
744  startpos = 0;
745  tr[ *this].m_startPos = startpos;
746  if(points.size())
747  points[offset] = npt;
748  }
749  else {
750  points.push_back(npt);
751  }
752  tr.mark(shot[ *graph].onUpdate(), graph.get());
753 }
754 
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),
758  m_direction(dir),
759  m_dirVector( (dir == DirAxisX) ? 1.0 : 0.0,
760  (dir == DirAxisY) ? 1.0 : 0.0, (dir == DirAxisZ) ? 1.0 : 0.0),
761  m_graph(graph),
762  m_label(create<XStringNode>("Label", true)),
763  m_x(create<XDoubleNode>("X", true)),
764  m_y(create<XDoubleNode>("Y", true)),
765  m_z(create<XDoubleNode>("Z", true)),
766  m_length(create<XDoubleNode>("Length", true)), // in screen coordinate
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)),
771  m_max(create<XDoubleNode>("Max", true)),
772  m_min(create<XDoubleNode>("Min", true)),
773  m_rightOrTopSided(create<XBoolNode>("RightOrTopSided", true)), //sit on right, top
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);
784 
785  iterate_commit([=](Transaction &tr){
786  tr[ *x()] = 0.15;
787  tr[ *y()] = 0.15;
788  tr[ *z()] = 0.15;
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;
806 
807  if(rightOrTop) {
808  if(dir == DirAxisY) tr[ *x()] = 1.0- tr[ *x()];
809  if(dir == DirAxisX) tr[ *y()] = 1.0- tr[ *y()];
810  }
811 
812  startAutoscale_(tr, true);
813 
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());
835  });
836 }
837 
838 
839 void
840 XAxis::startAutoscale_(const Snapshot &shot, bool clearscale) {
841  m_bLogscaleFixed = shot[ *logScale()];
842  m_bAutoscaleFixed = shot[ *autoScale()];
843  if(clearscale) {
844  m_minFixed = XGraph::VFLOAT_MAX;
845  m_maxFixed = m_bLogscaleFixed ? 0 : - XGraph::VFLOAT_MAX;
846  }
847  else {
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()];
852  }
853  m_invMaxMinusMinFixed = -1; //undef
854  m_invLogMaxOverMinFixed = -1; //undef
855 }
856 void
857 XAxis::startAutoscale(const Snapshot &shot, float, bool clearscale) {
858  startAutoscale_(shot, clearscale);
859 }
860 void
861 XAxis::fixScale(Transaction &tr, float resolution, bool suppressupdate) {
862  const Snapshot &shot(tr);
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;
868  }
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;
875  }
876  if(m_maxFixed != shot[ *maxValue()]) {
877  maxValue()->setFormat(shot[ *ticLabelFormat()].to_str().c_str());
878  tr[ *maxValue()] = m_maxFixed;
879  }
880  if(suppressupdate) {
881  tr.unmark(graph->lsnPropertyChanged());
882  }
883  performAutoFreq(shot, resolution);
884 }
885 void
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;
894  }
895  else {
896  m_majorFixed = shot[ *majorTicScale()];
897  m_minorFixed = shot[ *minorTicScale()];
898  }
899 }
900 
901 inline bool
902 XAxis::isIncluded(XGraph::VFloat x) {
903  return (x >= m_minFixed)
904  && ((m_direction == AxisWeight) || (x <= m_maxFixed));
905 }
906 inline void
907 XAxis::tryInclude(XGraph::VFloat x) {
908  //omits negative values in log scaling
909  if( !(m_bLogscaleFixed && (x <= 0))) {
910  if(m_bAutoscaleFixed) {
911  if(x > m_maxFixed) {
912  m_maxFixed = x;
913  m_invMaxMinusMinFixed = -1; //undef
914  m_invLogMaxOverMinFixed = -1; //undef
915  }
916  if(x < m_minFixed) {
917  m_minFixed = x;
918  m_invMaxMinusMinFixed = -1; //undef
919  m_invLogMaxOverMinFixed = -1; //undef
920  }
921  }
922  }
923 }
924 
925 void
926 XAxis::zoom(bool minchange, bool maxchange, XGraph::GFloat prop, XGraph::GFloat center) {
927  if(direction() == AxisWeight) return;
928 
929  if(maxchange) {
930  m_maxFixed = axisToVal(center + (XGraph::GFloat)0.5 / prop);
931  }
932  if(minchange) {
933  m_minFixed = axisToVal(center - (XGraph::GFloat)0.5 / prop);
934  }
935  m_invMaxMinusMinFixed = -1; //undef
936  m_invLogMaxOverMinFixed = -1; //undef
937 }
938 
939 XGraph::GFloat
940 XAxis::valToAxis(XGraph::VFloat x) {
941  XGraph::GFloat pos;
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;
948  }
949  else {
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;
954  }
955  return pos;
956 }
957 
958 XGraph::VFloat
959 XAxis::axisToVal(XGraph::GFloat pos, XGraph::GFloat axis_prec) {
960  XGraph::VFloat x = 0;
961  if(axis_prec <= 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);
965  }
966  else {
967  if(m_maxFixed < m_minFixed) return 0;
968  x = m_minFixed + pos *(m_maxFixed - m_minFixed);
969  }
970  return x;
971  }
972  else {
973  x = axisToVal(pos);
974  XGraph::VFloat dx = axisToVal(pos + axis_prec) - x;
975  return setprec(x, dx);
976  }
977 }
978 
979 void
980 XAxis::axisToScreen(const Snapshot &shot, XGraph::GFloat pos, XGraph::ScrPoint *scr) {
981  XGraph::SFloat len = shot[ *length()];
982  pos *= len;
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);
986 }
987 XGraph::GFloat
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()];
994  return pos;
995 }
996 XGraph::VFloat
997 XAxis::screenToVal(const Snapshot &shot, const XGraph::ScrPoint &scr) {
998  return axisToVal(screenToAxis(shot, scr));
999 }
1000 void
1001 XAxis::valToScreen(const Snapshot &shot, XGraph::VFloat val, XGraph::ScrPoint *scr) {
1002  axisToScreen(shot, valToAxis(val), scr);
1003 }
1004 XString
1005 XAxis::valToString(XGraph::VFloat val) {
1006  return formatDouble(( **ticLabelFormat())->to_str().c_str(), val);
1007 }
1008 
1009 XAxis::Tic
1010 XAxis::queryTic(int len, int pos, XGraph::VFloat *ticnum) {
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) {
1017  *ticnum = t;
1018  return MajorTic;
1019  }
1020  x = x / t;
1021  if(x < 1)
1022  t = VFLOAT_RINT(x / (XGraph::VFloat)0.1) * (XGraph::VFloat)0.1 * t;
1023  else
1024  t = VFLOAT_RINT(x) * t;
1025  if(GFLOAT_LRINT(valToAxis(t) * len) == pos) {
1026  *ticnum = t;
1027  return MinorTic;
1028  }
1029  return NoTics;
1030  }
1031  else {
1032  x = axisToVal((XGraph::GFloat)pos / len);
1033  t = VFLOAT_RINT(x / m_majorFixed) * m_majorFixed;
1034  if(GFLOAT_LRINT(valToAxis(t) * len) == pos) {
1035  *ticnum = t;
1036  return MajorTic;
1037  }
1038  t = VFLOAT_RINT(x / m_minorFixed) * m_minorFixed;
1039  if(GFLOAT_LRINT(valToAxis(t) * len) == pos) {
1040  *ticnum = t;
1041  return MinorTic;
1042  }
1043  return NoTics;
1044  }
1045 }
1046 
1047 
1048 void
1049 XAxis::drawLabel(const Snapshot &shot, XQGraphPainter *painter) {
1050  if(m_direction == AxisWeight) return;
1051 
1052  const int sizehint = 2;
1053  painter->setColor(shot[ *labelColor()]);
1054  XGraph::ScrPoint s1, s2, s3;
1055  axisToScreen(shot, 0.5, &s1);
1056  s2 = s1;
1057  axisToScreen(shot, 1.5, &s3);
1058  s3 -= s2;
1059  painter->posOffAxis(m_dirVector, &s1, AxisToLabel);
1060  s2 -= s1;
1061  s2 *= -1;
1062  if( !painter->selectFont(shot[ *label()], s1, s2, s3, sizehint)) {
1063  painter->drawText(s1, shot[ *label()]);
1064  return;
1065  }
1066 
1067  axisToScreen(shot, 1.02, &s1);
1068  axisToScreen(shot, 1.05, &s2);
1069  s2 -= s1;
1070  s3 = s1;
1071  painter->posOffAxis(m_dirVector, &s3, 0.7);
1072  s3 -= s1;
1073  if( !painter->selectFont(shot[ *label()], s1, s2, s3, sizehint)) {
1074  painter->drawText(s1, shot[ *label()]);
1075  return;
1076  }
1077 
1078  axisToScreen(shot, 0.5, &s1);
1079  s2 = s1;
1080  axisToScreen(shot, 1.5, &s3);
1081  s3 -= s2;
1082  painter->posOffAxis(m_dirVector, &s1, -AxisToLabel);
1083  s2 -= s1;
1084  s2 *= -1;
1085  if( !painter->selectFont(shot[ *label()], s1, s2, s3, sizehint)) {
1086  painter->drawText(s1, shot[ *label()]);
1087  return;
1088  }
1089 }
1090 
1091 
1092 int
1093 XAxis::drawAxis(const Snapshot &shot, XQGraphPainter *painter) {
1094  if(m_direction == AxisWeight) return -1;
1095 
1096  XGraph::SFloat LenMajorTicL = 0.01;
1097  XGraph::SFloat LenMinorTicL = 0.005;
1098 
1099  painter->setColor(shot[ *ticColor()]);
1100 
1101  XGraph::ScrPoint s1, s2;
1102  axisToScreen(shot, 0.0, &s1);
1103  axisToScreen(shot, 1.0, &s2);
1104 
1105  painter->beginLine();
1106  painter->setVertex(s1);
1107  painter->setVertex(s2);
1108  painter->endLine();
1109 
1110  if(shot[ *displayLabel()]) {
1111  drawLabel(shot, painter);
1112  }
1113  if(m_bLogscaleFixed && (m_minFixed < 0)) return -1;
1114  if(m_maxFixed <= m_minFixed) return -1;
1115 
1116  int len = SFLOAT_LRINT(shot[ *length()] / painter->resScreen());
1117  painter->defaultFont();
1118  XGraph::GFloat mindx = 2, lastg = -1;
1119  //dry-running to determine a font
1120  for(int i = 0; i < len; ++i) {
1121  XGraph::VFloat z;
1122  XGraph::GFloat x = (XGraph::GFloat)i / len;
1123  if(queryTic(len, i, &z) == MajorTic) {
1124  if(mindx > x - lastg) {
1125  axisToScreen(shot, x, &s1);
1126  s2 = s1;
1127  XGraph::ScrPoint s3;
1128  axisToScreen(shot, lastg, &s3);
1129  s3 -= s2;
1130  s3 *= 0.7;
1131  painter->posOffAxis(m_dirVector, &s1, AxisToTicLabel);
1132  s2 -= s1;
1133  s2 *= -1;
1134 
1135  double var = setprec(z, m_bLogscaleFixed ? (XGraph::VFloat)z : m_minorFixed);
1136  painter->selectFont(valToString(var), s1, s2, s3, 0);
1137 
1138  mindx = x - lastg;
1139  }
1140  lastg = x;
1141  }
1142  }
1143 
1144  for(int i = 0; i < len; ++i) {
1145  XGraph::VFloat z;
1146  XGraph::GFloat x = (XGraph::GFloat)i / len;
1147  switch(queryTic(len, i, &z)) {
1148  case MajorTic:
1149  if(shot[ *displayMajorTics()]) {
1150  axisToScreen(shot, x, &s1);
1151  painter->posOffAxis(m_dirVector, &s1, LenMajorTicL);
1152  axisToScreen(shot, x, &s2);
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);
1158  painter->endLine();
1159  }
1160  if(shot[ *displayTicLabels()]) {
1161  axisToScreen(shot, x, &s1);
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));
1165  }
1166  break;
1167  case MinorTic:
1168  if(shot[ *displayMinorTics()]) {
1169  axisToScreen(shot, x, &s1);
1170  painter->posOffAxis(m_dirVector, &s1, LenMinorTicL);
1171  axisToScreen(shot, x, &s2);
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);
1177  painter->endLine();
1178  }
1179  break;
1180  case NoTics:
1181  break;
1182  }
1183  }
1184  return 0;
1185 }
1186 
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;
1190 }
1191 
1192 void
1194  unsigned int cnt = (unsigned int)shot[ *maxCount()];
1195  m_ptsSnapped.resize(cnt);
1196  for(unsigned int i = 0; i < cnt; ++i) {
1197  XGraph::ValPoint &pt(m_ptsSnapped[i]);
1198  pt.x = m_curAxisX->axisToVal((XGraph::GFloat)i / cnt);
1199  pt.y = func(pt.x);
1200  pt.z = 0.0;
1201  }
1202 }
1203 

Generated for KAME4 by  doxygen 1.8.3