~ubuntu-branches/ubuntu/raring/voxbo/raring

« back to all changes in this revision

Viewing changes to vbwidgets/plotscreen.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michael Hanke
  • Date: 2010-06-06 11:33:11 UTC
  • Revision ID: james.westby@ubuntu.com-20100606113311-v3c13imdkkd5n7ae
Tags: upstream-1.8.5~svn1172
ImportĀ upstreamĀ versionĀ 1.8.5~svn1172

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
// plotscreen.cpp
 
3
// Copyright (c) 1998-2010 by The VoxBo Development Team
 
4
 
 
5
// This file is part of VoxBo
 
6
// 
 
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.
 
11
// 
 
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.
 
16
// 
 
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/>.
 
19
// 
 
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/
 
23
// 
 
24
// original version written by Dongbo Hu
 
25
 
 
26
using namespace std;
 
27
 
 
28
#include "plotscreen.h"
 
29
#include <math.h>
 
30
#include <algorithm>
 
31
#include <iostream>
 
32
#include <qlabel.h>
 
33
#include <qlayout.h>
 
34
#include <qmessagebox.h>
 
35
#include <qpainter.h>
 
36
#include <qpalette.h>
 
37
#include <qpushbutton.h>
 
38
#include <q3simplerichtext.h>
 
39
#include <qstring.h>
 
40
 
 
41
/* Basic constructor takes no arguments */
 
42
PlotScreen::PlotScreen(QWidget *parent)
 
43
  : QScrollArea(parent)
 
44
{
 
45
  init();
 
46
}
 
47
 
 
48
/* Destructor */
 
49
PlotScreen::~PlotScreen()
 
50
{
 
51
  clear();
 
52
}
 
53
 
 
54
/* This method is to initialize variables in PlotScreen class. */
 
55
void PlotScreen::init()
 
56
{
 
57
  setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
 
58
  setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
 
59
  pw = new PlotWidget;
 
60
  setWidget(pw);
 
61
 
 
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
 
66
 
 
67
  connect(pw, SIGNAL(xMagChanged(int)), this, SLOT(passMagSignal(int)));
 
68
  connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(setVisibleRange(int)));
 
69
}
 
70
 
 
71
/* Overloaded resizeEvent() */
 
72
void PlotScreen::resizeEvent(QResizeEvent* e)
 
73
{
 
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);
 
78
}
 
79
 
 
80
/* setMinimumSize() is an overloaded function. 
 
81
 * It also changes plotWidth, plotHeight, etc */
 
82
void PlotScreen::setMinimumSize(unsigned inputWidth, unsigned inputHeight )
 
83
{
 
84
  if (inputWidth < 100) {
 
85
    QMessageBox::critical(0, "Error", "Minimum PlotScreen window width is 100");
 
86
    return;
 
87
  }
 
88
  if (inputHeight < 100) {
 
89
    QMessageBox::critical(0, "Error", "Minimum PlotScreen window height is 100");
 
90
    return;
 
91
  }
 
92
 
 
93
  // ignores the value if it is in zoom mode
 
94
  if (pw->xMagnification != 1)
 
95
    return;
 
96
 
 
97
  int newWidth = inputWidth - 2 * frameWidth();
 
98
  int newHeight =  inputHeight - 2 * frameWidth() - horizontalScrollBar()->height();
 
99
  pw->resize(newWidth, newHeight);
 
100
  QWidget::setMinimumSize(inputWidth, inputHeight);
 
101
}
 
102
 
 
103
/* This method is to set the window's size, first number  width and second height */
 
104
void PlotScreen::setWindowSize(unsigned inputWidth, unsigned inputHeight)
 
105
{
 
106
  if (inputWidth < 100) {
 
107
    QMessageBox::critical(0, "Error", "Minimum PlotScreen window width is 100");
 
108
    return;
 
109
  }
 
110
  if (inputHeight < 100) {
 
111
    QMessageBox::critical(0, "Error", "Minimum PlotScreen window height is 100");
 
112
    return;
 
113
  }
 
114
 
 
115
  // ignores the value if it is in zoom mode
 
116
  if (pw->xMagnification != 1)
 
117
    return;
 
118
 
 
119
  int newWidth = inputWidth - 2 * frameWidth();
 
120
  int newHeight =  inputHeight - 2 * frameWidth() - horizontalScrollBar()->height();
 
121
  pw->resize(newWidth, newHeight);
 
122
 
 
123
  QWidget::setFixedSize(inputWidth, inputHeight);
 
124
}
 
125
 
 
126
/* This method is to set the window's width */
 
127
void PlotScreen::setWindowWidth(unsigned inputWidth)
 
128
{
 
129
  if (inputWidth < 100) {
 
130
    QMessageBox::critical(0, "Error", "Minimum PlotScreen window width is 100");
 
131
    return;
 
132
  }
 
133
 
 
134
  int newWidth = inputWidth - 2 * frameWidth();
 
135
  pw->setFixedWidth(newWidth);
 
136
  QWidget::setFixedWidth(inputWidth);
 
137
}
 
138
 
 
139
/* This method is to set the window's height */
 
140
void PlotScreen::setWindowHeight(unsigned inputHeight)
 
141
{
 
142
  if (inputHeight < 100) {
 
143
    QMessageBox::critical(0, "Error", "Minimum PlotScreen window height is 100");
 
144
    return;
 
145
  }
 
146
 
 
147
  int newHeight = inputHeight - 2 * frameWidth() - horizontalScrollBar()->height();
 
148
  pw->setFixedHeight(newHeight);
 
149
  QWidget::setFixedHeight(inputHeight);
 
150
}
 
151
 
 
152
/* This method is to set the frame's width */
 
153
void PlotScreen::setFrameWidth(unsigned inputWidth)
 
154
{
 
155
  pw->frameWidth = inputWidth;
 
156
}
 
157
 
 
158
/* This method sets the curve line's width in plot window */
 
159
void PlotScreen::setCurveLineWidth(unsigned inputWidth)
 
160
{
 
161
  pw->curveLineWidth = inputWidth; 
 
162
}
 
163
 
 
164
/* This method is to set the plot's size, first number width and second height */
 
165
void PlotScreen::setPlotSize(unsigned inputWidth, unsigned inputHeight)
 
166
{
 
167
  pw->setPlotSize(inputWidth, inputHeight);
 
168
}
 
169
 
 
170
/* This method is to set the plot's width */
 
171
void PlotScreen::setPlotWidth(unsigned inputWidth)
 
172
{
 
173
  pw->setPlotWidth(inputWidth);
 
174
}
 
175
 
 
176
/* This method is to set the plot's height */
 
177
void PlotScreen::setPlotHeight(unsigned inputHeight)
 
178
{
 
179
  pw->setPlotHeight(inputHeight);
 
180
}
 
181
 
 
182
/* Set outer window size and inner plot size together */
 
183
void PlotScreen::setFixedSize(unsigned outWidth, unsigned outHeight, unsigned inWidth, unsigned inHeight)
 
184
{
 
185
  pw->setFixedSize(outWidth, outHeight, inWidth, inHeight);
 
186
  QWidget::setFixedSize(outWidth, outHeight);
 
187
}
 
188
 
 
189
/* Wrapper function to addVector(VB_Vector &, QColor ) */
 
190
int PlotScreen::addVector(const VB_Vector* inputVec, QColor inputColor)
 
191
{
 
192
  return pw->addVector(*inputVec, inputColor);
 
193
}
 
194
 
 
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.
 
201
 *
 
202
 * It returns index of the new vector. */
 
