This diff has been collapsed as it changes many lines, (1395 lines changed)
Show them
Hide them
|
|
@@
-1574,10
+1574,7
void QCPLayerable::applyAntialiasingHint(QCPPainter *painter, bool localAntialia
|
|
1574
|
1574
|
|
|
1575
|
1575
|
\see initializeParentPlot
|
|
1576
|
1576
|
*/
|
|
1577
|
|
void QCPLayerable::parentPlotInitialized(QCustomPlot *parentPlot)
|
|
1578
|
|
{
|
|
1579
|
|
Q_UNUSED(parentPlot)
|
|
1580
|
|
}
|
|
|
1577
|
void QCPLayerable::parentPlotInitialized(QCustomPlot *parentPlot){Q_UNUSED(parentPlot)}
|
|
1581
|
1578
|
|
|
1582
|
1579
|
/*! \internal
|
|
1583
|
1580
|
|
|
@@
-2102,8
+2099,8
bool QCPRange::validRange(const QCPRange &range)
|
|
2102
|
2099
|
/* end of 'src/axis/range.cpp' */
|
|
2103
|
2100
|
|
|
2104
|
2101
|
|
|
2105
|
|
/* including file 'src/selection.cpp', size 21898 */
|
|
2106
|
|
/* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
|
|
|
2102
|
/* including file 'src/selection.cpp', size 21906 */
|
|
|
2103
|
/* commit 820d2282db70144c358c13433cd74b4175f9252b 2017-07-24 00:24:17 +0200 */
|
|
2107
|
2104
|
|
|
2108
|
2105
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
2109
|
2106
|
//////////////////// QCPDataRange
|
|
@@
-2406,7
+2403,7
QCPDataSelection &QCPDataSelection::operator+=(const QCPDataRange &other)
|
|
2406
|
2403
|
}
|
|
2407
|
2404
|
|
|
2408
|
2405
|
/*!
|
|
2409
|
|
Removes all data point indices that are described by \a other from this data range.
|
|
|
2406
|
Removes all data point indices that are described by \a other from this data selection.
|
|
2410
|
2407
|
*/
|
|
2411
|
2408
|
QCPDataSelection &QCPDataSelection::operator-=(const QCPDataSelection &other)
|
|
2412
|
2409
|
{
|
|
@@
-2417,7
+2414,7
QCPDataSelection &QCPDataSelection::operator-=(const QCPDataSelection &other)
|
|
2417
|
2414
|
}
|
|
2418
|
2415
|
|
|
2419
|
2416
|
/*!
|
|
2420
|
|
Removes all data point indices that are described by \a other from this data range.
|
|
|
2417
|
Removes all data point indices that are described by \a other from this data selection.
|
|
2421
|
2418
|
*/
|
|
2422
|
2419
|
QCPDataSelection &QCPDataSelection::operator-=(const QCPDataRange &other)
|
|
2423
|
2420
|
{
|
|
@@
-2930,8
+2927,8
void QCPSelectionRect::draw(QCPPainter *painter)
|
|
2930
|
2927
|
/* end of 'src/selectionrect.cpp' */
|
|
2931
|
2928
|
|
|
2932
|
2929
|
|
|
2933
|
|
/* including file 'src/layout.cpp', size 74302 */
|
|
2934
|
|
/* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
|
|
|
2930
|
/* including file 'src/layout.cpp', size 74663 */
|
|
|
2931
|
/* commit a872eb91ec087561efd83dd9cb041a26ab95ce55 2017-07-31 00:21:41 +0200 */
|
|
2935
|
2932
|
|
|
2936
|
2933
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
2937
|
2934
|
//////////////////// QCPMarginGroup
|
|
@@
-3572,12
+3569,13
QCPLayout::QCPLayout()
|
|
3572
|
3569
|
}
|
|
3573
|
3570
|
|
|
3574
|
3571
|
/*!
|
|
3575
|
|
First calls the QCPLayoutElement::update base class implementation to update the margins on this
|
|
3576
|
|
layout.
|
|
|
3572
|
If \a phase is \ref upLayout, calls \ref updateLayout, which subclasses may reimplement to
|
|
|
3573
|
reposition and resize their cells.
|
|
3577
|
3574
|
|
|
3578
|
|
Then calls \ref updateLayout which subclasses reimplement to reposition and resize their cells.
|
|
|
3575
|
Finally, the call is propagated down to all child \ref QCPLayoutElement "QCPLayoutElements".
|
|
3579
|
3576
|
|
|
3580
|
|
Finally, \ref update is called on all child elements.
|
|
|
3577
|
For details about this method and the update phases, see the documentation of \ref
|
|
|
3578
|
QCPLayoutElement::update.
|
|
3581
|
3579
|
*/
|
|
3582
|
3580
|
void QCPLayout::update(UpdatePhase phase)
|
|
3583
|
3581
|
{
|
|
@@
-4242,7
+4240,7
void QCPLayoutGrid::setWrap(int count)
|
|
4242
|
4240
|
|
|
4243
|
4241
|
If you want to have all current elements arranged in the new order, set \a rearrange to true. The
|
|
4244
|
4242
|
elements will be rearranged in a way that tries to preserve their linear index. However, empty
|
|
4245
|
|
cells are skipped during build-up of the new cell order, which shifts the succeding element's
|
|
|
4243
|
cells are skipped during build-up of the new cell order, which shifts the succeeding element's
|
|
4246
|
4244
|
index. The rearranging is performed even if the specified \a order is already the current fill
|
|
4247
|
4245
|
order. Thus this method can be used to re-wrap the current elements.
|
|
4248
|
4246
|
|
|
@@
-4337,7
+4335,8
void QCPLayoutGrid::insertRow(int newIndex)
|
|
4337
|
4335
|
|
|
4338
|
4336
|
/*!
|
|
4339
|
4337
|
Inserts a new column with empty cells at the column index \a newIndex. Valid values for \a
|
|
4340
|
|
newIndex range from 0 (inserts a row at the left) to \a rowCount (appends a row at the right).
|
|
|
4338
|
newIndex range from 0 (inserts a column at the left) to \a columnCount (appends a column at the
|
|
|
4339
|
right).
|
|
4341
|
4340
|
|
|
4342
|
4341
|
\see insertRow
|
|
4343
|
4342
|
*/
|
|
@@
-4411,7
+4410,9
void QCPLayoutGrid::indexToRowCol(int index, int &row, int &column) const
|
|
4411
|
4410
|
{
|
|
4412
|
4411
|
row = -1;
|
|
4413
|
4412
|
column = -1;
|
|
4414
|
|
if (columnCount() == 0 || rowCount() == 0)
|
|
|
4413
|
const int nCols = columnCount();
|
|
|
4414
|
const int nRows = rowCount();
|
|
|
4415
|
if (nCols == 0 || nRows == 0)
|
|
4415
|
4416
|
return;
|
|
4416
|
4417
|
if (index < 0 || index >= elementCount()) {
|
|
4417
|
4418
|
qDebug() << Q_FUNC_INFO << "index out of bounds:" << index;
|
|
@@
-4420,13
+4421,13
void QCPLayoutGrid::indexToRowCol(int index, int &row, int &column) const
|
|
4420
|
4421
|
|
|
4421
|
4422
|
switch (mFillOrder) {
|
|
4422
|
4423
|
case foRowsFirst: {
|
|
4423
|
|
column = index / rowCount();
|
|
4424
|
|
row = index % rowCount();
|
|
|
4424
|
column = index / nRows;
|
|
|
4425
|
row = index % nRows;
|
|
4425
|
4426
|
break;
|
|
4426
|
4427
|
}
|
|
4427
|
4428
|
case foColumnsFirst: {
|
|
4428
|
|
row = index / columnCount();
|
|
4429
|
|
column = index % columnCount();
|
|
|
4429
|
row = index / nCols;
|
|
|
4430
|
column = index % nCols;
|
|
4430
|
4431
|
break;
|
|
4431
|
4432
|
}
|
|
4432
|
4433
|
}
|
|
@@
-4592,9
+4593,8
QSize QCPLayoutGrid::minimumSizeHint() const
|
|
4592
|
4593
|
result.rwidth() += minColWidths.at(i);
|
|
4593
|
4594
|
for (int i = 0; i < minRowHeights.size(); ++i)
|
|
4594
|
4595
|
result.rheight() += minRowHeights.at(i);
|
|
4595
|
|
result.rwidth()
|
|
4596
|
|
+= qMax(0, columnCount() - 1) * mColumnSpacing + mMargins.left() + mMargins.right();
|
|
4597
|
|
result.rheight() += qMax(0, rowCount() - 1) * mRowSpacing + mMargins.top() + mMargins.bottom();
|
|
|
4596
|
result.rwidth() += qMax(0, columnCount() - 1) * mColumnSpacing;
|
|
|
4597
|
result.rheight() += qMax(0, rowCount() - 1) * mRowSpacing;
|
|
4598
|
4598
|
return result;
|
|
4599
|
4599
|
}
|
|
4600
|
4600
|
|
|
@@
-4609,9
+4609,8
QSize QCPLayoutGrid::maximumSizeHint() const
|
|
4609
|
4609
|
result.setWidth(qMin(result.width() + maxColWidths.at(i), QWIDGETSIZE_MAX));
|
|
4610
|
4610
|
for (int i = 0; i < maxRowHeights.size(); ++i)
|
|
4611
|
4611
|
result.setHeight(qMin(result.height() + maxRowHeights.at(i), QWIDGETSIZE_MAX));
|
|
4612
|
|
result.rwidth()
|
|
4613
|
|
+= qMax(0, columnCount() - 1) * mColumnSpacing + mMargins.left() + mMargins.right();
|
|
4614
|
|
result.rheight() += qMax(0, rowCount() - 1) * mRowSpacing + mMargins.top() + mMargins.bottom();
|
|
|
4612
|
result.rwidth() += qMax(0, columnCount() - 1) * mColumnSpacing;
|
|
|
4613
|
result.rheight() += qMax(0, rowCount() - 1) * mRowSpacing;
|
|
4615
|
4614
|
return result;
|
|
4616
|
4615
|
}
|
|
4617
|
4616
|
|
|
@@
-4620,8
+4619,9
QSize QCPLayoutGrid::maximumSizeHint() const
|
|
4620
|
4619
|
Places the minimum column widths and row heights into \a minColWidths and \a minRowHeights
|
|
4621
|
4620
|
respectively.
|
|
4622
|
4621
|
|
|
4623
|
|
The minimum height of a row is the largest minimum height of any element in that row. The minimum
|
|
4624
|
|
width of a column is the largest minimum width of any element in that column.
|
|
|
4622
|
The minimum height of a row is the largest minimum height of any element's outer rect in that
|
|
|
4623
|
row. The minimum width of a column is the largest minimum width of any element's outer rect in
|
|
|
4624
|
that column.
|
|
4625
|
4625
|
|
|
4626
|
4626
|
This is a helper function for \ref updateLayout.
|
|
4627
|
4627
|
|
|
@@
-4634,11
+4634,13
void QCPLayoutGrid::getMinimumRowColSizes(QVector<int> *minColWidths,
|
|
4634
|
4634
|
*minRowHeights = QVector<int>(rowCount(), 0);
|
|
4635
|
4635
|
for (int row = 0; row < rowCount(); ++row) {
|
|
4636
|
4636
|
for (int col = 0; col < columnCount(); ++col) {
|
|
4637
|
|
if (mElements.at(row).at(col)) {
|
|
4638
|
|
QSize minHint = mElements.at(row).at(col)->minimumSizeHint();
|
|
4639
|
|
QSize min = mElements.at(row).at(col)->minimumSize();
|
|
|
4637
|
if (QCPLayoutElement *el = mElements.at(row).at(col)) {
|
|
|
4638
|
QSize minHint = el->minimumSizeHint();
|
|
|
4639
|
QSize min = el->minimumSize();
|
|
4640
|
4640
|
QSize final(min.width() > 0 ? min.width() : minHint.width(),
|
|
4641
|
4641
|
min.height() > 0 ? min.height() : minHint.height());
|
|
|
4642
|
final += QSize(el->margins().left() + el->margins().right(),
|
|
|
4643
|
el->margins().top() + el->margins().bottom());
|
|
4642
|
4644
|
if (minColWidths->at(col) < final.width())
|
|
4643
|
4645
|
(*minColWidths)[col] = final.width();
|
|
4644
|
4646
|
if (minRowHeights->at(row) < final.height())
|
|
@@
-4653,8
+4655,9
void QCPLayoutGrid::getMinimumRowColSizes(QVector<int> *minColWidths,
|
|
4653
|
4655
|
Places the maximum column widths and row heights into \a maxColWidths and \a maxRowHeights
|
|
4654
|
4656
|
respectively.
|
|
4655
|
4657
|
|
|
4656
|
|
The maximum height of a row is the smallest maximum height of any element in that row. The
|
|
4657
|
|
maximum width of a column is the smallest maximum width of any element in that column.
|
|
|
4658
|
The maximum height of a row is the smallest maximum height of any element's outer rect in that
|
|
|
4659
|
row. The maximum width of a column is the smallest maximum width of any element's outer rect in
|
|
|
4660
|
that column.
|
|
4658
|
4661
|
|
|
4659
|
4662
|
This is a helper function for \ref updateLayout.
|
|
4660
|
4663
|
|
|
@@
-4667,11
+4670,13
void QCPLayoutGrid::getMaximumRowColSizes(QVector<int> *maxColWidths,
|
|
4667
|
4670
|
*maxRowHeights = QVector<int>(rowCount(), QWIDGETSIZE_MAX);
|
|
4668
|
4671
|
for (int row = 0; row < rowCount(); ++row) {
|
|
4669
|
4672
|
for (int col = 0; col < columnCount(); ++col) {
|
|
4670
|
|
if (mElements.at(row).at(col)) {
|
|
4671
|
|
QSize maxHint = mElements.at(row).at(col)->maximumSizeHint();
|
|
4672
|
|
QSize max = mElements.at(row).at(col)->maximumSize();
|
|
|
4673
|
if (QCPLayoutElement *el = mElements.at(row).at(col)) {
|
|
|
4674
|
QSize maxHint = el->maximumSizeHint();
|
|
|
4675
|
QSize max = el->maximumSize();
|
|
4673
|
4676
|
QSize final(max.width() < QWIDGETSIZE_MAX ? max.width() : maxHint.width(),
|
|
4674
|
4677
|
max.height() < QWIDGETSIZE_MAX ? max.height() : maxHint.height());
|
|
|
4678
|
final += QSize(el->margins().left() + el->margins().right(),
|
|
|
4679
|
el->margins().top() + el->margins().bottom());
|
|
4675
|
4680
|
if (maxColWidths->at(col) > final.width())
|
|
4676
|
4681
|
(*maxColWidths)[col] = final.width();
|
|
4677
|
4682
|
if (maxRowHeights->at(row) > final.height())
|
|
@@
-4820,22
+4825,25
void QCPLayoutInset::setInsetRect(int index, const QRectF &rect)
|
|
4820
|
4825
|
void QCPLayoutInset::updateLayout()
|
|
4821
|
4826
|
{
|
|
4822
|
4827
|
for (int i = 0; i < mElements.size(); ++i) {
|
|
|
4828
|
QCPLayoutElement *el = mElements.at(i);
|
|
4823
|
4829
|
QRect insetRect;
|
|
4824
|
4830
|
QSize finalMinSize, finalMaxSize;
|
|
4825
|
|
QSize minSizeHint = mElements.at(i)->minimumSizeHint();
|
|
4826
|
|
QSize maxSizeHint = mElements.at(i)->maximumSizeHint();
|
|
4827
|
|
finalMinSize.setWidth(mElements.at(i)->minimumSize().width() > 0
|
|
4828
|
|
? mElements.at(i)->minimumSize().width()
|
|
4829
|
|
: minSizeHint.width());
|
|
4830
|
|
finalMinSize.setHeight(mElements.at(i)->minimumSize().height() > 0
|
|
4831
|
|
? mElements.at(i)->minimumSize().height()
|
|
4832
|
|
: minSizeHint.height());
|
|
4833
|
|
finalMaxSize.setWidth(mElements.at(i)->maximumSize().width() < QWIDGETSIZE_MAX
|
|
4834
|
|
? mElements.at(i)->maximumSize().width()
|
|
|
4831
|
QSize minSizeHint = el->minimumSizeHint();
|
|
|
4832
|
QSize maxSizeHint = el->maximumSizeHint();
|
|
|
4833
|
finalMinSize.setWidth(el->minimumSize().width() > 0 ? el->minimumSize().width()
|
|
|
4834
|
: minSizeHint.width());
|
|
|
4835
|
finalMinSize.setHeight(el->minimumSize().height() > 0 ? el->minimumSize().height()
|
|
|
4836
|
: minSizeHint.height());
|
|
|
4837
|
finalMaxSize.setWidth(el->maximumSize().width() < QWIDGETSIZE_MAX
|
|
|
4838
|
? el->maximumSize().width()
|
|
4835
|
4839
|
: maxSizeHint.width());
|
|
4836
|
|
finalMaxSize.setHeight(mElements.at(i)->maximumSize().height() < QWIDGETSIZE_MAX
|
|
4837
|
|
? mElements.at(i)->maximumSize().height()
|
|
|
4840
|
finalMaxSize.setHeight(el->maximumSize().height() < QWIDGETSIZE_MAX
|
|
|
4841
|
? el->maximumSize().height()
|
|
4838
|
4842
|
: maxSizeHint.height());
|
|
|
4843
|
finalMinSize += QSize(el->margins().left() + el->margins().right(),
|
|
|
4844
|
el->margins().top() + el->margins().bottom());
|
|
|
4845
|
finalMaxSize += QSize(el->margins().left() + el->margins().right(),
|
|
|
4846
|
el->margins().top() + el->margins().bottom());
|
|
4839
|
4847
|
if (mInsetPlacement.at(i) == ipFree) {
|
|
4840
|
4848
|
insetRect = QRect(rect().x() + rect().width() * mInsetRect.at(i).x(),
|
|
4841
|
4849
|
rect().y() + rect().height() * mInsetRect.at(i).y(),
|
|
@@
-7150,8
+7158,8
QVector<double> QCPAxisTickerLog::createTickVector(double tickStep, const QCPRan
|
|
7150
|
7158
|
/* end of 'src/axis/axistickerlog.cpp' */
|
|
7151
|
7159
|
|
|
7152
|
7160
|
|
|
7153
|
|
/* including file 'src/axis/axis.cpp', size 94458 */
|
|
7154
|
|
/* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
|
|
|
7161
|
/* including file 'src/axis/axis.cpp', size 99397 */
|
|
|
7162
|
/* commit 0cc4d9f61f7bf45321a88fec89d909b020ffa26f 2017-08-14 00:43:29 +0200 */
|
|
7155
|
7163
|
|
|
7156
|
7164
|
|
|
7157
|
7165
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@@
-8643,11
+8651,11
double QCPAxis::coordToPixel(double value) const
|
|
8643
|
8651
|
}
|
|
8644
|
8652
|
else // mScaleType == stLogarithmic
|
|
8645
|
8653
|
{
|
|
8646
|
|
if (value >= 0 && mRange.upper < 0) // invalid value for logarithmic scale, just draw it
|
|
8647
|
|
// outside visible range
|
|
|
8654
|
if (value >= 0.0 && mRange.upper < 0.0) // invalid value for logarithmic scale, just
|
|
|
8655
|
// draw it outside visible range
|
|
8648
|
8656
|
return !mRangeReversed ? mAxisRect->right() + 200 : mAxisRect->left() - 200;
|
|
8649
|
|
else if (value <= 0 && mRange.upper > 0) // invalid value for logarithmic scale, just
|
|
8650
|
|
// draw it outside visible range
|
|
|
8657
|
else if (value <= 0.0 && mRange.upper >= 0.0) // invalid value for logarithmic scale,
|
|
|
8658
|
// just draw it outside visible range
|
|
8651
|
8659
|
return !mRangeReversed ? mAxisRect->left() - 200 : mAxisRect->right() + 200;
|
|
8652
|
8660
|
else {
|
|
8653
|
8661
|
if (!mRangeReversed)
|
|
@@
-8673,11
+8681,11
double QCPAxis::coordToPixel(double value) const
|
|
8673
|
8681
|
}
|
|
8674
|
8682
|
else // mScaleType == stLogarithmic
|
|
8675
|
8683
|
{
|
|
8676
|
|
if (value >= 0 && mRange.upper < 0) // invalid value for logarithmic scale, just draw it
|
|
8677
|
|
// outside visible range
|
|
|
8684
|
if (value >= 0.0 && mRange.upper < 0.0) // invalid value for logarithmic scale, just
|
|
|
8685
|
// draw it outside visible range
|
|
8678
|
8686
|
return !mRangeReversed ? mAxisRect->top() - 200 : mAxisRect->bottom() + 200;
|
|
8679
|
|
else if (value <= 0 && mRange.upper > 0) // invalid value for logarithmic scale, just
|
|
8680
|
|
// draw it outside visible range
|
|
|
8687
|
else if (value <= 0.0 && mRange.upper >= 0.0) // invalid value for logarithmic scale,
|
|
|
8688
|
// just draw it outside visible range
|
|
8681
|
8689
|
return !mRangeReversed ? mAxisRect->bottom() + 200 : mAxisRect->top() - 200;
|
|
8682
|
8690
|
else {
|
|
8683
|
8691
|
if (!mRangeReversed)
|
|
@@
-8868,6
+8876,132
void QCPAxis::deselectEvent(bool *selectionStateChanged)
|
|
8868
|
8876
|
|
|
8869
|
8877
|
/*! \internal
|
|
8870
|
8878
|
|
|
|
8879
|
This mouse event reimplementation provides the functionality to let the user drag individual axes
|
|
|
8880
|
exclusively, by startig the drag on top of the axis.
|
|
|
8881
|
|
|
|
8882
|
For the axis to accept this event and perform the single axis drag, the parent \ref QCPAxisRect
|
|
|
8883
|
must be configured accordingly, i.e. it must allow range dragging in the orientation of this axis
|
|
|
8884
|
(\ref QCPAxisRect::setRangeDrag) and this axis must be a draggable axis (\ref
|
|
|
8885
|
QCPAxisRect::setRangeDragAxes)
|
|
|
8886
|
|
|
|
8887
|
\seebaseclassmethod
|
|
|
8888
|
|
|
|
8889
|
\note The dragging of possibly multiple axes at once by starting the drag anywhere in the axis
|
|
|
8890
|
rect is handled by the axis rect's mouse event, e.g. \ref QCPAxisRect::mousePressEvent.
|
|
|
8891
|
*/
|
|
|
8892
|
void QCPAxis::mousePressEvent(QMouseEvent *event, const QVariant &details)
|
|
|
8893
|
{
|
|
|
8894
|
Q_UNUSED(details)
|
|
|
8895
|
if (!mParentPlot->interactions().testFlag(QCP::iRangeDrag)
|
|
|
8896
|
|| !mAxisRect->rangeDrag().testFlag(orientation())
|
|
|
8897
|
|| !mAxisRect->rangeDragAxes(orientation()).contains(this)) {
|
|
|
8898
|
event->ignore();
|
|
|
8899
|
return;
|
|
|
8900
|
}
|
|
|
8901
|
|
|
|
8902
|
if (event->buttons() & Qt::LeftButton) {
|
|
|
8903
|
mDragging = true;
|
|
|
8904
|
// initialize antialiasing backup in case we start dragging:
|
|
|
8905
|
if (mParentPlot->noAntialiasingOnDrag()) {
|
|
|
8906
|
mAADragBackup = mParentPlot->antialiasedElements();
|
|
|
8907
|
mNotAADragBackup = mParentPlot->notAntialiasedElements();
|
|
|
8908
|
}
|
|
|
8909
|
// Mouse range dragging interaction:
|
|
|
8910
|
if (mParentPlot->interactions().testFlag(QCP::iRangeDrag))
|
|
|
8911
|
mDragStartRange = mRange;
|
|
|
8912
|
}
|
|
|
8913
|
}
|
|
|
8914
|
|
|
|
8915
|
/*! \internal
|
|
|
8916
|
|
|
|
8917
|
This mouse event reimplementation provides the functionality to let the user drag individual axes
|
|
|
8918
|
exclusively, by startig the drag on top of the axis.
|
|
|
8919
|
|
|
|
8920
|
\seebaseclassmethod
|
|
|
8921
|
|
|
|
8922
|
\note The dragging of possibly multiple axes at once by starting the drag anywhere in the axis
|
|
|
8923
|
rect is handled by the axis rect's mouse event, e.g. \ref QCPAxisRect::mousePressEvent.
|
|
|
8924
|
|
|
|
8925
|
\see QCPAxis::mousePressEvent
|
|
|
8926
|
*/
|
|
|
8927
|
void QCPAxis::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos)
|
|
|
8928
|
{
|
|
|
8929
|
if (mDragging) {
|
|
|
8930
|
const double startPixel = orientation() == Qt::Horizontal ? startPos.x() : startPos.y();
|
|
|
8931
|
const double currentPixel
|
|
|
8932
|
= orientation() == Qt::Horizontal ? event->pos().x() : event->pos().y();
|
|
|
8933
|
if (mScaleType == QCPAxis::stLinear) {
|
|
|
8934
|
const double diff = pixelToCoord(startPixel) - pixelToCoord(currentPixel);
|
|
|
8935
|
setRange(mDragStartRange.lower + diff, mDragStartRange.upper + diff);
|
|
|
8936
|
}
|
|
|
8937
|
else if (mScaleType == QCPAxis::stLogarithmic) {
|
|
|
8938
|
const double diff = pixelToCoord(startPixel) / pixelToCoord(currentPixel);
|
|
|
8939
|
setRange(mDragStartRange.lower * diff, mDragStartRange.upper * diff);
|
|
|
8940
|
}
|
|
|
8941
|
|
|
|
8942
|
if (mParentPlot->noAntialiasingOnDrag())
|
|
|
8943
|
mParentPlot->setNotAntialiasedElements(QCP::aeAll);
|
|
|
8944
|
mParentPlot->replot(QCustomPlot::rpQueuedReplot);
|
|
|
8945
|
}
|
|
|
8946
|
}
|
|
|
8947
|
|
|
|
8948
|
/*! \internal
|
|
|
8949
|
|
|
|
8950
|
This mouse event reimplementation provides the functionality to let the user drag individual axes
|
|
|
8951
|
exclusively, by startig the drag on top of the axis.
|
|
|
8952
|
|
|
|
8953
|
\seebaseclassmethod
|
|
|
8954
|
|
|
|
8955
|
\note The dragging of possibly multiple axes at once by starting the drag anywhere in the axis
|
|
|
8956
|
rect is handled by the axis rect's mouse event, e.g. \ref QCPAxisRect::mousePressEvent.
|
|
|
8957
|
|
|
|
8958
|
\see QCPAxis::mousePressEvent
|
|
|
8959
|
*/
|
|
|
8960
|
void QCPAxis::mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos)
|
|
|
8961
|
{
|
|
|
8962
|
Q_UNUSED(event)
|
|
|
8963
|
Q_UNUSED(startPos)
|
|
|
8964
|
mDragging = false;
|
|
|
8965
|
if (mParentPlot->noAntialiasingOnDrag()) {
|
|
|
8966
|
mParentPlot->setAntialiasedElements(mAADragBackup);
|
|
|
8967
|
mParentPlot->setNotAntialiasedElements(mNotAADragBackup);
|
|
|
8968
|
}
|
|
|
8969
|
}
|
|
|
8970
|
|
|
|
8971
|
/*! \internal
|
|
|
8972
|
|
|
|
8973
|
This mouse event reimplementation provides the functionality to let the user zoom individual axes
|
|
|
8974
|
exclusively, by performing the wheel event on top of the axis.
|
|
|
8975
|
|
|
|
8976
|
For the axis to accept this event and perform the single axis zoom, the parent \ref QCPAxisRect
|
|
|
8977
|
must be configured accordingly, i.e. it must allow range zooming in the orientation of this axis
|
|
|
8978
|
(\ref QCPAxisRect::setRangeZoom) and this axis must be a zoomable axis (\ref
|
|
|
8979
|
QCPAxisRect::setRangeZoomAxes)
|
|
|
8980
|
|
|
|
8981
|
\seebaseclassmethod
|
|
|
8982
|
|
|
|
8983
|
\note The zooming of possibly multiple axes at once by performing the wheel event anywhere in the
|
|
|
8984
|
axis rect is handled by the axis rect's mouse event, e.g. \ref QCPAxisRect::wheelEvent.
|
|
|
8985
|
*/
|
|
|
8986
|
void QCPAxis::wheelEvent(QWheelEvent *event)
|
|
|
8987
|
{
|
|
|
8988
|
// Mouse range zooming interaction:
|
|
|
8989
|
if (!mParentPlot->interactions().testFlag(QCP::iRangeZoom)
|
|
|
8990
|
|| !mAxisRect->rangeZoom().testFlag(orientation())
|
|
|
8991
|
|| !mAxisRect->rangeZoomAxes(orientation()).contains(this)) {
|
|
|
8992
|
event->ignore();
|
|
|
8993
|
return;
|
|
|
8994
|
}
|
|
|
8995
|
|
|
|
8996
|
const double wheelSteps = event->delta() / 120.0; // a single step delta is +/-120 usually
|
|
|
8997
|
const double factor = qPow(mAxisRect->rangeZoomFactor(orientation()), wheelSteps);
|
|
|
8998
|
scaleRange(factor,
|
|
|
8999
|
pixelToCoord(orientation() == Qt::Horizontal ? event->pos().x() : event->pos().y()));
|
|
|
9000
|
mParentPlot->replot();
|
|
|
9001
|
}
|
|
|
9002
|
|
|
|
9003
|
/*! \internal
|
|
|
9004
|
|
|
8871
|
9005
|
A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter
|
|
8872
|
9006
|
before drawing axis lines.
|
|
8873
|
9007
|
|
|
@@
-9257,14
+9391,16
void QCPAxisPainterPrivate::draw(QCPPainter *painter)
|
|
9257
|
9391
|
painter->setBrush(QBrush(basePen.color()));
|
|
9258
|
9392
|
QCPVector2D baseLineVector(baseLine.dx(), baseLine.dy());
|
|
9259
|
9393
|
if (lowerEnding.style() != QCPLineEnding::esNone)
|
|
9260
|
|
lowerEnding.draw(painter, QCPVector2D(baseLine.p1())
|
|
9261
|
|
- baseLineVector.normalized() * lowerEnding.realLength()
|
|
9262
|
|
* (lowerEnding.inverted() ? -1 : 1),
|
|
|
9394
|
lowerEnding.draw(painter,
|
|
|
9395
|
QCPVector2D(baseLine.p1())
|
|
|
9396
|
- baseLineVector.normalized() * lowerEnding.realLength()
|
|
|
9397
|
* (lowerEnding.inverted() ? -1 : 1),
|
|
9263
|
9398
|
-baseLineVector);
|
|
9264
|
9399
|
if (upperEnding.style() != QCPLineEnding::esNone)
|
|
9265
|
|
upperEnding.draw(painter, QCPVector2D(baseLine.p2())
|
|
9266
|
|
+ baseLineVector.normalized() * upperEnding.realLength()
|
|
9267
|
|
* (upperEnding.inverted() ? -1 : 1),
|
|
|
9400
|
upperEnding.draw(painter,
|
|
|
9401
|
QCPVector2D(baseLine.p2())
|
|
|
9402
|
+ baseLineVector.normalized() * upperEnding.realLength()
|
|
|
9403
|
* (upperEnding.inverted() ? -1 : 1),
|
|
9268
|
9404
|
baseLineVector);
|
|
9269
|
9405
|
painter->setAntialiasing(antialiasingBackup);
|
|
9270
|
9406
|
|
|
@@
-9524,12
+9660,15
void QCPAxisPainterPrivate::placeTickLabel(QCPPainter *painter, double position,
|
|
9524
|
9660
|
cachedLabel->pixmap = QPixmap(labelData.rotatedTotalBounds.size()
|
|
9525
|
9661
|
* mParentPlot->bufferDevicePixelRatio());
|
|
9526
|
9662
|
#ifdef QCP_DEVICEPIXELRATIO_SUPPORTED
|
|
|
9663
|
#ifdef QCP_DEVICEPIXELRATIO_FLOAT
|
|
|
9664
|
cachedLabel->pixmap.setDevicePixelRatio(mParentPlot->devicePixelRatioF());
|
|
|
9665
|
#else
|
|
9527
|
9666
|
cachedLabel->pixmap.setDevicePixelRatio(mParentPlot->devicePixelRatio());
|
|
9528
|
9667
|
#endif
|
|
|
9668
|
#endif
|
|
9529
|
9669
|
}
|
|
9530
|
9670
|
else
|
|
9531
|
9671
|
cachedLabel->pixmap = QPixmap(labelData.rotatedTotalBounds.size());
|
|
9532
|
|
cachedLabel->pixmap = QPixmap(labelData.rotatedTotalBounds.size());
|
|
9533
|
9672
|
cachedLabel->pixmap.fill(Qt::transparent);
|
|
9534
|
9673
|
QCPPainter cachePainter(&cachedLabel->pixmap);
|
|
9535
|
9674
|
cachePainter.setPen(painter->pen());
|
|
@@
-9894,8
+10033,8
void QCPAxisPainterPrivate::getMaxTickLabelSize(const QFont &font, const QString
|
|
9894
|
10033
|
/* end of 'src/axis/axis.cpp' */
|
|
9895
|
10034
|
|
|
9896
|
10035
|
|
|
9897
|
|
/* including file 'src/scatterstyle.cpp', size 17420 */
|
|
9898
|
|
/* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
|
|
|
10036
|
/* including file 'src/scatterstyle.cpp', size 17450 */
|
|
|
10037
|
/* commit 820d2282db70144c358c13433cd74b4175f9252b 2017-07-24 00:24:17 +0200 */
|
|
9899
|
10038
|
|
|
9900
|
10039
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
9901
|
10040
|
//////////////////// QCPScatterStyle
|
|
@@
-10065,8
+10204,8
QCPScatterStyle::QCPScatterStyle(const QPixmap &pixmap)
|
|
10065
|
10204
|
|
|
10066
|
10205
|
The custom shape line will be drawn with \a pen and filled with \a brush. The size has a slightly
|
|
10067
|
10206
|
different meaning than for built-in scatter points: The custom path will be drawn scaled by a
|
|
10068
|
|
factor of \a size/6.0. Since the default \a size is 6, the custom path will appear at a its
|
|
10069
|
|
natural size by default. To double the size of the path for example, set \a size to 12.
|
|
|
10207
|
factor of \a size/6.0. Since the default \a size is 6, the custom path will appear in its
|
|
|
10208
|
original size by default. To for example double the size of the path, set \a size to 12.
|
|
10070
|
10209
|
*/
|
|
10071
|
10210
|
QCPScatterStyle::QCPScatterStyle(const QPainterPath &customPath, const QPen &pen,
|
|
10072
|
10211
|
const QBrush &brush, double size)
|
|
@@
-10253,10
+10392,9
void QCPScatterStyle::drawShape(QCPPainter *painter, double x, double y) const
|
|
10253
|
10392
|
break;
|
|
10254
|
10393
|
}
|
|
10255
|
10394
|
case ssDiamond: {
|
|
10256
|
|
painter->drawLine(QLineF(x - w, y, x, y - w));
|
|
10257
|
|
painter->drawLine(QLineF(x, y - w, x + w, y));
|
|
10258
|
|
painter->drawLine(QLineF(x + w, y, x, y + w));
|
|
10259
|
|
painter->drawLine(QLineF(x, y + w, x - w, y));
|
|
|
10395
|
QPointF lineArray[4]
|
|
|
10396
|
= {QPointF(x - w, y), QPointF(x, y - w), QPointF(x + w, y), QPointF(x, y + w)};
|
|
|
10397
|
painter->drawPolygon(lineArray, 4);
|
|
10260
|
10398
|
break;
|
|
10261
|
10399
|
}
|
|
10262
|
10400
|
case ssStar: {
|
|
@@
-10267,46
+10405,46
void QCPScatterStyle::drawShape(QCPPainter *painter, double x, double y) const
|
|
10267
|
10405
|
break;
|
|
10268
|
10406
|
}
|
|
10269
|
10407
|
case ssTriangle: {
|
|
10270
|
|
painter->drawLine(QLineF(x - w, y + 0.755 * w, x + w, y + 0.755 * w));
|
|
10271
|
|
painter->drawLine(QLineF(x + w, y + 0.755 * w, x, y - 0.977 * w));
|
|
10272
|
|
painter->drawLine(QLineF(x, y - 0.977 * w, x - w, y + 0.755 * w));
|
|
|
10408
|
QPointF lineArray[3] = {QPointF(x - w, y + 0.755 * w), QPointF(x + w, y + 0.755 * w),
|
|
|
10409
|
QPointF(x, y - 0.977 * w)};
|
|
|
10410
|
painter->drawPolygon(lineArray, 3);
|
|
10273
|
10411
|
break;
|
|
10274
|
10412
|
}
|
|
10275
|
10413
|
case ssTriangleInverted: {
|
|
10276
|
|
painter->drawLine(QLineF(x - w, y - 0.755 * w, x + w, y - 0.755 * w));
|
|
10277
|
|
painter->drawLine(QLineF(x + w, y - 0.755 * w, x, y + 0.977 * w));
|
|
10278
|
|
painter->drawLine(QLineF(x, y + 0.977 * w, x - w, y - 0.755 * w));
|
|
|
10414
|
QPointF lineArray[3] = {QPointF(x - w, y - 0.755 * w), QPointF(x + w, y - 0.755 * w),
|
|
|
10415
|
QPointF(x, y + 0.977 * w)};
|
|
|
10416
|
painter->drawPolygon(lineArray, 3);
|
|
10279
|
10417
|
break;
|
|
10280
|
10418
|
}
|
|
10281
|
10419
|
case ssCrossSquare: {
|
|
|
10420
|
painter->drawRect(QRectF(x - w, y - w, mSize, mSize));
|
|
10282
|
10421
|
painter->drawLine(QLineF(x - w, y - w, x + w * 0.95, y + w * 0.95));
|
|
10283
|
10422
|
painter->drawLine(QLineF(x - w, y + w * 0.95, x + w * 0.95, y - w));
|
|
10284
|
|
painter->drawRect(QRectF(x - w, y - w, mSize, mSize));
|
|
10285
|
10423
|
break;
|
|
10286
|
10424
|
}
|
|
10287
|
10425
|
case ssPlusSquare: {
|
|
|
10426
|
painter->drawRect(QRectF(x - w, y - w, mSize, mSize));
|
|
10288
|
10427
|
painter->drawLine(QLineF(x - w, y, x + w * 0.95, y));
|
|
10289
|
10428
|
painter->drawLine(QLineF(x, y + w, x, y - w));
|
|
10290
|
|
painter->drawRect(QRectF(x - w, y - w, mSize, mSize));
|
|
10291
|
10429
|
break;
|
|
10292
|
10430
|
}
|
|
10293
|
10431
|
case ssCrossCircle: {
|
|
|
10432
|
painter->drawEllipse(QPointF(x, y), w, w);
|
|
10294
|
10433
|
painter->drawLine(QLineF(x - w * 0.707, y - w * 0.707, x + w * 0.670, y + w * 0.670));
|
|
10295
|
10434
|
painter->drawLine(QLineF(x - w * 0.707, y + w * 0.670, x + w * 0.670, y - w * 0.707));
|
|
10296
|
|
painter->drawEllipse(QPointF(x, y), w, w);
|
|
10297
|
10435
|
break;
|
|
10298
|
10436
|
}
|
|
10299
|
10437
|
case ssPlusCircle: {
|
|
|
10438
|
painter->drawEllipse(QPointF(x, y), w, w);
|
|
10300
|
10439
|
painter->drawLine(QLineF(x - w, y, x + w, y));
|
|
10301
|
10440
|
painter->drawLine(QLineF(x, y + w, x, y - w));
|
|
10302
|
|
painter->drawEllipse(QPointF(x, y), w, w);
|
|
10303
|
10441
|
break;
|
|
10304
|
10442
|
}
|
|
10305
|
10443
|
case ssPeace: {
|
|
|
10444
|
painter->drawEllipse(QPointF(x, y), w, w);
|
|
10306
|
10445
|
painter->drawLine(QLineF(x, y - w, x, y + w));
|
|
10307
|
10446
|
painter->drawLine(QLineF(x, y, x - w * 0.707, y + w * 0.707));
|
|
10308
|
10447
|
painter->drawLine(QLineF(x, y, x + w * 0.707, y + w * 0.707));
|
|
10309
|
|
painter->drawEllipse(QPointF(x, y), w, w);
|
|
10310
|
10448
|
break;
|
|
10311
|
10449
|
}
|
|
10312
|
10450
|
case ssPixmap: {
|
|
@@
-10337,8
+10475,8
void QCPScatterStyle::drawShape(QCPPainter *painter, double x, double y) const
|
|
10337
|
10475
|
|
|
10338
|
10476
|
// amalgamation: add datacontainer.cpp
|
|
10339
|
10477
|
|
|
10340
|
|
/* including file 'src/plottable.cpp', size 38861 */
|
|
10341
|
|
/* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
|
|
|
10478
|
/* including file 'src/plottable.cpp', size 38845 */
|
|
|
10479
|
/* commit b0bed12626f942821097f43091126b6fb7163122 2017-08-13 17:17:33 +0200 */
|
|
10342
|
10480
|
|
|
10343
|
10481
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
10344
|
10482
|
//////////////////// QCPSelectionDecorator
|
|
@@
-10376,8
+10514,8
void QCPScatterStyle::drawShape(QCPPainter *painter, double x, double y) const
|
|
10376
|
10514
|
QCPSelectionDecorator::QCPSelectionDecorator()
|
|
10377
|
10515
|
: mPen(QColor(80, 80, 255), 2.5),
|
|
10378
|
10516
|
mBrush(Qt::NoBrush),
|
|
10379
|
|
mScatterStyle(QCPScatterStyle::ssNone, QPen(Qt::blue, 2), Qt::NoBrush, 6.0),
|
|
10380
|
|
mUsedScatterProperties(QCPScatterStyle::spPen),
|
|
|
10517
|
mScatterStyle(),
|
|
|
10518
|
mUsedScatterProperties(QCPScatterStyle::spNone),
|
|
10381
|
10519
|
mPlottable(0)
|
|
10382
|
10520
|
{
|
|
10383
|
10521
|
}
|
|
@@
-10420,6
+10558,8
void QCPSelectionDecorator::setScatterStyle(const QCPScatterStyle &scatterStyle,
|
|
10420
|
10558
|
Use this method to define which properties of the scatter style (set via \ref setScatterStyle)
|
|
10421
|
10559
|
will be used for selected data segments. All properties of the scatter style that are not
|
|
10422
|
10560
|
specified in \a properties will remain as specified in the plottable's original scatter style.
|
|
|
10561
|
|
|
|
10562
|
\see QCPScatterStyle::ScatterProperty
|
|
10423
|
10563
|
*/
|
|
10424
|
10564
|
void QCPSelectionDecorator::setUsedScatterProperties(
|
|
10425
|
10565
|
const QCPScatterStyle::ScatterProperties &properties)
|
|
@@
-12624,8
+12764,8
QCP::Interaction QCPAbstractItem::selectionCategory() const
|
|
12624
|
12764
|
/* end of 'src/item.cpp' */
|
|
12625
|
12765
|
|
|
12626
|
12766
|
|
|
12627
|
|
/* including file 'src/core.cpp', size 124243 */
|
|
12628
|
|
/* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
|
|
|
12767
|
/* including file 'src/core.cpp', size 125027 */
|
|
|
12768
|
/* commit 9ede7553208db59867d1ea9f1988cd90e3c7ffed 2017-08-13 17:25:24 +0200 */
|
|
12629
|
12769
|
|
|
12630
|
12770
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
12631
|
12771
|
//////////////////// QCustomPlot
|
|
@@
-12969,6
+13109,7
QCustomPlot::QCustomPlot(QWidget *parent)
|
|
12969
|
13109
|
mOpenGl(false),
|
|
12970
|
13110
|
mMouseHasMoved(false),
|
|
12971
|
13111
|
mMouseEventLayerable(0),
|
|
|
13112
|
mMouseSignalLayerable(0),
|
|
12972
|
13113
|
mReplotting(false),
|
|
12973
|
13114
|
mReplotQueued(false),
|
|
12974
|
13115
|
mOpenGlMultisamples(16),
|
|
@@
-12983,8
+13124,12
QCustomPlot::QCustomPlot(QWidget *parent)
|
|
12983
|
13124
|
currentLocale.setNumberOptions(QLocale::OmitGroupSeparator);
|
|
12984
|
13125
|
setLocale(currentLocale);
|
|
12985
|
13126
|
#ifdef QCP_DEVICEPIXELRATIO_SUPPORTED
|
|
|
13127
|
#ifdef QCP_DEVICEPIXELRATIO_FLOAT
|
|
|
13128
|
setBufferDevicePixelRatio(QWidget::devicePixelRatioF());
|
|
|
13129
|
#else
|
|
12986
|
13130
|
setBufferDevicePixelRatio(QWidget::devicePixelRatio());
|
|
12987
|
13131
|
#endif
|
|
|
13132
|
#endif
|
|
12988
|
13133
|
|
|
12989
|
13134
|
mOpenGlAntialiasedElementsBackup = mAntialiasedElements;
|
|
12990
|
13135
|
mOpenGlCacheLabelsBackup = mPlottingHints.testFlag(QCP::phCacheLabels);
|
|
@@
-13386,6
+13531,10
void QCustomPlot::setSelectionRect(QCPSelectionRect *selectionRect)
|
|
13386
|
13531
|
}
|
|
13387
|
13532
|
|
|
13388
|
13533
|
/*!
|
|
|
13534
|
\warning This is still an experimental feature and its performance depends on the system that it
|
|
|
13535
|
runs on. Having multiple QCustomPlot widgets in one application with enabled OpenGL rendering
|
|
|
13536
|
might cause context conflicts on some systems.
|
|
|
13537
|
|
|
13389
|
13538
|
This method allows to enable OpenGL plot rendering, for increased plotting performance of
|
|
13390
|
13539
|
graphically demanding plots (thick lines, translucent fills, etc.).
|
|
13391
|
13540
|
|
|
@@
-14934,12
+15083,20
void QCustomPlot::mousePressEvent(QMouseEvent *event)
|
|
14934
|
15083
|
mSelectionRect->startSelection(event);
|
|
14935
|
15084
|
}
|
|
14936
|
15085
|
else {
|
|
14937
|
|
// no selection rect interaction, so forward event to layerable under the cursor:
|
|
|
15086
|
// no selection rect interaction, prepare for click signal emission and forward event to
|
|
|
15087
|
// layerable under the cursor:
|
|
14938
|
15088
|
QList<QVariant> details;
|
|
14939
|
15089
|
QList<QCPLayerable *> candidates = layerableListAt(mMousePressPos, false, &details);
|
|
|
15090
|
if (!candidates.isEmpty()) {
|
|
|
15091
|
mMouseSignalLayerable = candidates.first(); // candidate for signal emission is always
|
|
|
15092
|
// topmost hit layerable (signal emitted in
|
|
|
15093
|
// release event)
|
|
|
15094
|
mMouseSignalLayerableDetails = details.first();
|
|
|
15095
|
}
|
|
|
15096
|
// forward event to topmost candidate which accepts the event:
|
|
14940
|
15097
|
for (int i = 0; i < candidates.size(); ++i) {
|
|
14941
|
|
event->accept(); // default impl of QCPLayerable's mouse events ignore the event, in
|
|
14942
|
|
// that case propagate to next candidate in list
|
|
|
15098
|
event->accept(); // default impl of QCPLayerable's mouse events call ignore() on the
|
|
|
15099
|
// event, in that case propagate to next candidate in list
|
|
14943
|
15100
|
candidates.at(i)->mousePressEvent(event, details.at(i));
|
|
14944
|
15101
|
if (event->isAccepted()) {
|
|
14945
|
15102
|
mMouseEventLayerable = candidates.at(i);
|
|
@@
-15010,22
+15167,25
void QCustomPlot::mouseReleaseEvent(QMouseEvent *event)
|
|
15010
|
15167
|
processPointSelection(event);
|
|
15011
|
15168
|
|
|
15012
|
15169
|
// emit specialized click signals of QCustomPlot instance:
|
|
15013
|
|
if (QCPAbstractPlottable *ap = qobject_cast<QCPAbstractPlottable *>(mMouseEventLayerable)) {
|
|
|
15170
|
if (QCPAbstractPlottable *ap
|
|
|
15171
|
= qobject_cast<QCPAbstractPlottable *>(mMouseSignalLayerable)) {
|
|
15014
|
15172
|
int dataIndex = 0;
|
|
15015
|
|
if (!mMouseEventLayerableDetails.value<QCPDataSelection>().isEmpty())
|
|
|
15173
|
if (!mMouseSignalLayerableDetails.value<QCPDataSelection>().isEmpty())
|
|
15016
|
15174
|
dataIndex
|
|
15017
|
|
= mMouseEventLayerableDetails.value<QCPDataSelection>().dataRange().begin();
|
|
|
15175
|
= mMouseSignalLayerableDetails.value<QCPDataSelection>().dataRange().begin();
|
|
15018
|
15176
|
emit plottableClick(ap, dataIndex, event);
|
|
15019
|
15177
|
}
|
|
15020
|
|
else if (QCPAxis *ax = qobject_cast<QCPAxis *>(mMouseEventLayerable))
|
|
15021
|
|
emit axisClick(ax, mMouseEventLayerableDetails.value<QCPAxis::SelectablePart>(), event);
|
|
15022
|
|
else if (QCPAbstractItem *ai = qobject_cast<QCPAbstractItem *>(mMouseEventLayerable))
|
|
|
15178
|
else if (QCPAxis *ax = qobject_cast<QCPAxis *>(mMouseSignalLayerable))
|
|
|
15179
|
emit axisClick(ax, mMouseSignalLayerableDetails.value<QCPAxis::SelectablePart>(),
|
|
|
15180
|
event);
|
|
|
15181
|
else if (QCPAbstractItem *ai = qobject_cast<QCPAbstractItem *>(mMouseSignalLayerable))
|
|
15023
|
15182
|
emit itemClick(ai, event);
|
|
15024
|
|
else if (QCPLegend *lg = qobject_cast<QCPLegend *>(mMouseEventLayerable))
|
|
|
15183
|
else if (QCPLegend *lg = qobject_cast<QCPLegend *>(mMouseSignalLayerable))
|
|
15025
|
15184
|
emit legendClick(lg, 0, event);
|
|
15026
|
15185
|
else if (QCPAbstractLegendItem *li
|
|
15027
|
|
= qobject_cast<QCPAbstractLegendItem *>(mMouseEventLayerable))
|
|
|
15186
|
= qobject_cast<QCPAbstractLegendItem *>(mMouseSignalLayerable))
|
|
15028
|
15187
|
emit legendClick(li->parentLegend(), li, event);
|
|
|
15188
|
mMouseSignalLayerable = 0;
|
|
15029
|
15189
|
}
|
|
15030
|
15190
|
|
|
15031
|
15191
|
if (mSelectionRect && mSelectionRect->isActive()) // Note: if a click was detected above, the
|
|
@@
-16469,8
+16629,9
void QCPColorGradient::updateColorBuffer()
|
|
16469
|
16629
|
hue -= 1.0;
|
|
16470
|
16630
|
if (useAlpha) {
|
|
16471
|
16631
|
const QRgb rgb
|
|
16472
|
|
= QColor::fromHsvF(hue, (1 - t) * lowHsv.saturationF()
|
|
16473
|
|
+ t * highHsv.saturationF(),
|
|
|
16632
|
= QColor::fromHsvF(hue,
|
|
|
16633
|
(1 - t) * lowHsv.saturationF()
|
|
|
16634
|
+ t * highHsv.saturationF(),
|
|
16474
|
16635
|
(1 - t) * lowHsv.valueF() + t * highHsv.valueF())
|
|
16475
|
16636
|
.rgb();
|
|
16476
|
16637
|
const float alpha = (1 - t) * lowHsv.alphaF() + t * highHsv.alphaF();
|
|
@@
-16479,8
+16640,9
void QCPColorGradient::updateColorBuffer()
|
|
16479
|
16640
|
}
|
|
16480
|
16641
|
else {
|
|
16481
|
16642
|
mColorBuffer[i]
|
|
16482
|
|
= QColor::fromHsvF(hue, (1 - t) * lowHsv.saturationF()
|
|
16483
|
|
+ t * highHsv.saturationF(),
|
|
|
16643
|
= QColor::fromHsvF(hue,
|
|
|
16644
|
(1 - t) * lowHsv.saturationF()
|
|
|
16645
|
+ t * highHsv.saturationF(),
|
|
16484
|
16646
|
(1 - t) * lowHsv.valueF() + t * highHsv.valueF())
|
|
16485
|
16647
|
.rgb();
|
|
16486
|
16648
|
}
|
|
@@
-16797,8
+16959,8
QCPSelectionDecoratorBracket::getPixelCoordinates(const QCPPlottableInterface1D
|
|
16797
|
16959
|
/* end of 'src/selectiondecorator-bracket.cpp' */
|
|
16798
|
16960
|
|
|
16799
|
16961
|
|
|
16800
|
|
/* including file 'src/layoutelements/layoutelement-axisrect.cpp', size 47509 */
|
|
16801
|
|
/* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
|
|
|
16962
|
/* including file 'src/layoutelements/layoutelement-axisrect.cpp', size 47584 */
|
|
|
16963
|
/* commit 77ba168312f935543fc31d1ae9b4cdcf34aae4f9 2017-08-13 18:29:48 +0200 */
|
|
16802
|
16964
|
|
|
16803
|
16965
|
|
|
16804
|
16966
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@@
-17052,7
+17214,7
QList<QCPAxis *> QCPAxisRect::axes() const
|
|
17052
|
17214
|
new QCPAxis instance is created internally. QCustomPlot owns the returned axis, so if you want to
|
|
17053
|
17215
|
remove an axis, use \ref removeAxis instead of deleting it manually.
|
|
17054
|
17216
|
|
|
17055
|
|
You may inject QCPAxis instances (or sublasses of QCPAxis) by setting \a axis to an axis that was
|
|
|
17217
|
You may inject QCPAxis instances (or subclasses of QCPAxis) by setting \a axis to an axis that was
|
|
17056
|
17218
|
previously created outside QCustomPlot. It is important to note that QCustomPlot takes ownership
|
|
17057
|
17219
|
of the axis, so you may not delete it afterwards. Further, the \a axis must have been created
|
|
17058
|
17220
|
with this axis rect as parent and with the same axis type as specified in \a type. If this is not
|
|
@@
-17165,6
+17327,12
bool QCPAxisRect::removeAxis(QCPAxis *axis)
|
|
17165
|
17327
|
while (it.hasNext()) {
|
|
17166
|
17328
|
it.next();
|
|
17167
|
17329
|
if (it.value().contains(axis)) {
|
|
|
17330
|
if (it.value().first() == axis && it.value().size() > 1) // if removing first axis,
|
|
|
17331
|
// transfer axis offset to the
|
|
|
17332
|
// new first axis (which at
|
|
|
17333
|
// this point is the second
|
|
|
17334
|
// axis, if it exists)
|
|
|
17335
|
it.value()[1]->setOffset(axis->offset());
|
|
17168
|
17336
|
mAxes[it.key()].removeOne(axis);
|
|
17169
|
17337
|
if (qobject_cast<QCustomPlot *>(parentPlot())) // make sure this isn't called from
|
|
17170
|
17338
|
// QObject dtor when QCustomPlot is
|
|
@@
-17934,9
+18102,6
void QCPAxisRect::layoutChanged()
|
|
17934
|
18102
|
void QCPAxisRect::mousePressEvent(QMouseEvent *event, const QVariant &details)
|
|
17935
|
18103
|
{
|
|
17936
|
18104
|
Q_UNUSED(details)
|
|
17937
|
|
mDragStart = event->pos(); // need this even when not LeftButton is pressed, to determine in
|
|
17938
|
|
// releaseEvent whether it was a full click (no position change
|
|
17939
|
|
// between press and release)
|
|
17940
|
18105
|
if (event->buttons() & Qt::LeftButton) {
|
|
17941
|
18106
|
mDragging = true;
|
|
17942
|
18107
|
// initialize antialiasing backup in case we start dragging:
|
|
@@
-17982,13
+18147,13
void QCPAxisRect::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos)
|
|
17982
|
18147
|
break;
|
|
17983
|
18148
|
if (ax->mScaleType == QCPAxis::stLinear) {
|
|
17984
|
18149
|
double diff
|
|
17985
|
|
= ax->pixelToCoord(mDragStart.x()) - ax->pixelToCoord(event->pos().x());
|
|
|
18150
|
= ax->pixelToCoord(startPos.x()) - ax->pixelToCoord(event->pos().x());
|
|
17986
|
18151
|
ax->setRange(mDragStartHorzRange.at(i).lower + diff,
|
|
17987
|
18152
|
mDragStartHorzRange.at(i).upper + diff);
|
|
17988
|
18153
|
}
|
|
17989
|
18154
|
else if (ax->mScaleType == QCPAxis::stLogarithmic) {
|
|
17990
|
18155
|
double diff
|
|
17991
|
|
= ax->pixelToCoord(mDragStart.x()) / ax->pixelToCoord(event->pos().x());
|
|
|
18156
|
= ax->pixelToCoord(startPos.x()) / ax->pixelToCoord(event->pos().x());
|
|
17992
|
18157
|
ax->setRange(mDragStartHorzRange.at(i).lower * diff,
|
|
17993
|
18158
|
mDragStartHorzRange.at(i).upper * diff);
|
|
17994
|
18159
|
}
|
|
@@
-18004,13
+18169,13
void QCPAxisRect::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos)
|
|
18004
|
18169
|
break;
|
|
18005
|
18170
|
if (ax->mScaleType == QCPAxis::stLinear) {
|
|
18006
|
18171
|
double diff
|
|
18007
|
|
= ax->pixelToCoord(mDragStart.y()) - ax->pixelToCoord(event->pos().y());
|
|
|
18172
|
= ax->pixelToCoord(startPos.y()) - ax->pixelToCoord(event->pos().y());
|
|
18008
|
18173
|
ax->setRange(mDragStartVertRange.at(i).lower + diff,
|
|
18009
|
18174
|
mDragStartVertRange.at(i).upper + diff);
|
|
18010
|
18175
|
}
|
|
18011
|
18176
|
else if (ax->mScaleType == QCPAxis::stLogarithmic) {
|
|
18012
|
18177
|
double diff
|
|
18013
|
|
= ax->pixelToCoord(mDragStart.y()) / ax->pixelToCoord(event->pos().y());
|
|
|
18178
|
= ax->pixelToCoord(startPos.y()) / ax->pixelToCoord(event->pos().y());
|
|
18014
|
18179
|
ax->setRange(mDragStartVertRange.at(i).lower * diff,
|
|
18015
|
18180
|
mDragStartVertRange.at(i).upper * diff);
|
|
18016
|
18181
|
}
|
|
@@
-18021,7
+18186,7
void QCPAxisRect::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos)
|
|
18021
|
18186
|
{
|
|
18022
|
18187
|
if (mParentPlot->noAntialiasingOnDrag())
|
|
18023
|
18188
|
mParentPlot->setNotAntialiasedElements(QCP::aeAll);
|
|
18024
|
|
mParentPlot->replot();
|
|
|
18189
|
mParentPlot->replot(QCustomPlot::rpQueuedReplot);
|
|
18025
|
18190
|
}
|
|
18026
|
18191
|
}
|
|
18027
|
18192
|
}
|
|
@@
-18082,8
+18247,8
void QCPAxisRect::wheelEvent(QWheelEvent *event)
|
|
18082
|
18247
|
/* end of 'src/layoutelements/layoutelement-axisrect.cpp' */
|
|
18083
|
18248
|
|
|
18084
|
18249
|
|
|
18085
|
|
/* including file 'src/layoutelements/layoutelement-legend.cpp', size 30933 */
|
|
18086
|
|
/* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
|
|
|
18250
|
/* including file 'src/layoutelements/layoutelement-legend.cpp', size 30971 */
|
|
|
18251
|
/* commit 305808813c9c6451dca8399c2fc66d68ebd24b5e 2017-08-15 23:03:07 +0200 */
|
|
18087
|
18252
|
|
|
18088
|
18253
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
18089
|
18254
|
//////////////////// QCPAbstractLegendItem
|
|
@@
-18286,9
+18451,7
void QCPAbstractLegendItem::deselectEvent(bool *selectionStateChanged)
|
|
18286
|
18451
|
QCPLegend::setIconBorderPen and \ref QCPLegend::setIconTextPadding.
|
|
18287
|
18452
|
|
|
18288
|
18453
|
The function \ref QCPAbstractPlottable::addToLegend/\ref QCPAbstractPlottable::removeFromLegend
|
|
18289
|
|
creates/removes legend items of this type in the default implementation. However, these functions
|
|
18290
|
|
may be reimplemented such that a different kind of legend item (e.g a direct subclass of
|
|
18291
|
|
QCPAbstractLegendItem) is used for that plottable.
|
|
|
18454
|
creates/removes legend items of this type.
|
|
18292
|
18455
|
|
|
18293
|
18456
|
Since QCPLegend is based on QCPLayoutGrid, a legend item itself is just a subclass of
|
|
18294
|
18457
|
QCPLayoutElement. While it could be added to a legend (or any other layout) via the normal layout
|
|
@@
-18395,10
+18558,8
QSize QCPPlottableLegendItem::minimumSizeHint() const
|
|
18395
|
18558
|
QSize iconSize = mParentLegend->iconSize();
|
|
18396
|
18559
|
textRect = fontMetrics.boundingRect(0, 0, 0, iconSize.height(), Qt::TextDontClip,
|
|
18397
|
18560
|
mPlottable->name());
|
|
18398
|
|
result.setWidth(iconSize.width() + mParentLegend->iconTextPadding() + textRect.width()
|
|
18399
|
|
+ mMargins.left() + mMargins.right());
|
|
18400
|
|
result.setHeight(qMax(textRect.height(), iconSize.height()) + mMargins.top()
|
|
18401
|
|
+ mMargins.bottom());
|
|
|
18561
|
result.setWidth(iconSize.width() + mParentLegend->iconTextPadding() + textRect.width());
|
|
|
18562
|
result.setHeight(qMax(textRect.height(), iconSize.height()));
|
|
18402
|
18563
|
return result;
|
|
18403
|
18564
|
}
|
|
18404
|
18565
|
|
|
@@
-18412,10
+18573,14
QSize QCPPlottableLegendItem::minimumSizeHint() const
|
|
18412
|
18573
|
|
|
18413
|
18574
|
A legend is a small box somewhere in the plot which lists plottables with their name and icon.
|
|
18414
|
18575
|
|
|
18415
|
|
Normally, the legend is populated by calling \ref QCPAbstractPlottable::addToLegend. The
|
|
18416
|
|
respective legend item can be removed with \ref QCPAbstractPlottable::removeFromLegend. However,
|
|
18417
|
|
QCPLegend also offers an interface to add and manipulate legend items directly: \ref item, \ref
|
|
18418
|
|
itemWithPlottable, \ref itemCount, \ref addItem, \ref removeItem, etc.
|
|
|
18576
|
A legend is populated with legend items by calling \ref QCPAbstractPlottable::addToLegend on the
|
|
|
18577
|
plottable, for which a legend item shall be created. In the case of the main legend (\ref
|
|
|
18578
|
QCustomPlot::legend), simply adding plottables to the plot while \ref
|
|
|
18579
|
QCustomPlot::setAutoAddPlottableToLegend is set to true (the default) creates corresponding
|
|
|
18580
|
legend items. The legend item associated with a certain plottable can be removed with \ref
|
|
|
18581
|
QCPAbstractPlottable::removeFromLegend. However, QCPLegend also offers an interface to add and
|
|
|
18582
|
manipulate legend items directly: \ref item, \ref itemWithPlottable, \ref itemCount, \ref
|
|
|
18583
|
addItem, \ref removeItem, etc.
|
|
18419
|
18584
|
|
|
18420
|
18585
|
Since \ref QCPLegend derives from \ref QCPLayoutGrid, it can be placed in any position a \ref
|
|
18421
|
18586
|
QCPLayoutElement may be positioned. The legend items are themselves \ref QCPLayoutElement
|
|
@@
-18570,7
+18735,7
void QCPLegend::setIconSize(const QSize &size)
|
|
18570
|
18735
|
}
|
|
18571
|
18736
|
|
|
18572
|
18737
|
/*! \overload
|
|
18573
|
|
*/
|
|
|
18738
|
*/
|
|
18574
|
18739
|
void QCPLegend::setIconSize(int width, int height)
|
|
18575
|
18740
|
{
|
|
18576
|
18741
|
mIconSize.setWidth(width);
|
|
@@
-19012,8
+19177,8
void QCPLegend::parentPlotInitialized(QCustomPlot *parentPlot)
|
|
19012
|
19177
|
/* end of 'src/layoutelements/layoutelement-legend.cpp' */
|
|
19013
|
19178
|
|
|
19014
|
19179
|
|
|
19015
|
|
/* including file 'src/layoutelements/layoutelement-textelement.cpp', size 12759 */
|
|
19016
|
|
/* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
|
|
|
19180
|
/* including file 'src/layoutelements/layoutelement-textelement.cpp', size 12561 */
|
|
|
19181
|
/* commit a872eb91ec087561efd83dd9cb041a26ab95ce55 2017-07-31 00:21:41 +0200 */
|
|
19017
|
19182
|
|
|
19018
|
19183
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
19019
|
19184
|
//////////////////// QCPTextElement
|
|
@@
-19299,10
+19464,7
void QCPTextElement::draw(QCPPainter *painter)
|
|
19299
|
19464
|
QSize QCPTextElement::minimumSizeHint() const
|
|
19300
|
19465
|
{
|
|
19301
|
19466
|
QFontMetrics metrics(mFont);
|
|
19302
|
|
QSize result = metrics.boundingRect(0, 0, 0, 0, Qt::AlignCenter, mText).size();
|
|
19303
|
|
result.rwidth() += mMargins.left() + mMargins.right();
|
|
19304
|
|
result.rheight() += mMargins.top() + mMargins.bottom();
|
|
19305
|
|
return result;
|
|
|
19467
|
return metrics.boundingRect(0, 0, 0, 0, Qt::AlignCenter, mText).size();
|
|
19306
|
19468
|
}
|
|
19307
|
19469
|
|
|
19308
|
19470
|
/* inherits documentation from base class */
|
|
@@
-19310,7
+19472,6
QSize QCPTextElement::maximumSizeHint() const
|
|
19310
|
19472
|
{
|
|
19311
|
19473
|
QFontMetrics metrics(mFont);
|
|
19312
|
19474
|
QSize result = metrics.boundingRect(0, 0, 0, 0, Qt::AlignCenter, mText).size();
|
|
19313
|
|
result.rheight() += mMargins.top() + mMargins.bottom();
|
|
19314
|
19475
|
result.setWidth(QWIDGETSIZE_MAX);
|
|
19315
|
19476
|
return result;
|
|
19316
|
19477
|
}
|
|
@@
-19838,12
+19999,14
void QCPColorScale::update(UpdatePhase phase)
|
|
19838
|
19999
|
switch (phase) {
|
|
19839
|
20000
|
case upMargins: {
|
|
19840
|
20001
|
if (mType == QCPAxis::atBottom || mType == QCPAxis::atTop) {
|
|
19841
|
|
setMaximumSize(QWIDGETSIZE_MAX, mBarWidth + mAxisRect.data()->margins().top()
|
|
19842
|
|
+ mAxisRect.data()->margins().bottom()
|
|
19843
|
|
+ margins().top() + margins().bottom());
|
|
19844
|
|
setMinimumSize(0, mBarWidth + mAxisRect.data()->margins().top()
|
|
19845
|
|
+ mAxisRect.data()->margins().bottom() + margins().top()
|
|
19846
|
|
+ margins().bottom());
|
|
|
20002
|
setMaximumSize(QWIDGETSIZE_MAX,
|
|
|
20003
|
mBarWidth + mAxisRect.data()->margins().top()
|
|
|
20004
|
+ mAxisRect.data()->margins().bottom() + margins().top()
|
|
|
20005
|
+ margins().bottom());
|
|
|
20006
|
setMinimumSize(0,
|
|
|
20007
|
mBarWidth + mAxisRect.data()->margins().top()
|
|
|
20008
|
+ mAxisRect.data()->margins().bottom() + margins().top()
|
|
|
20009
|
+ margins().bottom());
|
|
19847
|
20010
|
}
|
|
19848
|
20011
|
else {
|
|
19849
|
20012
|
setMaximumSize(mBarWidth + mAxisRect.data()->margins().left()
|
|
@@
-20100,8
+20263,8
void QCPColorScaleAxisRectPrivate::axisSelectableChanged(QCPAxis::SelectablePart
|
|
20100
|
20263
|
/* end of 'src/layoutelements/layoutelement-colorscale.cpp' */
|
|
20101
|
20264
|
|
|
20102
|
20265
|
|
|
20103
|
|
/* including file 'src/plottables/plottable-graph.cpp', size 72363 */
|
|
20104
|
|
/* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
|
|
|
20266
|
/* including file 'src/plottables/plottable-graph.cpp', size 73960 */
|
|
|
20267
|
/* commit 7e7381ef4f218e004d72a218820634fff0959d1b 2017-08-02 00:02:36 +0200 */
|
|
20105
|
20268
|
|
|
20106
|
20269
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
20107
|
20270
|
//////////////////// QCPGraphData
|
|
@@
-20649,6
+20812,12
void QCPGraph::getLines(QVector<QPointF> *lines, const QCPDataRange &dataRange)
|
|
20649
|
20812
|
if (mLineStyle != lsNone)
|
|
20650
|
20813
|
getOptimizedLineData(&lineData, begin, end);
|
|
20651
|
20814
|
|
|
|
20815
|
if (mKeyAxis->rangeReversed()
|
|
|
20816
|
!= (mKeyAxis->orientation() == Qt::Vertical)) // make sure key pixels are sorted ascending
|
|
|
20817
|
// in lineData (significantly simplifies
|
|
|
20818
|
// following processing)
|
|
|
20819
|
std::reverse(lineData.begin(), lineData.end());
|
|
|
20820
|
|
|
20652
|
20821
|
switch (mLineStyle) {
|
|
20653
|
20822
|
case lsNone:
|
|
20654
|
20823
|
lines->clear();
|
|
@@
-20704,6
+20873,13
void QCPGraph::getScatters(QVector<QPointF> *scatters, const QCPDataRange &dataR
|
|
20704
|
20873
|
|
|
20705
|
20874
|
QVector<QCPGraphData> data;
|
|
20706
|
20875
|
getOptimizedScatterData(&data, begin, end);
|
|
|
20876
|
|
|
|
20877
|
if (mKeyAxis->rangeReversed()
|
|
|
20878
|
!= (mKeyAxis->orientation() == Qt::Vertical)) // make sure key pixels are sorted ascending
|
|
|
20879
|
// in data (significantly simplifies following
|
|
|
20880
|
// processing)
|
|
|
20881
|
std::reverse(data.begin(), data.end());
|
|
|
20882
|
|
|
20707
|
20883
|
scatters->resize(data.size());
|
|
20708
|
20884
|
if (keyAxis->orientation() == Qt::Vertical) {
|
|
20709
|
20885
|
for (int i = 0; i < data.size(); ++i) {
|
|
@@
-20744,8
+20920,6
QVector<QPointF> QCPGraph::dataToLines(const QVector<QCPGraphData> &data) const
|
|
20744
|
20920
|
return result;
|
|
20745
|
20921
|
}
|
|
20746
|
20922
|
|
|
20747
|
|
result.reserve(data.size() + 2); // added 2 to reserve memory for lower/upper fill base points
|
|
20748
|
|
// that might be needed for fill
|
|
20749
|
20923
|
result.resize(data.size());
|
|
20750
|
20924
|
|
|
20751
|
20925
|
// transform data points to pixels:
|
|
@@
-20786,8
+20960,6
QVector<QPointF> QCPGraph::dataToStepLeftLines(const QVector<QCPGraphData> &data
|
|
20786
|
20960
|
return result;
|
|
20787
|
20961
|
}
|
|
20788
|
20962
|
|
|
20789
|
|
result.reserve(data.size() * 2 + 2); // added 2 to reserve memory for lower/upper fill base
|
|
20790
|
|
// points that might be needed for fill
|
|
20791
|
20963
|
result.resize(data.size() * 2);
|
|
20792
|
20964
|
|
|
20793
|
20965
|
// calculate steps from data and transform to pixel coordinates:
|
|
@@
-20838,8
+21010,6
QVector<QPointF> QCPGraph::dataToStepRightLines(const QVector<QCPGraphData> &dat
|
|
20838
|
21010
|
return result;
|
|
20839
|
21011
|
}
|
|
20840
|
21012
|
|
|
20841
|
|
result.reserve(data.size() * 2 + 2); // added 2 to reserve memory for lower/upper fill base
|
|
20842
|
|
// points that might be needed for fill
|
|
20843
|
21013
|
result.resize(data.size() * 2);
|
|
20844
|
21014
|
|
|
20845
|
21015
|
// calculate steps from data and transform to pixel coordinates:
|
|
@@
-20890,8
+21060,6
QVector<QPointF> QCPGraph::dataToStepCenterLines(const QVector<QCPGraphData> &da
|
|
20890
|
21060
|
return result;
|
|
20891
|
21061
|
}
|
|
20892
|
21062
|
|
|
20893
|
|
result.reserve(data.size() * 2 + 2); // added 2 to reserve memory for lower/upper fill base
|
|
20894
|
|
// points that might be needed for fill
|
|
20895
|
21063
|
result.resize(data.size() * 2);
|
|
20896
|
21064
|
|
|
20897
|
21065
|
// calculate steps from data and transform to pixel coordinates:
|
|
@@
-20954,8
+21122,7
QVector<QPointF> QCPGraph::dataToImpulseLines(const QVector<QCPGraphData> &data)
|
|
20954
|
21122
|
return result;
|
|
20955
|
21123
|
}
|
|
20956
|
21124
|
|
|
20957
|
|
result.resize(data.size()
|
|
20958
|
|
* 2); // no need to reserve 2 extra points because impulse plot has no fill
|
|
|
21125
|
result.resize(data.size() * 2);
|
|
20959
|
21126
|
|
|
20960
|
21127
|
// transform data points to pixels:
|
|
20961
|
21128
|
if (keyAxis->orientation() == Qt::Vertical) {
|
|
@@
-20984,15
+21151,16
QVector<QPointF> QCPGraph::dataToImpulseLines(const QVector<QCPGraphData> &data)
|
|
20984
|
21151
|
|
|
20985
|
21152
|
Draws the fill of the graph using the specified \a painter, with the currently set brush.
|
|
20986
|
21153
|
|
|
20987
|
|
\a lines contains the points of the graph line, in pixel coordinates.
|
|
|
21154
|
Depending on whether a normal fill or a channel fill (\ref setChannelFillGraph) is needed, \ref
|
|
|
21155
|
getFillPolygon or \ref getChannelFillPolygon are used to find the according fill polygons.
|
|
20988
|
21156
|
|
|
20989
|
|
If the fill is a normal fill towards the zero-value-line, only the points in \a lines are
|
|
20990
|
|
required and two extra points at the zero-value-line, which are added by \ref addFillBasePoints
|
|
20991
|
|
and removed by \ref removeFillBasePoints after the fill drawing is done.
|
|
|
21157
|
In order to handle NaN Data points correctly (the fill needs to be split into disjoint areas),
|
|
|
21158
|
this method first determines a list of non-NaN segments with \ref getNonNanSegments, on which to
|
|
|
21159
|
operate. In the channel fill case, \ref getOverlappingSegments is used to consolidate the non-NaN
|
|
|
21160
|
segments of the two involved graphs, before passing the overlapping pairs to \ref
|
|
|
21161
|
getChannelFillPolygon.
|
|
20992
|
21162
|
|
|
20993
|
|
On the other hand if the fill is a channel fill between this QCPGraph and another QCPGraph (\a
|
|
20994
|
|
mChannelFillGraph), the more complex polygon is calculated with the \ref getChannelFillPolygon
|
|
20995
|
|
function, and then drawn.
|
|
|
21163
|
Pass the points of this graph's line as \a lines, in pixel coordinates.
|
|
20996
|
21164
|
|
|
20997
|
21165
|
\see drawLinePlot, drawImpulsePlot, drawScatterPlot
|
|
20998
|
21166
|
*/
|
|
@@
-21004,15
+21172,25
void QCPGraph::drawFill(QCPPainter *painter, QVector<QPointF> *lines) const
|
|
21004
|
21172
|
return;
|
|
21005
|
21173
|
|
|
21006
|
21174
|
applyFillAntialiasingHint(painter);
|
|
|
21175
|
QVector<QCPDataRange> segments = getNonNanSegments(lines, keyAxis()->orientation());
|
|
21007
|
21176
|
if (!mChannelFillGraph) {
|
|
21008
|
21177
|
// draw base fill under graph, fill goes all the way to the zero-value-line:
|
|
21009
|
|
addFillBasePoints(lines);
|
|
21010
|
|
painter->drawPolygon(QPolygonF(*lines));
|
|
21011
|
|
removeFillBasePoints(lines);
|
|
|
21178
|
for (int i = 0; i < segments.size(); ++i)
|
|
|
21179
|
painter->drawPolygon(getFillPolygon(lines, segments.at(i)));
|
|
21012
|
21180
|
}
|
|
21013
|
21181
|
else {
|
|
21014
|
|
// draw channel fill between this graph and mChannelFillGraph:
|
|
21015
|
|
painter->drawPolygon(getChannelFillPolygon(lines));
|
|
|
21182
|
// draw fill between this graph and mChannelFillGraph:
|
|
|
21183
|
QVector<QPointF> otherLines;
|
|
|
21184
|
mChannelFillGraph->getLines(&otherLines, QCPDataRange(0, mChannelFillGraph->dataCount()));
|
|
|
21185
|
if (!otherLines.isEmpty()) {
|
|
|
21186
|
QVector<QCPDataRange> otherSegments
|
|
|
21187
|
= getNonNanSegments(&otherLines, mChannelFillGraph->keyAxis()->orientation());
|
|
|
21188
|
QVector<QPair<QCPDataRange, QCPDataRange> > segmentPairs
|
|
|
21189
|
= getOverlappingSegments(segments, lines, otherSegments, &otherLines);
|
|
|
21190
|
for (int i = 0; i < segmentPairs.size(); ++i)
|
|
|
21191
|
painter->drawPolygon(getChannelFillPolygon(lines, segmentPairs.at(i).first,
|
|
|
21192
|
&otherLines, segmentPairs.at(i).second));
|
|
|
21193
|
}
|
|
21016
|
21194
|
}
|
|
21017
|
21195
|
}
|
|
21018
|
21196
|
|
|
@@
-21205,12
+21383,8
void QCPGraph::getOptimizedLineData(QVector<QCPGraphData> *lineData,
|
|
21205
|
21383
|
else // don't use adaptive sampling algorithm, transfer points one-to-one from the data
|
|
21206
|
21384
|
// container into the output
|
|
21207
|
21385
|
{
|
|
21208
|
|
QCPGraphDataContainer::const_iterator it = begin;
|
|
21209
|
|
lineData->reserve(dataCount + 2); // +2 for possible fill end points
|
|
21210
|
|
while (it != end) {
|
|
21211
|
|
lineData->append(*it);
|
|
21212
|
|
++it;
|
|
21213
|
|
}
|
|
|
21386
|
lineData->resize(dataCount);
|
|
|
21387
|
std::copy(begin, end, lineData->begin());
|
|
21214
|
21388
|
}
|
|
21215
|
21389
|
}
|
|
21216
|
21390
|
|
|
@@
-21479,151
+21653,177
void QCPGraph::getVisibleDataBounds(QCPGraphDataContainer::const_iterator &begin
|
|
21479
|
21653
|
}
|
|
21480
|
21654
|
}
|
|
21481
|
21655
|
|
|
21482
|
|
/*! \internal
|
|
|
21656
|
/*! \internal
|
|
21483
|
21657
|
|
|
21484
|
|
The line vector generated by e.g. \ref getLines describes only the line that connects the data
|
|
21485
|
|
points. If the graph needs to be filled, two additional points need to be added at the
|
|
21486
|
|
value-zero-line in the lower and upper key positions of the graph. This function calculates these
|
|
21487
|
|
points and adds them to the end of \a lineData. Since the fill is typically drawn before the line
|
|
21488
|
|
stroke, these added points need to be removed again after the fill is done, with the
|
|
21489
|
|
removeFillBasePoints function.
|
|
|
21658
|
This method goes through the passed points in \a lineData and returns a list of the segments
|
|
|
21659
|
which don't contain NaN data points.
|
|
21490
|
21660
|
|
|
21491
|
|
The expanding of \a lines by two points will not cause unnecessary memory reallocations, because
|
|
21492
|
|
the data vector generation functions (e.g. \ref getLines) reserve two extra points when they
|
|
21493
|
|
allocate memory for \a lines.
|
|
|
21661
|
\a keyOrientation defines whether the \a x or \a y member of the passed QPointF is used to check
|
|
|
21662
|
for NaN. If \a keyOrientation is \c Qt::Horizontal, the \a y member is checked, if it is \c
|
|
|
21663
|
Qt::Vertical, the \a x member is checked.
|
|
21494
|
21664
|
|
|
21495
|
|
\see removeFillBasePoints, lowerFillBasePoint, upperFillBasePoint
|
|
|
21665
|
\see getOverlappingSegments, drawFill
|
|
21496
|
21666
|
*/
|
|
21497
|
|
void QCPGraph::addFillBasePoints(QVector<QPointF> *lines) const
|
|
|
21667
|
QVector<QCPDataRange> QCPGraph::getNonNanSegments(const QVector<QPointF> *lineData,
|
|
|
21668
|
Qt::Orientation keyOrientation) const
|
|
21498
|
21669
|
{
|
|
21499
|
|
if (!mKeyAxis) {
|
|
21500
|
|
qDebug() << Q_FUNC_INFO << "invalid key axis";
|
|
21501
|
|
return;
|
|
21502
|
|
}
|
|
21503
|
|
if (!lines) {
|
|
21504
|
|
qDebug() << Q_FUNC_INFO << "passed null as lineData";
|
|
21505
|
|
return;
|
|
21506
|
|
}
|
|
21507
|
|
if (lines->isEmpty())
|
|
21508
|
|
return;
|
|
|
21670
|
QVector<QCPDataRange> result;
|
|
|
21671
|
const int n = lineData->size();
|
|
|
21672
|
|
|
|
21673
|
QCPDataRange currentSegment(-1, -1);
|
|
|
21674
|
int i = 0;
|
|
21509
|
21675
|
|
|
21510
|
|
// append points that close the polygon fill at the key axis:
|
|
21511
|
|
if (mKeyAxis.data()->orientation() == Qt::Vertical) {
|
|
21512
|
|
*lines << upperFillBasePoint(lines->last().y());
|
|
21513
|
|
*lines << lowerFillBasePoint(lines->first().y());
|
|
|
21676
|
if (keyOrientation == Qt::Horizontal) {
|
|
|
21677
|
while (i < n) {
|
|
|
21678
|
while (i < n && qIsNaN(lineData->at(i).y())) // seek next non-NaN data point
|
|
|
21679
|
++i;
|
|
|
21680
|
if (i == n)
|
|
|
21681
|
break;
|
|
|
21682
|
currentSegment.setBegin(i++);
|
|
|
21683
|
while (i < n && !qIsNaN(lineData->at(i).y())) // seek next NaN data point or end of data
|
|
|
21684
|
++i;
|
|
|
21685
|
currentSegment.setEnd(i++);
|
|
|
21686
|
result.append(currentSegment);
|
|
|
21687
|
}
|
|
21514
|
21688
|
}
|
|
21515
|
|
else {
|
|
21516
|
|
*lines << upperFillBasePoint(lines->last().x());
|
|
21517
|
|
*lines << lowerFillBasePoint(lines->first().x());
|
|
|
21689
|
else // keyOrientation == Qt::Vertical
|
|
|
21690
|
{
|
|
|
21691
|
while (i < n) {
|
|
|
21692
|
while (i < n && qIsNaN(lineData->at(i).x())) // seek next non-NaN data point
|
|
|
21693
|
++i;
|
|
|
21694
|
if (i == n)
|
|
|
21695
|
break;
|
|
|
21696
|
currentSegment.setBegin(i++);
|
|
|
21697
|
while (i < n && !qIsNaN(lineData->at(i).x())) // seek next NaN data point or end of data
|
|
|
21698
|
++i;
|
|
|
21699
|
currentSegment.setEnd(i++);
|
|
|
21700
|
result.append(currentSegment);
|
|
|
21701
|
}
|
|
21518
|
21702
|
}
|
|
|
21703
|
return result;
|
|
21519
|
21704
|
}
|
|
21520
|
21705
|
|
|
21521
|
|
/*! \internal
|
|
|
21706
|
/*! \internal
|
|
|
21707
|
|
|
|
21708
|
This method takes two segment lists (e.g. created by \ref getNonNanSegments) \a thisSegments and
|
|
|
21709
|
\a otherSegments, and their associated point data \a thisData and \a otherData.
|
|
|
21710
|
|
|
|
21711
|
It returns all pairs of segments (the first from \a thisSegments, the second from \a
|
|
|
21712
|
otherSegments), which overlap in plot coordinates.
|
|
|
21713
|
|
|
|
21714
|
This method is useful in the case of a channel fill between two graphs, when only those non-NaN
|
|
|
21715
|
segments which actually overlap in their key coordinate shall be considered for drawing a channel
|
|
|
21716
|
fill polygon.
|
|
21522
|
21717
|
|
|
21523
|
|
removes the two points from \a lines that were added by \ref addFillBasePoints.
|
|
|
21718
|
It is assumed that the passed segments in \a thisSegments are ordered ascending by index, and
|
|
|
21719
|
that the segments don't overlap themselves. The same is assumed for the segments in \a
|
|
|
21720
|
otherSegments. This is fulfilled when the segments are obtained via \ref getNonNanSegments.
|
|
21524
|
21721
|
|
|
21525
|
|
\see addFillBasePoints, lowerFillBasePoint, upperFillBasePoint
|
|
|
21722
|
\see getNonNanSegments, segmentsIntersect, drawFill, getChannelFillPolygon
|
|
21526
|
21723
|
*/
|
|
21527
|
|
void QCPGraph::removeFillBasePoints(QVector<QPointF> *lines) const
|
|
|
21724
|
QVector<QPair<QCPDataRange, QCPDataRange> > QCPGraph::getOverlappingSegments(
|
|
|
21725
|
QVector<QCPDataRange> thisSegments, const QVector<QPointF> *thisData,
|
|
|
21726
|
QVector<QCPDataRange> otherSegments, const QVector<QPointF> *otherData) const
|
|
21528
|
21727
|
{
|
|
21529
|
|
if (!lines) {
|
|
21530
|
|
qDebug() << Q_FUNC_INFO << "passed null as lineData";
|
|
21531
|
|
return;
|
|
|
21728
|
QVector<QPair<QCPDataRange, QCPDataRange> > result;
|
|
|
21729
|
if (thisData->isEmpty() || otherData->isEmpty() || thisSegments.isEmpty()
|
|
|
21730
|
|| otherSegments.isEmpty())
|
|
|
21731
|
return result;
|
|
|
21732
|
|
|
|
21733
|
int thisIndex = 0;
|
|
|
21734
|
int otherIndex = 0;
|
|
|
21735
|
const bool verticalKey = mKeyAxis->orientation() == Qt::Vertical;
|
|
|
21736
|
while (thisIndex < thisSegments.size() && otherIndex < otherSegments.size()) {
|
|
|
21737
|
if (thisSegments.at(thisIndex).size()
|
|
|
21738
|
< 2) // segments with fewer than two points won't have a fill anyhow
|
|
|
21739
|
{
|
|
|
21740
|
++thisIndex;
|
|
|
21741
|
continue;
|
|
|
21742
|
}
|
|
|
21743
|
if (otherSegments.at(otherIndex).size()
|
|
|
21744
|
< 2) // segments with fewer than two points won't have a fill anyhow
|
|
|
21745
|
{
|
|
|
21746
|
++otherIndex;
|
|
|
21747
|
continue;
|
|
|
21748
|
}
|
|
|
21749
|
double thisLower, thisUpper, otherLower, otherUpper;
|
|
|
21750
|
if (!verticalKey) {
|
|
|
21751
|
thisLower = thisData->at(thisSegments.at(thisIndex).begin()).x();
|
|
|
21752
|
thisUpper = thisData->at(thisSegments.at(thisIndex).end() - 1).x();
|
|
|
21753
|
otherLower = otherData->at(otherSegments.at(otherIndex).begin()).x();
|
|
|
21754
|
otherUpper = otherData->at(otherSegments.at(otherIndex).end() - 1).x();
|
|
|
21755
|
}
|
|
|
21756
|
else {
|
|
|
21757
|
thisLower = thisData->at(thisSegments.at(thisIndex).begin()).y();
|
|
|
21758
|
thisUpper = thisData->at(thisSegments.at(thisIndex).end() - 1).y();
|
|
|
21759
|
otherLower = otherData->at(otherSegments.at(otherIndex).begin()).y();
|
|
|
21760
|
otherUpper = otherData->at(otherSegments.at(otherIndex).end() - 1).y();
|
|
|
21761
|
}
|
|
|
21762
|
|
|
|
21763
|
int bPrecedence;
|
|
|
21764
|
if (segmentsIntersect(thisLower, thisUpper, otherLower, otherUpper, bPrecedence))
|
|
|
21765
|
result.append(QPair<QCPDataRange, QCPDataRange>(thisSegments.at(thisIndex),
|
|
|
21766
|
otherSegments.at(otherIndex)));
|
|
|
21767
|
|
|
|
21768
|
if (bPrecedence <= 0) // otherSegment doesn't reach as far as thisSegment, so continue with
|
|
|
21769
|
// next otherSegment, keeping current thisSegment
|
|
|
21770
|
++otherIndex;
|
|
|
21771
|
else // otherSegment reaches further than thisSegment, so continue with next thisSegment,
|
|
|
21772
|
// keeping current otherSegment
|
|
|
21773
|
++thisIndex;
|
|
21532
|
21774
|
}
|
|
21533
|
|
if (lines->isEmpty())
|
|
21534
|
|
return;
|
|
21535
|
21775
|
|
|
21536
|
|
lines->remove(lines->size() - 2, 2);
|
|
|
21776
|
return result;
|
|
21537
|
21777
|
}
|
|
21538
|
21778
|
|
|
21539
|
|
/*! \internal
|
|
|
21779
|
/*! \internal
|
|
|
21780
|
|
|
|
21781
|
Returns whether the segments defined by the coordinates (aLower, aUpper) and (bLower, bUpper)
|
|
|
21782
|
have overlap.
|
|
21540
|
21783
|
|
|
21541
|
|
called by \ref addFillBasePoints to conveniently assign the point which closes the fill polygon
|
|
21542
|
|
on the lower side of the zero-value-line parallel to the key axis. The logarithmic axis scale
|
|
21543
|
|
case is a bit special, since the zero-value-line in pixel coordinates is in positive or negative
|
|
21544
|
|
infinity. So this case is handled separately by just closing the fill polygon on the axis which
|
|
21545
|
|
lies in the direction towards the zero value.
|
|
|
21784
|
The output parameter \a bPrecedence indicates whether the \a b segment reaches farther than the
|
|
|
21785
|
\a a segment or not. If \a bPrecedence returns 1, segment \a b reaches the farthest to higher
|
|
|
21786
|
coordinates (i.e. bUpper > aUpper). If it returns -1, segment \a a reaches the farthest. Only if
|
|
|
21787
|
both segment's upper bounds are identical, 0 is returned as \a bPrecedence.
|
|
21546
|
21788
|
|
|
21547
|
|
\a lowerKey will be the the key (in pixels) of the returned point. Depending on whether the key
|
|
21548
|
|
axis is horizontal or vertical, \a lowerKey will end up as the x or y value of the returned
|
|
21549
|
|
point, respectively.
|
|
|
21789
|
It is assumed that the lower bounds always have smaller or equal values than the upper bounds.
|
|
21550
|
21790
|
|
|
21551
|
|
\see upperFillBasePoint, addFillBasePoints
|
|
|
21791
|
\see getOverlappingSegments
|
|
21552
|
21792
|
*/
|
|
21553
|
|
QPointF QCPGraph::lowerFillBasePoint(double lowerKey) const
|
|
|
21793
|
bool QCPGraph::segmentsIntersect(double aLower, double aUpper, double bLower, double bUpper,
|
|
|
21794
|
int &bPrecedence) const
|
|
21554
|
21795
|
{
|
|
21555
|
|
QCPAxis *keyAxis = mKeyAxis.data();
|
|
21556
|
|
QCPAxis *valueAxis = mValueAxis.data();
|
|
21557
|
|
if (!keyAxis || !valueAxis) {
|
|
21558
|
|
qDebug() << Q_FUNC_INFO << "invalid key or value axis";
|
|
21559
|
|
return QPointF();
|
|
|
21796
|
bPrecedence = 0;
|
|
|
21797
|
if (aLower > bUpper) {
|
|
|
21798
|
bPrecedence = -1;
|
|
|
21799
|
return false;
|
|
21560
|
21800
|
}
|
|
21561
|
|
|
|
21562
|
|
QPointF point;
|
|
21563
|
|
if (valueAxis->scaleType() == QCPAxis::stLinear) {
|
|
21564
|
|
if (keyAxis->axisType() == QCPAxis::atLeft) {
|
|
21565
|
|
point.setX(valueAxis->coordToPixel(0));
|
|
21566
|
|
point.setY(lowerKey);
|
|
21567
|
|
}
|
|
21568
|
|
else if (keyAxis->axisType() == QCPAxis::atRight) {
|
|
21569
|
|
point.setX(valueAxis->coordToPixel(0));
|
|
21570
|
|
point.setY(lowerKey);
|
|
21571
|
|
}
|
|
21572
|
|
else if (keyAxis->axisType() == QCPAxis::atTop) {
|
|
21573
|
|
point.setX(lowerKey);
|
|
21574
|
|
point.setY(valueAxis->coordToPixel(0));
|
|
21575
|
|
}
|
|
21576
|
|
else if (keyAxis->axisType() == QCPAxis::atBottom) {
|
|
21577
|
|
point.setX(lowerKey);
|
|
21578
|
|
point.setY(valueAxis->coordToPixel(0));
|
|
21579
|
|
}
|
|
|
21801
|
else if (bLower > aUpper) {
|
|
|
21802
|
bPrecedence = 1;
|
|
|
21803
|
return false;
|
|
21580
|
21804
|
}
|
|
21581
|
|
else // valueAxis->mScaleType == QCPAxis::stLogarithmic
|
|
21582
|
|
{
|
|
21583
|
|
// In logarithmic scaling we can't just draw to value zero so we just fill all the way
|
|
21584
|
|
// to the axis which is in the direction towards zero
|
|
21585
|
|
if (keyAxis->orientation() == Qt::Vertical) {
|
|
21586
|
|
if ((valueAxis->range().upper < 0 && !valueAxis->rangeReversed())
|
|
21587
|
|
|| (valueAxis->range().upper > 0 && valueAxis->rangeReversed())) // if range is
|
|
21588
|
|
// negative, zero
|
|
21589
|
|
// is on opposite
|
|
21590
|
|
// side of key axis
|
|
21591
|
|
point.setX(keyAxis->axisRect()->right());
|
|
21592
|
|
else
|
|
21593
|
|
point.setX(keyAxis->axisRect()->left());
|
|
21594
|
|
point.setY(lowerKey);
|
|
21595
|
|
}
|
|
21596
|
|
else if (keyAxis->axisType() == QCPAxis::atTop
|
|
21597
|
|
|| keyAxis->axisType() == QCPAxis::atBottom) {
|
|
21598
|
|
point.setX(lowerKey);
|
|
21599
|
|
if ((valueAxis->range().upper < 0 && !valueAxis->rangeReversed())
|
|
21600
|
|
|| (valueAxis->range().upper > 0 && valueAxis->rangeReversed())) // if range is
|
|
21601
|
|
// negative, zero
|
|
21602
|
|
// is on opposite
|
|
21603
|
|
// side of key axis
|
|
21604
|
|
point.setY(keyAxis->axisRect()->top());
|
|
21605
|
|
else
|
|
21606
|
|
point.setY(keyAxis->axisRect()->bottom());
|
|
21607
|
|
}
|
|
|
21805
|
else {
|
|
|
21806
|
if (aUpper > bUpper)
|
|
|
21807
|
bPrecedence = -1;
|
|
|
21808
|
else if (aUpper < bUpper)
|
|
|
21809
|
bPrecedence = 1;
|
|
|
21810
|
|
|
|
21811
|
return true;
|
|
21608
|
21812
|
}
|
|
21609
|
|
return point;
|
|
21610
|
21813
|
}
|
|
21611
|
21814
|
|
|
21612
|
21815
|
/*! \internal
|
|
21613
|
21816
|
|
|
21614
|
|
called by \ref addFillBasePoints to conveniently assign the point which closes the fill
|
|
21615
|
|
polygon on the upper side of the zero-value-line parallel to the key axis. The logarithmic axis
|
|
21616
|
|
scale case is a bit special, since the zero-value-line in pixel coordinates is in positive or
|
|
21617
|
|
negative infinity. So this case is handled separately by just closing the fill polygon on the
|
|
21618
|
|
axis which lies in the direction towards the zero value.
|
|
|
21817
|
Returns the point which closes the fill polygon on the zero-value-line parallel to the key axis.
|
|
|
21818
|
The logarithmic axis scale case is a bit special, since the zero-value-line in pixel coordinates
|
|
|
21819
|
is in positive or negative infinity. So this case is handled separately by just closing the fill
|
|
|
21820
|
polygon on the axis which lies in the direction towards the zero value.
|
|
21619
|
21821
|
|
|
21620
|
|
\a upperKey will be the the key (in pixels) of the returned point. Depending on whether the key
|
|
21621
|
|
axis is horizontal or vertical, \a upperKey will end up as the x or y value of the returned
|
|
21622
|
|
point, respectively.
|
|
21623
|
|
|
|
21624
|
|
\see lowerFillBasePoint, addFillBasePoints
|
|
|
21822
|
\a matchingDataPoint will provide the key (in pixels) of the returned point. Depending on whether
|
|
|
21823
|
the key axis of this graph is horizontal or vertical, \a matchingDataPoint will provide the x or
|
|
|
21824
|
y value of the returned point, respectively.
|
|
21625
|
21825
|
*/
|
|
21626
|
|
QPointF QCPGraph::upperFillBasePoint(double upperKey) const
|
|
|
21826
|
QPointF QCPGraph::getFillBasePoint(QPointF matchingDataPoint) const
|
|
21627
|
21827
|
{
|
|
21628
|
21828
|
QCPAxis *keyAxis = mKeyAxis.data();
|
|
21629
|
21829
|
QCPAxis *valueAxis = mValueAxis.data();
|
|
@@
-21632,23
+21832,16
QPointF QCPGraph::upperFillBasePoint(double upperKey) const
|
|
21632
|
21832
|
return QPointF();
|
|
21633
|
21833
|
}
|
|
21634
|
21834
|
|
|
21635
|
|
QPointF point;
|
|
|
21835
|
QPointF result;
|
|
21636
|
21836
|
if (valueAxis->scaleType() == QCPAxis::stLinear) {
|
|
21637
|
|
if (keyAxis->axisType() == QCPAxis::atLeft) {
|
|
21638
|
|
point.setX(valueAxis->coordToPixel(0));
|
|
21639
|
|
point.setY(upperKey);
|
|
|
21837
|
if (keyAxis->orientation() == Qt::Horizontal) {
|
|
|
21838
|
result.setX(matchingDataPoint.x());
|
|
|
21839
|
result.setY(valueAxis->coordToPixel(0));
|
|
21640
|
21840
|
}
|
|
21641
|
|
else if (keyAxis->axisType() == QCPAxis::atRight) {
|
|
21642
|
|
point.setX(valueAxis->coordToPixel(0));
|
|
21643
|
|
point.setY(upperKey);
|
|
21644
|
|
}
|
|
21645
|
|
else if (keyAxis->axisType() == QCPAxis::atTop) {
|
|
21646
|
|
point.setX(upperKey);
|
|
21647
|
|
point.setY(valueAxis->coordToPixel(0));
|
|
21648
|
|
}
|
|
21649
|
|
else if (keyAxis->axisType() == QCPAxis::atBottom) {
|
|
21650
|
|
point.setX(upperKey);
|
|
21651
|
|
point.setY(valueAxis->coordToPixel(0));
|
|
|
21841
|
else // keyAxis->orientation() == Qt::Vertical
|
|
|
21842
|
{
|
|
|
21843
|
result.setX(valueAxis->coordToPixel(0));
|
|
|
21844
|
result.setY(matchingDataPoint.y());
|
|
21652
|
21845
|
}
|
|
21653
|
21846
|
}
|
|
21654
|
21847
|
else // valueAxis->mScaleType == QCPAxis::stLogarithmic
|
|
@@
-21661,40
+21854,80
QPointF QCPGraph::upperFillBasePoint(double upperKey) const
|
|
21661
|
21854
|
// negative, zero
|
|
21662
|
21855
|
// is on opposite
|
|
21663
|
21856
|
// side of key axis
|
|
21664
|
|
point.setX(keyAxis->axisRect()->right());
|
|
|
21857
|
result.setX(keyAxis->axisRect()->right());
|
|
21665
|
21858
|
else
|
|
21666
|
|
point.setX(keyAxis->axisRect()->left());
|
|
21667
|
|
point.setY(upperKey);
|
|
|
21859
|
result.setX(keyAxis->axisRect()->left());
|
|
|
21860
|
result.setY(matchingDataPoint.y());
|
|
21668
|
21861
|
}
|
|
21669
|
21862
|
else if (keyAxis->axisType() == QCPAxis::atTop
|
|
21670
|
21863
|
|| keyAxis->axisType() == QCPAxis::atBottom) {
|
|
21671
|
|
point.setX(upperKey);
|
|
|
21864
|
result.setX(matchingDataPoint.x());
|
|
21672
|
21865
|
if ((valueAxis->range().upper < 0 && !valueAxis->rangeReversed())
|
|
21673
|
21866
|
|| (valueAxis->range().upper > 0 && valueAxis->rangeReversed())) // if range is
|
|
21674
|
21867
|
// negative, zero
|
|
21675
|
21868
|
// is on opposite
|
|
21676
|
21869
|
// side of key axis
|
|
21677
|
|
point.setY(keyAxis->axisRect()->top());
|
|
|
21870
|
result.setY(keyAxis->axisRect()->top());
|
|
21678
|
21871
|
else
|
|
21679
|
|
point.setY(keyAxis->axisRect()->bottom());
|
|
|
21872
|
result.setY(keyAxis->axisRect()->bottom());
|
|
21680
|
21873
|
}
|
|
21681
|
21874
|
}
|
|
21682
|
|
return point;
|
|
|
21875
|
return result;
|
|
21683
|
21876
|
}
|
|
21684
|
21877
|
|
|
21685
|
21878
|
/*! \internal
|
|
21686
|
21879
|
|
|
21687
|
|
Generates the polygon needed for drawing channel fills between this graph and the graph specified
|
|
21688
|
|
in \a mChannelFillGraph (see \ref setChannelFillGraph). The data points representing the line of
|
|
21689
|
|
this graph in pixel coordinates must be passed in \a lines, the corresponding points of the other
|
|
21690
|
|
graph are generated by calling its \ref getLines method.
|
|
|
21880
|
Returns the polygon needed for drawing normal fills between this graph and the key axis.
|
|
21691
|
21881
|
|
|
21692
|
|
This method may return an empty polygon if the key ranges of the two graphs have no overlap of if
|
|
21693
|
|
they don't have the same orientation (e.g. one key axis vertical, the other horizontal). For
|
|
21694
|
|
increased performance (due to implicit sharing), it is recommended to keep the returned QPolygonF
|
|
21695
|
|
const.
|
|
|
21882
|
Pass the graph's data points (in pixel coordinates) as \a lineData, and specify the \a segment
|
|
|
21883
|
which shall be used for the fill. The collection of \a lineData points described by \a segment
|
|
|
21884
|
must not contain NaN data points (see \ref getNonNanSegments).
|
|
|
21885
|
|
|
|
21886
|
The returned fill polygon will be closed at the key axis (the zero-value line) for linear value
|
|
|
21887
|
axes. For logarithmic value axes the polygon will reach just beyond the corresponding axis rect
|
|
|
21888
|
side (see \ref getFillBasePoint).
|
|
|
21889
|
|
|
|
21890
|
For increased performance (due to implicit sharing), keep the returned QPolygonF const.
|
|
|
21891
|
|
|
|
21892
|
\see drawFill, getNonNanSegments
|
|
|
21893
|
*/
|
|
|
21894
|
const QPolygonF QCPGraph::getFillPolygon(const QVector<QPointF> *lineData,
|
|
|
21895
|
QCPDataRange segment) const
|
|
|
21896
|
{
|
|
|
21897
|
if (segment.size() < 2)
|
|
|
21898
|
return QPolygonF();
|
|
|
21899
|
QPolygonF result(segment.size() + 2);
|
|
|
21900
|
|
|
|
21901
|
result[0] = getFillBasePoint(lineData->at(segment.begin()));
|
|
|
21902
|
std::copy(lineData->constBegin() + segment.begin(), lineData->constBegin() + segment.end(),
|
|
|
21903
|
result.begin() + 1);
|
|
|
21904
|
result[result.size() - 1] = getFillBasePoint(lineData->at(segment.end() - 1));
|
|
|
21905
|
|
|
|
21906
|
return result;
|
|
|
21907
|
}
|
|
|
21908
|
|
|
|
21909
|
/*! \internal
|
|
|
21910
|
|
|
|
21911
|
Returns the polygon needed for drawing (partial) channel fills between this graph and the graph
|
|
|
21912
|
specified by \ref setChannelFillGraph.
|
|
|
21913
|
|
|
|
21914
|
The data points of this graph are passed as pixel coordinates via \a thisData, the data of the
|
|
|
21915
|
other graph as \a otherData. The returned polygon will be calculated for the specified data
|
|
|
21916
|
segments \a thisSegment and \a otherSegment, pertaining to the respective \a thisData and \a
|
|
|
21917
|
otherData, respectively.
|
|
|
21918
|
|
|
|
21919
|
The passed \a thisSegment and \a otherSegment should correspond to the segment pairs returned by
|
|
|
21920
|
\ref getOverlappingSegments, to make sure only segments that actually have key coordinate overlap
|
|
|
21921
|
need to be processed here.
|
|
|
21922
|
|
|
|
21923
|
For increased performance due to implicit sharing, keep the returned QPolygonF const.
|
|
|
21924
|
|
|
|
21925
|
\see drawFill, getOverlappingSegments, getNonNanSegments
|
|
21696
|
21926
|
*/
|
|
21697
|
|
const QPolygonF QCPGraph::getChannelFillPolygon(const QVector<QPointF> *lines) const
|
|
|
21927
|
const QPolygonF QCPGraph::getChannelFillPolygon(const QVector<QPointF> *thisData,
|
|
|
21928
|
QCPDataRange thisSegment,
|
|
|
21929
|
const QVector<QPointF> *otherData,
|
|
|
21930
|
QCPDataRange otherSegment) const
|
|
21698
|
21931
|
{
|
|
21699
|
21932
|
if (!mChannelFillGraph)
|
|
21700
|
21933
|
return QPolygonF();
|
|
@@
-21715,55
+21948,35
const QPolygonF QCPGraph::getChannelFillPolygon(const QVector<QPointF> *lines) c
|
|
21715
|
21948
|
// fits, valueAxis will fit too, because it's always orthogonal to
|
|
21716
|
21949
|
// keyAxis)
|
|
21717
|
21950
|
|
|
21718
|
|
if (lines->isEmpty())
|
|
|
21951
|
if (thisData->isEmpty())
|
|
21719
|
21952
|
return QPolygonF();
|
|
21720
|
|
QVector<QPointF> otherData;
|
|
21721
|
|
mChannelFillGraph.data()->getLines(&otherData,
|
|
21722
|
|
QCPDataRange(0, mChannelFillGraph.data()->dataCount()));
|
|
21723
|
|
if (otherData.isEmpty())
|
|
21724
|
|
return QPolygonF();
|
|
21725
|
|
QVector<QPointF> thisData;
|
|
21726
|
|
thisData.reserve(
|
|
21727
|
|
lines->size()
|
|
21728
|
|
+ otherData.size()); // because we will join both vectors at end of this function
|
|
21729
|
|
for (int i = 0; i < lines->size(); ++i) // don't use the vector<<(vector), it squeezes
|
|
21730
|
|
// internally, which ruins the performance tuning with
|
|
21731
|
|
// reserve()
|
|
21732
|
|
thisData << lines->at(i);
|
|
21733
|
|
|
|
|
21953
|
QVector<QPointF> thisSegmentData(thisSegment.size());
|
|
|
21954
|
QVector<QPointF> otherSegmentData(otherSegment.size());
|
|
|
21955
|
std::copy(thisData->constBegin() + thisSegment.begin(),
|
|
|
21956
|
thisData->constBegin() + thisSegment.end(), thisSegmentData.begin());
|
|
|
21957
|
std::copy(otherData->constBegin() + otherSegment.begin(),
|
|
|
21958
|
otherData->constBegin() + otherSegment.end(), otherSegmentData.begin());
|
|
21734
|
21959
|
// pointers to be able to swap them, depending which data range needs cropping:
|
|
21735
|
|
QVector<QPointF> *staticData = &thisData;
|
|
21736
|
|
QVector<QPointF> *croppedData = &otherData;
|
|
|
21960
|
QVector<QPointF> *staticData = &thisSegmentData;
|
|
|
21961
|
QVector<QPointF> *croppedData = &otherSegmentData;
|
|
21737
|
21962
|
|
|
21738
|
21963
|
// crop both vectors to ranges in which the keys overlap (which coord is key, depends on
|
|
21739
|
21964
|
// axisType):
|
|
21740
|
21965
|
if (keyAxis->orientation() == Qt::Horizontal) {
|
|
21741
|
21966
|
// x is key
|
|
21742
|
|
// if an axis range is reversed, the data point keys will be descending. Reverse them, since
|
|
21743
|
|
// following algorithm assumes ascending keys:
|
|
21744
|
|
if (staticData->first().x() > staticData->last().x()) {
|
|
21745
|
|
int size = staticData->size();
|
|
21746
|
|
for (int i = 0; i < size / 2; ++i)
|
|
21747
|
|
qSwap((*staticData)[i], (*staticData)[size - 1 - i]);
|
|
21748
|
|
}
|
|
21749
|
|
if (croppedData->first().x() > croppedData->last().x()) {
|
|
21750
|
|
int size = croppedData->size();
|
|
21751
|
|
for (int i = 0; i < size / 2; ++i)
|
|
21752
|
|
qSwap((*croppedData)[i], (*croppedData)[size - 1 - i]);
|
|
21753
|
|
}
|
|
21754
|
21967
|
// crop lower bound:
|
|
21755
|
21968
|
if (staticData->first().x() < croppedData->first().x()) // other one must be cropped
|
|
21756
|
21969
|
qSwap(staticData, croppedData);
|
|
21757
|
|
int lowBound = findIndexBelowX(croppedData, staticData->first().x());
|
|
|
21970
|
const int lowBound = findIndexBelowX(croppedData, staticData->first().x());
|
|
21758
|
21971
|
if (lowBound == -1)
|
|
21759
|
21972
|
return QPolygonF(); // key ranges have no overlap
|
|
21760
|
21973
|
croppedData->remove(0, lowBound);
|
|
21761
|
|
// set lowest point of cropped data to fit exactly key position of first static data
|
|
21762
|
|
// point via linear interpolation:
|
|
|
21974
|
// set lowest point of cropped data to fit exactly key position of first static data point
|
|
|
21975
|
// via linear interpolation:
|
|
21763
|
21976
|
if (croppedData->size() < 2)
|
|
21764
|
21977
|
return QPolygonF(); // need at least two points for interpolation
|
|
21765
|
21978
|
double slope;
|
|
21766
|
|
if (croppedData->at(1).x() - croppedData->at(0).x() != 0)
|
|
|
21979
|
if (!qFuzzyCompare(croppedData->at(1).x(), croppedData->at(0).x()))
|
|
21767
|
21980
|
slope = (croppedData->at(1).y() - croppedData->at(0).y())
|
|
21768
|
21981
|
/ (croppedData->at(1).x() - croppedData->at(0).x());
|
|
21769
|
21982
|
else
|
|
@@
-21779,12
+21992,12
const QPolygonF QCPGraph::getChannelFillPolygon(const QVector<QPointF> *lines) c
|
|
21779
|
21992
|
if (highBound == -1)
|
|
21780
|
21993
|
return QPolygonF(); // key ranges have no overlap
|
|
21781
|
21994
|
croppedData->remove(highBound + 1, croppedData->size() - (highBound + 1));
|
|
21782
|
|
// set highest point of cropped data to fit exactly key position of last static data
|
|
21783
|
|
// point via linear interpolation:
|
|
|
21995
|
// set highest point of cropped data to fit exactly key position of last static data point
|
|
|
21996
|
// via linear interpolation:
|
|
21784
|
21997
|
if (croppedData->size() < 2)
|
|
21785
|
|
return QPolygonF(); // need at least two points for interpolation
|
|
21786
|
|
int li = croppedData->size() - 1; // last index
|
|
21787
|
|
if (croppedData->at(li).x() - croppedData->at(li - 1).x() != 0)
|
|
|
21998
|
return QPolygonF(); // need at least two points for interpolation
|
|
|
21999
|
const int li = croppedData->size() - 1; // last index
|
|
|
22000
|
if (!qFuzzyCompare(croppedData->at(li).x(), croppedData->at(li - 1).x()))
|
|
21788
|
22001
|
slope = (croppedData->at(li).y() - croppedData->at(li - 1).y())
|
|
21789
|
22002
|
/ (croppedData->at(li).x() - croppedData->at(li - 1).x());
|
|
21790
|
22003
|
else
|
|
@@
-21796,36
+22009,20
const QPolygonF QCPGraph::getChannelFillPolygon(const QVector<QPointF> *lines) c
|
|
21796
|
22009
|
else // mKeyAxis->orientation() == Qt::Vertical
|
|
21797
|
22010
|
{
|
|
21798
|
22011
|
// y is key
|
|
21799
|
|
// similar to "x is key" but switched x,y. Further, lower/upper meaning is inverted compared
|
|
21800
|
|
// to x,
|
|
21801
|
|
// because in pixel coordinates, y increases from top to bottom, not bottom to top like data
|
|
21802
|
|
// coordinate.
|
|
21803
|
|
// if an axis range is reversed, the data point keys will be descending. Reverse them, since
|
|
21804
|
|
// following algorithm assumes ascending keys:
|
|
21805
|
|
if (staticData->first().y() < staticData->last().y()) {
|
|
21806
|
|
int size = staticData->size();
|
|
21807
|
|
for (int i = 0; i < size / 2; ++i)
|
|
21808
|
|
qSwap((*staticData)[i], (*staticData)[size - 1 - i]);
|
|
21809
|
|
}
|
|
21810
|
|
if (croppedData->first().y() < croppedData->last().y()) {
|
|
21811
|
|
int size = croppedData->size();
|
|
21812
|
|
for (int i = 0; i < size / 2; ++i)
|
|
21813
|
|
qSwap((*croppedData)[i], (*croppedData)[size - 1 - i]);
|
|
21814
|
|
}
|
|
21815
|
22012
|
// crop lower bound:
|
|
21816
|
|
if (staticData->first().y() > croppedData->first().y()) // other one must be cropped
|
|
|
22013
|
if (staticData->first().y() < croppedData->first().y()) // other one must be cropped
|
|
21817
|
22014
|
qSwap(staticData, croppedData);
|
|
21818
|
|
int lowBound = findIndexAboveY(croppedData, staticData->first().y());
|
|
|
22015
|
int lowBound = findIndexBelowY(croppedData, staticData->first().y());
|
|
21819
|
22016
|
if (lowBound == -1)
|
|
21820
|
22017
|
return QPolygonF(); // key ranges have no overlap
|
|
21821
|
22018
|
croppedData->remove(0, lowBound);
|
|
21822
|
|
// set lowest point of cropped data to fit exactly key position of first static data
|
|
21823
|
|
// point via linear interpolation:
|
|
|
22019
|
// set lowest point of cropped data to fit exactly key position of first static data point
|
|
|
22020
|
// via linear interpolation:
|
|
21824
|
22021
|
if (croppedData->size() < 2)
|
|
21825
|
22022
|
return QPolygonF(); // need at least two points for interpolation
|
|
21826
|
22023
|
double slope;
|
|
21827
|
|
if (croppedData->at(1).y() - croppedData->at(0).y()
|
|
21828
|
|
!= 0) // avoid division by zero in step plots
|
|
|
22024
|
if (!qFuzzyCompare(croppedData->at(1).y(),
|
|
|
22025
|
croppedData->at(0).y())) // avoid division by zero in step plots
|
|
21829
|
22026
|
slope = (croppedData->at(1).x() - croppedData->at(0).x())
|
|
21830
|
22027
|
/ (croppedData->at(1).y() - croppedData->at(0).y());
|
|
21831
|
22028
|
else
|
|
@@
-21835,19
+22032,19
const QPolygonF QCPGraph::getChannelFillPolygon(const QVector<QPointF> *lines) c
|
|
21835
|
22032
|
(*croppedData)[0].setY(staticData->first().y());
|
|
21836
|
22033
|
|
|
21837
|
22034
|
// crop upper bound:
|
|
21838
|
|
if (staticData->last().y() < croppedData->last().y()) // other one must be cropped
|
|
|
22035
|
if (staticData->last().y() > croppedData->last().y()) // other one must be cropped
|
|
21839
|
22036
|
qSwap(staticData, croppedData);
|
|
21840
|
|
int highBound = findIndexBelowY(croppedData, staticData->last().y());
|
|
|
22037
|
int highBound = findIndexAboveY(croppedData, staticData->last().y());
|
|
21841
|
22038
|
if (highBound == -1)
|
|
21842
|
22039
|
return QPolygonF(); // key ranges have no overlap
|
|
21843
|
22040
|
croppedData->remove(highBound + 1, croppedData->size() - (highBound + 1));
|
|
21844
|
|
// set highest point of cropped data to fit exactly key position of last static data
|
|
21845
|
|
// point via linear interpolation:
|
|
|
22041
|
// set highest point of cropped data to fit exactly key position of last static data point
|
|
|
22042
|
// via linear interpolation:
|
|
21846
|
22043
|
if (croppedData->size() < 2)
|
|
21847
|
22044
|
return QPolygonF(); // need at least two points for interpolation
|
|
21848
|
22045
|
int li = croppedData->size() - 1; // last index
|
|
21849
|
|
if (croppedData->at(li).y() - croppedData->at(li - 1).y()
|
|
21850
|
|
!= 0) // avoid division by zero in step plots
|
|
|
22046
|
if (!qFuzzyCompare(croppedData->at(li).y(),
|
|
|
22047
|
croppedData->at(li - 1).y())) // avoid division by zero in step plots
|
|
21851
|
22048
|
slope = (croppedData->at(li).x() - croppedData->at(li - 1).x())
|
|
21852
|
22049
|
/ (croppedData->at(li).y() - croppedData->at(li - 1).y());
|
|
21853
|
22050
|
else
|
|
@@
-21858,16
+22055,17
const QPolygonF QCPGraph::getChannelFillPolygon(const QVector<QPointF> *lines) c
|
|
21858
|
22055
|
}
|
|
21859
|
22056
|
|
|
21860
|
22057
|
// return joined:
|
|
21861
|
|
for (int i = otherData.size() - 1; i >= 0;
|
|
|
22058
|
for (int i = otherSegmentData.size() - 1; i >= 0;
|
|
21862
|
22059
|
--i) // insert reversed, otherwise the polygon will be twisted
|
|
21863
|
|
thisData << otherData.at(i);
|
|
21864
|
|
return QPolygonF(thisData);
|
|
|
22060
|
thisSegmentData << otherSegmentData.at(i);
|
|
|
22061
|
return QPolygonF(thisSegmentData);
|
|
21865
|
22062
|
}
|
|
21866
|
22063
|
|
|
21867
|
22064
|
/*! \internal
|
|
21868
|
22065
|
|
|
21869
|
22066
|
Finds the smallest index of \a data, whose points x value is just above \a x. Assumes x values in
|
|
21870
|
|
\a data points are ordered ascending, as is the case when plotting with horizontal key axis.
|
|
|
22067
|
\a data points are ordered ascending, as is ensured by \ref getLines/\ref getScatters if the key
|
|
|
22068
|
axis is horizontal.
|
|
21871
|
22069
|
|
|
21872
|
22070
|
Used to calculate the channel fill polygon, see \ref getChannelFillPolygon.
|
|
21873
|
22071
|
*/
|
|
@@
-21887,7
+22085,8
int QCPGraph::findIndexAboveX(const QVector<QPointF> *data, double x) const
|
|
21887
|
22085
|
/*! \internal
|
|
21888
|
22086
|
|
|
21889
|
22087
|
Finds the highest index of \a data, whose points x value is just below \a x. Assumes x values in
|
|
21890
|
|
\a data points are ordered ascending, as is the case when plotting with horizontal key axis.
|
|
|
22088
|
\a data points are ordered ascending, as is ensured by \ref getLines/\ref getScatters if the key
|
|
|
22089
|
axis is horizontal.
|
|
21891
|
22090
|
|
|
21892
|
22091
|
Used to calculate the channel fill polygon, see \ref getChannelFillPolygon.
|
|
21893
|
22092
|
*/
|
|
@@
-21907,18
+22106,19
int QCPGraph::findIndexBelowX(const QVector<QPointF> *data, double x) const
|
|
21907
|
22106
|
/*! \internal
|
|
21908
|
22107
|
|
|
21909
|
22108
|
Finds the smallest index of \a data, whose points y value is just above \a y. Assumes y values in
|
|
21910
|
|
\a data points are ordered descending, as is the case when plotting with vertical key axis.
|
|
|
22109
|
\a data points are ordered ascending, as is ensured by \ref getLines/\ref getScatters if the key
|
|
|
22110
|
axis is vertical.
|
|
21911
|
22111
|
|
|
21912
|
22112
|
Used to calculate the channel fill polygon, see \ref getChannelFillPolygon.
|
|
21913
|
22113
|
*/
|
|
21914
|
22114
|
int QCPGraph::findIndexAboveY(const QVector<QPointF> *data, double y) const
|
|
21915
|
22115
|
{
|
|
21916
|
|
for (int i = 0; i < data->size(); ++i) {
|
|
|
22116
|
for (int i = data->size() - 1; i >= 0; --i) {
|
|
21917
|
22117
|
if (data->at(i).y() < y) {
|
|
21918
|
|
if (i > 0)
|
|
21919
|
|
return i - 1;
|
|
|
22118
|
if (i < data->size() - 1)
|
|
|
22119
|
return i + 1;
|
|
21920
|
22120
|
else
|
|
21921
|
|
return 0;
|
|
|
22121
|
return data->size() - 1;
|
|
21922
|
22122
|
}
|
|
21923
|
22123
|
}
|
|
21924
|
22124
|
return -1;
|
|
@@
-21994,19
+22194,19
double QCPGraph::pointDistance(const QPointF &pixelPoint,
|
|
21994
|
22194
|
/*! \internal
|
|
21995
|
22195
|
|
|
21996
|
22196
|
Finds the highest index of \a data, whose points y value is just below \a y. Assumes y values in
|
|
21997
|
|
\a data points are ordered descending, as is the case when plotting with vertical key axis (since
|
|
21998
|
|
keys are ordered ascending).
|
|
|
22197
|
\a data points are ordered ascending, as is ensured by \ref getLines/\ref getScatters if the key
|
|
|
22198
|
axis is vertical.
|
|
21999
|
22199
|
|
|
22000
|
22200
|
Used to calculate the channel fill polygon, see \ref getChannelFillPolygon.
|
|
22001
|
22201
|
*/
|
|
22002
|
22202
|
int QCPGraph::findIndexBelowY(const QVector<QPointF> *data, double y) const
|
|
22003
|
22203
|
{
|
|
22004
|
|
for (int i = data->size() - 1; i >= 0; --i) {
|
|
|
22204
|
for (int i = 0; i < data->size(); ++i) {
|
|
22005
|
22205
|
if (data->at(i).y() > y) {
|
|
22006
|
|
if (i < data->size() - 1)
|
|
22007
|
|
return i + 1;
|
|
|
22206
|
if (i > 0)
|
|
|
22207
|
return i - 1;
|
|
22008
|
22208
|
else
|
|
22009
|
|
return data->size() - 1;
|
|
|
22209
|
return 0;
|
|
22010
|
22210
|
}
|
|
22011
|
22211
|
}
|
|
22012
|
22212
|
return -1;
|
|
@@
-22014,8
+22214,8
int QCPGraph::findIndexBelowY(const QVector<QPointF> *data, double y) const
|
|
22014
|
22214
|
/* end of 'src/plottables/plottable-graph.cpp' */
|
|
22015
|
22215
|
|
|
22016
|
22216
|
|
|
22017
|
|
/* including file 'src/plottables/plottable-curve.cpp', size 60009 */
|
|
22018
|
|
/* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
|
|
|
22217
|
/* including file 'src/plottables/plottable-curve.cpp', size 63527 */
|
|
|
22218
|
/* commit 63bcca79007f7f56dce5dd035560f2e871d1dfc1 2017-07-20 18:02:21 +0200 */
|
|
22019
|
22219
|
|
|
22020
|
22220
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
22021
|
22221
|
//////////////////// QCPCurveData
|
|
@@
-22179,6
+22379,7
QCPCurve::QCPCurve(QCPAxis *keyAxis, QCPAxis *valueAxis)
|
|
22179
|
22379
|
|
|
22180
|
22380
|
setScatterStyle(QCPScatterStyle());
|
|
22181
|
22381
|
setLineStyle(lsLine);
|
|
|
22382
|
setScatterSkip(0);
|
|
22182
|
22383
|
}
|
|
22183
|
22384
|
|
|
22184
|
22385
|
QCPCurve::~QCPCurve()
|
|
@@
-22881,54
+23082,74
QPointF QCPCurve::getOptimizedPoint(int otherRegion, double otherKey, double oth
|
|
22881
|
23082
|
double value, double keyMin, double valueMax, double keyMax,
|
|
22882
|
23083
|
double valueMin) const
|
|
22883
|
23084
|
{
|
|
22884
|
|
double intersectKey = keyMin; // initial value is just fail-safe
|
|
22885
|
|
double intersectValue = valueMax; // initial value is just fail-safe
|
|
|
23085
|
// The intersection point interpolation here is done in pixel coordinates, so we don't need to
|
|
|
23086
|
// differentiate between different axis scale types. Note that the nomenclature
|
|
|
23087
|
// top/left/bottom/right/min/max is with respect to the rect in plot coordinates, wich may be
|
|
|
23088
|
// different in pixel coordinates (horz/vert key axes, reversed ranges)
|
|
|
23089
|
|
|
|
23090
|
const double keyMinPx = mKeyAxis->coordToPixel(keyMin);
|
|
|
23091
|
const double keyMaxPx = mKeyAxis->coordToPixel(keyMax);
|
|
|
23092
|
const double valueMinPx = mValueAxis->coordToPixel(valueMin);
|
|
|
23093
|
const double valueMaxPx = mValueAxis->coordToPixel(valueMax);
|
|
|
23094
|
const double otherValuePx = mValueAxis->coordToPixel(otherValue);
|
|
|
23095
|
const double valuePx = mValueAxis->coordToPixel(value);
|
|
|
23096
|
const double otherKeyPx = mKeyAxis->coordToPixel(otherKey);
|
|
|
23097
|
const double keyPx = mKeyAxis->coordToPixel(key);
|
|
|
23098
|
double intersectKeyPx = keyMinPx; // initial key just a fail-safe
|
|
|
23099
|
double intersectValuePx = valueMinPx; // initial value just a fail-safe
|
|
22886
|
23100
|
switch (otherRegion) {
|
|
22887
|
23101
|
case 1: // top and left edge
|
|
22888
|
23102
|
{
|
|
22889
|
|
intersectValue = valueMax;
|
|
22890
|
|
intersectKey
|
|
22891
|
|
= otherKey
|
|
22892
|
|
+ (key - otherKey) / (value - otherValue) * (intersectValue - otherValue);
|
|
22893
|
|
if (intersectKey < keyMin
|
|
22894
|
|
|| intersectKey > keyMax) // doesn't intersect, so must intersect other:
|
|
|
23103
|
intersectValuePx = valueMaxPx;
|
|
|
23104
|
intersectKeyPx = otherKeyPx
|
|
|
23105
|
+ (keyPx - otherKeyPx) / (valuePx - otherValuePx)
|
|
|
23106
|
* (intersectValuePx - otherValuePx);
|
|
|
23107
|
if (intersectKeyPx < qMin(keyMinPx, keyMaxPx)
|
|
|
23108
|
|| intersectKeyPx > qMax(keyMinPx, keyMaxPx)) // check whether top edge is not
|
|
|
23109
|
// intersected, then it must be left
|
|
|
23110
|
// edge (qMin/qMax necessary since
|
|
|
23111
|
// axes may be reversed)
|
|
22895
|
23112
|
{
|
|
22896
|
|
intersectKey = keyMin;
|
|
22897
|
|
intersectValue
|
|
22898
|
|
= otherValue
|
|
22899
|
|
+ (value - otherValue) / (key - otherKey) * (intersectKey - otherKey);
|
|
|
23113
|
intersectKeyPx = keyMinPx;
|
|
|
23114
|
intersectValuePx = otherValuePx
|
|
|
23115
|
+ (valuePx - otherValuePx) / (keyPx - otherKeyPx)
|
|
|
23116
|
* (intersectKeyPx - otherKeyPx);
|
|
22900
|
23117
|
}
|
|
22901
|
23118
|
break;
|
|
22902
|
23119
|
}
|
|
22903
|
23120
|
case 2: // left edge
|
|
22904
|
23121
|
{
|
|
22905
|
|
intersectKey = keyMin;
|
|
22906
|
|
intersectValue
|
|
22907
|
|
= otherValue + (value - otherValue) / (key - otherKey) * (intersectKey - otherKey);
|
|
|
23122
|
intersectKeyPx = keyMinPx;
|
|
|
23123
|
intersectValuePx
|
|
|
23124
|
= otherValuePx
|
|
|
23125
|
+ (valuePx - otherValuePx) / (keyPx - otherKeyPx) * (intersectKeyPx - otherKeyPx);
|
|
22908
|
23126
|
break;
|
|
22909
|
23127
|
}
|
|
22910
|
23128
|
case 3: // bottom and left edge
|
|
22911
|
23129
|
{
|
|
22912
|
|
intersectValue = valueMin;
|
|
22913
|
|
intersectKey
|
|
22914
|
|
= otherKey
|
|
22915
|
|
+ (key - otherKey) / (value - otherValue) * (intersectValue - otherValue);
|
|
22916
|
|
if (intersectKey < keyMin
|
|
22917
|
|
|| intersectKey > keyMax) // doesn't intersect, so must intersect other:
|
|
|
23130
|
intersectValuePx = valueMinPx;
|
|
|
23131
|
intersectKeyPx = otherKeyPx
|
|
|
23132
|
+ (keyPx - otherKeyPx) / (valuePx - otherValuePx)
|
|
|
23133
|
* (intersectValuePx - otherValuePx);
|
|
|
23134
|
if (intersectKeyPx < qMin(keyMinPx, keyMaxPx)
|
|
|
23135
|
|| intersectKeyPx > qMax(keyMinPx, keyMaxPx)) // check whether bottom edge is not
|
|
|
23136
|
// intersected, then it must be left
|
|
|
23137
|
// edge (qMin/qMax necessary since
|
|
|
23138
|
// axes may be reversed)
|
|
22918
|
23139
|
{
|
|
22919
|
|
intersectKey = keyMin;
|
|
22920
|
|
intersectValue
|
|
22921
|
|
= otherValue
|
|
22922
|
|
+ (value - otherValue) / (key - otherKey) * (intersectKey - otherKey);
|
|
|
23140
|
intersectKeyPx = keyMinPx;
|
|
|
23141
|
intersectValuePx = otherValuePx
|
|
|
23142
|
+ (valuePx - otherValuePx) / (keyPx - otherKeyPx)
|
|
|
23143
|
* (intersectKeyPx - otherKeyPx);
|
|
22923
|
23144
|
}
|
|
22924
|
23145
|
break;
|
|
22925
|
23146
|
}
|
|
22926
|
23147
|
case 4: // top edge
|
|
22927
|
23148
|
{
|
|
22928
|
|
intersectValue = valueMax;
|
|
22929
|
|
intersectKey
|
|
22930
|
|
= otherKey
|
|
22931
|
|
+ (key - otherKey) / (value - otherValue) * (intersectValue - otherValue);
|
|
|
23149
|
intersectValuePx = valueMaxPx;
|
|
|
23150
|
intersectKeyPx = otherKeyPx
|
|
|
23151
|
+ (keyPx - otherKeyPx) / (valuePx - otherValuePx)
|
|
|
23152
|
* (intersectValuePx - otherValuePx);
|
|
22932
|
23153
|
break;
|
|
22933
|
23154
|
}
|
|
22934
|
23155
|
case 5: {
|
|
@@
-22937,53
+23158,63
QPointF QCPCurve::getOptimizedPoint(int otherRegion, double otherKey, double oth
|
|
22937
|
23158
|
}
|
|
22938
|
23159
|
case 6: // bottom edge
|
|
22939
|
23160
|
{
|
|
22940
|
|
intersectValue = valueMin;
|
|
22941
|
|
intersectKey
|
|
22942
|
|
= otherKey
|
|
22943
|
|
+ (key - otherKey) / (value - otherValue) * (intersectValue - otherValue);
|
|
|
23161
|
intersectValuePx = valueMinPx;
|
|
|
23162
|
intersectKeyPx = otherKeyPx
|
|
|
23163
|
+ (keyPx - otherKeyPx) / (valuePx - otherValuePx)
|
|
|
23164
|
* (intersectValuePx - otherValuePx);
|
|
22944
|
23165
|
break;
|
|
22945
|
23166
|
}
|
|
22946
|
23167
|
case 7: // top and right edge
|
|
22947
|
23168
|
{
|
|
22948
|
|
intersectValue = valueMax;
|
|
22949
|
|
intersectKey
|
|
22950
|
|
= otherKey
|
|
22951
|
|
+ (key - otherKey) / (value - otherValue) * (intersectValue - otherValue);
|
|
22952
|
|
if (intersectKey < keyMin
|
|
22953
|
|
|| intersectKey > keyMax) // doesn't intersect, so must intersect other:
|
|
|
23169
|
intersectValuePx = valueMaxPx;
|
|
|
23170
|
intersectKeyPx = otherKeyPx
|
|
|
23171
|
+ (keyPx - otherKeyPx) / (valuePx - otherValuePx)
|
|
|
23172
|
* (intersectValuePx - otherValuePx);
|
|
|
23173
|
if (intersectKeyPx < qMin(keyMinPx, keyMaxPx)
|
|
|
23174
|
|| intersectKeyPx > qMax(keyMinPx, keyMaxPx)) // check whether top edge is not
|
|
|
23175
|
// intersected, then it must be right
|
|
|
23176
|
// edge (qMin/qMax necessary since
|
|
|
23177
|
// axes may be reversed)
|
|
22954
|
23178
|
{
|
|
22955
|
|
intersectKey = keyMax;
|
|
22956
|
|
intersectValue
|
|
22957
|
|
= otherValue
|
|
22958
|
|
+ (value - otherValue) / (key - otherKey) * (intersectKey - otherKey);
|
|
|
23179
|
intersectKeyPx = keyMaxPx;
|
|
|
23180
|
intersectValuePx = otherValuePx
|
|
|
23181
|
+ (valuePx - otherValuePx) / (keyPx - otherKeyPx)
|
|
|
23182
|
* (intersectKeyPx - otherKeyPx);
|
|
22959
|
23183
|
}
|
|
22960
|
23184
|
break;
|
|
22961
|
23185
|
}
|
|
22962
|
23186
|
case 8: // right edge
|
|
22963
|
23187
|
{
|
|
22964
|
|
intersectKey = keyMax;
|
|
22965
|
|
intersectValue
|
|
22966
|
|
= otherValue + (value - otherValue) / (key - otherKey) * (intersectKey - otherKey);
|
|
|
23188
|
intersectKeyPx = keyMaxPx;
|
|
|
23189
|
intersectValuePx
|
|
|
23190
|
= otherValuePx
|
|
|
23191
|
+ (valuePx - otherValuePx) / (keyPx - otherKeyPx) * (intersectKeyPx - otherKeyPx);
|
|
22967
|
23192
|
break;
|
|
22968
|
23193
|
}
|
|
22969
|
23194
|
case 9: // bottom and right edge
|
|
22970
|
23195
|
{
|
|
22971
|
|
intersectValue = valueMin;
|
|
22972
|
|
intersectKey
|
|
22973
|
|
= otherKey
|
|
22974
|
|
+ (key - otherKey) / (value - otherValue) * (intersectValue - otherValue);
|
|
22975
|
|
if (intersectKey < keyMin
|
|
22976
|
|
|| intersectKey > keyMax) // doesn't intersect, so must intersect other:
|
|
|
23196
|
intersectValuePx = valueMinPx;
|
|
|
23197
|
intersectKeyPx = otherKeyPx
|
|
|
23198
|
+ (keyPx - otherKeyPx) / (valuePx - otherValuePx)
|
|
|
23199
|
* (intersectValuePx - otherValuePx);
|
|
|
23200
|
if (intersectKeyPx < qMin(keyMinPx, keyMaxPx)
|
|
|
23201
|
|| intersectKeyPx > qMax(keyMinPx, keyMaxPx)) // check whether bottom edge is not
|
|
|
23202
|
// intersected, then it must be right
|
|
|
23203
|
// edge (qMin/qMax necessary since
|
|
|
23204
|
// axes may be reversed)
|
|
22977
|
23205
|
{
|
|
22978
|
|
intersectKey = keyMax;
|
|
22979
|
|
intersectValue
|
|
22980
|
|
= otherValue
|
|
22981
|
|
+ (value - otherValue) / (key - otherKey) * (intersectKey - otherKey);
|
|
|
23206
|
intersectKeyPx = keyMaxPx;
|
|
|
23207
|
intersectValuePx = otherValuePx
|
|
|
23208
|
+ (valuePx - otherValuePx) / (keyPx - otherKeyPx)
|
|
|
23209
|
* (intersectKeyPx - otherKeyPx);
|
|
22982
|
23210
|
}
|
|
22983
|
23211
|
break;
|
|
22984
|
23212
|
}
|
|
22985
|
23213
|
}
|
|
22986
|
|
return coordsToPixels(intersectKey, intersectValue);
|
|
|
23214
|
if (mKeyAxis->orientation() == Qt::Horizontal)
|
|
|
23215
|
return QPointF(intersectKeyPx, intersectValuePx);
|
|
|
23216
|
else
|
|
|
23217
|
return QPointF(intersectValuePx, intersectKeyPx);
|
|
22987
|
23218
|
}
|
|
22988
|
23219
|
|
|
22989
|
23220
|
/*! \internal
|
|
@@
-23496,44
+23727,79
bool QCPCurve::getTraverse(double prevKey, double prevValue, double key, double
|
|
23496
|
23727
|
double keyMin, double valueMax, double keyMax, double valueMin,
|
|
23497
|
23728
|
QPointF &crossA, QPointF &crossB) const
|
|
23498
|
23729
|
{
|
|
23499
|
|
QList<QPointF> intersections; // x of QPointF corresponds to key and y to value
|
|
|
23730
|
// The intersection point interpolation here is done in pixel coordinates, so we don't need to
|
|
|
23731
|
// differentiate between different axis scale types. Note that the nomenclature
|
|
|
23732
|
// top/left/bottom/right/min/max is with respect to the rect in plot coordinates, wich may be
|
|
|
23733
|
// different in pixel coordinates (horz/vert key axes, reversed ranges)
|
|
|
23734
|
|
|
|
23735
|
QList<QPointF> intersections;
|
|
|
23736
|
const double valueMinPx = mValueAxis->coordToPixel(valueMin);
|
|
|
23737
|
const double valueMaxPx = mValueAxis->coordToPixel(valueMax);
|
|
|
23738
|
const double keyMinPx = mKeyAxis->coordToPixel(keyMin);
|
|
|
23739
|
const double keyMaxPx = mKeyAxis->coordToPixel(keyMax);
|
|
|
23740
|
const double keyPx = mKeyAxis->coordToPixel(key);
|
|
|
23741
|
const double valuePx = mValueAxis->coordToPixel(value);
|
|
|
23742
|
const double prevKeyPx = mKeyAxis->coordToPixel(prevKey);
|
|
|
23743
|
const double prevValuePx = mValueAxis->coordToPixel(prevValue);
|
|
23500
|
23744
|
if (qFuzzyIsNull(key - prevKey)) // line is parallel to value axis
|
|
23501
|
23745
|
{
|
|
23502
|
|
// due to region filter in mayTraverseR(), if line is parallel to value or key axis, R is
|
|
23503
|
|
// traversed here
|
|
|
23746
|
// due to region filter in mayTraverse(), if line is parallel to value or key axis, region 5
|
|
|
23747
|
// is traversed here
|
|
23504
|
23748
|
intersections.append(
|
|
23505
|
|
QPointF(key, valueMin)); // direction will be taken care of at end of method
|
|
23506
|
|
intersections.append(QPointF(key, valueMax));
|
|
|
23749
|
mKeyAxis->orientation() == Qt::Horizontal
|
|
|
23750
|
? QPointF(keyPx, valueMinPx)
|
|
|
23751
|
: QPointF(valueMinPx, keyPx)); // direction will be taken care of at end of method
|
|
|
23752
|
intersections.append(mKeyAxis->orientation() == Qt::Horizontal
|
|
|
23753
|
? QPointF(keyPx, valueMaxPx)
|
|
|
23754
|
: QPointF(valueMaxPx, keyPx));
|
|
23507
|
23755
|
}
|
|
23508
|
23756
|
else if (qFuzzyIsNull(value - prevValue)) // line is parallel to key axis
|
|
23509
|
23757
|
{
|
|
23510
|
|
// due to region filter in mayTraverseR(), if line is parallel to value or key axis, R is
|
|
23511
|
|
// traversed here
|
|
|
23758
|
// due to region filter in mayTraverse(), if line is parallel to value or key axis, region 5
|
|
|
23759
|
// is traversed here
|
|
23512
|
23760
|
intersections.append(
|
|
23513
|
|
QPointF(keyMin, value)); // direction will be taken care of at end of method
|
|
23514
|
|
intersections.append(QPointF(keyMax, value));
|
|
|
23761
|
mKeyAxis->orientation() == Qt::Horizontal
|
|
|
23762
|
? QPointF(keyMinPx, valuePx)
|
|
|
23763
|
: QPointF(valuePx, keyMinPx)); // direction will be taken care of at end of method
|
|
|
23764
|
intersections.append(mKeyAxis->orientation() == Qt::Horizontal
|
|
|
23765
|
? QPointF(keyMaxPx, valuePx)
|
|
|
23766
|
: QPointF(valuePx, keyMaxPx));
|
|
23515
|
23767
|
}
|
|
23516
|
23768
|
else // line is skewed
|
|
23517
|
23769
|
{
|
|
23518
|
23770
|
double gamma;
|
|
23519
|
|
double keyPerValue = (key - prevKey) / (value - prevValue);
|
|
|
23771
|
double keyPerValuePx = (keyPx - prevKeyPx) / (valuePx - prevValuePx);
|
|
23520
|
23772
|
// check top of rect:
|
|
23521
|
|
gamma = prevKey + (valueMax - prevValue) * keyPerValue;
|
|
23522
|
|
if (gamma >= keyMin && gamma <= keyMax)
|
|
23523
|
|
intersections.append(QPointF(gamma, valueMax));
|
|
|
23773
|
gamma = prevKeyPx + (valueMaxPx - prevValuePx) * keyPerValuePx;
|
|
|
23774
|
if (gamma >= qMin(keyMinPx, keyMaxPx)
|
|
|
23775
|
&& gamma <= qMax(keyMinPx, keyMaxPx)) // qMin/qMax necessary since axes may be reversed
|
|
|
23776
|
intersections.append(mKeyAxis->orientation() == Qt::Horizontal
|
|
|
23777
|
? QPointF(gamma, valueMaxPx)
|
|
|
23778
|
: QPointF(valueMaxPx, gamma));
|
|
23524
|
23779
|
// check bottom of rect:
|
|
23525
|
|
gamma = prevKey + (valueMin - prevValue) * keyPerValue;
|
|
23526
|
|
if (gamma >= keyMin && gamma <= keyMax)
|
|
23527
|
|
intersections.append(QPointF(gamma, valueMin));
|
|
23528
|
|
double valuePerKey = 1.0 / keyPerValue;
|
|
|
23780
|
gamma = prevKeyPx + (valueMinPx - prevValuePx) * keyPerValuePx;
|
|
|
23781
|
if (gamma >= qMin(keyMinPx, keyMaxPx)
|
|
|
23782
|
&& gamma <= qMax(keyMinPx, keyMaxPx)) // qMin/qMax necessary since axes may be reversed
|
|
|
23783
|
intersections.append(mKeyAxis->orientation() == Qt::Horizontal
|
|
|
23784
|
? QPointF(gamma, valueMinPx)
|
|
|
23785
|
: QPointF(valueMinPx, gamma));
|
|
|
23786
|
const double valuePerKeyPx = 1.0 / keyPerValuePx;
|
|
23529
|
23787
|
// check left of rect:
|
|
23530
|
|
gamma = prevValue + (keyMin - prevKey) * valuePerKey;
|
|
23531
|
|
if (gamma >= valueMin && gamma <= valueMax)
|
|
23532
|
|
intersections.append(QPointF(keyMin, gamma));
|
|
|
23788
|
gamma = prevValuePx + (keyMinPx - prevKeyPx) * valuePerKeyPx;
|
|
|
23789
|
if (gamma >= qMin(valueMinPx, valueMaxPx)
|
|
|
23790
|
&& gamma <= qMax(valueMinPx,
|
|
|
23791
|
valueMaxPx)) // qMin/qMax necessary since axes may be reversed
|
|
|
23792
|
intersections.append(mKeyAxis->orientation() == Qt::Horizontal
|
|
|
23793
|
? QPointF(keyMinPx, gamma)
|
|
|
23794
|
: QPointF(gamma, keyMinPx));
|
|
23533
|
23795
|
// check right of rect:
|
|
23534
|
|
gamma = prevValue + (keyMax - prevKey) * valuePerKey;
|
|
23535
|
|
if (gamma >= valueMin && gamma <= valueMax)
|
|
23536
|
|
intersections.append(QPointF(keyMax, gamma));
|
|
|
23796
|
gamma = prevValuePx + (keyMaxPx - prevKeyPx) * valuePerKeyPx;
|
|
|
23797
|
if (gamma >= qMin(valueMinPx, valueMaxPx)
|
|
|
23798
|
&& gamma <= qMax(valueMinPx,
|
|
|
23799
|
valueMaxPx)) // qMin/qMax necessary since axes may be reversed
|
|
|
23800
|
intersections.append(mKeyAxis->orientation() == Qt::Horizontal
|
|
|
23801
|
? QPointF(keyMaxPx, gamma)
|
|
|
23802
|
: QPointF(gamma, keyMaxPx));
|
|
23537
|
23803
|
}
|
|
23538
|
23804
|
|
|
23539
|
23805
|
// handle cases where found points isn't exactly 2:
|
|
@@
-23562,12
+23828,16
bool QCPCurve::getTraverse(double prevKey, double prevValue, double key, double
|
|
23562
|
23828
|
}
|
|
23563
|
23829
|
|
|
23564
|
23830
|
// possibly re-sort points so optimized point segment has same direction as original segment:
|
|
23565
|
|
if ((key - prevKey) * (intersections.at(1).x() - intersections.at(0).x())
|
|
23566
|
|
+ (value - prevValue) * (intersections.at(1).y() - intersections.at(0).y())
|
|
|
23831
|
double xDelta = keyPx - prevKeyPx;
|
|
|
23832
|
double yDelta = valuePx - prevValuePx;
|
|
|
23833
|
if (mKeyAxis->orientation() != Qt::Horizontal)
|
|
|
23834
|
qSwap(xDelta, yDelta);
|
|
|
23835
|
if (xDelta * (intersections.at(1).x() - intersections.at(0).x())
|
|
|
23836
|
+ yDelta * (intersections.at(1).y() - intersections.at(0).y())
|
|
23567
|
23837
|
< 0) // scalar product of both segments < 0 -> opposite direction
|
|
23568
|
23838
|
intersections.move(0, 1);
|
|
23569
|
|
crossA = coordsToPixels(intersections.at(0).x(), intersections.at(0).y());
|
|
23570
|
|
crossB = coordsToPixels(intersections.at(1).x(), intersections.at(1).y());
|
|
|
23839
|
crossA = intersections.at(0);
|
|
|
23840
|
crossB = intersections.at(1);
|
|
23571
|
23841
|
return true;
|
|
23572
|
23842
|
}
|
|
23573
|
23843
|
|
|
@@
-25678,8
+25948,8
QCPStatisticalBox::getWhiskerBarLines(QCPStatisticalBoxDataContainer::const_iter
|
|
25678
|
25948
|
/* end of 'src/plottables/plottable-statisticalbox.cpp' */
|
|
25679
|
25949
|
|
|
25680
|
25950
|
|
|
25681
|
|
/* including file 'src/plottables/plottable-colormap.cpp', size 47531 */
|
|
25682
|
|
/* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
|
|
|
25951
|
/* including file 'src/plottables/plottable-colormap.cpp', size 47881 */
|
|
|
25952
|
/* commit 83a770151292397b3ba4984108d7ed167a9aec65 2017-08-13 16:22:21 +0200 */
|
|
25683
|
25953
|
|
|
25684
|
25954
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
25685
|
25955
|
//////////////////// QCPColorMapData
|
|
@@
-26350,6
+26620,7
QCPColorMap::QCPColorMap(QCPAxis *keyAxis, QCPAxis *valueAxis)
|
|
26350
|
26620
|
: QCPAbstractPlottable(keyAxis, valueAxis),
|
|
26351
|
26621
|
mDataScaleType(QCPAxis::stLinear),
|
|
26352
|
26622
|
mMapData(new QCPColorMapData(10, 10, QCPRange(0, 5), QCPRange(0, 5))),
|
|
|
26623
|
mGradient(QCPColorGradient::gpCold),
|
|
26353
|
26624
|
mInterpolate(true),
|
|
26354
|
26625
|
mTightBoundary(false),
|
|
26355
|
26626
|
mMapImageInvalidated(true)
|
|
@@
-26709,73
+26980,81
void QCPColorMap::updateMapImage()
|
|
26709
|
26980
|
mMapImage = QImage(
|
|
26710
|
26981
|
QSize(valueSize * valueOversamplingFactor, keySize * keyOversamplingFactor), format);
|
|
26711
|
26982
|
|
|
26712
|
|
QImage *localMapImage = &mMapImage; // this is the image on which the colorization operates.
|
|
26713
|
|
// Either the final mMapImage, or if we need oversampling,
|
|
26714
|
|
// mUndersampledMapImage
|
|
26715
|
|
if (keyOversamplingFactor > 1 || valueOversamplingFactor > 1) {
|
|
26716
|
|
// resize undersampled map image to actual key/value cell sizes:
|
|
26717
|
|
if (keyAxis->orientation() == Qt::Horizontal
|
|
26718
|
|
&& (mUndersampledMapImage.width() != keySize
|
|
26719
|
|
|| mUndersampledMapImage.height() != valueSize))
|
|
26720
|
|
mUndersampledMapImage = QImage(QSize(keySize, valueSize), format);
|
|
26721
|
|
else if (keyAxis->orientation() == Qt::Vertical
|
|
26722
|
|
&& (mUndersampledMapImage.width() != valueSize
|
|
26723
|
|
|| mUndersampledMapImage.height() != keySize))
|
|
26724
|
|
mUndersampledMapImage = QImage(QSize(valueSize, keySize), format);
|
|
26725
|
|
localMapImage
|
|
26726
|
|
= &mUndersampledMapImage; // make the colorization run on the undersampled image
|
|
26727
|
|
}
|
|
26728
|
|
else if (!mUndersampledMapImage.isNull())
|
|
26729
|
|
mUndersampledMapImage = QImage(); // don't need oversampling mechanism anymore (map size has
|
|
26730
|
|
// changed) but mUndersampledMapImage still has nonzero
|
|
26731
|
|
// size, free it
|
|
26732
|
|
|
|
26733
|
|
const double *rawData = mMapData->mData;
|
|
26734
|
|
const unsigned char *rawAlpha = mMapData->mAlpha;
|
|
26735
|
|
if (keyAxis->orientation() == Qt::Horizontal) {
|
|
26736
|
|
const int lineCount = valueSize;
|
|
26737
|
|
const int rowCount = keySize;
|
|
26738
|
|
for (int line = 0; line < lineCount; ++line) {
|
|
26739
|
|
QRgb *pixels = reinterpret_cast<QRgb *>(localMapImage->scanLine(
|
|
26740
|
|
lineCount - 1 - line)); // invert scanline index because QImage counts scanlines
|
|
26741
|
|
// from top, but our vertical index counts from bottom
|
|
26742
|
|
// (mathematical coordinate system)
|
|
26743
|
|
if (rawAlpha)
|
|
26744
|
|
mGradient.colorize(rawData + line * rowCount, rawAlpha + line * rowCount,
|
|
26745
|
|
mDataRange, pixels, rowCount, 1,
|
|
26746
|
|
mDataScaleType == QCPAxis::stLogarithmic);
|
|
26747
|
|
else
|
|
26748
|
|
mGradient.colorize(rawData + line * rowCount, mDataRange, pixels, rowCount, 1,
|
|
26749
|
|
mDataScaleType == QCPAxis::stLogarithmic);
|
|
26750
|
|
}
|
|
|
26983
|
if (mMapImage.isNull()) {
|
|
|
26984
|
qDebug() << Q_FUNC_INFO << "Couldn't create map image (possibly too large for memory)";
|
|
|
26985
|
mMapImage = QImage(QSize(10, 10), format);
|
|
|
26986
|
mMapImage.fill(Qt::black);
|
|
26751
|
26987
|
}
|
|
26752
|
|
else // keyAxis->orientation() == Qt::Vertical
|
|
26753
|
|
{
|
|
26754
|
|
const int lineCount = keySize;
|
|
26755
|
|
const int rowCount = valueSize;
|
|
26756
|
|
for (int line = 0; line < lineCount; ++line) {
|
|
26757
|
|
QRgb *pixels = reinterpret_cast<QRgb *>(localMapImage->scanLine(
|
|
26758
|
|
lineCount - 1 - line)); // invert scanline index because QImage counts scanlines
|
|
26759
|
|
// from top, but our vertical index counts from bottom
|
|
26760
|
|
// (mathematical coordinate system)
|
|
26761
|
|
if (rawAlpha)
|
|
26762
|
|
mGradient.colorize(rawData + line, rawAlpha + line, mDataRange, pixels, rowCount,
|
|
26763
|
|
lineCount, mDataScaleType == QCPAxis::stLogarithmic);
|
|
26764
|
|
else
|
|
26765
|
|
mGradient.colorize(rawData + line, mDataRange, pixels, rowCount, lineCount,
|
|
26766
|
|
mDataScaleType == QCPAxis::stLogarithmic);
|
|
|
26988
|
else {
|
|
|
26989
|
QImage *localMapImage = &mMapImage; // this is the image on which the colorization operates.
|
|
|
26990
|
// Either the final mMapImage, or if we need
|
|
|
26991
|
// oversampling, mUndersampledMapImage
|
|
|
26992
|
if (keyOversamplingFactor > 1 || valueOversamplingFactor > 1) {
|
|
|
26993
|
// resize undersampled map image to actual key/value cell sizes:
|
|
|
26994
|
if (keyAxis->orientation() == Qt::Horizontal
|
|
|
26995
|
&& (mUndersampledMapImage.width() != keySize
|
|
|
26996
|
|| mUndersampledMapImage.height() != valueSize))
|
|
|
26997
|
mUndersampledMapImage = QImage(QSize(keySize, valueSize), format);
|
|
|
26998
|
else if (keyAxis->orientation() == Qt::Vertical
|
|
|
26999
|
&& (mUndersampledMapImage.width() != valueSize
|
|
|
27000
|
|| mUndersampledMapImage.height() != keySize))
|
|
|
27001
|
mUndersampledMapImage = QImage(QSize(valueSize, keySize), format);
|
|
|
27002
|
localMapImage
|
|
|
27003
|
= &mUndersampledMapImage; // make the colorization run on the undersampled image
|
|
|
27004
|
}
|
|
|
27005
|
else if (!mUndersampledMapImage.isNull())
|
|
|
27006
|
mUndersampledMapImage = QImage(); // don't need oversampling mechanism anymore (map size
|
|
|
27007
|
// has changed) but mUndersampledMapImage still has
|
|
|
27008
|
// nonzero size, free it
|
|
|
27009
|
|
|
|
27010
|
const double *rawData = mMapData->mData;
|
|
|
27011
|
const unsigned char *rawAlpha = mMapData->mAlpha;
|
|
|
27012
|
if (keyAxis->orientation() == Qt::Horizontal) {
|
|
|
27013
|
const int lineCount = valueSize;
|
|
|
27014
|
const int rowCount = keySize;
|
|
|
27015
|
for (int line = 0; line < lineCount; ++line) {
|
|
|
27016
|
QRgb *pixels = reinterpret_cast<QRgb *>(localMapImage->scanLine(
|
|
|
27017
|
lineCount - 1 - line)); // invert scanline index because QImage counts scanlines
|
|
|
27018
|
// from top, but our vertical index counts from bottom
|
|
|
27019
|
// (mathematical coordinate system)
|
|
|
27020
|
if (rawAlpha)
|
|
|
27021
|
mGradient.colorize(rawData + line * rowCount, rawAlpha + line * rowCount,
|
|
|
27022
|
mDataRange, pixels, rowCount, 1,
|
|
|
27023
|
mDataScaleType == QCPAxis::stLogarithmic);
|
|
|
27024
|
else
|
|
|
27025
|
mGradient.colorize(rawData + line * rowCount, mDataRange, pixels, rowCount, 1,
|
|
|
27026
|
mDataScaleType == QCPAxis::stLogarithmic);
|
|
|
27027
|
}
|
|
|
27028
|
}
|
|
|
27029
|
else // keyAxis->orientation() == Qt::Vertical
|
|
|
27030
|
{
|
|
|
27031
|
const int lineCount = keySize;
|
|
|
27032
|
const int rowCount = valueSize;
|
|
|
27033
|
for (int line = 0; line < lineCount; ++line) {
|
|
|
27034
|
QRgb *pixels = reinterpret_cast<QRgb *>(localMapImage->scanLine(
|
|
|
27035
|
lineCount - 1 - line)); // invert scanline index because QImage counts scanlines
|
|
|
27036
|
// from top, but our vertical index counts from bottom
|
|
|
27037
|
// (mathematical coordinate system)
|
|
|
27038
|
if (rawAlpha)
|
|
|
27039
|
mGradient.colorize(rawData + line, rawAlpha + line, mDataRange, pixels,
|
|
|
27040
|
rowCount, lineCount,
|
|
|
27041
|
mDataScaleType == QCPAxis::stLogarithmic);
|
|
|
27042
|
else
|
|
|
27043
|
mGradient.colorize(rawData + line, mDataRange, pixels, rowCount, lineCount,
|
|
|
27044
|
mDataScaleType == QCPAxis::stLogarithmic);
|
|
|
27045
|
}
|
|
26767
|
27046
|
}
|
|
26768
|
|
}
|
|
26769
|
27047
|
|
|
26770
|
|
if (keyOversamplingFactor > 1 || valueOversamplingFactor > 1) {
|
|
26771
|
|
if (keyAxis->orientation() == Qt::Horizontal)
|
|
26772
|
|
mMapImage = mUndersampledMapImage.scaled(keySize * keyOversamplingFactor,
|
|
26773
|
|
valueSize * valueOversamplingFactor,
|
|
26774
|
|
Qt::IgnoreAspectRatio, Qt::FastTransformation);
|
|
26775
|
|
else
|
|
26776
|
|
mMapImage = mUndersampledMapImage.scaled(valueSize * valueOversamplingFactor,
|
|
26777
|
|
keySize * keyOversamplingFactor,
|
|
26778
|
|
Qt::IgnoreAspectRatio, Qt::FastTransformation);
|
|
|
27048
|
if (keyOversamplingFactor > 1 || valueOversamplingFactor > 1) {
|
|
|
27049
|
if (keyAxis->orientation() == Qt::Horizontal)
|
|
|
27050
|
mMapImage = mUndersampledMapImage.scaled(
|
|
|
27051
|
keySize * keyOversamplingFactor, valueSize * valueOversamplingFactor,
|
|
|
27052
|
Qt::IgnoreAspectRatio, Qt::FastTransformation);
|
|
|
27053
|
else
|
|
|
27054
|
mMapImage = mUndersampledMapImage.scaled(
|
|
|
27055
|
valueSize * valueOversamplingFactor, keySize * keyOversamplingFactor,
|
|
|
27056
|
Qt::IgnoreAspectRatio, Qt::FastTransformation);
|
|
|
27057
|
}
|
|
26779
|
27058
|
}
|
|
26780
|
27059
|
mMapData->mDataModified = false;
|
|
26781
|
27060
|
mMapImageInvalidated = false;
|
|
@@
-27939,8
+28218,8
QRectF QCPFinancial::selectionHitBox(QCPFinancialDataContainer::const_iterator i
|
|
27939
|
28218
|
/* end of 'src/plottables/plottable-financial.cpp' */
|
|
27940
|
28219
|
|
|
27941
|
28220
|
|
|
27942
|
|
/* including file 'src/plottables/plottable-errorbar.cpp', size 37210 */
|
|
27943
|
|
/* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
|
|
|
28221
|
/* including file 'src/plottables/plottable-errorbar.cpp', size 37355 */
|
|
|
28222
|
/* commit 6f159843e9ec9ea6431b26591937aea13a9f2751 2017-07-25 11:13:32 +0200 */
|
|
27944
|
28223
|
|
|
27945
|
28224
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
27946
|
28225
|
//////////////////// QCPErrorBarsData
|
|
@@
-28671,8
+28950,8
void QCPErrorBars::getErrorBarLines(QCPErrorBarsDataContainer::const_iterator it
|
|
28671
|
28950
|
QPointF centerPixel = mDataPlottable->interface1D()->dataPixelPosition(index);
|
|
28672
|
28951
|
if (qIsNaN(centerPixel.x()) || qIsNaN(centerPixel.y()))
|
|
28673
|
28952
|
return;
|
|
28674
|
|
QCPAxis *errorAxis = mErrorType == etValueError ? mValueAxis : mKeyAxis;
|
|
28675
|
|
QCPAxis *orthoAxis = mErrorType == etValueError ? mKeyAxis : mValueAxis;
|
|
|
28953
|
QCPAxis *errorAxis = mErrorType == etValueError ? mValueAxis.data() : mKeyAxis.data();
|
|
|
28954
|
QCPAxis *orthoAxis = mErrorType == etValueError ? mKeyAxis.data() : mValueAxis.data();
|
|
28676
|
28955
|
const double centerErrorAxisPixel
|
|
28677
|
28956
|
= errorAxis->orientation() == Qt::Horizontal ? centerPixel.x() : centerPixel.y();
|
|
28678
|
28957
|
const double centerOrthoAxisPixel
|
|
@@
-28806,6
+29085,10
double QCPErrorBars::pointDistance(const QPointF &pixelPoint,
|
|
28806
|
29085
|
closestData = mDataContainer->constEnd();
|
|
28807
|
29086
|
if (!mDataPlottable || mDataContainer->isEmpty())
|
|
28808
|
29087
|
return -1.0;
|
|
|
29088
|
if (!mKeyAxis || !mValueAxis) {
|
|
|
29089
|
qDebug() << Q_FUNC_INFO << "invalid key or value axis";
|
|
|
29090
|
return -1.0;
|
|
|
29091
|
}
|
|
28809
|
29092
|
|
|
28810
|
29093
|
QCPErrorBarsDataContainer::const_iterator begin, end;
|
|
28811
|
29094
|
getVisibleDataBounds(begin, end, QCPDataRange(0, dataCount()));
|