3
// Copyright (c) 1998-2010 by The VoxBo Development Team
5
// This file is part of VoxBo
7
// VoxBo is free software: you can redistribute it and/or modify it
8
// under the terms of the GNU General Public License as published by
9
// the Free Software Foundation, either version 3 of the License, or
10
// (at your option) any later version.
12
// VoxBo is distributed in the hope that it will be useful, but
13
// WITHOUT ANY WARRANTY; without even the implied warranty of
14
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
// General Public License for more details.
17
// You should have received a copy of the GNU General Public License
18
// along with VoxBo. If not, see <http://www.gnu.org/licenses/>.
20
// For general information on VoxBo, including the latest complete
21
// source code and binary distributions, manual, and associated files,
22
// see the VoxBo home page at: http://www.voxbo.org/
24
// original version written by Dongbo Hu
28
#include "plotscreen.h"
34
#include <qmessagebox.h>
37
#include <qpushbutton.h>
38
#include <q3simplerichtext.h>
41
/* Basic constructor takes no arguments */
42
PlotScreen::PlotScreen(QWidget *parent)
49
PlotScreen::~PlotScreen()
54
/* This method is to initialize variables in PlotScreen class. */
55
void PlotScreen::init()
57
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
58
setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
62
int hBarHeight = horizontalScrollBar()->height();
63
QWidget::setMinimumSize(pw->width() + 2 * frameWidth(), pw->height() + 2 * frameWidth() + hBarHeight);
64
setPaletteBackgroundColor( pw->bkgdColor );
65
setFocusPolicy(Qt::ClickFocus); // Interface has to be clicked before focus
67
connect(pw, SIGNAL(xMagChanged(int)), this, SLOT(passMagSignal(int)));
68
connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(setVisibleRange(int)));
71
/* Overloaded resizeEvent() */
72
void PlotScreen::resizeEvent(QResizeEvent* e)
74
QWidget::resizeEvent(e);
75
int pw_width = pw->xMagnification * width();
76
int pw_height = height() - 2 * frameWidth() - horizontalScrollBar()->height();
77
pw->resize(pw_width, pw_height);
80
/* setMinimumSize() is an overloaded function.
81
* It also changes plotWidth, plotHeight, etc */
82
void PlotScreen::setMinimumSize(unsigned inputWidth, unsigned inputHeight )
84
if (inputWidth < 100) {
85
QMessageBox::critical(0, "Error", "Minimum PlotScreen window width is 100");
88
if (inputHeight < 100) {
89
QMessageBox::critical(0, "Error", "Minimum PlotScreen window height is 100");
93
// ignores the value if it is in zoom mode
94
if (pw->xMagnification != 1)
97
int newWidth = inputWidth - 2 * frameWidth();
98
int newHeight = inputHeight - 2 * frameWidth() - horizontalScrollBar()->height();
99
pw->resize(newWidth, newHeight);
100
QWidget::setMinimumSize(inputWidth, inputHeight);
103
/* This method is to set the window's size, first number width and second height */
104
void PlotScreen::setWindowSize(unsigned inputWidth, unsigned inputHeight)
106
if (inputWidth < 100) {
107
QMessageBox::critical(0, "Error", "Minimum PlotScreen window width is 100");
110
if (inputHeight < 100) {
111
QMessageBox::critical(0, "Error", "Minimum PlotScreen window height is 100");
115
// ignores the value if it is in zoom mode
116
if (pw->xMagnification != 1)
119
int newWidth = inputWidth - 2 * frameWidth();
120
int newHeight = inputHeight - 2 * frameWidth() - horizontalScrollBar()->height();
121
pw->resize(newWidth, newHeight);
123
QWidget::setFixedSize(inputWidth, inputHeight);
126
/* This method is to set the window's width */
127
void PlotScreen::setWindowWidth(unsigned inputWidth)
129
if (inputWidth < 100) {
130
QMessageBox::critical(0, "Error", "Minimum PlotScreen window width is 100");
134
int newWidth = inputWidth - 2 * frameWidth();
135
pw->setFixedWidth(newWidth);
136
QWidget::setFixedWidth(inputWidth);
139
/* This method is to set the window's height */
140
void PlotScreen::setWindowHeight(unsigned inputHeight)
142
if (inputHeight < 100) {
143
QMessageBox::critical(0, "Error", "Minimum PlotScreen window height is 100");
147
int newHeight = inputHeight - 2 * frameWidth() - horizontalScrollBar()->height();
148
pw->setFixedHeight(newHeight);
149
QWidget::setFixedHeight(inputHeight);
152
/* This method is to set the frame's width */
153
void PlotScreen::setFrameWidth(unsigned inputWidth)
155
pw->frameWidth = inputWidth;
158
/* This method sets the curve line's width in plot window */
159
void PlotScreen::setCurveLineWidth(unsigned inputWidth)
161
pw->curveLineWidth = inputWidth;
164
/* This method is to set the plot's size, first number width and second height */
165
void PlotScreen::setPlotSize(unsigned inputWidth, unsigned inputHeight)
167
pw->setPlotSize(inputWidth, inputHeight);
170
/* This method is to set the plot's width */
171
void PlotScreen::setPlotWidth(unsigned inputWidth)
173
pw->setPlotWidth(inputWidth);
176
/* This method is to set the plot's height */
177
void PlotScreen::setPlotHeight(unsigned inputHeight)
179
pw->setPlotHeight(inputHeight);
182
/* Set outer window size and inner plot size together */
183
void PlotScreen::setFixedSize(unsigned outWidth, unsigned outHeight, unsigned inWidth, unsigned inHeight)
185
pw->setFixedSize(outWidth, outHeight, inWidth, inHeight);
186
QWidget::setFixedSize(outWidth, outHeight);
189
/* Wrapper function to addVector(VB_Vector &, QColor ) */
190
int PlotScreen::addVector(const VB_Vector* inputVec, QColor inputColor)
192
return pw->addVector(*inputVec, inputColor);
195
/* This method is to add a new vector into the list of VB_Vector objects which will be shown.
196
* Note that this function also initializes the corresponding element in xMinList, xMaxList, colorList,
197
* yMinList, yMaxList and plot mode. By default, x minimum is 0, x maximum is the vector's length - 1,
198
* the plot mode is 1 (connect points together).
199
* The reason why maximum is the vector's length-1 is because in mode 1, if there are n elements in the vector,
200
* only n - 1 lines are drawn. The number of points counting from 0 to length -1 will be the number of elements.
202
* It returns index of the new vector. */
203
int PlotScreen::addVector(const VB_Vector& newVec, QColor inputColor)
205
return pw->addVector(newVec, inputColor);
208
/* Wrapper function of int addVector(VB_Vector &, double , double , QColor, unsigned) */
209
int PlotScreen::addVector(const VB_Vector* inputVec, double inputXMin, double inputXLength,
210
QColor inputColor, unsigned mode)
212
return pw->addVector(inputVec, inputXMin, inputXLength, inputColor, mode);
215
/* This function will add a new vector and set its min and max length on X axis.
216
* It does addVector(VB_Vector *), setNewVecX() and setPlotColor() in one step.
217
* It returns the new vector's index. */
218
int PlotScreen::addVector(const VB_Vector& inputVec, double inputXMin, double inputXLength,
219
QColor inputColor, unsigned mode)
221
return pw->addVector(inputVec, inputXMin, inputXLength, inputColor, mode);
224
/* Read an input file into a new VB_Vector object, then add it to vecList. */
225
int PlotScreen::addVecFile(const char* inputFile, QColor inputColor)
227
return pw->addVecFile(inputFile, inputColor);
230
/* Read an input file and set it's range on X axis and plot color. */
231
int PlotScreen::addVecFile(const char* inputFile, double inputXMin, double inputXLength,
232
QColor inputColor, unsigned mode)
234
return pw->addVector(inputFile, inputXMin, inputXLength, inputColor, mode);
237
/* This method is to delete a certain VB_Vector object from vector container. */
238
void PlotScreen::delVector(unsigned vecIndex)
240
pw->delVector(vecIndex);
243
/* This function resets active curve's index */
244
void PlotScreen::resetActiveCurve(unsigned vecIndex)
246
pw->resetActiveCurve(vecIndex);
249
/* This method is to set a new vector's starting value on X axis. */
250
void PlotScreen::setNewVecXMin(unsigned vecIndex, double inputXMin)
252
pw->setNewVecXMin(vecIndex, inputXMin);
255
/* This method is to set a new vector's total length on X axis. */
256
void PlotScreen::setNewVecXLength(unsigned vecIndex, double inputXLength)
258
pw->setNewVecXLength(vecIndex, inputXLength);
261
/* This method is to set a new vector's starting value and the total length on X axis.
262
* It combines setNewVecXMin() and setNewVecXLength() together. */
263
void PlotScreen::setNewVecX(unsigned vecIndex, double inputXMin, double inputXLength)
265
pw->setNewVecX(vecIndex, inputXMin, inputXLength);
268
/* This method will set all vector's minimum and maximum on X axis */
269
void PlotScreen::setAllNewX(double inputXMin, double inputXLength)
271
pw->setAllNewX(inputXMin, inputXLength);
275
/* Set a certain curve's color. */
276
void PlotScreen::setPlotColor(unsigned inputIndex, QColor inputColor)
278
if (inputIndex < pw->vecList.size())
279
pw->colorList[inputIndex] = inputColor;
281
printf("setPlotColor(): vecIndex out of range\n");
284
/* This method will set the plot mode for all vectors in the pool
285
* It only accepts one argument: the new plot mode */
286
void PlotScreen::setPlotMode(unsigned inputMode)
288
if (inputMode == 0 || inputMode > 4) {
289
printf("setPlotMode(unsigned): invalid plot mode.\n");
293
for (unsigned i = 0 ; i < pw->plotModeList.size(); i++)
294
pw->plotModeList[i] = inputMode;
297
/* This function will set a certain vector's plot mode in the pool
298
* It accepts two arguments: the first integer is the vector's index,
299
* the second is the new mode for that vector. */
300
void PlotScreen::setPlotMode(unsigned vecIndex, unsigned inputMode)
302
if (vecIndex >= pw->plotModeList.size())
303
printf("setPlotMode(unsigned, unsigned): vecIndex out of range.\n");
304
else if (inputMode == 0 || inputMode > 4)
305
printf("setPlotMode(unsigned, unsigned): invalid plot mode.\n");
307
pw->plotModeList[vecIndex] = inputMode;
310
/* This method is to clear the screen completely. */
311
void PlotScreen::clear()
317
/* Update both scroll area and plot widget inside */
318
void PlotScreen::update()
320
QScrollArea::update();
324
/* setFirstVector() will clear the vectors pool and add one vector into the pool.
325
* This function is written specially for gdw interface, since only one covariates
326
* will be shown on the upperwindow. */
327
void PlotScreen::setFirstVector(VB_Vector *inputVec)
329
pw->setFirstVector(inputVec);
332
/* setFirstXMarkMin() will set the first vector's original minimum value marked on X axis.
333
* It is written specially for gdw interface */
334
void PlotScreen::setFirstXMarkMin(double inputValue)
336
pw->setNewVecXMin(0, inputValue);
339
/* This method is to set the first vector's original total length on X axis.
340
* It is written specially for gdw interface. */
341
void PlotScreen::setFirstXLength(double inputLength)
343
pw->setNewVecXLength(0, inputLength);
346
/* This function will return the first vector's minimum element value */
347
double PlotScreen::getFirstXMin()
349
return pw->xMinList[0];
352
/* This function returns the full length of X axis */
353
double PlotScreen::getFullXLength()
355
double tmpVal = pw->getMax(pw->xMaxList) - pw->getMin(pw->xMinList);
359
/* This function will return the first vector's total length shown on X axis. */
360
double PlotScreen::getFirstXLength()
362
return (pw->xMaxList[0] - pw->xMinList[0]);
365
/* This function returns the first vector's plot mode */
366
int PlotScreen::getFirstPlotMode()
368
return pw->plotModeList[0];
371
/* This function is written specially for gdw interface so that when plot mode is
372
* changed from even to odd or from odd to even, the upsampling ratio is considered. */
373
void PlotScreen::setRatio(unsigned inputRatio)
375
if (inputRatio == 0) {
376
printf("setRatio() in PlotWidget: ratio must be positive\n");
380
pw->ratio = inputRatio;
383
/* This function will return the number of vectors in the pool. */
384
unsigned PlotScreen::getVecNum()
386
return pw->vecList.size();
389
/* This method is to set the graph's backgrond color */
390
void PlotScreen::setBkgdColor(QColor &inputColor)
392
pw->bkgdColor = inputColor;
393
pw->setPaletteBackgroundColor(inputColor);
396
/* This method is to set the frame edge's color */
397
void PlotScreen::setEdgeColor(QColor &inputColor)
399
pw->edgeColor = inputColor;
402
/* This method is to set axis' color */
403
void PlotScreen::setAxisColor(QColor &inputColor)
405
pw->axisColor = inputColor;
408
/* This method is to set X and Y axis caption color */
409
void PlotScreen::setCaptionColor(QColor &inputColor)
411
pw->captionColor = inputColor;
414
/* This method is to set caption on X axis */
415
void PlotScreen::setXCaption(QString inputText)
417
pw->xCaption = inputText;
420
/* This method is to set X axis caption's coordinates */
421
void PlotScreen::setXCaptionPost(unsigned x, unsigned y)
423
pw->xCaptionPostX = x;
424
pw->xCaptionPostY = y;
427
/* This method is to set caption on Y axis */
428
void PlotScreen::setYCaption(QString inputText)
430
pw->yCaption = inputText;
433
/* This method is to set Y axis caption's coordinates */
434
void PlotScreen::setYCaptionPost(unsigned x, unsigned y)
436
pw->yCaptionPostX = x, pw->yCaptionPostY = y;
440
/* enableFixedY() will set zoomYFlag to a certain value */
441
void PlotScreen::enableFixedY(bool inputFlag)
443
pw->enableFixedY(inputFlag);
446
/* getFixedYFlag() returns the current value of zoomYFlag */
447
bool PlotScreen::getFixedYFlag()
449
return pw->zoomYFlag;
452
/* setFixedY() will set the lower and upper bounds on Y axis */
453
void PlotScreen::setFixedY(double inputStart, double inputEnd)
455
pw->setFixedY(inputStart, inputEnd);
458
/* This method returns the original input Vector */
459
VB_Vector PlotScreen::getInputVector(unsigned vecIndex)
461
return pw->vecList[vecIndex];
464
/* This function sets the color of vertical line (generated by mouse press) */
465
void PlotScreen::setVLineColor(QColor inputColor)
467
pw->vLineColor = inputColor;
470
/* This function will enable/disbale mouse press, release and movement */
471
void PlotScreen::setMouseEnabled(bool inputStat)
473
pw->mouseEnabled = inputStat;
476
/* This function will enable/disable shift key functionality */
477
void PlotScreen::setShiftEnabled(bool inputStat)
479
pw->shiftEnabled = inputStat;
482
/* This function will enable/disable space key functionality */
483
void PlotScreen::setSpaceEnabled(bool inputStat)
485
pw->spaceEnabled = inputStat;
488
/* This function will enable/disable F1-F4 function keys */
489
void PlotScreen::setFKeyEnabled(bool inputStat)
491
pw->FKeyEnabled = inputStat;
494
/* Emit x magnification change signal */
495
void PlotScreen::passMagSignal(int newVal)
497
emit(xMagChanged(newVal));
500
/* Slot that sets the visible range for PlotWidget */
501
void PlotScreen::setVisibleRange(int newVal)
503
if (pw->width() <= width()) {
504
pw->visible_start = 0;
508
float hbar_range = horizontalScrollBar()->maximum() - horizontalScrollBar()->minimum();
509
pw->visible_start = (pw->width() - width()) * newVal / hbar_range;
512
/* This is a slot to restore the default X axis starting and ending positions */
513
void PlotScreen::centerX()
518
/* This is a slot to change x axis magnification */
519
void PlotScreen::setXMag(int inputVal)
521
pw->setXMag(inputVal);
524
/*************************************************************
525
* Member functions of PlotWidget
526
*************************************************************/
527
/* Basic constructor takes no arguments */
528
PlotWidget::PlotWidget(QWidget *parent)
535
PlotWidget::~PlotWidget()
543
/* This method is to initialize variables in PlotWidget class. */
544
void PlotWidget::init()
546
windowWidth = 600, windowHeight = 200, frameWidth = 2; // default size of the window and frame width
547
plotWidth = 500, plotHeight = 100; // default size of the plot
548
leftOffset = (windowWidth - plotWidth) / 2; // space between the frame and plot on left side
549
upOffset = (windowHeight - plotHeight) / 2; // space between the frame and plot on upper side
550
bkgdColor = Qt::black; // default background color is black
551
edgeColor = Qt::white; // default edge color is white
552
axisColor = Qt::white; // default X and Y axis color is white
553
captionColor = Qt::white; // default X and Y axis caption's color is white
554
plotMode = 1; // default mode is 1
557
xCaption = "X Axis"; // Default X axis
558
yCaption = "Y Axis"; // Default Y axis
559
xCaptionPostX = windowWidth / 2 - 10; // X caption: 10 pixels to the left side of the center of X axis
560
xCaptionPostY = upOffset + plotHeight + 35; // X caption coordinate of y: 35 pixels down from X axis
561
yCaptionPostX = leftOffset - 20; // Y caption of x: 20 pixels to the left side of the center
562
yCaptionPostY = upOffset - 10; // Y axis caption of y: 10 pixels down from upper edge
564
yDivisionInPixel = 0;
566
zoomYStart = zoomYEnd = 0;
568
setLineWidth(frameWidth);
569
setFrameStyle( Panel | Sunken );
570
setBackgroundMode( Qt::PaletteBase );
572
QWidget::setMinimumSize(windowWidth + 2 * frameWidth, windowHeight + 2 * frameWidth);
573
setPaletteBackgroundColor( bkgdColor );
576
QFont myFont("Helvetica", 8);
579
mouseX = mouseY = myX = 0;
580
vLineColor = Qt::white;
583
mouseEnabled = true; // mouse is enabled by default
584
shiftEnabled = true; // shift key enabled by default
585
spaceEnabled = true; // space key enabled by default
586
FKeyEnabled = true; // F1-F4 keys enabled by default
587
shiftPressed = false; // shift key not pressed by default
588
activeCurve = 0; // 1st vector is active by default
592
setFocusPolicy(Qt::ClickFocus); // Interface has to be clicked before focus
595
/* This method is to clear the screen completely. */
596
void PlotWidget::clear()
604
plotModeList.clear();
607
xLengthInPixel.clear();
609
// Reset highlighted curve's index and pen color to default
613
/* Function that is in charge of painting. */
614
void PlotWidget::paintEvent(QPaintEvent* )
621
p.drawRect(leftOffset, upOffset, plotWidth, plotHeight);
632
/* Overloaded resizeEvent() */
633
void PlotWidget::resizeEvent(QResizeEvent* e)
635
QWidget::resizeEvent(e);
636
windowHeight = height() - 2 * frameWidth;
637
windowWidth = width() - 2 * frameWidth;
641
/* Reset plot size */
642
void PlotWidget::resizePlot()
644
int totalWidth = windowWidth + 2 * frameWidth;
645
if (totalWidth >= 300)
646
plotWidth = windowWidth - 100;
648
plotWidth = windowWidth - 40;
650
int totalHeight = windowHeight + 2 * frameWidth;
651
if (totalHeight >= 200)
652
plotHeight = windowHeight - 100;
654
plotHeight = windowHeight - 40;
660
/* This method is to set the plot's size, first number width and second height */
661
void PlotWidget::setPlotSize(unsigned inputWidth, unsigned inputHeight)
663
if (inputWidth + 40 > windowWidth) {
664
QMessageBox::critical(0, "Error",
665
"Outer window width should be at least 40 pixels larger than inner width");
668
if (inputHeight + 40 > windowHeight) {
669
QMessageBox::critical(0, "Error",
670
"Outer window height should be at least 40 pixels larger than inner height");
674
plotWidth = inputWidth;
675
plotHeight = inputHeight;
679
/* This method is to set the plot's width */
680
void PlotWidget::setPlotWidth(unsigned inputWidth)
682
if (inputWidth + 40 > windowWidth) {
683
printf("%d: Invalid plot width\n", inputWidth);
686
plotWidth = inputWidth;
690
/* This method is to set the plot's height */
691
void PlotWidget::setPlotHeight(unsigned inputHeight)
693
if (inputHeight + 40 > windowHeight) {
694
printf("%d: Invalid plot height\n", inputHeight);
698
plotHeight = inputHeight;
702
/* Set outer window size and inner plot size together */
703
void PlotWidget::setFixedSize(unsigned outWidth, unsigned outHeight, unsigned inWidth, unsigned inHeight)
705
unsigned w1 = outWidth - 2 * frameWidth;
706
unsigned h1 = outHeight - 2 * frameWidth;
708
if (inWidth + 40 > w1) {
709
QMessageBox::critical(0, "Error",
710
"Outer window width should be at least 40 pixels larger than inner width");
713
if (inHeight + 40 > h1) {
714
QMessageBox::critical(0, "Error",
715
"Outer window height should be at least 40 pixels larger than inner height");
719
QMessageBox::critical(0, "Error", "Minimum PlotWidget window width is 100");
723
QMessageBox::critical(0, "Error", "Minimum PlotWidget window height is 100");
727
windowWidth = w1, windowHeight = h1;
728
plotWidth = inWidth, plotHeight = inHeight;
730
QWidget::setFixedSize(outWidth, outHeight);
733
/* updateSize() will update the variables which are related to the window size.
734
* It is called in setWindowSize(), setWindowWidth(), setWindowHeight() and
735
* setPlotSize(), setPlotWidth(), setPlotHeight() */
736
void PlotWidget::updateSize()
738
leftOffset = (windowWidth - plotWidth) / 2;
739
upOffset = (windowHeight - plotHeight) / 2;
740
xCaptionPostX = width() / 2 - 10;
741
xCaptionPostY = windowHeight - upOffset + 35;
742
yCaptionPostX = leftOffset - 20;
743
yCaptionPostY = upOffset - 10;
746
/* Wrapper function to addVector(VB_Vector &, QColor ) */
747
int PlotWidget::addVector(const VB_Vector* inputVec, QColor inputColor)
749
return addVector(*inputVec, inputColor);
752
/* This method is to add a new vector into the list of VB_Vector objects which will be shown.
753
* Note that this function also initializes the corresponding element in xMinList, xMaxList, colorList,
754
* yMinList, yMaxList and plot mode. By default, x minimum is 0, x maximum is the vector's length - 1,
755
* the plot mode is 1 (connect points together).
756
* The reason why maximum is the vector's length-1 is because in mode 1, if there are n elements in the vector,
757
* only n - 1 lines are drawn. The number of points counting from 0 to length -1 will be the number of elements.
759
* It returns index of the new vector. */
760
int PlotWidget::addVector(const VB_Vector& newVec, QColor inputColor)
762
vecList.push_back(newVec);
763
xMinList.push_back(0);
764
xMaxList.push_back((double)newVec.getLength() - 1);
765
colorList.push_back(inputColor);
767
double tmpMin, tmpMax;
768
if (newVec.getVariance() < 1e-10)
769
tmpMin = tmpMax = newVec.getVectorMean();
771
tmpMin = newVec.getMinElement();
772
tmpMax = newVec.getMaxElement();
774
yMinList.push_back(tmpMin);
775
yMaxList.push_back(tmpMax);
777
plotModeList.push_back(1);
778
xStartPost.push_back(0);
779
xLengthInPixel.push_back(0);
781
return vecList.size() - 1;
784
/* Wrapper function of int addVector(VB_Vector &, double , double , QColor, unsigned) */
785
int PlotWidget::addVector(const VB_Vector* inputVec, double inputXMin, double inputXLength,
786
QColor inputColor, unsigned mode)
788
return addVector(*inputVec, inputXMin, inputXLength, inputColor, mode);
791
/* This function will add a new vector and set its min and max length on X axis.
792
* It does addVector(VB_Vector *), setNewVecX() and setPlotColor() in one step.
793
* It returns the new vector's index. */
794
int PlotWidget::addVector(const VB_Vector& inputVec, double inputXMin, double inputXLength,
795
QColor inputColor, unsigned mode)
797
if (inputXLength <= 0) {
798
printf("addVector(): inputXLength must be positive.\n");
802
if (mode == 0 || mode > 4) {
803
printf("addVector(): invalid plot mode.\n");
807
vecList.push_back(inputVec);
808
xMinList.push_back(inputXMin);
809
xMaxList.push_back(inputXMin + inputXLength);
810
colorList.push_back(inputColor);
812
double tmpMin, tmpMax;
813
if (inputVec.getVariance() < 1e-10)
814
tmpMin = tmpMax = inputVec.getVectorMean();
816
tmpMin = inputVec.getMinElement();
817
tmpMax = inputVec.getMaxElement();
819
yMinList.push_back(tmpMin);
820
yMaxList.push_back(tmpMax);
822
plotModeList.push_back(mode);
823
xStartPost.push_back(0);
824
xLengthInPixel.push_back(0);
826
return vecList.size() - 1;
829
/* Read an input file into a new VB_Vector object, then add it to vecList. */
830
int PlotWidget::addVecFile(const char* inputFile, QColor inputColor)
832
VB_Vector newVector(inputFile);
833
return addVector(newVector, inputColor);
836
/* Read an input file and set it's range on X axis and plot color. */
837
int PlotWidget::addVecFile(const char* inputFile, double inputXMin, double inputXLength,
838
QColor inputColor, unsigned mode)
840
VB_Vector newVec(inputFile);
841
return addVector(newVec, inputXMin, inputXLength, inputColor, mode);
844
/* This method is to delete a certain VB_Vector object from vector container. */
845
void PlotWidget::delVector(unsigned vecIndex)
847
if (vecIndex < vecList.size()) {
848
vecList.erase(vecList.begin() + vecIndex);
849
xMinList.erase(xMinList.begin() + vecIndex);
850
xMaxList.erase(xMaxList.begin() + vecIndex);
851
yMinList.erase(yMinList.begin() + vecIndex);
852
yMaxList.erase(yMaxList.begin() + vecIndex);
853
colorList.erase(colorList.begin() + vecIndex);
854
plotModeList.erase(plotModeList.begin() + vecIndex);
855
xStartPost.erase(xStartPost.begin() + vecIndex);
856
xLengthInPixel.erase(xLengthInPixel.begin() + vecIndex);
857
// Reset active curve's index
858
resetActiveCurve(vecIndex);
861
printf("delVector(): vecIndex out of range\n");
864
/* This function resets active curve's index */
865
void PlotWidget::resetActiveCurve(unsigned vecIndex)
867
/* If the highlighted curve is going to be deleted and it is
868
* the last curve, set the first curve to be highlighted */
869
if (vecIndex == activeCurve && vecIndex == vecList.size() - 1)
871
// If the deleted curve is before the highlighted, decrease activeCurve by 1
872
else if (vecIndex < activeCurve)
876
/* This method is to set a new vector's starting value on X axis. */
877
void PlotWidget::setNewVecXMin(unsigned vecIndex, double inputXMin)
879
if (vecIndex < vecList.size()) {
880
xMinList[vecIndex] = inputXMin;
883
printf("setNewVecXMin(): vecIndex out of range\n");
886
/* This method is to set a new vector's total length on X axis. */
887
void PlotWidget::setNewVecXLength(unsigned vecIndex, double inputXLength)
889
if (inputXLength <= 0) {
890
printf("setNewVecXLength(): inputXLength must be positive.\n");
894
if (vecIndex < vecList.size())
895
xMaxList[vecIndex] = xMinList[vecIndex] + inputXLength;
897
printf("setNewVecXLength(): vecIndex out of range\n");
901
/* This method is to set a new vector's starting value and the total length on X axis.
902
* It combines setNewVecXMin() and setNewVecXLength() together. */
903
void PlotWidget::setNewVecX(unsigned vecIndex, double inputXMin, double inputXLength)
905
if (inputXLength <= 0) {
906
printf("setNewVecX(): inputXLength must be positive.\n");
910
if (vecIndex < vecList.size()) {
911
xMinList[vecIndex] = inputXMin;
912
xMaxList[vecIndex] = inputXMin + inputXLength;
915
printf("setNewVecX(): vecIndex out of range\n");
918
/* This method will set all vector's minimum and maximum on X axis */
919
void PlotWidget::setAllNewX(double inputXMin, double inputXLength)
921
for (unsigned i = 0; i < vecList.size(); i++)
922
setNewVecX(i, inputXMin, inputXLength);
925
/* setFirstVector() will clear the vectors pool and add one vector into the pool.
926
* This function is written specially for gdw interface, since only one covariates
927
* will be shown on the upperwindow. */
928
void PlotWidget::setFirstVector(VB_Vector *inputVec)
930
if (vecList.size() > 0)
936
/* setFirstXMarkMin() will set the first vector's original minimum value marked on X axis.
937
* It is written specially for gdw interface */
938
void PlotWidget::setFirstXMarkMin(double inputValue)
940
setNewVecXMin(0, inputValue);
943
/* This method is to set the first vector's original total length on X axis.
944
* It is written specially for gdw interface. */
945
void PlotWidget::setFirstXLength(double inputLength)
947
if (inputLength <=0) {
948
printf("setFirstXLength(): inputLength must be positive.\n");
952
setNewVecXLength(0, inputLength);
955
/* This is the function to calculate the marked values which will be shown on X axis */
956
void PlotWidget::calcXMark()
958
plotXMarkMin = getMin(xMinList);
959
plotXLength = getMax(xMaxList) - plotXMarkMin;
962
/* This method is to draw X axis, including the caption. */
963
void PlotWidget::drawXAxis(QPainter& p)
966
//if ((int) xCaptionPostX >= visibleWidth() || xCaptionPostY >= windowHeight)
967
if (xCaptionPostX >= windowWidth || xCaptionPostY >= windowHeight)
968
QMessageBox::critical(0, "Error", "The position assigned for X axis caption is not correct.");
970
p.drawText(xCaptionPostX, xCaptionPostY, xCaption);
973
double n = getXRange(plotXLength);
974
double xDivision = n / 100.0; // Each division's value on X axis
975
double xDivisionNumDb = plotXLength / xDivision; // This variable makes the x mark more accurate
976
int xDivisionNumber = (int) xDivisionNumDb; // Number of divisions on X axis (integer)
977
double xDivisionInPixel = (double) plotWidth / xDivisionNumDb; // Each division's value on X axis in pixel
979
/* Distance from the upper edge of window to X axis, (theoretically it should be upOffset + plotHeight,
980
* but minus one make it look nicer.) */
981
int xAxisPost = upOffset + plotHeight - 1; // -1 makes it look nicer
982
int shortMark = 2, longMark = 5; // Short mark is 2 pixels, longer one is 5 pixels
984
for ( int i = 1; i <= xDivisionNumber; i++) { // Draw a shorter line to mark each division
985
p.drawLine(leftOffset + (int)(xDivisionInPixel * i), xAxisPost, leftOffset +
986
(int)(xDivisionInPixel * i), xAxisPost - shortMark ); // bottom
987
p.drawLine(leftOffset + (int)(xDivisionInPixel * i), upOffset, leftOffset +
988
(int)(xDivisionInPixel * i), upOffset + shortMark ); // up
991
int increment = getIncrement(xDivisionNumber); // This variable controls the interval of the marks
992
int labelWidth = plotWidth / (xDivisionNumber / increment + 1);
993
int xMarkX = leftOffset - labelWidth / 2; // x coordinate of marks on x axis
994
int xMarkY = upOffset + plotHeight + 15; // y coordinate of marks on x axis
997
for ( int i = 0; i <= xDivisionNumber; i+= increment) {
998
p.drawLine(leftOffset + (int)(xDivisionInPixel * i), xAxisPost, leftOffset +
999
(int)(xDivisionInPixel * i), xAxisPost - longMark); // bottom
1000
p.drawLine(leftOffset + (int)(xDivisionInPixel * i), upOffset, leftOffset +
1001
(int)(xDivisionInPixel * i), upOffset + longMark); // up
1003
xMarkInDb = plotXMarkMin + xDivision * i;
1004
if (abs(xMarkInDb) < 1e-7 && xDivision > 1e-7)
1006
QString xLabel = QString::number(xMarkInDb);
1007
// mark the divisions
1008
p.drawText(xMarkX + (int)(xDivisionInPixel * i), xMarkY - 10, labelWidth, 20, Qt::AlignHCenter, xLabel);
1012
/* calcYMark() will compare the max and min values of each VB_Vector objects
1013
* and figure out the final min and max */
1014
void PlotWidget::calcYMark()
1017
plotYMarkMin = zoomYStart;
1018
plotYLength = zoomYEnd - zoomYStart;
1023
plotYMarkMin = getMin(yMinList);
1024
plotYLength = getMax(yMaxList) - plotYMarkMin;
1026
// Set yDivision, which is each division's value on Y axis
1027
if (plotYLength > 0) {
1028
double yRange = getYRange(plotYLength);
1029
if (plotYLength / (yRange / 10.0) >= 5)
1030
yDivision = yRange / 10.0;
1031
else if (plotYLength / (yRange / 20.0) >= 5)
1032
yDivision = yRange / 20.0;
1034
yDivision = yRange / 50.0;
1036
else if (plotYMarkMin)
1037
yDivision = plotYMarkMin;
1042
/* This method is to draw Y axis, including its caption */
1043
void PlotWidget::drawYAxis(QPainter& p)
1045
p.setPen(axisColor);
1046
// Draw Y axis caption
1047
if (yCaptionPostX <= 0 || yCaptionPostY <= 0)
1048
QMessageBox::critical(0, "Error", "The position you assigned for Y axis caption is not correct. \
1049
<P>Please change it and try again.");
1051
p.drawText(yCaptionPostX, yCaptionPostY, yCaption);
1054
double max = plotYLength + plotYMarkMin;
1055
double yDivisionNumber;
1056
// Most of the times plotYLength should be positive
1057
if (plotYLength > 0) {
1059
yBaseValue = plotYMarkMin; // Minimum value of the labels on Y axis
1060
yMaxValue = plotYLength + plotYMarkMin; // Maximum value of the labels on Y axis
1061
// Number of divisions on Y axis
1062
yDivisionNumber = plotYLength / yDivision;
1064
// If zoomYFlag isn't set, draw Y axis automatically
1066
double yMin = floor( plotYMarkMin / yDivision );
1067
double diffMin = plotYMarkMin - yMin * yDivision;
1068
/* 1e-2 is an arbitrary value to make sure no point will overlap with X axis.
1069
* No paractical use, it just makes the plot look silightly nicer. Same setup for yMax. */
1070
if (diffMin <= yDivision * 1e-2)
1072
double yMax = ceil(max / yDivision);
1073
double diffMax = yMax * yDivision - max;
1074
if (diffMax <= yDivision * 1e-2)
1077
yBaseValue = yDivision * yMin; // Minimum value of the labels on Y axis
1078
yMaxValue = yDivision * yMax; // Maximum value of the labels on Y axis
1079
yDivisionNumber = yMax - yMin;
1081
yDivisionInPixel = (double) plotHeight / yDivisionNumber;
1082
// Distance from left side of the frame to right side of the plot area, -1 makes it seem nicer
1083
int yAxisPost = leftOffset + plotWidth - 1;
1084
// Distance from minimum Y axis mark point to upper side of the frame
1085
int yMinPost = upOffset + plotHeight;
1086
double foo = yBaseValue / yDivision;
1087
int foo_int = (int) foo;
1088
double firstMark, firstY;
1090
if (foo == (double) foo_int) {
1092
firstY = yBaseValue;
1093
yStartDivision = foo_int;
1096
firstMark = ((double) foo_int + 1.0 - foo) * yDivisionInPixel;
1097
firstY = ((double) foo_int + 1.0) * yDivision;
1098
yStartDivision = foo_int + 1;
1101
firstMark = ((double) foo_int - foo) * yDivisionInPixel;
1102
firstY = (double) foo_int * yDivision;
1103
yStartDivision = foo_int;
1105
/* Force the mark value to be zero when it's smaller than 1e-7 and the division
1106
* is larger than 1e-7. Without this somtimes it's nonzero when it is supposed to
1107
* be because of rounding error. */
1108
if (abs(firstY) < 1.0e-7 && yDivision > 1.0e-7)
1111
int increment = getIncrement(yDivisionNumber);
1112
int shortMark = 2, longMark = 5;
1113
int yMarkX = 0; // x coordinate of Y axis marks
1114
int yMarkY = upOffset + plotHeight - 5; // y coordinate of Y axis marks
1115
// Loop to mark divisions in shorter line
1116
for ( int i = 0; i <= (int) yDivisionNumber; i++) {
1117
if ((yStartDivision + i) % increment != 0) {
1118
p.drawLine(leftOffset, yMinPost - (int)(firstMark + yDivisionInPixel * i), leftOffset + shortMark,
1119
yMinPost - (int)(firstMark + yDivisionInPixel * i)); // Left
1120
p.drawLine(yAxisPost, yMinPost - (int)(firstMark + yDivisionInPixel * i), yAxisPost - shortMark,
1121
yMinPost - (int)(firstMark + yDivisionInPixel * i)); // Right
1124
p.drawLine(leftOffset, yMinPost - (int)(firstMark + yDivisionInPixel * i), leftOffset + longMark,
1125
yMinPost - (int)(firstMark + yDivisionInPixel * i)); // Left
1126
p.drawLine(yAxisPost, yMinPost - (int)(firstMark + yDivisionInPixel * i), yAxisPost - longMark,
1127
yMinPost - (int)(firstMark + yDivisionInPixel * i)); // Right
1128
if (abs(firstY) < 1.0e-7 && yDivision > 1.0e-7)
1130
QString yLabel = QString::number(firstY);
1131
yLabel.truncate(7); // Only keep the first 7 characters in the label
1132
// label Y axis divisions with value
1133
p.drawText(yMarkX, yMarkY - (int)(firstMark + yDivisionInPixel * i),
1134
leftOffset - 5, 20, Qt::AlignRight, yLabel);
1136
firstY += yDivision;
1141
/* When all the elements are equal to a positive value, set Y axis base value to be
1142
* zero, separate Y axis in two divisions, with the element's value in the middle. */
1144
int yDivisionNumber = 2;
1145
yDivisionInPixel = (double) plotHeight / (double) yDivisionNumber;
1146
yBaseValue = 0; // Set Y base value to be 0
1147
yMaxValue = 2 * max;
1149
// Now mark each division using longer marks on left and right sides
1150
p.drawLine(leftOffset, upOffset + plotHeight / 2, leftOffset + 5,
1151
upOffset + plotHeight / 2);
1152
p.drawLine(leftOffset + plotWidth, upOffset+plotHeight/2, leftOffset + plotWidth-5,
1153
upOffset + plotHeight / 2);
1154
QString yLabel1 = QString::number(max);
1155
yLabel1.truncate(7);
1156
QString yLabel2 = QString::number(max * 2);
1157
yLabel2.truncate(7);
1158
// Label the divisions on the left side: 0, max, 2*max (from bottom to upper side)
1160
p.drawText(yMarkX, upOffset + plotHeight - 8, leftOffset - 5, 20, Qt::AlignRight, "0");
1161
p.drawText(yMarkX, upOffset + plotHeight / 2 - 8, leftOffset - 5, 20, Qt::AlignRight, yLabel1);
1162
p.drawText(yMarkX, upOffset - 8, leftOffset - 5, 20, Qt::AlignRight, yLabel2);
1165
/* When all the elements are equal to a negative value, set Y axis base value to be twice
1166
* the value, separate Y axis in two divisions, with the element's value in the middle. */
1168
int yDivisionNumber = 2;
1169
yDivisionInPixel = (double) plotHeight / (double) yDivisionNumber;
1170
yBaseValue = 2 * max; // Set Y base value to be 2*max
1173
// Now mark each division using longer marks on left and right sides
1174
p.drawLine(leftOffset, upOffset + plotHeight / 2, leftOffset + 5, upOffset + plotHeight / 2);
1175
p.drawLine(leftOffset + plotWidth, upOffset + plotHeight/2, leftOffset + plotWidth-5,
1176
upOffset + plotHeight / 2);
1177
QString yLabel1 = QString::number(max);
1178
yLabel1.truncate(7);
1179
QString yLabel2 = QString::number(max * 2);
1180
yLabel2.truncate(7);
1181
// Label the divisions on the left side: 2*max, max, 0 (from bottom to upper side)
1183
p.drawText(yMarkX, upOffset - 8, leftOffset - 5, 20, Qt::AlignRight, "0");
1184
p.drawText(yMarkX, upOffset + plotHeight / 2 - 8, leftOffset - 5, 20, Qt::AlignRight, yLabel1);
1185
p.drawText(yMarkX, upOffset + plotHeight - 8, leftOffset - 5, 20, Qt::AlignRight, yLabel2);
1188
/* When all the elements are equal to zero, set Y base value to be -1, maximum value of Y axis is +1,
1189
* zero is in the middle. */
1191
int yDivisionNumber = 2;
1192
yDivisionInPixel = (double) plotHeight / (double) yDivisionNumber;
1196
// Now mark each division using longer marks on left and right sides
1197
p.drawLine(leftOffset, upOffset + plotHeight / 2, leftOffset + 5, upOffset + plotHeight / 2);
1198
p.drawLine(leftOffset + plotWidth, upOffset + plotHeight/2, leftOffset + plotWidth-5,
1199
upOffset + plotHeight / 2);
1202
p.drawText(yMarkX, upOffset - 8, leftOffset - 5, 20, Qt::AlignRight, "1");
1203
p.drawText(yMarkX, upOffset + plotHeight / 2 - 8, leftOffset - 5, 20, Qt::AlignRight, "0");
1204
p.drawText(yMarkX, upOffset + plotHeight - 8, leftOffset - 5, 20, Qt::AlignRight, "-1");
1208
/* drawGraph() draws the graph inside, it's only a wrapper for drawInModeX() (X is 1, 2, 3 or 4) */
1209
void PlotWidget::drawGraph(QPainter& p)
1211
for (unsigned i = 0; i < vecList.size(); i++) {
1214
int currentWidth = curveLineWidth;
1215
if (vecList.size() > 1 && i == activeCurve)
1217
QPen curvePen(colorList[i], currentWidth);
1220
unsigned currentMode = plotModeList[i];
1221
plotVector = new VB_Vector(vecList[i]);
1222
if (currentMode == 1)
1224
else if (currentMode == 2)
1226
else if (currentMode == 3)
1228
else if (currentMode == 4)
1231
printf("drawGraph(): invalid plot mode.\n");
1236
/* calcXIndex() calculates starting and ending index of a certain vector
1237
* based on the vector's plotXLength and plotXMarkMin. */
1238
void PlotWidget::calcXIndex(unsigned vecIndex)
1240
double xMin = xMinList[vecIndex];
1241
double xMax = xMaxList[vecIndex];
1243
xLengthInPixel[vecIndex] = (xMax - xMin) / plotXLength * plotWidth;
1244
xStartPost[vecIndex] = (xMin - plotXMarkMin) / plotXLength * plotWidth + (double)leftOffset;
1247
/* checkVal() is a simple function to check whether an input value is between yBaseValue
1248
* and yMaxValue. It returns true if it is, false if not. This unction is written to check
1249
* whether a certain element should be drawn or not in the graph. */
1250
int PlotWidget::checkVal(double inputVal)
1252
if (inputVal > yMaxValue)
1254
if (inputVal < yBaseValue)
1259
/* calcXEdge() calculates the x coorinate of the edge points.
1260
* This function accepts four arguments:
1261
* yStart is the y value of first points, yEdge is y axis end value,
1262
* yEnd is the second point's y cvalue, which will be out of Y axis range;
1263
* xTotal is the difference of the two points' X coordinates;
1264
* This function returns the x coordinate of the point where Y axis edge and
1265
* the line connetcted by the two points intersect. */
1266
double PlotWidget::calcXEdge(double yStart, double yEdge, double yEnd, double xTotal)
1268
double yTotal = abs(yEnd - yStart);
1269
double yShownup = abs(yEdge - yStart);
1271
return xTotal * yShownup / yTotal;
1274
/* This method is to draw the graph in mode 1, which simply connects the points together.
1275
* The biggest difference between mode 1 and mode 2 is: In mode 1, if there are n elements in a vector,
1276
* n-1 lines will be drawn. But in mode 2, the number of lines drawn will be n, since each element will
1277
* correspond to a horizonal line. */
1278
void PlotWidget::drawInMode1(QPainter& p, unsigned vecIndex)
1280
// default is 149, theoretically should be 150, but 149 looks nicer
1281
int yMinPost = upOffset + plotHeight - 1;
1282
int yMaxPost = upOffset - 1;
1283
int element1 = 0, element2 = 0;
1286
unsigned vecLen = vecList[vecIndex].getLength();
1288
// Note the difference between mode 1 and 2 here!
1289
xInPixel = xLengthInPixel[vecIndex] / (double) (vecLen - 1);
1290
for (unsigned x = 0; x < vecLen - 1; x++ ) {
1291
val1 = plotVector->getElement(x);
1292
val2 = plotVector->getElement(x + 1);
1293
element1 = (int) ((plotVector->getElement(x) - yBaseValue) / yDivision * yDivisionInPixel);
1294
element2 = (int) ((plotVector->getElement(x + 1) - yBaseValue) / yDivision * yDivisionInPixel);
1295
m = ( x + 1 ) * xInPixel;
1296
// If both points are in Y axis range, connect them by a line
1297
if (checkVal(val1) == 0 && checkVal(val2) == 0) {
1298
p.drawLine((int) (xStartPost[vecIndex] + m - xInPixel), yMinPost - element1,
1299
(int) (xStartPost[vecIndex] + m), yMinPost - element2);
1301
// If the first point is in Y range, but the second point is bigger than Y maximum value,
1302
// connect until the Y upper edge
1303
else if (checkVal(val1) == 0 && checkVal(val2) == 1) {
1304
double xEdge = calcXEdge(val1, yMaxValue, val2, xInPixel);
1305
p.drawLine((int)(xStartPost[vecIndex] + m - xInPixel), yMinPost - element1,
1306
(int)(xStartPost[vecIndex] + m - xInPixel + xEdge), yMaxPost);
1308
// If the first point is in Y range, but the second point is less than Y minimum value,
1309
// connect until the Y lower edge
1310
else if (checkVal(val1) == 0 && checkVal(val2) == -1) {
1311
double xEdge = calcXEdge(val1, yBaseValue, val2, xInPixel);
1312
p.drawLine((int)(xStartPost[vecIndex] + m - xInPixel), yMinPost - element1,
1313
(int)(xStartPost[vecIndex] + m - xInPixel + xEdge), yMinPost);
1315
// If the first point is out of Y range (upper), but the second point is in Y range,
1316
// connect from the Y upper edge to the second point
1317
else if (checkVal(val1) == 1 && checkVal(val2) == 0) {
1318
double xEdge = calcXEdge(val1, yMaxValue, val2, xInPixel);
1319
p.drawLine((int)(xStartPost[vecIndex] + m - xInPixel + xEdge), yMaxPost,
1320
(int)(xStartPost[vecIndex] + m), yMinPost - element2);
1322
// If the first point is out of Y range (lower), but the second point is in the range,
1323
// connect until the Y lower edge
1324
else if (checkVal(val1) == -1 && checkVal(val2) == 0) {
1325
double xEdge = calcXEdge(val1, yBaseValue, val2, xInPixel);
1326
p.drawLine((int)(xStartPost[vecIndex] + m - xInPixel + xEdge), yMinPost,
1327
(int)(xStartPost[vecIndex] + m), yMinPost - element2);
1332
/* This method draws the graph in mode 2, which first draws a horizontal line,
1333
* then connect the lines together. It's designed to simulate Geoff's IDL code to
1334
* draw the block design reference function (eg. motor1.ref). */
1335
void PlotWidget::drawInMode2(QPainter& p, unsigned vecIndex)
1337
int yMinPost = upOffset + plotHeight - 1;
1338
int yMaxPost = upOffset - 1;
1339
int element1 = 0, element2 = 0;
1340
double val1 = 0, val2 = 0;
1342
unsigned vecLen = vecList[vecIndex].getLength();
1344
// Key difference between mode 1, 3 and 2, 4
1345
xInPixel = xLengthInPixel[vecIndex] / (double) vecLen;
1346
for ( unsigned x = 0; x < vecLen - 1; x++ ) {
1347
val1 = plotVector->getElement(x);
1348
val2 = plotVector->getElement(x + 1);
1349
element1 = (int) ((plotVector->getElement(x) - yBaseValue) / yDivision * yDivisionInPixel);
1350
element2 = (int) ((plotVector->getElement(x + 1) - yBaseValue) / yDivision * yDivisionInPixel);
1351
m = ( x + 1 ) * xInPixel;
1352
// If both points are in Y range
1353
if (checkVal(val1) == 0 && checkVal(val2) == 0) {
1354
// Draw a flat line first
1355
p.drawLine((int) (xStartPost[vecIndex] + m - xInPixel), yMinPost - element1,
1356
(int) (xStartPost[vecIndex] + m), yMinPost - element1);
1357
// Then draw a vertical line to connect the lines together, copied from Geoff's IDL interface
1358
p.drawLine((int) (xStartPost[vecIndex] + m), yMinPost - element1,
1359
(int) (xStartPost[vecIndex] + m), yMinPost - element2);
1361
// If the first point is in range but second point out of Y range (upper)
1362
else if (checkVal(val1) == 0 && checkVal(val2) == 1) {
1363
// First draw a flat line
1364
p.drawLine((int) (xStartPost[vecIndex] + m - xInPixel), yMinPost - element1,
1365
(int) (xStartPost[vecIndex] + m), yMinPost - element1);
1366
// Then draw a vertical line up to Y axis maximum
1367
p.drawLine((int) (xStartPost[vecIndex] + m), yMinPost - element1,
1368
(int) (xStartPost[vecIndex] + m), yMaxPost);
1370
// If the first point is out of Y range (upper), but the second point is inside
1371
else if (checkVal(val1) == 1 && checkVal(val2) == 0) {
1372
// Simply draw a vertical line between Y maximum and the second point
1373
p.drawLine((int) (xStartPost[vecIndex] + m), yMaxPost,
1374
(int) (xStartPost[vecIndex] + m), yMinPost - element2);
1376
// If the first point is outside (lower) and second point is inside
1377
else if (checkVal(val1) == -1 && checkVal(val2) == 0) {
1378
// Simply draw a vertical line between Y minimum and the second point
1379
p.drawLine((int) (xStartPost[vecIndex] + m), yMaxPost,
1380
(int) (xStartPost[vecIndex] + m), yMinPost - element2);
1383
// If the last point is inside, draw a flat line for it
1384
if (checkVal(val2) == 0)
1385
p.drawLine((int) (xStartPost[vecIndex] + xLengthInPixel[vecIndex] - xInPixel), yMinPost - element2,
1386
(int) (xStartPost[vecIndex] + xLengthInPixel[vecIndex]), yMinPost - element2);
1389
/* drawInMode3() is similar to drawInMode1(), but it only draws a small point for each element
1390
* It DOESN'T connect the points together. */
1391
void PlotWidget::drawInMode3(QPainter& p, unsigned vecIndex)
1393
int yMinPost = upOffset + plotHeight - 1;
1397
unsigned vecLen = vecList[vecIndex].getLength();
1398
xInPixel = xLengthInPixel[vecIndex] / (double) (vecLen - 1);
1399
for (unsigned x = 0; x <= vecLen - 1; x++ ) {
1400
val1 = plotVector->getElement(x);
1401
element1 = (int) ((plotVector->getElement(x) - yBaseValue) / yDivision * yDivisionInPixel);
1402
m = ( x + 1 ) * xInPixel;
1403
// Draw a circle whose radius is 2 and the center is where the point should be
1404
if (checkVal(val1) == 0)
1405
p.drawEllipse((int) (xStartPost[vecIndex] + m - xInPixel) - 2, yMinPost - element1 - 2, 4, 4);
1409
/* drawInMode4() is similar to drawInMode2(), but it only draws a horizonal line.
1410
* It doesn't connect these lines together. */
1411
void PlotWidget::drawInMode4(QPainter& p, unsigned vecIndex)
1413
int yMinPost = upOffset + plotHeight - 1;
1414
int element1 = 0, element2 = 0;
1416
double val1 = 0, val2 = 0;
1417
unsigned vecLen = vecList[vecIndex].getLength();
1418
// The calculation of xInPixel is one of the key differences between mode 1, 3 and 2, 4
1419
xInPixel = xLengthInPixel[vecIndex] / (double) (vecLen);
1420
for (unsigned x = 0; x < vecLen - 1; x++ ) {
1421
val1 = plotVector->getElement(x);
1422
val2 = plotVector->getElement(x + 1);
1423
element1 = (int) ((plotVector->getElement(x) - yBaseValue) / yDivision * yDivisionInPixel);
1424
element2 = (int) ((plotVector->getElement(x + 1) - yBaseValue) / yDivision * yDivisionInPixel);
1425
m = ( x + 1 ) * xInPixel;
1426
// Draw a horizontal line
1427
if (checkVal(val1) == 0)
1428
p.drawLine ((int) (xStartPost[vecIndex] + m - xInPixel), yMinPost - element1,
1429
(int) (xStartPost[vecIndex] + m), yMinPost - element1);
1432
// Draw the horizonal line for the last element
1433
if (checkVal(val2) == 0)
1434
p.drawLine((int) (xStartPost[vecIndex] + xLengthInPixel[vecIndex] - xInPixel), yMinPost - element2,
1435
(int) (xStartPost[vecIndex] + xLengthInPixel[vecIndex]), yMinPost - element2);
1438
/* Method to draw text which rotates certain degrees at a certain point */
1439
void PlotWidget::drawRotatedText(QPainter& p, float degrees, int x, int y, const QString & text)
1442
p.translate(x, y); // Translate the painter to a certain point
1443
p.rotate(degrees); // Rotate the coordinate
1444
p.drawText(0, 0, text); // Draw text at new coordinates of (0,0)
1448
/* enableFixedY() will set zoomYFlag to a certain value */
1449
void PlotWidget::enableFixedY(bool inputFlag)
1451
zoomYFlag = inputFlag;
1454
zoomYStart = zoomYEnd = 0;
1456
else if (zoomYStart == 0 && zoomYEnd == 0) {
1457
zoomYStart = yBaseValue;
1458
zoomYEnd = yMaxValue;
1462
/* setFixedY() will set the lower and upper bounds on Y axis */
1463
void PlotWidget::setFixedY(double inputStart, double inputEnd)
1465
if (vecList.size() == 0)
1466
QMessageBox::critical(0, "Error",
1467
"setFixedY(): Please first input a vector for the plot area.");
1468
else if (inputStart > getMax(yMaxList))
1469
QMessageBox::critical(0, "Error",
1470
"setFixedY(): The starting value on Y axis is larger than the maximum permitted.");
1471
else if (inputEnd < getMin(yMinList))
1472
QMessageBox::critical(0, "Error",
1473
"setFixedY(): The ending value on Y axis is less than the minimum permitted.");
1474
else if (inputEnd <= inputStart)
1475
QMessageBox::critical(0, "Error",
1476
"setFixedY(): The ending value must be larger than the starting value.");
1478
zoomYStart = inputStart;
1479
zoomYEnd = inputEnd;
1485
/* This method is used to gauge X axis range.
1486
* Note: the inputNumber must be nonnegative! */
1487
double PlotWidget::getXRange(double inputNumber)
1490
// when inputNumber is non-positive, return 0
1491
if (inputNumber <= 0)
1493
else if (inputNumber == 1)
1495
else if (inputNumber > 1.0) {
1496
while ( inputNumber > n )
1498
return n; // returnNumber / 10 < inputNumber <= returnNumber
1501
while ( inputNumber <= n )
1503
return n * 10; // returnNumber / 10 < inputNumber <= returnNumber
1507
/* This method is used to gauge Y axis range.
1508
* Note the difference between getXYange() and getYRange() */
1509
double PlotWidget::getYRange(double inputNumber)
1512
// when inputNumber is non-positive, return 0
1513
if (inputNumber <= 0)
1515
else if (inputNumber == 1)
1517
else if (inputNumber > 1.0) {
1518
while ( inputNumber > n ) {
1519
// if a number is between 1.0 and 1.1, return 1, because an extra division will cover it
1520
if (inputNumber < n * 1.1)
1525
return n; // returnNumber / 10 < inputNumber <= returnNumber
1528
while ( inputNumber <= n )
1530
return n * 10; // returnNumber / 10 < inputNumber <= returnNumber
1534
/* This method determines the seperation of each marked values on x/y axis. */
1535
int PlotWidget::getIncrement(double inputNumber)
1537
// If there are more than 50 divisions, mark the value once every 10 divisions
1538
if (inputNumber > 50.0)
1540
// If there are more than 10 divisions, mark the value once every 5 divisions
1541
if (inputNumber > 10.0)
1543
// If there are 5 - 10 divisions, mark the value once every 2 divisions
1544
if (inputNumber > 5.0)
1546
// If there are less than or equal to 5 divisions, mark all of them
1550
/* This method returns the minimum of the vectors' starting value on X axis */
1551
double PlotWidget::getMin(std::vector< double > inputArr)
1553
double tmp = inputArr[0];
1554
for (int i = 1; i < (int)inputArr.size(); i++) {
1555
if (tmp > inputArr[i])
1564
/* This method returns the maximum of the vectors' ending value on X axis */
1565
double PlotWidget::getMax(std::vector< double > inputArr)
1567
double tmp = inputArr[0];
1568
if (inputArr.size() == 1)
1571
for (int i = 1; i < (int)inputArr.size(); i++) {
1572
if (tmp < inputArr[i])
1580
/* When mouse is pressed, draw a vertical line at its current position,
1581
* print out the current coordinate of the curve on the screen */
1582
void PlotWidget::mousePressEvent( QMouseEvent *myMouse )
1584
// when mouse button is clicked, set the keyboard focus to current screen
1587
// Do nothing if mouse is disabled or no curve at all
1588
if (!mouseEnabled || vecList.size() == 0)
1591
mouseX = myMouse->x();
1592
mouseY = myMouse->y();
1593
// Do nothing if mouse is out of X axis range
1598
/* if myX is zero, do not draw vertical line (for example, the mouse
1599
* position is inside plot window but outside of active curve's range. */
1604
/* This function checks whether a point's X coordinate is out of scale or not */
1605
bool PlotWidget::chkMouseX()
1607
// Is mouse position out of plot range?
1608
if ((unsigned) mouseX < leftOffset || (unsigned) mouseX > plotWidth + leftOffset)
1610
// Is mouse out of visible area?
1611
if (mouseX < visible_start || mouseX > visible_start + parentWidget()->width())
1617
/* This function will set up myX, which is the position where a vertical line is drawn.
1618
* Depending on whether shift key is pressed, the line position is different. */
1619
void PlotWidget::setMyX()
1621
if (!shiftPressed) {
1626
double startPix = xStartPost[activeCurve];
1627
double totalPix = xLengthInPixel[activeCurve];
1628
if (mouseX < startPix || mouseX > startPix + totalPix) {
1633
int currentMode = plotModeList[activeCurve];
1634
int vecLen = vecList[activeCurve].getLength();
1635
double x_ratio = ((double) mouseX - startPix) / totalPix;
1636
double x_index, ratio2;
1637
if (currentMode % 2) {
1638
x_index = x_ratio * (vecLen - 1);
1639
double x1 = round(x_index);
1640
ratio2 = x1 / (vecLen - 1);
1643
x_index = x_ratio * vecLen;
1644
double x1 = round(x_index);
1645
ratio2 = x1 / vecLen;
1648
myX = (unsigned) (startPix + totalPix * ratio2);
1651
/* This function adds a QWidget on screen when mouse is pressed */
1652
void PlotWidget::addVLine(QPainter& p)
1654
p.setPen(vLineColor);
1655
if (vecList.size() > 1)
1656
p.setPen(colorList[activeCurve]);
1657
p.drawLine(myX, upOffset, myX, upOffset + plotHeight);
1660
/* This function draws X and Y coordinates according to the shift key and plot mode status */
1661
void PlotWidget::addVLineTxt(QPainter& p)
1663
QFont lineFont = QFont();
1664
lineFont.setPixelSize(upOffset / 3);
1665
lineFont.setBold(true);
1666
p.setFont(lineFont);
1667
// Print message if selected curve is out of range
1668
if (xLengthInPixel[activeCurve] == 0) {
1669
p.drawText(visible_start + parentWidget()->width() / 4, upOffset / 2,
1670
parentWidget()->width() / 2, upOffset / 2 - 1,
1671
Qt::AlignLeft, "Selected curve not shown");
1675
if (vecList.size() > 1)
1676
p.setPen(colorList[activeCurve]);
1678
if (!shiftPressed && plotModeList[activeCurve] % 2 != 0)
1680
else if (!shiftPressed && plotModeList[activeCurve] % 2 == 0)
1682
else if (plotModeList[activeCurve] % 2 != 0)
1688
p.drawText(visible_start + parentWidget()->width() / 4, upOffset / 2,
1689
parentWidget()->width() / 4, upOffset / 2 - 1,
1690
Qt::AlignRight, vline_x);
1691
p.drawText(visible_start + parentWidget()->width() / 2, upOffset / 2,
1692
parentWidget()->width() / 4, upOffset / 2 - 1,
1693
Qt::AlignLeft, vline_y);
1696
/* When mouse is released, erase the vertical line and number on screen */
1697
void PlotWidget::mouseReleaseEvent(QMouseEvent*)
1699
if (!mouseEnabled || vecList.size() == 0)
1702
mouseX = mouseY = 0;
1707
/* This function tracks the mouse movement and erases previous vertical line,
1708
* then draw another vertical line at current position. */
1709
void PlotWidget::mouseMoveEvent(QMouseEvent* myMouse )
1711
if (!mouseEnabled || vecList.size() == 0)
1714
mouseX = myMouse->x();
1715
mouseY = myMouse->y();
1725
/* Mouse wheel movement will also zoom in/out in X direction */
1726
void PlotWidget::wheelEvent ( QWheelEvent* e )
1728
if (!mouseEnabled || vecList.size() == 0)
1731
// when e->delta() is 120, wheel is moving upward, zoom in X axis
1734
// when e->delta() is -120, wheel is moving downward, zoom out X axis
1739
/* Overwrited function to handle key press event */
1740
void PlotWidget::keyPressEvent( QKeyEvent *e )
1742
// Ignore ctrl and s key presses so that they will be handled by parent widget;
1743
// Otherwise the two keys won't response in parent widget
1744
if (e->key() == Qt::Key_Control || e->key() == Qt::Key_S)
1747
// Do nothing if no vector available
1748
if (vecList.size() == 0)
1750
// shift key pressed
1751
if (e->key() == Qt::Key_Shift)
1753
// space key pressed
1754
else if (e->key() == Qt::Key_Space)
1756
// up arrow key pressed
1757
else if (e->key() == Qt::Key_Up)
1759
// down arrow key pressed
1760
else if (e->key() == Qt::Key_Down)
1762
// "1" key is pressed
1763
else if (e->key() == Qt::Key_1)
1765
// pressFKey() deals with the rest of keyboard presses
1770
/* Overwritten function to handle key release event */
1771
void PlotWidget::keyReleaseEvent ( QKeyEvent * e )
1773
// Ignore ctrl and s key presses so that they will be handled by parent widget;
1774
// Otherwise the two keys won't response in parent widget
1775
if (e->key() == Qt::Key_Control || e->key() == Qt::Key_S)
1778
// Do nothing if no vector available
1779
if (vecList.size() == 0)
1782
// If the released key is not shift, ignore it
1783
if (e->key() != Qt::Key_Shift)
1785
// If shift key is disabled, ignore it
1789
shiftPressed = false;
1790
if (xLengthInPixel[activeCurve] == 0)
1795
// When shift key is released, change X and Y coordinates print out
1800
/* This function deals with shift key press.
1801
* It changes X and Y coordinates printout. */
1802
void PlotWidget::pressShift()
1807
shiftPressed = true;
1808
if (xLengthInPixel[activeCurve] == 0)
1818
/* This function deals with space key press.
1819
* It activates the next curve and update the whole screen. */
1820
void PlotWidget::pressSpace()
1824
if (vecList.size() < 2)
1827
int newIndex = (activeCurve + 1) % vecList.size();
1828
if (xLengthInPixel[newIndex] == 0)
1831
activeCurve = newIndex;
1835
/* This function deals with up arrow key press.
1836
* It changes the starting and ending position of the curve.
1837
* It is equivalent to moving magnification slider bar to rigth side (zoom in) */
1838
void PlotWidget::pressUp()
1840
if (xMagnification == 10)
1844
int newWidth = xMagnification * parentWidget()->width();
1845
resize(newWidth, height());
1848
emit(xMagChanged(xMagnification));
1851
/* This function deals with down arrow key press.
1852
* It changes the starting and ending position of the curve.
1853
* It is equivalent to moving magnification slider bar to left side (zoom out) */
1854
void PlotWidget::pressDown()
1856
if (xMagnification == 1)
1860
int newWidth = xMagnification * parentWidget()->width();
1861
resize(newWidth, height());
1864
emit(xMagChanged(xMagnification));
1867
/* This function deals with "1" key press.
1868
* It changes the starting and ending position of the curve.
1869
* It is equivalent to clicking the center button to restore the default view */
1870
void PlotWidget::press1key()
1875
/* This is a slot to restore the default X axis starting and ending positions */
1876
void PlotWidget::centerX()
1878
if (xMagnification == 1)
1882
int newWidth = parentWidget()->width();
1883
resize(newWidth, height());
1886
emit(xMagChanged(1));
1889
/* This is a slot to change x axis magnification */
1890
void PlotWidget::setXMag(int inputVal)
1892
xMagnification = inputVal;
1893
int newWidth = xMagnification * parentWidget()->width();
1894
resize(newWidth, height());
1898
/* This function deals with F1-F4 key press.
1899
* It changes activated curve's plot mode and update the whole screen. */
1900
void PlotWidget::pressFKey(QKeyEvent *e)
1905
unsigned newMode = 0;
1906
if (e->key() == Qt::Key_F1)
1908
else if (e->key() == Qt::Key_F2)
1910
else if (e->key() == Qt::Key_F3)
1912
else if (e->key() == Qt::Key_F4)
1914
// If the key pressed is not F1-F4, ignore it
1917
// If the new mode is same as original, ignore it
1918
if (newMode == plotModeList[activeCurve])
1921
int orgMode = plotModeList[activeCurve];
1922
// Change X axis length if the mode is changed from 1 or 3 to 2 or 4
1923
if (orgMode % 2 != 0 && newMode % 2 == 0) {
1924
double orgLength = xMaxList[activeCurve] - xMinList[activeCurve];
1925
double vecLen = (double) (vecList[activeCurve].getLength() / ratio);
1926
double newLen = orgLength / (vecLen - 1) * vecLen;
1927
setNewVecXLength(activeCurve, newLen);
1929
// Change X axis length if the mode is changed from 2 or 4 to 1 or 3
1930
else if (orgMode % 2 == 0 && newMode % 2 != 0) {
1931
double orgLength = xMaxList[activeCurve] - xMinList[activeCurve];
1932
double vecLen = (double) (vecList[activeCurve].getLength() / ratio);
1933
setNewVecXLength(activeCurve, orgLength / vecLen * (vecLen - 1));
1935
plotModeList[activeCurve] = newMode;
1940
/* This function prints out the current mouse position's coordinate */
1941
void PlotWidget::setXY_13()
1943
double x_ratio = (double) (mouseX - leftOffset) / (double) plotWidth;
1944
double x_graph = plotXMarkMin + x_ratio * plotXLength;
1945
vline_x = "X=" + QString::number(x_graph) + ", ";
1947
double startPix = xStartPost[activeCurve];
1948
double totalPix = xLengthInPixel[activeCurve];
1949
if (mouseX < startPix || myX > startPix + totalPix)
1952
int vecLen = vecList[activeCurve].getLength();;
1953
double x_ratio = (double) (mouseX - startPix) / totalPix;
1954
double x_index = x_ratio * (vecLen - 1);
1955
int x1 = (int) x_index;
1957
if (x1 == vecLen - 1)
1958
y_graph = vecList[activeCurve].getElement(x1);
1960
double y1 = vecList[activeCurve].getElement(x1);
1961
double y2 = vecList[activeCurve].getElement(x1 + 1);
1962
y_graph = y1 + (y2 - y1) * (x_index - x1);
1964
vline_y = "Y=" + QString::number(y_graph);
1968
/* This function prints out the current mouse position's X coordinate */
1969
void PlotWidget::setXY_24()
1971
double x_ratio = (double) (mouseX - leftOffset) / (double) plotWidth;
1972
double x_graph = plotXMarkMin + x_ratio * plotXLength;
1973
vline_x = "X=" + QString::number(x_graph) + ", ";
1975
double startPix = xStartPost[activeCurve];
1976
double totalPix = xLengthInPixel[activeCurve];
1977
if (mouseX < startPix || mouseX > startPix + totalPix)
1980
int vecLen = vecList[activeCurve].getLength();
1981
double x_ratio = ((double) mouseX - startPix) / totalPix;
1982
double x_index = x_ratio * vecLen;
1983
int x1 = (int) x_index;
1984
if (x1 > vecLen - 1)
1986
double y_graph = vecList[activeCurve].getElement(x1);
1987
vline_y = "Y=" + QString::number(y_graph);
1991
/* This function prints out X coordinate of the data point that is closest to mouse position */
1992
void PlotWidget::setXY_shift13()
1994
double startPix = xStartPost[activeCurve];
1995
double totalPix = xLengthInPixel[activeCurve];
1996
if (mouseX < startPix || mouseX > startPix + totalPix)
1999
int vecLen = vecList[activeCurve].getLength();
2000
double x_ratio = ((double) mouseX - startPix) / totalPix;
2001
double x_index = x_ratio * (vecLen - 1);
2002
double x1 = round(x_index);
2003
double ratio2 = x1 / (vecLen - 1);
2004
double dataStart = startPix + totalPix * ratio2;
2005
x_ratio = (dataStart - leftOffset) / plotWidth;
2006
double x_graph = plotXMarkMin + x_ratio * plotXLength;
2007
vline_x = "X=" + QString::number(x_graph) + ", ";
2010
if (mouseX < startPix || mouseX > startPix + totalPix)
2013
int vecLen = vecList[activeCurve].getLength();
2014
double x_ratio = (double) (mouseX - startPix) / totalPix;
2015
double x_index = x_ratio * (vecLen - 1);
2016
int x_index_int = (int) round(x_index);
2017
double y_graph = vecList[activeCurve].getElement(x_index_int);
2018
vline_y = "Y=" + QString::number(y_graph);
2022
/* This function prints out X coordinate of the data point that is closest to mouse position */
2023
void PlotWidget::setXY_shift24()
2025
double startPix = xStartPost[activeCurve];
2026
double totalPix = xLengthInPixel[activeCurve];
2027
if (mouseX < startPix || mouseX > startPix + totalPix)
2030
int vecLen = vecList[activeCurve].getLength();
2031
double x_ratio = ((double) mouseX - startPix) / totalPix;
2032
double x_index = x_ratio * vecLen;
2033
double x1 = round(x_index);
2034
double ratio2 = x1 / vecLen;
2035
double dataStart = startPix + totalPix * ratio2;
2036
x_ratio = (dataStart - leftOffset) / plotWidth;
2037
double x_graph = plotXMarkMin + x_ratio * plotXLength;
2038
vline_x = "X=" + QString::number(x_graph) + ", ";
2041
if (mouseX < startPix || mouseX > startPix + totalPix)
2044
int vecLen = vecList[activeCurve].getLength();
2045
double x_ratio = ((double) mouseX - startPix) / totalPix;
2046
double x_index = x_ratio * vecLen;
2047
int x1 = (int) round(x_index);
2048
if (x1 > vecLen - 1)
2050
double y_graph = vecList[activeCurve].getElement(x1);
2051
vline_y = "Y=" + QString::number(y_graph);