203
int PlotScreen::addVector(const VB_Vector& newVec, QColor inputColor)
 
204
{
 
205
  return pw->addVector(newVec, inputColor);
 
206
}
 
207
 
 
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)
 
211
{
 
212
  return pw->addVector(inputVec, inputXMin, inputXLength, inputColor, mode);
 
213
}
 
214
 
 
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)
 
220
{
 
221
  return pw->addVector(inputVec, inputXMin, inputXLength, inputColor, mode);
 
222
}
 
223
 
 
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)
 
226
{
 
227
  return pw->addVecFile(inputFile, inputColor);
 
228
}
 
229
 
 
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)
 
233
{
 
234
  return pw->addVector(inputFile, inputXMin, inputXLength, inputColor, mode);
 
235
}
 
236
 
 
237
/* This method is to delete a certain VB_Vector object from vector container. */
 
238
void PlotScreen::delVector(unsigned vecIndex)
 
239
{
 
240
  pw->delVector(vecIndex);
 
241
}
 
242
 
 
243
/* This function resets active curve's index */
 
244
void PlotScreen::resetActiveCurve(unsigned vecIndex)
 
245
{
 
246
  pw->resetActiveCurve(vecIndex);
 
247
}
 
248
 
 
249
/* This method is to set a new vector's starting value on X axis. */
 
250
void PlotScreen::setNewVecXMin(unsigned vecIndex, double inputXMin)
 
251
{
 
252
  pw->setNewVecXMin(vecIndex, inputXMin);
 
253
}
 
254
 
 
255
/* This method is to set a new vector's total length on X axis. */
 
256
void PlotScreen::setNewVecXLength(unsigned vecIndex, double inputXLength)
 
257
{
 
258
  pw->setNewVecXLength(vecIndex, inputXLength);
 
259
}
 
260
 
 
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)
 
264
{
 
265
  pw->setNewVecX(vecIndex, inputXMin, inputXLength);
 
266
}
 
267
 
 
268
/* This method will set all vector's minimum and maximum on X axis */
 
269
void PlotScreen::setAllNewX(double inputXMin, double inputXLength)
 
270
{
 
271
  pw->setAllNewX(inputXMin, inputXLength);
 
272
 
 
273
}
 
274
 
 
275
/* Set a certain curve's color. */
 
276
void PlotScreen::setPlotColor(unsigned inputIndex, QColor inputColor)
 
277
{
 
278
  if (inputIndex < pw->vecList.size())
 
279
    pw->colorList[inputIndex] = inputColor;
 
280
  else 
 
281
    printf("setPlotColor(): vecIndex out of range\n");
 
282
}
 
283
 
 
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)
 
287
{
 
288
  if (inputMode == 0 || inputMode > 4) {
 
289
    printf("setPlotMode(unsigned): invalid plot mode.\n");
 
290
    return;
 
291
  }
 
292
 
 
293
  for (unsigned i = 0 ; i < pw->plotModeList.size(); i++)
 
294
    pw->plotModeList[i] = inputMode;
 
295
}
 
296
 
 
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)
 
301
{
 
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");
 
306
  else
 
307
    pw->plotModeList[vecIndex] = inputMode;
 
308
}
 
309
 
 
310
/* This method is to clear the screen completely. */
 
311
void PlotScreen::clear()
 
312
{
 
313
  pw->clear();
 
314
}
 
315
 
 
316
 
 
317
/* Update both scroll area and plot widget inside */
 
318
void PlotScreen::update()
 
319
{
 
320
  QScrollArea::update();
 
321
  pw->update();
 
322
}
 
323
 
 
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)
 
328
{
 
329
  pw->setFirstVector(inputVec);
 
330
}
 
331
 
 
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)
 
335
{
 
336
  pw->setNewVecXMin(0, inputValue);
 
337
}
 
338
 
 
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)
 
342
{
 
343
  pw->setNewVecXLength(0, inputLength);
 
344
}
 
345
 
 
346
/* This function will return the first vector's minimum element value */
 
347
double PlotScreen::getFirstXMin()
 
348
{
 
349
  return pw->xMinList[0];
 
350
}
 
351
 
 
352
/* This function returns the full length of X axis */
 
353
double PlotScreen::getFullXLength()
 
354
{
 
355
  double tmpVal = pw->getMax(pw->xMaxList) - pw->getMin(pw->xMinList); 
 
356
  return tmpVal;
 
357
}
 
358
 
 
359
/* This function will return the first vector's total length shown on X axis. */
 
360
double PlotScreen::getFirstXLength()
 
361
{
 
362
  return (pw->xMaxList[0] - pw->xMinList[0]);
 
363
}
 
364
 
 
365
/* This function returns the first vector's plot mode */
 
366
int PlotScreen::getFirstPlotMode()
 
367
{
 
368
  return pw->plotModeList[0];
 
369
}
 
370
 
 
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)
 
374
{
 
375
  if (inputRatio == 0) {
 
376
    printf("setRatio() in PlotWidget: ratio must be positive\n");
 
377
    return;
 
378
  }
 
379
 
 
380
  pw->ratio = inputRatio; 
 
381
}
 
382
 
 
383
/* This function will return the number of vectors in the pool. */
 
384
unsigned PlotScreen::getVecNum()
 
385
{
 
386
  return pw->vecList.size();
 
387
}
 
388
 
 
389
/* This method is to set the graph's backgrond color */
 
390
void PlotScreen::setBkgdColor(QColor &inputColor)
 
391
{
 
392
  pw->bkgdColor = inputColor;
 
393
  pw->setPaletteBackgroundColor(inputColor);
 
394
}
 
395
 
 
396
/* This method is to set the frame edge's color */
 
397
void PlotScreen::setEdgeColor(QColor &inputColor)
 
398
{
 
399
  pw->edgeColor = inputColor;
 
400
}
 
401
 
 
402
/* This method is to set axis' color */
 
403
void PlotScreen::setAxisColor(QColor &inputColor)
 
404
{
 
405
  pw->axisColor = inputColor;
 
406
}
 
407
 
 
408
/* This method is to set X and Y axis caption color */
 
409
void PlotScreen::setCaptionColor(QColor &inputColor)
 
410
{
 
411
  pw->captionColor = inputColor;
 
412
}
 
413
 
 
414
/* This method is to set caption on X axis */
 
415
void PlotScreen::setXCaption(QString inputText)
 
416
{
 
417
  pw->xCaption = inputText;
 
418
}
 
419
 
 
420
/* This method is to set X axis caption's coordinates */
 
421
void PlotScreen::setXCaptionPost(unsigned x, unsigned y)
 
422
{
 
423
  pw->xCaptionPostX = x;
 
424
  pw->xCaptionPostY = y;
 
425
}
 
426
 
 
427
/* This method is to set caption on Y axis */
 
428
void PlotScreen::setYCaption(QString inputText)
 
429
{
 
430
  pw->yCaption = inputText;
 
431
}
 
432
 
 
433
/* This method is to set Y axis caption's coordinates */
 
434
void PlotScreen::setYCaptionPost(unsigned x, unsigned y)
 
435
{
 
436
  pw->yCaptionPostX = x, pw->yCaptionPostY = y;
 
437
}
 
438
 
 
439
 
 
440
/* enableFixedY() will set zoomYFlag to a certain value */
 
441
void PlotScreen::enableFixedY(bool inputFlag)
 
442
{
 
443
  pw->enableFixedY(inputFlag);
 
444
}
 
445
 
 
446
/* getFixedYFlag() returns the current value of zoomYFlag */
 
