14 #include "graphpainter.h"
16 #include "graphwidget.h"
18 #include <QFontMetrics>
21 #define SELECT_WIDTH 0.02
22 #define SELECT_DEPTH 0.1
29 return 1.0f / max(m_pItem->width(), m_pItem->height());
34 repaintBuffer(x1, y1, x2, y2);
41 windowToScreen(m_pItem->width() / 2, m_pItem->height() / 2, 0.0, &scr);
42 windowToScreen(m_pItem->width() / 2, m_pItem->height() / 2, 1.0, &dir_proj);
46 if(screenToWindow(*src, &x, &y, &z))
return;
47 x = x / m_pItem->width() - 0.5;
48 y = y / m_pItem->height() - 0.5;
49 double r1 = x*x + y*y;
51 s1.vectorProduct(dir);
55 int ret = screenToWindow(*src, &x, &y, &z);
56 x = x / m_pItem->width() - 0.5;
57 y = y / m_pItem->height() - 0.5;
58 double r2 = x*x + y*y;
59 if(ret || ((r2 - r1) * offset < 0) ) {
67 shared_ptr<XAxis> found_axis;
69 if(shot.size(m_graph->axes())) {
71 for(
auto it = axes_list.begin(); it != axes_list.end(); it++) {
72 auto axis = dynamic_pointer_cast<
XAxis>(*it);
75 axis->axisToScreen(shot, axis->screenToAxis(shot, s1), &s2);
87 shared_ptr<XAxis> *axis1, shared_ptr<XAxis> *axis2) {
89 shared_ptr<XPlot> plot_found;
90 if(shot.size(m_graph->plots())) {
91 const auto &plots_list( *shot.list(m_graph->plots()));
92 for(
auto it = plots_list.begin(); it != plots_list.end(); it++) {
93 shared_ptr<XPlot> plot = dynamic_pointer_cast<
XPlot>( *it);
95 shared_ptr<XAxis> axisx = shot[ *plot->axisX()];
96 shared_ptr<XAxis> axisy = shot[ *plot->axisY()];
97 shared_ptr<XAxis> axisz = shot[ *plot->axisZ()];
100 plot->screenToGraph(shot, s1, &g1);
101 if((fabs(g1.x) < zmin) && axisz) {
107 if((fabs(g1.y) < zmin) && axisz) {
113 if(fabs(g1.z) < zmin) {
125 XQGraphPainter::selectObjs(
int x,
int y, SelectionState state, SelectionMode mode) {
126 m_pointerLastPos[0] = x;
127 m_pointerLastPos[1] = y;
130 if(state != SelStart)
return;
136 m_selectionStateNow = state;
139 m_selectionModeNow = mode;
140 m_selStartPos[0] = x;
141 m_selStartPos[1] = y;
142 m_tiltLastPos[0] = x;
143 m_tiltLastPos[1] = y;
146 m_foundPlane.reset();
148 (
int)(SELECT_WIDTH * m_pItem->width()),
149 (
int)(SELECT_WIDTH * m_pItem->height()),
150 &m_startScrPos, &m_startScrDX, &m_startScrDY);
152 m_foundPlane = findPlane(
Snapshot( *m_graph), m_startScrPos, &m_foundPlaneAxis1, &m_foundPlaneAxis2);
153 m_finishScrPos = m_startScrPos;
158 (
int)(SELECT_WIDTH * m_pItem->width()),
159 (
int)(SELECT_WIDTH * m_pItem->height()),
160 &m_startScrPos, &m_startScrDX, &m_startScrDY);
161 if(z < 1.0) m_foundAxis = findAxis(
Snapshot( *m_graph), m_startScrPos);
162 m_finishScrPos = m_startScrPos;
170 mode = m_selectionModeNow;
174 mode = m_selectionModeNow;
175 m_selectionModeNow = SelNone;
180 m_foundPlane.reset();
182 (
int)(SELECT_WIDTH * m_pItem->width()),
183 (
int)(SELECT_WIDTH * m_pItem->height()),
184 &m_finishScrPos, &m_finishScrDX, &m_finishScrDY);
186 m_foundPlane = findPlane(
Snapshot( *m_graph), m_finishScrPos, &m_foundPlaneAxis1, &m_foundPlaneAxis2);
190 (
int)(SELECT_WIDTH * m_pItem->width()),
191 (
int)(SELECT_WIDTH * m_pItem->height()),
192 &m_finishScrPos, &m_finishScrDX, &m_finishScrDY);
196 (
int)(SELECT_WIDTH * m_pItem->width()),
197 (
int)(SELECT_WIDTH * m_pItem->height()),
198 &m_finishScrPos, &m_finishScrDX, &m_finishScrDY);
202 float x0 = (float)m_tiltLastPos[0] / m_pItem->width() - 0.5;
203 float y0 = (1.0f - (float)m_tiltLastPos[1] / m_pItem->height()) - 0.5;
205 float x1 = (float)x / m_pItem->width() - 0.5;
206 float y1 = (1.0f - (float)y / m_pItem->height()) - 0.5;
209 x2 = y0 * z1 - z0 * y1;
210 y2 = z0 * x1 - x0 * z1;
211 z2 = x0 * y1 - y0 * x1;
212 float k = sqrt(x2*x2 + y2*y2 + z2*z2);
213 x2 /= k; y2 /= k; z2 /= k;
214 viewRotate( -pow(k/(z0/4), 1.4f)*90, x2, y2, z2);
215 m_tiltLastPos[0] = x;
216 m_tiltLastPos[1] = y;
222 if(state == SelFinish) {
223 if((abs(x - m_selStartPos[0]) < 3) && (abs(y - m_selStartPos[1]) < 3)) {
231 if(tr.size(m_graph->axes())) {
232 const auto &axes_list( *tr.list(m_graph->axes()));
233 for(
auto it = axes_list.begin(); it != axes_list.end(); it++) {
234 shared_ptr<XAxis> axis = static_pointer_cast<
XAxis>(*it);
235 if(tr[ *axis->autoScale()].isUIEnabled())
236 tr[ *axis->autoScale()] =
true;
241 if(tr[ *m_foundAxis->autoScale()].isUIEnabled())
242 tr[ *m_foundAxis->autoScale()] =
true;
257 if(m_foundPlane && !(m_startScrPos == m_finishScrPos) ) {
258 XGraph::VFloat src1 = m_foundPlaneAxis1->screenToVal(tr, m_startScrPos);
259 XGraph::VFloat src2 = m_foundPlaneAxis2->screenToVal(tr, m_startScrPos);
260 XGraph::VFloat dst1 = m_foundPlaneAxis1->screenToVal(tr, m_finishScrPos);
261 XGraph::VFloat dst2 = m_foundPlaneAxis2->screenToVal(tr, m_finishScrPos);
263 if(tr[ *m_foundPlaneAxis1->minValue()].isUIEnabled())
264 tr[ *m_foundPlaneAxis1->minValue()] = double(min(src1, dst1));
265 if(tr[ *m_foundPlaneAxis1->maxValue()].isUIEnabled())
266 tr[ *m_foundPlaneAxis1->maxValue()] = double(max(src1, dst1));
267 if(tr[ *m_foundPlaneAxis1->autoScale()].isUIEnabled())
268 tr[ *m_foundPlaneAxis1->autoScale()] =
false;
269 if(tr[ *m_foundPlaneAxis2->minValue()].isUIEnabled())
270 tr[ *m_foundPlaneAxis2->minValue()] = double(min(src2, dst2));
271 if(tr[ *m_foundPlaneAxis2->maxValue()].isUIEnabled())
272 tr[ *m_foundPlaneAxis2->maxValue()] = double(max(src2, dst2));
273 if(tr[ *m_foundPlaneAxis2->autoScale()].isUIEnabled())
274 tr[ *m_foundPlaneAxis2->autoScale()] =
false;
279 if(m_foundAxis && !(m_startScrPos == m_finishScrPos) ) {
280 XGraph::VFloat src = m_foundAxis->screenToVal(tr, m_startScrPos);
281 XGraph::VFloat dst = m_foundAxis->screenToVal(tr, m_finishScrPos);
282 double _min = std::min(src, dst);
283 double _max = std::max(src, dst);
284 if(tr[ *m_foundAxis->minValue()].isUIEnabled())
285 tr[ *m_foundAxis->minValue()] = _min;
286 if(tr[ *m_foundAxis->maxValue()].isUIEnabled())
287 tr[ *m_foundAxis->maxValue()] = _max;
288 if(tr[ *m_foundAxis->autoScale()].isUIEnabled())
289 tr[ *m_foundAxis->autoScale()] =
false;
299 repaintGraph(0, 0, m_pItem->width(), m_pItem->height() );
303 XQGraphPainter::wheel(
int x,
int y,
double deg)
305 if(fabs(deg) < 1.0)
return;
306 double a = ((double)x / m_pItem->width() - 0.5);
307 double b = ((double)y / m_pItem->height() - 0.5);
308 if( max(fabs(a), fabs(b)) < 0.35) {
309 zoom(min(1.15, max(0.85, exp(deg * 0.04))), x, y);
312 if( (a - b) * (a + b) > 0 ) {
313 viewRotate(30.0 * deg / fabs(deg), -1.0, 0.0, 0.0,
false);
316 viewRotate(30.0 * deg / fabs(deg), 0.0, 1.0, 0.0,
false);
318 repaintGraph(0, 0, m_pItem->width(), m_pItem->height() );
322 XQGraphPainter::zoom(
double zoomscale,
int ,
int ) {
326 if(tr.size(m_graph->axes())) {
327 const auto &axes_list( *tr.list(m_graph->axes()));
328 for(
auto it = axes_list.begin(); it != axes_list.end(); ++it) {
329 shared_ptr<XAxis> axis = static_pointer_cast<
XAxis>( *it);
330 if(tr[ *axis->autoScale()].isUIEnabled())
331 tr[ *axis->autoScale()] =
false;
334 m_graph->zoomAxes(tr,
resScreen(), zoomscale, s1);
340 repaintGraph(0, 0, m_pItem->width(), m_pItem->height() );
346 switch ( m_selectionModeNow ) {
349 XGraph::VFloat dst1 = m_foundPlaneAxis1->screenToVal(shot, m_finishScrPos);
350 XGraph::VFloat dst1dx = m_foundPlaneAxis1->screenToVal(shot, m_finishScrDX) - dst1;
351 XGraph::VFloat dst1dy = m_foundPlaneAxis1->screenToVal(shot, m_finishScrDY) - dst1;
352 XGraph::VFloat dst2 = m_foundPlaneAxis2->screenToVal(shot, m_finishScrPos);
353 XGraph::VFloat dst2dx = m_foundPlaneAxis2->screenToVal(shot, m_finishScrDX) - dst2;
354 XGraph::VFloat dst2dy = m_foundPlaneAxis2->screenToVal(shot, m_finishScrDY) - dst2;
356 dst1 = setprec(dst1, sqrt(dst1dx*dst1dx + dst1dy*dst1dy));
357 dst2 = setprec(dst2, sqrt(dst2dx*dst2dx + dst2dy*dst2dy));
358 msg += QString(
"(%1, %2)")
359 .arg(m_foundPlaneAxis1->valToString(dst1).c_str())
360 .arg(m_foundPlaneAxis2->valToString(dst2).c_str());
363 msg = i18n(
"R-DBL-CLICK TO SHOW HELP");
367 if(m_foundPlane && !(m_startScrPos == m_finishScrPos) ) {
368 XGraph::VFloat src1 = m_foundPlaneAxis1->screenToVal(shot, m_startScrPos);
369 XGraph::VFloat src1dx = m_foundPlaneAxis1->screenToVal(shot, m_startScrDX) - src1;
370 XGraph::VFloat src1dy = m_foundPlaneAxis1->screenToVal(shot, m_startScrDY) - src1;
371 XGraph::VFloat src2 = m_foundPlaneAxis2->screenToVal(shot, m_startScrPos);
372 XGraph::VFloat src2dx = m_foundPlaneAxis2->screenToVal(shot, m_startScrDX) - src2;
373 XGraph::VFloat src2dy = m_foundPlaneAxis2->screenToVal(shot, m_startScrDY) - src2;
374 XGraph::VFloat dst1 = m_foundPlaneAxis1->screenToVal(shot, m_finishScrPos);
375 XGraph::VFloat dst1dx = m_foundPlaneAxis1->screenToVal(shot, m_finishScrDX) - dst1;
376 XGraph::VFloat dst1dy = m_foundPlaneAxis1->screenToVal(shot, m_finishScrDY) - dst1;
377 XGraph::VFloat dst2 = m_foundPlaneAxis2->screenToVal(shot, m_finishScrPos);
378 XGraph::VFloat dst2dx = m_foundPlaneAxis2->screenToVal(shot, m_finishScrDX) - dst2;
379 XGraph::VFloat dst2dy = m_foundPlaneAxis2->screenToVal(shot, m_finishScrDY) - dst2;
381 src1 = setprec(src1, sqrt(src1dx*src1dx + src1dy*src1dy));
382 src2 = setprec(src2, sqrt(src2dx*src2dx + src2dy*src2dy));
383 dst1 = setprec(dst1, sqrt(dst1dx*dst1dx + dst1dy*dst1dy));
384 dst2 = setprec(dst2, sqrt(dst2dx*dst2dx + dst2dy*dst2dy));
385 msg += QString(
"(%1, %2) - (%3, %4)")
386 .arg(m_foundPlaneAxis1->valToString(src1).c_str())
387 .arg(m_foundPlaneAxis2->valToString(src2).c_str())
388 .arg(m_foundPlaneAxis1->valToString(dst1).c_str())
389 .arg(m_foundPlaneAxis2->valToString(dst2).c_str());
392 m_foundPlaneAxis1->valToScreen(shot, dst1, &sd1);
393 m_foundPlaneAxis1->valToScreen(shot, src1, &sd2);
395 sd1 += m_startScrPos;
397 m_foundPlaneAxis2->valToScreen(shot, dst2, &ss1);
398 m_foundPlaneAxis2->valToScreen(shot, src2, &ss2);
400 ss1 += m_startScrPos;
404 setVertex(m_startScrPos);
406 setVertex(m_finishScrPos);
412 if(m_foundAxis && !(m_startScrPos == m_finishScrPos) ) {
413 XGraph::VFloat src = m_foundAxis->screenToVal(shot, m_startScrPos);
414 XGraph::VFloat srcdx = m_foundAxis->screenToVal(shot, m_startScrDX) - src;
415 XGraph::VFloat srcdy = m_foundAxis->screenToVal(shot, m_startScrDY) - src;
416 XGraph::VFloat dst = m_foundAxis->screenToVal(shot, m_finishScrPos);
417 XGraph::VFloat dstdx = m_foundAxis->screenToVal(shot, m_finishScrDX) - dst;
418 XGraph::VFloat dstdy = m_foundAxis->screenToVal(shot, m_finishScrDY) - dst;
420 src = setprec(src, sqrt(srcdx*srcdx + srcdy*srcdy));
421 dst = setprec(dst, sqrt(dstdx*dstdx + dstdy*dstdy));
423 msg += QString(
"%1 - %2")
424 .arg(m_foundAxis->valToString(src).c_str())
425 .arg(m_foundAxis->valToString(dst).c_str());
427 XGraph::GFloat src1 = m_foundAxis->valToAxis(src);
428 XGraph::GFloat dst1 = m_foundAxis->valToAxis(dst);
432 m_foundAxis->axisToScreen(shot, src1, &s1);
433 posOffAxis(m_foundAxis->dirVector(), &s1, -0.02);
434 m_foundAxis->axisToScreen(shot, src1, &s2);
435 posOffAxis(m_foundAxis->dirVector(), &s2, +0.02);
436 m_foundAxis->axisToScreen(shot, dst1, &s3);
437 posOffAxis(m_foundAxis->dirVector(), &s3, +0.02);
438 m_foundAxis->axisToScreen(shot, dst1, &s4);
439 posOffAxis(m_foundAxis->dirVector(), &s4, -0.02);
447 m_foundAxis->axisToScreen(shot, src1, &s1);
448 posOffAxis(m_foundAxis->dirVector(), &s1, -0.1);
449 m_foundAxis->axisToScreen(shot, src1, &s2);
450 posOffAxis(m_foundAxis->dirVector(), &s2, 0.05);
453 m_foundAxis->axisToScreen(shot, dst1, &s1);
454 posOffAxis(m_foundAxis->dirVector(), &s1, -0.1);
455 m_foundAxis->axisToScreen(shot, dst1, &s2);
456 posOffAxis(m_foundAxis->dirVector(), &s2, 0.05);
470 XQGraphPainter::showHelp() {
472 repaintGraph(0, 0, m_pItem->width(), m_pItem->height());
477 setColor(shot[ *m_graph->titleColor()]);
479 m_curAlign = Qt::AlignTop | Qt::AlignHCenter;
482 if(m_onScreenMsg.length() ) {
483 selectFont(m_onScreenMsg,
XGraph::ScrPoint(0.6, 0.05, 0.01),
XGraph::ScrPoint(1, 0, 0),
XGraph::ScrPoint(0, 0.05, 0), 0);
484 setColor(shot[ *m_graph->titleColor()]);
485 m_curAlign = Qt::AlignBottom | Qt::AlignLeft;
489 if(shot[ *m_graph->drawLegends()] &&
490 (m_selectionModeNow == SelNone)) {
491 if(shot.size(m_graph->plots())) {
497 if(m_pointerLastPos[0] > m_pItem->width() / 2)
499 if(m_pointerLastPos[1] < m_pItem->height() / 2)
500 y1 = 1.0f - y1 + plots_list.size() * dy;
501 float x2 = x1 - 0.01;
502 float x3 = x1 + 0.08;
504 m_curAlign = Qt::AlignVCenter | Qt::AlignRight;
506 for(
auto it = plots_list.begin(); it != plots_list.end(); it++) {
507 auto plot = static_pointer_cast<
XPlot>( *it);
508 selectFont(shot[ *plot->label()],
XGraph::ScrPoint(x2,y2,z),
XGraph::ScrPoint(1, 0, 0),
XGraph::ScrPoint(0, dy, 0), 0);
511 setColor(shot[ *m_graph->backGround()], 0.7);
518 setColor(shot[ *m_graph->titleColor()], 0.05);
526 m_curAlign = Qt::AlignVCenter | Qt::AlignRight;
529 for(
auto it = plots_list.begin(); it != plots_list.end(); it++) {
530 setColor(shot[ *m_graph->titleColor()], 1.0);
531 auto plot = static_pointer_cast<
XPlot>( *it);
534 (x3 - x1)/1.5f, dy/1.2f);
541 XQGraphPainter::drawOnScreenHelp(
const Snapshot &shot, QPainter *qpainter) {
545 QColor cl(QRgb((
unsigned int)shot[ *m_graph->backGround()]));
546 cl.setAlpha(lrint(0.3 * 255));
547 qpainter->fillRect(QRect(0, 0, m_pItem->width(), m_pItem->height()), cl);
548 cl = QColor(QRgb((
unsigned int)shot[ *m_graph->titleColor()]));
549 cl.setAlpha(lrint(0.55 * 255));
550 qpainter->fillRect(QRect(0, 0, m_pItem->width(), m_pItem->height()), cl);
551 m_curTextColor = QRgb(shot[ *m_graph->backGround()]);
554 m_curAlign = Qt::AlignTop | Qt::AlignHCenter;
556 m_curAlign = Qt::AlignVCenter | Qt::AlignLeft;
560 selectFont(i18n(
"Single Click Right Button on Axis : Auto-scale"),
XGraph::ScrPoint(x,y,z),
XGraph::ScrPoint(1, 0, 0),
XGraph::ScrPoint(0, dy, 0), 0);
562 drawText(
XGraph::ScrPoint(x, y, z), i18n(
"Press Left Button on Plot : Manual Scale"));
564 drawText(
XGraph::ScrPoint(x, y, z), i18n(
"Press Right Button along Axis: Manual Scale"));
566 drawText(
XGraph::ScrPoint(x, y, z), i18n(
"Single Click Right Button on Axis : Auto-scale"));
568 drawText(
XGraph::ScrPoint(x, y, z), i18n(
"Single Click Right Button elsewhere : Auto-scale all"));
570 drawText(
XGraph::ScrPoint(x, y, z), i18n(
"Press Middle Button : Tilt plots"));
572 drawText(
XGraph::ScrPoint(x, y, z), i18n(
"Single Click Middle Button : Reset tilting"));
574 drawText(
XGraph::ScrPoint(x, y, z), i18n(
"Wheel around Center : (Un)Zoom all Plots"));
576 drawText(
XGraph::ScrPoint(x, y, z), i18n(
"Wheel at Side : Tilt by 30deg."));
578 drawText(
XGraph::ScrPoint(x, y, z), i18n(
"Double Click Left Button : Show Dialog"));
580 drawText(
XGraph::ScrPoint(x, y, z), i18n(
"Double Click Right Button : This Help"));
585 return m_graph->iterate_commit([=](
Transaction &tr){
591 setColor((QRgb)shot[ *m_graph->backGround()], 0.3);
592 if(shot.size(m_graph->plots())) {
593 const auto &plots_list( *shot.list(m_graph->plots()));
594 for(
auto it = plots_list.begin(); it != plots_list.end(); it++) {
595 auto plot = static_pointer_cast<
XPlot>( *it);
605 plot->graphToScreen(shot, g1, &s1);
606 plot->graphToScreen(shot, g2, &s2);
607 plot->graphToScreen(shot, g3, &s3);
608 plot->graphToScreen(shot, g4, &s4);
609 plot->graphToScreen(shot, g5, &s5);
610 plot->graphToScreen(shot, g6, &s6);
611 plot->graphToScreen(shot, g7, &s7);
612 plot->graphToScreen(shot, g8, &s8);
618 shared_ptr<XAxis> axisz = shot[ *plot->axisZ()];
635 const double axistomarker = 0.05;
636 if(shot.size(m_graph->axes())) {
637 const auto &axes_list( *shot.list(m_graph->axes()));
638 for(
auto it = axes_list.begin(); it != axes_list.end(); it++) {
639 auto axis = static_pointer_cast<
XAxis>( *it);
641 if((axis->direction() != XAxis::DirAxisZ) || m_bTilted) {
643 axis->axisToScreen(shot, 0.0, &s10);
644 axis->axisToScreen(shot, 1.0, &s20);
664 XQGraphPainter::drawOffScreenGrids(
const Snapshot &shot) {
665 if(shot.size(m_graph->plots())) {
666 const auto &plots_list( *shot.list(m_graph->plots()));
667 for(
auto it = plots_list.begin(); it != plots_list.end(); it++) {
668 auto plot = dynamic_pointer_cast<
XPlot>( *it);
669 plot->drawGrid(shot,
this, m_bTilted);
674 XQGraphPainter::drawOffScreenPoints(
const Snapshot &shot) {
675 if(shot.size(m_graph->plots())) {
676 const auto &plots_list( *shot.list(m_graph->plots()));
677 for(
auto it = plots_list.begin(); it != plots_list.end(); it++) {
678 auto plot = static_pointer_cast<
XPlot>( *it);
684 XQGraphPainter::drawOffScreenAxes(
const Snapshot &shot) {
685 if(shot.size(m_graph->axes())) {
686 const auto &axes_list( *shot.list(m_graph->axes()));
687 for(
auto it = axes_list.begin(); it != axes_list.end(); it++) {
688 auto axis = static_pointer_cast<
XAxis>( *it);
689 if((axis->direction() != XAxis::DirAxisZ) || m_bTilted)
690 axis->drawAxis(shot,
this);