447
bool PlotScreen::getFixedYFlag()
 
448
{
 
449
  return pw->zoomYFlag;
 
450
}
 
451
 
 
452
/* setFixedY() will set the lower and upper bounds on Y axis */
 
453
void PlotScreen::setFixedY(double inputStart, double inputEnd)
 
454
{
 
455
  pw->setFixedY(inputStart, inputEnd);
 
456
}
 
457
 
 
458
/* This method returns the original input Vector */
 
459
VB_Vector PlotScreen::getInputVector(unsigned vecIndex)
 
460
{
 
461
  return pw->vecList[vecIndex];
 
462
}
 
463
 
 
464
/* This function sets the color of vertical line (generated by mouse press) */
 
465
void PlotScreen::setVLineColor(QColor inputColor)
 
466
{
 
467
  pw->vLineColor = inputColor;
 
468
}
 
469
 
 
470
/* This function will enable/disbale mouse press, release and movement */
 
471
void PlotScreen::setMouseEnabled(bool inputStat)
 
472
{
 
473
  pw->mouseEnabled = inputStat;
 
474
}
 
475
 
 
476
/* This function will enable/disable shift key functionality */
 
477
void PlotScreen::setShiftEnabled(bool inputStat)
 
478
{
 
479
  pw->shiftEnabled = inputStat;
 
480
}
 
481
 
 
482
/* This function will enable/disable space key functionality */
 
483
void PlotScreen::setSpaceEnabled(bool inputStat)
 
484
{
 
485
  pw->spaceEnabled = inputStat;
 
486
}
 
487
 
 
488
/* This function will enable/disable F1-F4 function keys */
 
489
void PlotScreen::setFKeyEnabled(bool inputStat)
 
490
{
 
491
  pw->FKeyEnabled = inputStat;
 
492
}
 
493
 
 
494
/* Emit x magnification change signal */
 
495
void PlotScreen::passMagSignal(int newVal)
 
496
{
 
497
  emit(xMagChanged(newVal));
 
498
}
 
499
 
 
500
/* Slot that sets the visible range for PlotWidget */
 
501
void PlotScreen::setVisibleRange(int newVal)
 
502
{
 
503
  if (pw->width() <= width()) {
 
504
    pw->visible_start = 0;
 
505
    return;
 
506
  }
 
507
 
 
508
  float hbar_range = horizontalScrollBar()->maximum() - horizontalScrollBar()->minimum();
 
509
  pw->visible_start = (pw->width() - width()) * newVal / hbar_range;
 
510
}
 
511
 
 
512
/* This is a slot to restore the default X axis starting and ending positions */
 
513
void PlotScreen::centerX()
 
514
{
 
515
  pw->centerX();
 
516
}
 
517
 
 
518
/* This is a slot to change x axis magnification */
 
519
void PlotScreen::setXMag(int inputVal)
 
520
{
 
521
  pw->setXMag(inputVal);
 
522
}
 
523
 
 
524
/*************************************************************
 
525
 * Member functions of PlotWidget
 
526
 *************************************************************/
 
527
/* Basic constructor takes no arguments */
 
528
PlotWidget::PlotWidget(QWidget *parent)
 
529
  : QFrame(parent)
 
530
{
 
531
  init();
 
532
}
 
533
 
 
534
/* Destructor */
 
535
PlotWidget::~PlotWidget()
 
536
{
 
537
  clear();
 
538
 
 
539
  if (plotVector)
 
540
    delete plotVector;
 
541
}
 
542
 
 
543
/* This method is to initialize variables in PlotWidget class. */
 
544
void PlotWidget::init()
 
545
{
 
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
 
555
  plotVector = 0;
 
556
  
 
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  
 
563
  yDivision = 0;
 
564
  yDivisionInPixel = 0;
 
565
  zoomYFlag = false;
 
566
  zoomYStart = zoomYEnd = 0;
 
567
 
 
568
  setLineWidth(frameWidth);
 
569
  setFrameStyle( Panel | Sunken );
 
570
  setBackgroundMode( Qt::PaletteBase );
 
571
 
 
572
  QWidget::setMinimumSize(windowWidth + 2 * frameWidth, windowHeight + 2 * frameWidth);
 
573
  setPaletteBackgroundColor( bkgdColor );
 
574
 
 
575
  curveLineWidth = 0;
 
576
  QFont myFont("Helvetica", 8);
 
577
  setFont(myFont);
 
578
 
 
579
  mouseX = mouseY = myX = 0;
 
580
  vLineColor = Qt::white;
 
581
  visible_start = 0;
 
582
 
 
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
 
589
  ratio = 1;
 
590
 
 
591
  xMagnification = 1;
 
592
  setFocusPolicy(Qt::ClickFocus); // Interface has to be clicked before focus
 
593
}
 
594
 
 
595
/* This method is to clear the screen completely. */
 
596
void PlotWidget::clear()
 
597
{
 
598
  vecList.clear();
 
599
  xMinList.clear();
 
600
  xMaxList.clear();
 
601
  yMinList.clear();
 
602
  yMaxList.clear();
 
603
  colorList.clear();
 
604
  plotModeList.clear();
 
605
 
 
606
  xStartPost.clear();
 
607
  xLengthInPixel.clear();
 
608
 
 
609
  // Reset highlighted curve's index and pen color to default
 
610
  activeCurve = 0;
 
611
}
 
612
 
 
613
/* Function that is in charge of painting. */
 
614
void PlotWidget::paintEvent(QPaintEvent* )
 
615
{
 
616
  if (!vecList.size()) 
 
617
    return;
 
618
 
 
619
  QPainter p(this);
 
620
  p.setPen(edgeColor);
 
621
  p.drawRect(leftOffset, upOffset, plotWidth, plotHeight);
 
622
  
 
623
  drawXAxis(p);
 
624
  drawYAxis(p);
 
625
  drawGraph(p);
 
626
  if (myX) {
 
627
    addVLine(p);
 
628
    addVLineTxt(p);
 
629
  }
 
630
}
 
631
 
 
632
/* Overloaded resizeEvent() */
 
633
void PlotWidget::resizeEvent(QResizeEvent* e)
 
634
{
 
635
  QWidget::resizeEvent(e);
 
636
  windowHeight = height() - 2 * frameWidth;
 
637
  windowWidth = width() - 2 * frameWidth;
 
638
  resizePlot();
 
639
}
 
640
 
 
641
/* Reset plot size */
 
642
void PlotWidget::resizePlot()
 
643
{
 
644
  int totalWidth = windowWidth + 2 * frameWidth;
 
645
  if (totalWidth >= 300)
 
646
    plotWidth = windowWidth - 100; 
 
647
  else
 
648
    plotWidth = windowWidth - 40;
 
649
 
 
650
  int totalHeight = windowHeight + 2 * frameWidth;
 
651
  if (totalHeight >= 200)
 
652
    plotHeight = windowHeight - 100; 
 
653
  else
 
654
    plotHeight = windowHeight - 40;
 
655
 
 
656
  updateSize();
 
657
  updateGeometry();
 
658
}
 
659
 
 
660
/* This method is to set the plot's size, first number width and second height */
 
661
void PlotWidget::setPlotSize(unsigned inputWidth, unsigned inputHeight)
 
662
{
 
663
  if (inputWidth + 40 > windowWidth) {
 
664
    QMessageBox::critical(0, "Error", 
 
665
                          "Outer window width should be at least 40 pixels larger than inner width");
 
666
    return;
 
667
  }
 
668
  if (inputHeight + 40 > windowHeight) {
 
669
    QMessageBox::critical(0, "Error", 
 
670
                          "Outer window height should be at least 40 pixels larger than inner height");
 
671
    return;
 
672
  }
 
673
 
 
674
  plotWidth = inputWidth;
 
675
  plotHeight = inputHeight;
 
676
  updateSize();
 
677
}
 
678
 
 
679
/* This method is to set the plot's width */
 
680
void PlotWidget::setPlotWidth(unsigned inputWidth)
 
681
{
 
682
  if (inputWidth  + 40 > windowWidth) {
 
683
    printf("%d: Invalid plot width\n", inputWidth);
 
684
    return;
 
685
  }
 
686
  plotWidth = inputWidth;
 
687
  updateSize();
 
688
}
 
689
 
 
690
/* This method is to set the plot's height */
 
691
void PlotWidget::setPlotHeight(unsigned inputHeight)
 
692
{
 
693
  if (inputHeight + 40 > windowHeight) {
 
694
    printf("%d: Invalid plot height\n", inputHeight);
 
695
    return;
 
696
  }
 
697
 
 
698
  plotHeight = inputHeight;
 
699
  updateSize();
 
700
}
 
701
 
 
702
/* Set outer window size and inner plot size together */
 
703
void PlotWidget::setFixedSize(unsigned outWidth, unsigned outHeight, unsigned inWidth, unsigned inHeight)
 
704
{
 
705
  unsigned w1 = outWidth - 2 * frameWidth;
 
706
  unsigned h1 = outHeight - 2 * frameWidth;
 
707
 
 
708
  if (inWidth + 40 > w1) {
 
709
    QMessageBox::critical(0, "Error", 
 
710
                          "Outer window width should be at least 40 pixels larger than inner width");
 
711
    return;
 
712
  }
 
713
  if (inHeight + 40 > h1) {
 
714
    QMessageBox::critical(0, "Error", 
 
715
                          "Outer window height should be at least 40 pixels larger than inner height");
 
716
    return;
 
717
  }
 
718
  if (w1 < 100) {
 
719
    QMessageBox::critical(0, "Error", "Minimum PlotWidget window width is 100");
 
720
    return;
 
721
  }
 
722
  if (h1 < 100) {
 
723
    QMessageBox::critical(0, "Error", "Minimum PlotWidget window height is 100");
 
724
    return;
 
725
  }
 
726
 
 
727
  windowWidth = w1, windowHeight = h1;
 
728
  plotWidth = inWidth, plotHeight = inHeight;
 
729
  updateSize();
 
730
  QWidget::setFixedSize(outWidth, outHeight);
 
731
}
 
732
 
 
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()
 
737
{
 
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;
 
744
}
 
745
 
 
746
/* Wrapper function to addVector(VB_Vector &, QColor ) */
 
747
int PlotWidget::addVector(const VB_Vector* inputVec, QColor inputColor)
 
748
{
 
749
  return addVector(*inputVec, inputColor);
 
750
}
 
751
 
 
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.
 
758
 *
 
759
 * It returns index of the new vector. */
 
760
int PlotWidget::addVector(const VB_Vector& newVec, QColor inputColor)
 
761
{
 
762
  vecList.push_back(newVec);
 
763
  xMinList.push_back(0);  
 
764
  xMaxList.push_back((double)newVec.getLength() - 1);
 
765
  colorList.push_back(inputColor);
 
766
 
 
767
  double tmpMin, tmpMax;
 
768
  if (newVec.getVariance() < 1e-10)
 
769
    tmpMin = tmpMax = newVec.getVectorMean();
 
770
  else {
 
771
    tmpMin = newVec.getMinElement();
 
772
    tmpMax = newVec.getMaxElement();
 
773
  }
 
774
  yMinList.push_back(tmpMin);
 
775
  yMaxList.push_back(tmpMax);
 
776
 
 
777
  plotModeList.push_back(1);
 
778
  xStartPost.push_back(0);
 
779
  xLengthInPixel.push_back(0);
 
780
 
 
781
  return vecList.size() - 1;
 
782
}
 
783
 
 
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)
 
787
{
 
788
  return addVector(*inputVec, inputXMin, inputXLength, inputColor, mode);
 
789
}
 
790
 
 
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)
 
796
{
 
797
  if (inputXLength <= 0) {
 
798
    printf("addVector(): inputXLength must be positive.\n");
 
799
    return -1;
 
800
  }
 
801
 
 
802
  if (mode == 0 || mode > 4) {
 
803
    printf("addVector(): invalid plot mode.\n");
 
804
    return -2;
 
805
  }
 
806
 
 
807
  vecList.push_back(inputVec);
 
808
  xMinList.push_back(inputXMin);
 
809
  xMaxList.push_back(inputXMin + inputXLength);
 
810
  colorList.push_back(inputColor);
 
811
 
 
812
  double tmpMin, tmpMax;
 
813
  if (inputVec.getVariance() < 1e-10)
 
814
    tmpMin = tmpMax = inputVec.getVectorMean();
 
815
  else {
 
816
    tmpMin = inputVec.getMinElement();
 
817
    tmpMax = inputVec.getMaxElement();
 
818
  }
 
819
  yMinList.push_back(tmpMin);
 
820
  yMaxList.push_back(tmpMax);
 
821
 
 
822
  plotModeList.push_back(mode);
 
823
  xStartPost.push_back(0);
 
824
  xLengthInPixel.push_back(0);
 
825
 
 
826
  return vecList.size() - 1;
 
827
}
 
828
 
 
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)
 
831
{
 
832
  VB_Vector newVector(inputFile); 
 
833
  return addVector(newVector, inputColor);
 
834
}
 
835
 
 
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)
 
839
{
 
840
  VB_Vector newVec(inputFile); 
 
841
  return addVector(newVec, inputXMin, inputXLength, inputColor, mode);
 
842
}
 
843
 
 
844
/* This method is to delete a certain VB_Vector object from vector container. */
 
845
void PlotWidget::delVector(unsigned vecIndex)
 
846
{
 
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);
 
859
  }
 
860
  else 
 
861
    printf("delVector(): vecIndex out of range\n");
 
862
}
 
863
 
 
864
/* This function resets active curve's index */
 
865
void PlotWidget::resetActiveCurve(unsigned vecIndex)
 
866
{
 
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)
 
870
    activeCurve = 0;
 
871
  // If the deleted curve is before the highlighted, decrease activeCurve by 1
 
872
  else if (vecIndex < activeCurve)
 
873
    activeCurve--;
 
874
}
 
875
 
 
876
/* This method is to set a new vector's starting value on X axis. */
 
877
void PlotWidget::setNewVecXMin(unsigned vecIndex, double inputXMin)
 
878
{
 
879
  if (vecIndex < vecList.size()) {
 
880
    xMinList[vecIndex] = inputXMin;
 
881
  }
 
882
  else
 
883
    printf("setNewVecXMin(): vecIndex out of range\n");
 
884
}
 
885
 
 
886
/* This method is to set a new vector's total length on X axis. */
 
887
void PlotWidget::setNewVecXLength(unsigned vecIndex, double inputXLength)
 
888
{
 
889
  if (inputXLength <= 0) {
 
890
    printf("setNewVecXLength(): inputXLength must be positive.\n");
 
891
    return;
 
892
  }
 
893
 
 
894
  if (vecIndex < vecList.size())
 
895
    xMaxList[vecIndex] = xMinList[vecIndex] + inputXLength;
 
896
  else
 
897
    printf("setNewVecXLength(): vecIndex out of range\n");
 
898
 
 
899
}
 
900
 
 
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)
 
904
{
 
905
  if (inputXLength <= 0) {
 
906
    printf("setNewVecX(): inputXLength must be positive.\n");
 
907
    return;
 
908
  }
 
909
 
 
910
  if (vecIndex < vecList.size()) {
 
911
    xMinList[vecIndex] = inputXMin;
 
912
    xMaxList[vecIndex] = inputXMin + inputXLength;
 
913
  }
 
914
  else
 
915
    printf("setNewVecX(): vecIndex out of range\n");
 
916
}
 
917
 
 
918
/* This method will set all vector's minimum and maximum on X axis */
 
919
void PlotWidget::setAllNewX(double inputXMin, double inputXLength)
 
920
{
 
921
  for (unsigned  i = 0; i < vecList.size(); i++)
 
922
    setNewVecX(i, inputXMin, inputXLength);
 
923
}
 
924
 
 
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)
 
929
{
 
930
  if (vecList.size() > 0)
 
931
    clear();
 
932
 
 
933
  addVector(inputVec); 
 
934
}
 
935
 
 
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)
 
939
{
 
940
  setNewVecXMin(0, inputValue);
 
941
}
 
942
 
 
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)
 
946
{
 
947
  if (inputLength <=0) {
 
948
    printf("setFirstXLength(): inputLength must be positive.\n");
 
949
    return;
 
950
  }
 
951
 
 
952
  setNewVecXLength(0, inputLength);
 
953
}
 
954
 
 
955
/* This is the function to calculate the marked values which will be shown on X axis */
 
956
void PlotWidget::calcXMark()
 
957
{
 
958
  plotXMarkMin = getMin(xMinList);
 
959
  plotXLength = getMax(xMaxList) - plotXMarkMin;    
 
960
}
 
961
 
 
962
/* This method is to draw X axis, including the caption. */
 
963
void PlotWidget::drawXAxis(QPainter& p)
 
964
{
 
965
  p.setPen(axisColor);
 
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.");
 
969
  else
 
970
    p.drawText(xCaptionPostX, xCaptionPostY, xCaption);
 
971
 
 
972
  calcXMark();
 
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  
 
978
 
 
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
 
983
 
 
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
 
989
  }
 
990
 
 
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
 
995
 
 
996
  double xMarkInDb;
 
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
 
1002
 
 
1003
    xMarkInDb = plotXMarkMin + xDivision * i;
 
1004
    if (abs(xMarkInDb) < 1e-7 && xDivision > 1e-7)
 
1005
      xMarkInDb = 0;
 
1006
    QString xLabel = QString::number(xMarkInDb);
 
1007
    // mark the divisions
 
1008
    p.drawText(xMarkX + (int)(xDivisionInPixel * i), xMarkY - 10, labelWidth, 20, Qt::AlignHCenter, xLabel);
 
1009
  } 
 
1010
}
 
1011
 
 
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()
 
1015
{
 
1016
  if (zoomYFlag) {
 
1017
    plotYMarkMin = zoomYStart;
 
1018
    plotYLength = zoomYEnd - zoomYStart;
 
1019
    if (yDivision)
 
1020
      return;
 
1021
  }
 
1022
  else {
 
1023
    plotYMarkMin = getMin(yMinList);
 
1024
    plotYLength = getMax(yMaxList) - plotYMarkMin;    
 
1025
  }
 
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;
 
1033
    else
 
1034
      yDivision = yRange / 50.0;
 
1035
  }
 
1036
  else if (plotYMarkMin)
 
1037
    yDivision = plotYMarkMin;
 
1038
  else 
 
1039
    yDivision = 1; 
 
1040
}
 
1041
 
 
1042
/* This method is to draw Y axis, including its caption */
 
1043
void PlotWidget::drawYAxis(QPainter& p)
 
1044
{
 
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.");
 
1050
  else
 
1051
    p.drawText(yCaptionPostX, yCaptionPostY, yCaption);
 
1052
 
 
1053
  calcYMark();
 
1054
  double max = plotYLength + plotYMarkMin;
 
1055
  double yDivisionNumber;
 
1056
  // Most of the times plotYLength should be positive
 
1057
  if (plotYLength > 0) {          
 
1058
    if (zoomYFlag) {
 
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;
 
1063
    }
 
1064
    // If zoomYFlag isn't set, draw Y axis automatically
 
1065
    else {
 
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)
 
1071
        yMin--;
 
1072
      double yMax = ceil(max / yDivision);
 
1073
      double diffMax = yMax * yDivision - max;
 
1074
      if (diffMax <= yDivision * 1e-2)
 
1075
        yMax++;;
 
1076
 
 
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;
 
1080
    }
 
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;
 
1089
    int yStartDivision;
 
1090
    if (foo == (double) foo_int) {
 
1091
      firstMark = 0;
 
1092
      firstY = yBaseValue;
 
1093
      yStartDivision = foo_int;
 
1094
    }
 
1095
    else if (foo > 0) {
 
1096
      firstMark = ((double) foo_int + 1.0 - foo) * yDivisionInPixel;
 
1097
      firstY = ((double) foo_int + 1.0) * yDivision;
 
1098
      yStartDivision = foo_int + 1;
 
1099
    }
 
1100
    else {
 
1101
      firstMark = ((double) foo_int - foo) * yDivisionInPixel;
 
1102
      firstY = (double) foo_int * yDivision;
 
1103
      yStartDivision = foo_int;
 
1104
    }
 
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)
 
1109
      firstY = 0;
 
1110
 
 
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
 
1122
      }
 
1123
      else {
 
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)
 
1129
          firstY = 0;
 
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);  
 
1135
      }
 
1136
      firstY += yDivision;
 
1137
    }
 
1138
 
 
1139
  }
 
1140
 
 
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. */
 
1143
  else if (max > 0) {
 
1144
    int yDivisionNumber = 2;
 
1145
    yDivisionInPixel =  (double) plotHeight / (double) yDivisionNumber;
 
1146
    yBaseValue = 0;   // Set Y base value to be 0
 
1147
    yMaxValue = 2 * max;
 
1148
 
 
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)
 
1159
    int yMarkX = 0;
 
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);
 
1163
  }
 
1164
 
 
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. */
 
1167
  else if (max < 0) { 
 
1168
    int yDivisionNumber = 2;
 
1169
    yDivisionInPixel =  (double) plotHeight / (double) yDivisionNumber;
 
1170
    yBaseValue = 2 * max; // Set Y base value to be 2*max
 
1171
    yMaxValue = 0;
 
1172
 
 
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)
 
1182
    int yMarkX = 0;    
 
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);
 
1186
  }
 
1187
 
 
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. */
 
1190
  else {
 
1191
    int yDivisionNumber = 2;
 
1192
    yDivisionInPixel =  (double) plotHeight / (double) yDivisionNumber;
 
1193
    yBaseValue = -1;
 
1194
    yMaxValue = 1;
 
1195
 
 
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);
 
1200
 
 
1201
    int yMarkX = 0;    
 
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");
 
1205
  } 
 
1206
}
 
1207
 
 
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)
 
1210
{
 
1211
  for (unsigned i = 0; i < vecList.size(); i++) {
 
1212
    calcXIndex(i);
 
1213
 
 
1214
    int currentWidth = curveLineWidth;
 
1215
    if (vecList.size() > 1 && i == activeCurve)
 
1216
      currentWidth += 2;
 
1217
    QPen curvePen(colorList[i], currentWidth);
 
1218
    p.setPen(curvePen);
 
1219
 
 
1220
    unsigned currentMode = plotModeList[i];
 
1221
    plotVector = new VB_Vector(vecList[i]);
 
1222
    if (currentMode == 1)
 
1223
      drawInMode1(p, i);
 
1224
    else if (currentMode == 2)
 
1225
      drawInMode2(p, i);
 
1226
    else if (currentMode == 3)
 
1227
      drawInMode3(p, i);
 
1228
    else if (currentMode == 4)
 
1229
      drawInMode4(p, i);
 
1230
    else 
 
1231
      printf("drawGraph(): invalid plot mode.\n");
 
1232
  }
 
1233
 
 
1234
}
 
1235
 
 
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)
 
1239
{
 
1240
  double xMin = xMinList[vecIndex];
 
1241
  double xMax = xMaxList[vecIndex];
 
1242
 
 
1243
  xLengthInPixel[vecIndex] = (xMax - xMin) / plotXLength * plotWidth;
 
1244
  xStartPost[vecIndex] = (xMin - plotXMarkMin) / plotXLength * plotWidth + (double)leftOffset;
 
1245
}
 
1246
 
 
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)
 
1251
{
 
1252
  if (inputVal > yMaxValue)
 
1253
    return 1;
 
1254
  if (inputVal < yBaseValue)
 
1255
    return -1; 
 
1256
  return 0;
 
1257
}
 
1258
 
 
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)
 
1267
{
 
1268
  double yTotal = abs(yEnd - yStart);
 
1269
  double yShownup = abs(yEdge - yStart);
 
1270
 
 
1271
  return xTotal * yShownup / yTotal;
 
1272
}
 
1273
 
 
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)
 
1279
{
 
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;
 
1284
  double m;
 
1285
  double val1, val2;
 
1286
  unsigned vecLen = vecList[vecIndex].getLength();
 
1287
 
 
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);
 
1300
    }
 
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);
 
1307
    } 
 
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);
 
1314
    }
 
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);
 
1321
    }
 
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);
 
1328
    }
 
1329
  }
 
1330
}
 
1331
 
 
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)
 
1336
{
 
1337
  int yMinPost = upOffset + plotHeight - 1;
 
1338
  int yMaxPost = upOffset - 1;
 
1339
  int element1 = 0, element2 = 0;
 
1340
  double val1 = 0, val2 = 0;
 
1341
  double m;
 
1342
  unsigned vecLen = vecList[vecIndex].getLength();
 
1343
 
 
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);
 
1360
    }
 
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);
 
1369
    }
 
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);
 
1375
    }
 
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);
 
1381
    }
 
1382
  }
 
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); 
 
1387
}
 
1388
 
 
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)
 
1392
{
 
1393
  int yMinPost = upOffset + plotHeight - 1;
 
1394
  int element1 = 0;
 
1395
  double m;
 
1396
  double val1;
 
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);
 
1406
  }
 
1407
}
 
1408
 
 
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)
 
1412
{
 
1413
  int yMinPost = upOffset + plotHeight - 1;
 
1414
  int element1 = 0, element2 = 0;
 
1415
  double m;
 
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);
 
1430
  }
 
1431
 
 
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); 
 
1436
}
 
1437
 
 
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)
 
1440
{
 
1441
  p.save();  
 
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) 
 
1445
  p.restore();     
 
1446
}
 
1447
 
 
1448
/* enableFixedY() will set zoomYFlag to a certain value */
 
1449
void PlotWidget::enableFixedY(bool inputFlag)
 
1450
{
 
1451
  zoomYFlag = inputFlag;
 
1452
  if (!zoomYFlag) {
 
1453
    yDivision = 0;
 
1454
    zoomYStart = zoomYEnd = 0;
 
1455
  }
 
1456
  else if (zoomYStart == 0 && zoomYEnd == 0) {
 
1457
    zoomYStart = yBaseValue;
 
1458
    zoomYEnd = yMaxValue;
 
1459
  }
 
1460
}
 
1461
 
 
1462
/* setFixedY() will set the lower and upper bounds on Y axis */
 
1463
void PlotWidget::setFixedY(double inputStart, double inputEnd)
 
1464
{
 
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.");
 
1477
  else {
 
1478
    zoomYStart = inputStart;
 
1479
    zoomYEnd = inputEnd;
 
1480
    yDivision = 0;
 
1481
    zoomYFlag = true;
 
1482
  }
 
1483
}
 
1484
 
 
1485
/* This method is used to gauge X axis range. 
 
1486
 * Note: the inputNumber must be nonnegative! */
 
1487
double PlotWidget::getXRange(double inputNumber)
 
1488
{
 
1489
  double n = 1.0;
 
1490
  // when inputNumber is non-positive, return 0
 
1491
  if (inputNumber <= 0)
 
1492
    return 0;
 
1493
  else if (inputNumber == 1)
 
1494
    return 1.0;
 
1495
  else if (inputNumber > 1.0) {
 
1496
    while ( inputNumber > n )
 
1497
      n *= 10.0;  
 
1498
    return n;           // returnNumber / 10 < inputNumber <= returnNumber
 
1499
  }
 
1500
  else {
 
1501
    while ( inputNumber <= n )
 
1502
      n /= 10.0;
 
1503
    return n * 10;      // returnNumber / 10 < inputNumber <= returnNumber
 
1504
  }
 
1505
}
 
1506
 
 
1507
/* This method is used to gauge Y axis range. 
 
1508
 * Note the difference between getXYange() and getYRange() */
 
1509
double PlotWidget::getYRange(double inputNumber)
 
1510
{
 
1511
  double n = 1.0;
 
1512
  // when inputNumber is non-positive, return 0
 
1513
  if (inputNumber <= 0)
 
1514
    return 0;
 
1515
  else if (inputNumber == 1)
 
1516
    return 1.0;
 
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)
 
1521
        return n;
 
1522
      else
 
1523
        n *= 10.0;  
 
1524
    }
 
1525
    return n;           // returnNumber / 10 < inputNumber <= returnNumber
 
1526
  }
 
1527
  else {
 
1528
    while ( inputNumber <= n )
 
1529
      n /= 10.0;
 
1530
    return n * 10;      // returnNumber / 10 < inputNumber <= returnNumber
 
1531
  }
 
1532
}
 
1533
 
 
1534
/* This method determines the seperation of each marked values on x/y axis. */
 
1535
int PlotWidget::getIncrement(double inputNumber)
 
1536
{
 
1537
  // If there are more than 50 divisions, mark the value once every 10 divisions
 
1538
  if (inputNumber > 50.0)      
 
1539
    return 10;
 
1540
  // If there are more than 10 divisions, mark the value once every 5 divisions
 
1541
  if (inputNumber > 10.0) 
 
1542
    return 5;
 
1543
  // If there are 5 - 10 divisions, mark the value once every 2 divisions
 
1544
  if (inputNumber > 5.0)  
 
1545
    return 2;
 
1546
  // If there are less than or equal to 5 divisions, mark all of them
 
1547
    return 1;
 
1548
}
 
1549
 
 
1550
/* This method returns the minimum of the vectors' starting value on X axis */
 
1551
double PlotWidget::getMin(std::vector< double > inputArr)
 
1552
{
 
1553
  double tmp = inputArr[0]; 
 
1554
  for (int i = 1; i < (int)inputArr.size(); i++) {
 
1555
    if (tmp > inputArr[i])
 
1556
      tmp = inputArr[i];
 
1557
    else
 
1558
      continue;
 
1559
  }
 
1560
  
 
1561
  return tmp;
 
1562
}
 
1563
 
 
1564
/* This method returns the maximum of the vectors' ending value on X axis */
 
1565
double PlotWidget::getMax(std::vector< double > inputArr)
 
1566
{
 
1567
  double tmp = inputArr[0];
 
1568
  if (inputArr.size() == 1)
 
1569
    return tmp;
 
1570
 
 
1571
  for (int i = 1; i < (int)inputArr.size(); i++) {
 
1572
    if (tmp < inputArr[i])
 
1573
      tmp = inputArr[i];
 
1574
    else
 
1575
      continue;
 
1576
  }  
 
1577
  return tmp;
 
1578
}
 
1579
 
 
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 )
 
1583
{
 
1584
  // when mouse button is clicked, set the keyboard focus to current screen
 
1585
  setFocus();
 
1586
 
 
1587
  // Do nothing if mouse is disabled or no curve at all
 
1588
  if (!mouseEnabled || vecList.size() == 0)
 
1589
    return;
 
1590
 
 
1591
  mouseX = myMouse->x();
 
1592
  mouseY = myMouse->y();
 
1593
  // Do nothing if mouse is out of X axis range
 
1594
  if (!chkMouseX()) {
 
1595
    myX = 0;
 
1596
    return;
 
1597
  }
 
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. */ 
 
1600
  setMyX();
 
1601
  update();  
 
1602
}
 
1603
 
 
1604
/* This function checks whether a point's X coordinate is out of scale or not */
 
1605
bool PlotWidget::chkMouseX()
 
1606
{
 
1607
  // Is mouse position out of plot range?
 
1608
  if ((unsigned) mouseX < leftOffset || (unsigned) mouseX > plotWidth + leftOffset)
 
1609
    return false;
 
1610
  // Is mouse out of visible area?
 
1611
  if (mouseX < visible_start || mouseX > visible_start + parentWidget()->width())
 
1612
    return false;
 
1613
 
 
1614
  return true;
 
1615
}
 
1616
 
 
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()
 
1620
{
 
1621
  if (!shiftPressed) {
 
1622
    myX = mouseX;
 
1623
    return;
 
1624
  }
 
1625
 
 
1626
  double startPix = xStartPost[activeCurve];
 
1627
  double totalPix = xLengthInPixel[activeCurve];
 
1628
  if (mouseX < startPix || mouseX > startPix + totalPix) {
 
1629
    myX = 0;
 
1630
    return;
 
1631
  }
 
1632
 
 
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);
 
1641
  }
 
1642
  else {
 
1643
    x_index = x_ratio * vecLen;
 
1644
    double x1 = round(x_index);
 
1645
    ratio2 = x1 / vecLen;
 
1646
  }
 
1647
 
 
1648
  myX = (unsigned) (startPix + totalPix * ratio2);
 
1649
}
 
1650
 
 
1651
/* This function adds a QWidget on screen when mouse is pressed */
 
1652
void PlotWidget::addVLine(QPainter& p)
 
1653
{
 
1654
  p.setPen(vLineColor);
 
1655
  if (vecList.size() > 1) 
 
1656
    p.setPen(colorList[activeCurve]);
 
1657
  p.drawLine(myX, upOffset, myX, upOffset + plotHeight);
 
1658
}
 
1659
 
 
1660
/* This function draws X and Y coordinates according to the shift key and plot mode status */
 
1661
void PlotWidget::addVLineTxt(QPainter& p)
 
1662
{
 
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");
 
1672
    return;
 
1673
  }
 
1674
 
 
1675
  if (vecList.size() > 1) 
 
1676
    p.setPen(colorList[activeCurve]);
 
1677
 
 
1678
  if (!shiftPressed && plotModeList[activeCurve] % 2 != 0) 
 
1679
    setXY_13();
 
1680
  else if (!shiftPressed && plotModeList[activeCurve] % 2 == 0)
 
1681
    setXY_24();
 
1682
  else if (plotModeList[activeCurve] % 2 != 0)
 
1683
    setXY_shift13();
 
1684
  else {
 
1685
    setXY_shift24();
 
1686
  }
 
1687
 
 
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);
 
1694
}
 
1695
 
 
1696
/* When mouse is released, erase the vertical line and number on screen */
 
1697
void PlotWidget::mouseReleaseEvent(QMouseEvent*)
 
1698
{
 
1699
  if (!mouseEnabled || vecList.size() == 0)
 
1700
    return;
 
1701
 
 
1702
  mouseX = mouseY = 0;
 
1703
  myX = 0;
 
1704
  update();
 
1705
}
 
1706
 
 
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 )
 
1710
{
 
1711
  if (!mouseEnabled || vecList.size() == 0)
 
1712
    return;
 
1713
 
 
1714
  mouseX = myMouse->x();
 
1715
  mouseY = myMouse->y();
 
1716
  if (!chkMouseX()) {
 
1717
    myX = 0;
 
1718
    return;
 
1719
  }
 
1720
 
 
1721
  setMyX();
 
1722
  update();
 
1723
}
 
1724
 
 
1725
/* Mouse wheel movement will also zoom in/out in X direction */
 
1726
void PlotWidget::wheelEvent ( QWheelEvent* e )
 
1727
{
 
1728
  if (!mouseEnabled || vecList.size() == 0)
 
1729
    return;
 
1730
 
 
1731
  // when e->delta() is 120, wheel is moving upward, zoom in X axis
 
1732
  if (e->delta() > 0)
 
1733
    pressUp();
 
1734
  // when e->delta() is -120, wheel is moving downward, zoom out X axis
 
1735
  else
 
1736
    pressDown();
 
1737
}
 
1738
 
 
1739
/* Overwrited function to handle key press event */
 
1740
void PlotWidget::keyPressEvent( QKeyEvent *e )
 
1741
{
 
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)
 
1745
    e->ignore();
 
1746
 
 
1747
  // Do nothing if no vector available
 
1748
  if (vecList.size() == 0)
 
1749
    return;
 
1750
  // shift key pressed
 
1751
  if (e->key() == Qt::Key_Shift)
 
1752
    pressShift();
 
1753
  // space key pressed
 
1754
  else if (e->key() == Qt::Key_Space)
 
1755
    pressSpace();
 
1756
  // up arrow key pressed
 
1757
  else if (e->key() == Qt::Key_Up)
 
1758
    pressUp();
 
1759
  // down arrow key pressed
 
1760
  else if (e->key() == Qt::Key_Down)
 
1761
    pressDown();
 
1762
  // "1" key is pressed
 
1763
  else if (e->key() == Qt::Key_1)
 
1764
    press1key();
 
1765
  // pressFKey() deals with the rest of keyboard presses
 
1766
  else
 
1767
    pressFKey(e);
 
1768
}
 
1769
 
 
1770
/* Overwritten function to handle key release event */
 
1771
void PlotWidget::keyReleaseEvent ( QKeyEvent * e )
 
1772
{
 
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)
 
1776
    e->ignore();
 
1777
 
 
1778
  // Do nothing if no vector available
 
1779
  if (vecList.size() == 0)
 
1780
    return;
 
1781
 
 
1782
  // If the released key is not shift, ignore it
 
1783
  if (e->key() != Qt::Key_Shift)
 
1784
    return;
 
1785
  // If shift key is disabled, ignore it
 
1786
  if (!shiftEnabled)
 
1787
    return;
 
1788
 
 
1789
  shiftPressed = false;
 
1790
  if (xLengthInPixel[activeCurve] == 0)
 
1791
    return;
 
1792
  if (!chkMouseX())
 
1793
    return;
 
1794
 
 
1795
  // When shift key is released, change X and Y coordinates print out
 
1796
  myX = mouseX;
 
1797
  update();
 
1798
}
 
1799
 
 
1800
/* This function deals with shift key press.
 
1801
 * It changes X and Y coordinates printout. */
 
1802
void PlotWidget::pressShift()
 
1803
{
 
1804
  if (!shiftEnabled)
 
1805
    return;
 
1806
 
 
1807
  shiftPressed = true;
 
1808
  if (xLengthInPixel[activeCurve] == 0)
 
1809
    return;
 
1810
 
 
1811
  if (!chkMouseX())
 
1812
    return;
 
1813
 
 
1814
  setMyX();
 
1815
  update();
 
1816
}
 
1817
 
 
1818
/* This function deals with space key press.
 
1819
 * It activates the next curve and update the whole screen. */
 
1820
void PlotWidget::pressSpace()
 
1821
{
 
1822
  if (!spaceEnabled)
 
1823
    return;
 
1824
  if (vecList.size() < 2)
 
1825
    return;
 
1826
 
 
1827
  int newIndex = (activeCurve + 1) % vecList.size();
 
1828
  if (xLengthInPixel[newIndex] == 0)
 
1829
    return;
 
1830
 
 
1831
  activeCurve = newIndex;
 
1832
  update();
 
1833
}
 
1834
 
 
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()
 
1839
{
 
1840
  if (xMagnification == 10)
 
1841
    return;
 
1842
 
 
1843
  xMagnification++;
 
1844
  int newWidth = xMagnification * parentWidget()->width();
 
1845
  resize(newWidth, height());
 
1846
  update();
 
1847
 
 
1848
  emit(xMagChanged(xMagnification));
 
1849
}
 
1850
 
 
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()
 
1855
{
 
1856
  if (xMagnification == 1)
 
1857
    return;
 
1858
 
 
1859
  xMagnification--;
 
1860
  int newWidth = xMagnification * parentWidget()->width();
 
1861
  resize(newWidth, height());
 
1862
  update();
 
1863
 
 
1864
  emit(xMagChanged(xMagnification));
 
1865
}
 
1866
 
 
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()
 
1871
{
 
1872
  centerX();
 
1873
}
 
1874
 
 
1875
/* This is a slot to restore the default X axis starting and ending positions */
 
1876
void PlotWidget::centerX()
 
1877
{
 
1878
  if (xMagnification == 1) 
 
1879
    return;
 
1880
 
 
1881
  xMagnification = 1;
 
1882
  int newWidth = parentWidget()->width();
 
1883
  resize(newWidth, height());
 
1884
  update();
 
1885
 
 
1886
  emit(xMagChanged(1));
 
1887
}
 
1888
 
 
1889
/* This is a slot to change x axis magnification */
 
1890
void PlotWidget::setXMag(int inputVal)
 
1891
{
 
1892
  xMagnification = inputVal;
 
1893
  int newWidth = xMagnification * parentWidget()->width();
 
1894
  resize(newWidth, height());
 
1895
  update();
 
1896
}
 
1897
 
 
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)
 
1901
{
 
1902
  if (!FKeyEnabled)
 
1903
    return;
 
1904
 
 
1905
  unsigned newMode = 0;
 
1906
  if (e->key() == Qt::Key_F1)
 
1907
    newMode = 1;
 
1908
  else if (e->key() == Qt::Key_F2) 
 
1909
    newMode = 2;
 
1910
  else if (e->key() == Qt::Key_F3)
 
1911
    newMode = 3;
 
1912
  else if (e->key() == Qt::Key_F4)
 
1913
    newMode = 4;
 
1914
  // If the key pressed is not F1-F4, ignore it
 
1915
  if (newMode == 0)
 
1916
    return;
 
1917
  // If the new mode is same as original, ignore it
 
1918
  if (newMode == plotModeList[activeCurve])
 
1919
    return;
 
1920
 
 
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);
 
1928
  }
 
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));
 
1934
  }
 
1935
  plotModeList[activeCurve] = newMode;
 
1936
 
 
1937
  update();
 
1938
}
 
1939
 
 
1940
/* This function prints out the current mouse position's coordinate */
 
1941
void PlotWidget::setXY_13()
 
1942
{
 
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) + ", ";
 
1946
 
 
1947
  double startPix = xStartPost[activeCurve];
 
1948
  double totalPix = xLengthInPixel[activeCurve];
 
1949
  if (mouseX < startPix || myX > startPix + totalPix) 
 
1950
    vline_y = "Y=NA";
 
1951
  else {
 
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;
 
1956
    double y_graph;
 
1957
    if (x1 == vecLen - 1)
 
1958
      y_graph = vecList[activeCurve].getElement(x1);
 
1959
    else {
 
1960
      double y1 = vecList[activeCurve].getElement(x1);
 
1961
      double y2 = vecList[activeCurve].getElement(x1 + 1);
 
1962
      y_graph = y1 + (y2 - y1) * (x_index - x1);
 
1963
    }
 
1964
    vline_y = "Y=" + QString::number(y_graph);
 
1965
  }
 
1966
}
 
1967
 
 
1968
/* This function prints out the current mouse position's X coordinate */
 
1969
void PlotWidget::setXY_24()
 
1970
{
 
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) + ", ";
 
1974
 
 
1975
  double startPix = xStartPost[activeCurve];
 
1976
  double totalPix = xLengthInPixel[activeCurve];
 
1977
  if (mouseX < startPix || mouseX > startPix + totalPix) 
 
1978
    vline_y = "Y=NA";
 
1979
  else {
 
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)
 
1985
      x1 = vecLen - 1;
 
1986
    double y_graph = vecList[activeCurve].getElement(x1);
 
1987
    vline_y = "Y=" + QString::number(y_graph);
 
1988
  }
 
1989
}
 
1990
 
 
1991
/* This function prints out X coordinate of the data point that is closest to mouse position */
 
1992
void PlotWidget::setXY_shift13()
 
1993
{  
 
1994
  double startPix = xStartPost[activeCurve];
 
1995
  double totalPix = xLengthInPixel[activeCurve];
 
1996
  if (mouseX < startPix || mouseX > startPix + totalPix) 
 
1997
    vline_x = "X=NA, ";
 
1998
  else {
 
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) + ", ";
 
2008
  }
 
2009
 
 
2010
  if (mouseX < startPix || mouseX > startPix + totalPix) 
 
2011
    vline_y = "Y=NA";
 
2012
  else {
 
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);
 
2019
  }
 
2020
}
 
2021
 
 
2022
/* This function prints out X coordinate of the data point that is closest to mouse position */
 
2023
void PlotWidget::setXY_shift24()
 
2024
{
 
2025
  double startPix = xStartPost[activeCurve];
 
2026
  double totalPix = xLengthInPixel[activeCurve];
 
2027
  if (mouseX < startPix || mouseX > startPix + totalPix) 
 
2028
    vline_x = "X=NA, ";
 
2029
  else {
 
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) + ", ";
 
2039
  }
 
2040
 
 
2041
  if (mouseX < startPix || mouseX > startPix + totalPix) 
 
2042
    vline_y = "Y=NA";
 
2043
  else {
 
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)
 
2049
      x1 = vecLen - 1;
 
2050
    double y_graph = vecList[activeCurve].getElement(x1);
 
2051
    vline_y = "Y=" + QString::number(y_graph);
 
2052
  }
 
2053
}