##// END OF EJS Templates
QCustomPlot update to the latest version on upstream repo....
jeandet -
r653:ec050eaa9816
parent child
Show More
@@ -42,6 +42,9
42
42
43 #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
43 #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
44 #define QCP_DEVICEPIXELRATIO_SUPPORTED
44 #define QCP_DEVICEPIXELRATIO_SUPPORTED
45 #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
46 #define QCP_DEVICEPIXELRATIO_FLOAT
47 #endif
45 #endif
48 #endif
46
49
47 #include <QtCore/QCache>
50 #include <QtCore/QCache>
@@ -109,8 +112,8 class QCPColorMap;
109 class QCPColorScale;
112 class QCPColorScale;
110 class QCPBars;
113 class QCPBars;
111
114
112 /* including file 'src/global.h', size 16131 */
115 /* including file 'src/global.h', size 16225 */
113 /* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
116 /* commit e7c6a5540d344a96d107dce53f9d4414a09a7320 2017-07-25 00:52:29 +0200 */
114
117
115 // decl definitions for shared library compilation/usage:
118 // decl definitions for shared library compilation/usage:
116 #if defined(QCUSTOMPLOT_COMPILE_LIBRARY)
119 #if defined(QCUSTOMPLOT_COMPILE_LIBRARY)
@@ -1794,8 +1797,8 protected:
1794 /* end of 'src/axis/axistickerdatetime.h' */
1797 /* end of 'src/axis/axistickerdatetime.h' */
1795
1798
1796
1799
1797 /* including file 'src/axis/axistickertime.h', size 3288 */
1800 /* including file 'src/axis/axistickertime.h', size 3542 */
1798 /* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
1801 /* commit c38adb94d83c6a752597a5d43d45c0561fbe1d4d 2017-08-13 17:37:53 +0200 */
1799
1802
1800 class QCP_LIB_DECL QCPAxisTickerTime : public QCPAxisTicker {
1803 class QCP_LIB_DECL QCPAxisTickerTime : public QCPAxisTicker {
1801 Q_GADGET
1804 Q_GADGET
@@ -1805,7 +1808,17 public:
1805
1808
1806 \see setFieldWidth, setTimeFormat
1809 \see setFieldWidth, setTimeFormat
1807 */
1810 */
1808 enum TimeUnit { tuMilliseconds, tuSeconds, tuMinutes, tuHours, tuDays };
1811 enum TimeUnit {
1812 tuMilliseconds ///< Milliseconds, one thousandth of a second (%%z in \ref setTimeFormat)
1813 ,
1814 tuSeconds ///< Seconds (%%s in \ref setTimeFormat)
1815 ,
1816 tuMinutes ///< Minutes (%%m in \ref setTimeFormat)
1817 ,
1818 tuHours ///< Hours (%%h in \ref setTimeFormat)
1819 ,
1820 tuDays ///< Days (%%d in \ref setTimeFormat)
1821 };
1809 Q_ENUMS(TimeUnit)
1822 Q_ENUMS(TimeUnit)
1810
1823
1811 QCPAxisTickerTime();
1824 QCPAxisTickerTime();
@@ -2026,8 +2039,8 protected:
2026 /* end of 'src/axis/axistickerlog.h' */
2039 /* end of 'src/axis/axistickerlog.h' */
2027
2040
2028
2041
2029 /* including file 'src/axis/axis.h', size 20230 */
2042 /* including file 'src/axis/axis.h', size 20634 */
2030 /* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
2043 /* commit 0cc4d9f61f7bf45321a88fec89d909b020ffa26f 2017-08-14 00:43:29 +0200 */
2031
2044
2032 class QCP_LIB_DECL QCPGrid : public QCPLayerable {
2045 class QCP_LIB_DECL QCPGrid : public QCPLayerable {
2033 Q_OBJECT
2046 Q_OBJECT
@@ -2364,6 +2377,9 protected:
2364 QVector<double> mSubTickVector;
2377 QVector<double> mSubTickVector;
2365 bool mCachedMarginValid;
2378 bool mCachedMarginValid;
2366 int mCachedMargin;
2379 int mCachedMargin;
2380 bool mDragging;
2381 QCPRange mDragStartRange;
2382 QCP::AntialiasedElements mAADragBackup, mNotAADragBackup;
2367
2383
2368 // introduced virtual methods:
2384 // introduced virtual methods:
2369 virtual int calculateMargin();
2385 virtual int calculateMargin();
@@ -2376,6 +2392,11 protected:
2376 virtual void selectEvent(QMouseEvent *event, bool additive, const QVariant &details,
2392 virtual void selectEvent(QMouseEvent *event, bool additive, const QVariant &details,
2377 bool *selectionStateChanged) Q_DECL_OVERRIDE;
2393 bool *selectionStateChanged) Q_DECL_OVERRIDE;
2378 virtual void deselectEvent(bool *selectionStateChanged) Q_DECL_OVERRIDE;
2394 virtual void deselectEvent(bool *selectionStateChanged) Q_DECL_OVERRIDE;
2395 // mouse events:
2396 virtual void mousePressEvent(QMouseEvent *event, const QVariant &details);
2397 virtual void mouseMoveEvent(QMouseEvent *event, const QPointF &startPos);
2398 virtual void mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos);
2399 virtual void wheelEvent(QWheelEvent *event);
2379
2400
2380 // non-virtual methods:
2401 // non-virtual methods:
2381 void setupTickVectors();
2402 void setupTickVectors();
@@ -2612,8 +2633,8 Q_DECLARE_METATYPE(QCPScatterStyle::ScatterShape)
2612 /* end of 'src/scatterstyle.h' */
2633 /* end of 'src/scatterstyle.h' */
2613
2634
2614
2635
2615 /* including file 'src/datacontainer.h', size 4535 */
2636 /* including file 'src/datacontainer.h', size 4596 */
2616 /* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
2637 /* commit bee82298bd87b91a50093fb0b81cd7c734724a6f 2017-08-13 16:10:24 +0200 */
2617
2638
2618 /*! \relates QCPDataContainer
2639 /*! \relates QCPDataContainer
2619 Returns whether the sort key of \a a is less than the sort key of \a b.
2640 Returns whether the sort key of \a a is less than the sort key of \a b.
@@ -2627,7 +2648,8 inline bool qcpLessThanSortKey(const DataType &a, const DataType &b)
2627 }
2648 }
2628
2649
2629 template <class DataType>
2650 template <class DataType>
2630 class QCP_LIB_DECL QCPDataContainer {
2651 class QCPDataContainer // no QCP_LIB_DECL, template class ends up in header (cpp included below)
2652 {
2631 public:
2653 public:
2632 typedef typename QVector<DataType>::const_iterator const_iterator;
2654 typedef typename QVector<DataType>::const_iterator const_iterator;
2633 typedef typename QVector<DataType>::iterator iterator;
2655 typedef typename QVector<DataType>::iterator iterator;
@@ -2686,8 +2708,8 protected:
2686
2708
2687 // include implementation in header since it is a class template:
2709 // include implementation in header since it is a class template:
2688
2710
2689 /* including file 'src/datacontainer.cpp', size 31224 */
2711 /* including file 'src/datacontainer.cpp', size 31349 */
2690 /* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
2712 /* commit 820d2282db70144c358c13433cd74b4175f9252b 2017-07-24 00:24:17 +0200 */
2691
2713
2692 ////////////////////////////////////////////////////////////////////////////////////////////////////
2714 ////////////////////////////////////////////////////////////////////////////////////////////////////
2693 //////////////////// QCPDataContainer
2715 //////////////////// QCPDataContainer
@@ -3403,7 +3425,8 QCPRange QCPDataContainer<DataType>::valueRange(bool &foundRange, QCP::SignDomai
3403
3425
3404 /*!
3426 /*!
3405 Makes sure \a begin and \a end mark a data range that is both within the bounds of this data
3427 Makes sure \a begin and \a end mark a data range that is both within the bounds of this data
3406 container's data, as well as within the specified \a dataRange.
3428 container's data, as well as within the specified \a dataRange. The initial range described by
3429 the passed iterators \a begin and \a end is never expanded, only contracted if necessary.
3407
3430
3408 This function doesn't require for \a dataRange to be within the bounds of this data container's
3431 This function doesn't require for \a dataRange to be within the bounds of this data container's
3409 valid range.
3432 valid range.
@@ -3660,8 +3683,8 private:
3660 /* end of 'src/plottable.h' */
3683 /* end of 'src/plottable.h' */
3661
3684
3662
3685
3663 /* including file 'src/item.h', size 9368 */
3686 /* including file 'src/item.h', size 9384 */
3664 /* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
3687 /* commit 681a87c5e5365a5c7187d20b4077031003c48449 2017-07-23 23:46:48 +0200 */
3665
3688
3666 class QCP_LIB_DECL QCPItemAnchor {
3689 class QCP_LIB_DECL QCPItemAnchor {
3667 Q_GADGET
3690 Q_GADGET
@@ -3750,7 +3773,7 public:
3750 QCPAxis *keyAxis() const { return mKeyAxis.data(); }
3773 QCPAxis *keyAxis() const { return mKeyAxis.data(); }
3751 QCPAxis *valueAxis() const { return mValueAxis.data(); }
3774 QCPAxis *valueAxis() const { return mValueAxis.data(); }
3752 QCPAxisRect *axisRect() const;
3775 QCPAxisRect *axisRect() const;
3753 virtual QPointF pixelPosition() const;
3776 virtual QPointF pixelPosition() const Q_DECL_OVERRIDE;
3754
3777
3755 // setters:
3778 // setters:
3756 void setType(PositionType type);
3779 void setType(PositionType type);
@@ -3857,8 +3880,8 private:
3857 /* end of 'src/item.h' */
3880 /* end of 'src/item.h' */
3858
3881
3859
3882
3860 /* including file 'src/core.h', size 14797 */
3883 /* including file 'src/core.h', size 14886 */
3861 /* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
3884 /* commit 29aafbce469a36d175d4fb32cbfd1f50a6072890 2016-10-12 19:21:24 +0200 */
3862
3885
3863 class QCP_LIB_DECL QCustomPlot : public QWidget {
3886 class QCP_LIB_DECL QCustomPlot : public QWidget {
3864 Q_OBJECT
3887 Q_OBJECT
@@ -4091,7 +4114,9 protected:
4091 QPoint mMousePressPos;
4114 QPoint mMousePressPos;
4092 bool mMouseHasMoved;
4115 bool mMouseHasMoved;
4093 QPointer<QCPLayerable> mMouseEventLayerable;
4116 QPointer<QCPLayerable> mMouseEventLayerable;
4117 QPointer<QCPLayerable> mMouseSignalLayerable;
4094 QVariant mMouseEventLayerableDetails;
4118 QVariant mMouseEventLayerableDetails;
4119 QVariant mMouseSignalLayerableDetails;
4095 bool mReplotting;
4120 bool mReplotting;
4096 bool mReplotQueued;
4121 bool mReplotQueued;
4097 int mOpenGlMultisamples;
4122 int mOpenGlMultisamples;
@@ -4153,11 +4178,12 Q_DECLARE_METATYPE(QCustomPlot::RefreshPriority)
4153 /* end of 'src/core.h' */
4178 /* end of 'src/core.h' */
4154
4179
4155
4180
4156 /* including file 'src/plottable1d.h', size 4250 */
4181 /* including file 'src/plottable1d.h', size 4544 */
4157 /* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
4182 /* commit bee82298bd87b91a50093fb0b81cd7c734724a6f 2017-08-13 16:10:24 +0200 */
4158
4183
4159 class QCP_LIB_DECL QCPPlottableInterface1D {
4184 class QCPPlottableInterface1D {
4160 public:
4185 public:
4186 virtual ~QCPPlottableInterface1D() {}
4161 // introduced pure virtual methods:
4187 // introduced pure virtual methods:
4162 virtual int dataCount() const = 0;
4188 virtual int dataCount() const = 0;
4163 virtual double dataMainKey(int index) const = 0;
4189 virtual double dataMainKey(int index) const = 0;
@@ -4172,8 +4198,11 public:
4172 };
4198 };
4173
4199
4174 template <class DataType>
4200 template <class DataType>
4175 class QCP_LIB_DECL QCPAbstractPlottable1D : public QCPAbstractPlottable,
4201 class QCPAbstractPlottable1D : public QCPAbstractPlottable,
4176 public QCPPlottableInterface1D {
4202 public QCPPlottableInterface1D // no QCP_LIB_DECL, template class
4203 // ends up in header (cpp included
4204 // below)
4205 {
4177 // No Q_OBJECT macro due to template class
4206 // No Q_OBJECT macro due to template class
4178
4207
4179 public:
4208 public:
@@ -4181,20 +4210,22 public:
4181 virtual ~QCPAbstractPlottable1D();
4210 virtual ~QCPAbstractPlottable1D();
4182
4211
4183 // virtual methods of 1d plottable interface:
4212 // virtual methods of 1d plottable interface:
4184 virtual int dataCount() const;
4213 virtual int dataCount() const Q_DECL_OVERRIDE;
4185 virtual double dataMainKey(int index) const;
4214 virtual double dataMainKey(int index) const Q_DECL_OVERRIDE;
4186 virtual double dataSortKey(int index) const;
4215 virtual double dataSortKey(int index) const Q_DECL_OVERRIDE;
4187 virtual double dataMainValue(int index) const;
4216 virtual double dataMainValue(int index) const Q_DECL_OVERRIDE;
4188 virtual QCPRange dataValueRange(int index) const;
4217 virtual QCPRange dataValueRange(int index) const Q_DECL_OVERRIDE;
4189 virtual QPointF dataPixelPosition(int index) const;
4218 virtual QPointF dataPixelPosition(int index) const Q_DECL_OVERRIDE;
4190 virtual bool sortKeyIsMainKey() const;
4219 virtual bool sortKeyIsMainKey() const Q_DECL_OVERRIDE;
4191 virtual QCPDataSelection selectTestRect(const QRectF &rect, bool onlySelectable) const;
4220 virtual QCPDataSelection selectTestRect(const QRectF &rect,
4192 virtual int findBegin(double sortKey, bool expandedRange = true) const;
4221 bool onlySelectable) const Q_DECL_OVERRIDE;
4193 virtual int findEnd(double sortKey, bool expandedRange = true) const;
4222 virtual int findBegin(double sortKey, bool expandedRange = true) const Q_DECL_OVERRIDE;
4223 virtual int findEnd(double sortKey, bool expandedRange = true) const Q_DECL_OVERRIDE;
4194
4224
4195 // virtual methods:
4225 // reimplemented virtual methods:
4196 virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details = 0) const;
4226 virtual double selectTest(const QPointF &pos, bool onlySelectable,
4197 virtual QCPPlottableInterface1D *interface1D() { return this; }
4227 QVariant *details = 0) const Q_DECL_OVERRIDE;
4228 virtual QCPPlottableInterface1D *interface1D() Q_DECL_OVERRIDE { return this; }
4198
4229
4199 protected:
4230 protected:
4200 // property members:
4231 // property members:
@@ -4863,8 +4894,8 Q_DECLARE_METATYPE(QCPColorGradient::GradientPreset)
4863 /* end of 'src/colorgradient.h' */
4894 /* end of 'src/colorgradient.h' */
4864
4895
4865
4896
4866 /* including file 'src/selectiondecorator-bracket.h', size 4426 */
4897 /* including file 'src/selectiondecorator-bracket.h', size 4442 */
4867 /* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
4898 /* commit 681a87c5e5365a5c7187d20b4077031003c48449 2017-07-23 23:46:48 +0200 */
4868
4899
4869 class QCP_LIB_DECL QCPSelectionDecoratorBracket : public QCPSelectionDecorator {
4900 class QCP_LIB_DECL QCPSelectionDecoratorBracket : public QCPSelectionDecorator {
4870 Q_GADGET
4901 Q_GADGET
@@ -4916,7 +4947,7 public:
4916 virtual void drawBracket(QCPPainter *painter, int direction) const;
4947 virtual void drawBracket(QCPPainter *painter, int direction) const;
4917
4948
4918 // virtual methods:
4949 // virtual methods:
4919 virtual void drawDecoration(QCPPainter *painter, QCPDataSelection selection);
4950 virtual void drawDecoration(QCPPainter *painter, QCPDataSelection selection) Q_DECL_OVERRIDE;
4920
4951
4921 protected:
4952 protected:
4922 // property members:
4953 // property members:
@@ -4938,8 +4969,8 Q_DECLARE_METATYPE(QCPSelectionDecoratorBracket::BracketStyle)
4938 /* end of 'src/selectiondecorator-bracket.h' */
4969 /* end of 'src/selectiondecorator-bracket.h' */
4939
4970
4940
4971
4941 /* including file 'src/layoutelements/layoutelement-axisrect.h', size 7528 */
4972 /* including file 'src/layoutelements/layoutelement-axisrect.h', size 7507 */
4942 /* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
4973 /* commit 77ba168312f935543fc31d1ae9b4cdcf34aae4f9 2017-08-13 18:29:48 +0200 */
4943
4974
4944 class QCP_LIB_DECL QCPAxisRect : public QCPLayoutElement {
4975 class QCP_LIB_DECL QCPAxisRect : public QCPLayoutElement {
4945 Q_OBJECT
4976 Q_OBJECT
@@ -5037,7 +5068,6 protected:
5037 // non-property members:
5068 // non-property members:
5038 QList<QCPRange> mDragStartHorzRange, mDragStartVertRange;
5069 QList<QCPRange> mDragStartHorzRange, mDragStartVertRange;
5039 QCP::AntialiasedElements mAADragBackup, mNotAADragBackup;
5070 QCP::AntialiasedElements mAADragBackup, mNotAADragBackup;
5040 QPoint mDragStart;
5041 bool mDragging;
5071 bool mDragging;
5042 QHash<QCPAxis::AxisType, QList<QCPAxis *> > mAxes;
5072 QHash<QCPAxis::AxisType, QList<QCPAxis *> > mAxes;
5043
5073
@@ -5378,8 +5408,8 private:
5378 /* end of 'src/layoutelements/layoutelement-textelement.h' */
5408 /* end of 'src/layoutelements/layoutelement-textelement.h' */
5379
5409
5380
5410
5381 /* including file 'src/layoutelements/layoutelement-colorscale.h', size 5907 */
5411 /* including file 'src/layoutelements/layoutelement-colorscale.h', size 5923 */
5382 /* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
5412 /* commit 681a87c5e5365a5c7187d20b4077031003c48449 2017-07-23 23:46:48 +0200 */
5383
5413
5384
5414
5385 class QCPColorScaleAxisRectPrivate : public QCPAxisRect {
5415 class QCPColorScaleAxisRectPrivate : public QCPAxisRect {
@@ -5398,7 +5428,7 protected:
5398 using QCPAxisRect::mouseReleaseEvent;
5428 using QCPAxisRect::mouseReleaseEvent;
5399 using QCPAxisRect::wheelEvent;
5429 using QCPAxisRect::wheelEvent;
5400 using QCPAxisRect::update;
5430 using QCPAxisRect::update;
5401 virtual void draw(QCPPainter *painter);
5431 virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE;
5402 void updateGradientImage();
5432 void updateGradientImage();
5403 Q_SLOT void axisSelectionChanged(QCPAxis::SelectableParts selectedParts);
5433 Q_SLOT void axisSelectionChanged(QCPAxis::SelectableParts selectedParts);
5404 Q_SLOT void axisSelectableChanged(QCPAxis::SelectableParts selectableParts);
5434 Q_SLOT void axisSelectableChanged(QCPAxis::SelectableParts selectableParts);
@@ -5486,8 +5516,8 private:
5486 /* end of 'src/layoutelements/layoutelement-colorscale.h' */
5516 /* end of 'src/layoutelements/layoutelement-colorscale.h' */
5487
5517
5488
5518
5489 /* including file 'src/plottables/plottable-graph.h', size 8826 */
5519 /* including file 'src/plottables/plottable-graph.h', size 9294 */
5490 /* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
5520 /* commit f3881770eaf7366171012ad01cad2aaf5f61dd27 2017-06-23 02:48:21 +0200 */
5491
5521
5492 class QCP_LIB_DECL QCPGraphData {
5522 class QCP_LIB_DECL QCPGraphData {
5493 public:
5523 public:
@@ -5624,11 +5654,20 protected:
5624 QVector<QPointF> dataToStepRightLines(const QVector<QCPGraphData> &data) const;
5654 QVector<QPointF> dataToStepRightLines(const QVector<QCPGraphData> &data) const;
5625 QVector<QPointF> dataToStepCenterLines(const QVector<QCPGraphData> &data) const;
5655 QVector<QPointF> dataToStepCenterLines(const QVector<QCPGraphData> &data) const;
5626 QVector<QPointF> dataToImpulseLines(const QVector<QCPGraphData> &data) const;
5656 QVector<QPointF> dataToImpulseLines(const QVector<QCPGraphData> &data) const;
5627 void addFillBasePoints(QVector<QPointF> *lines) const;
5657 QVector<QCPDataRange> getNonNanSegments(const QVector<QPointF> *lineData,
5628 void removeFillBasePoints(QVector<QPointF> *lines) const;
5658 Qt::Orientation keyOrientation) const;
5629 QPointF lowerFillBasePoint(double lowerKey) const;
5659 QVector<QPair<QCPDataRange, QCPDataRange> >
5630 QPointF upperFillBasePoint(double upperKey) const;
5660 getOverlappingSegments(QVector<QCPDataRange> thisSegments, const QVector<QPointF> *thisData,
5631 const QPolygonF getChannelFillPolygon(const QVector<QPointF> *lines) const;
5661 QVector<QCPDataRange> otherSegments,
5662 const QVector<QPointF> *otherData) const;
5663 bool segmentsIntersect(double aLower, double aUpper, double bLower, double bUpper,
5664 int &bPrecedence) const;
5665 QPointF getFillBasePoint(QPointF matchingDataPoint) const;
5666 const QPolygonF getFillPolygon(const QVector<QPointF> *lineData, QCPDataRange segment) const;
5667 const QPolygonF getChannelFillPolygon(const QVector<QPointF> *lineData,
5668 QCPDataRange thisSegment,
5669 const QVector<QPointF> *otherData,
5670 QCPDataRange otherSegment) const;
5632 int findIndexBelowX(const QVector<QPointF> *data, double x) const;
5671 int findIndexBelowX(const QVector<QPointF> *data, double x) const;
5633 int findIndexAboveX(const QVector<QPointF> *data, double x) const;
5672 int findIndexAboveX(const QVector<QPointF> *data, double x) const;
5634 int findIndexBelowY(const QVector<QPointF> *data, double y) const;
5673 int findIndexBelowY(const QVector<QPointF> *data, double y) const;
@@ -6425,8 +6464,8 Q_DECLARE_METATYPE(QCPFinancial::ChartStyle)
6425 /* end of 'src/plottables/plottable-financial.h' */
6464 /* end of 'src/plottables/plottable-financial.h' */
6426
6465
6427
6466
6428 /* including file 'src/plottables/plottable-errorbar.h', size 7567 */
6467 /* including file 'src/plottables/plottable-errorbar.h', size 7727 */
6429 /* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
6468 /* commit 681a87c5e5365a5c7187d20b4077031003c48449 2017-07-23 23:46:48 +0200 */
6430
6469
6431 class QCP_LIB_DECL QCPErrorBarsData {
6470 class QCP_LIB_DECL QCPErrorBarsData {
6432 public:
6471 public:
@@ -6505,16 +6544,17 public:
6505 void addData(double errorMinus, double errorPlus);
6544 void addData(double errorMinus, double errorPlus);
6506
6545
6507 // virtual methods of 1d plottable interface:
6546 // virtual methods of 1d plottable interface:
6508 virtual int dataCount() const;
6547 virtual int dataCount() const Q_DECL_OVERRIDE;
6509 virtual double dataMainKey(int index) const;
6548 virtual double dataMainKey(int index) const Q_DECL_OVERRIDE;
6510 virtual double dataSortKey(int index) const;
6549 virtual double dataSortKey(int index) const Q_DECL_OVERRIDE;
6511 virtual double dataMainValue(int index) const;
6550 virtual double dataMainValue(int index) const Q_DECL_OVERRIDE;
6512 virtual QCPRange dataValueRange(int index) const;
6551 virtual QCPRange dataValueRange(int index) const Q_DECL_OVERRIDE;
6513 virtual QPointF dataPixelPosition(int index) const;
6552 virtual QPointF dataPixelPosition(int index) const Q_DECL_OVERRIDE;
6514 virtual bool sortKeyIsMainKey() const;
6553 virtual bool sortKeyIsMainKey() const Q_DECL_OVERRIDE;
6515 virtual QCPDataSelection selectTestRect(const QRectF &rect, bool onlySelectable) const;
6554 virtual QCPDataSelection selectTestRect(const QRectF &rect,
6516 virtual int findBegin(double sortKey, bool expandedRange = true) const;
6555 bool onlySelectable) const Q_DECL_OVERRIDE;
6517 virtual int findEnd(double sortKey, bool expandedRange = true) const;
6556 virtual int findBegin(double sortKey, bool expandedRange = true) const Q_DECL_OVERRIDE;
6557 virtual int findEnd(double sortKey, bool expandedRange = true) const Q_DECL_OVERRIDE;
6518
6558
6519 // reimplemented virtual methods:
6559 // reimplemented virtual methods:
6520 virtual double selectTest(const QPointF &pos, bool onlySelectable,
6560 virtual double selectTest(const QPointF &pos, bool onlySelectable,
This diff has been collapsed as it changes many lines, (1257 lines changed) Show them Hide them
@@ -1574,10 +1574,7 void QCPLayerable::applyAntialiasingHint(QCPPainter *painter, bool localAntialia
1574
1574
1575 \see initializeParentPlot
1575 \see initializeParentPlot
1576 */
1576 */
1577 void QCPLayerable::parentPlotInitialized(QCustomPlot *parentPlot)
1577 void QCPLayerable::parentPlotInitialized(QCustomPlot *parentPlot){Q_UNUSED(parentPlot)}
1578 {
1579 Q_UNUSED(parentPlot)
1580 }
1581
1578
1582 /*! \internal
1579 /*! \internal
1583
1580
@@ -2102,8 +2099,8 bool QCPRange::validRange(const QCPRange &range)
2102 /* end of 'src/axis/range.cpp' */
2099 /* end of 'src/axis/range.cpp' */
2103
2100
2104
2101
2105 /* including file 'src/selection.cpp', size 21898 */
2102 /* including file 'src/selection.cpp', size 21906 */
2106 /* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
2103 /* commit 820d2282db70144c358c13433cd74b4175f9252b 2017-07-24 00:24:17 +0200 */
2107
2104
2108 ////////////////////////////////////////////////////////////////////////////////////////////////////
2105 ////////////////////////////////////////////////////////////////////////////////////////////////////
2109 //////////////////// QCPDataRange
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 QCPDataSelection &QCPDataSelection::operator-=(const QCPDataSelection &other)
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 QCPDataSelection &QCPDataSelection::operator-=(const QCPDataRange &other)
2419 QCPDataSelection &QCPDataSelection::operator-=(const QCPDataRange &other)
2423 {
2420 {
@@ -2930,8 +2927,8 void QCPSelectionRect::draw(QCPPainter *painter)
2930 /* end of 'src/selectionrect.cpp' */
2927 /* end of 'src/selectionrect.cpp' */
2931
2928
2932
2929
2933 /* including file 'src/layout.cpp', size 74302 */
2930 /* including file 'src/layout.cpp', size 74663 */
2934 /* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
2931 /* commit a872eb91ec087561efd83dd9cb041a26ab95ce55 2017-07-31 00:21:41 +0200 */
2935
2932
2936 ////////////////////////////////////////////////////////////////////////////////////////////////////
2933 ////////////////////////////////////////////////////////////////////////////////////////////////////
2937 //////////////////// QCPMarginGroup
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
3572 If \a phase is \ref upLayout, calls \ref updateLayout, which subclasses may reimplement to
3576 layout.
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 void QCPLayout::update(UpdatePhase phase)
3580 void QCPLayout::update(UpdatePhase phase)
3583 {
3581 {
@@ -4242,7 +4240,7 void QCPLayoutGrid::setWrap(int count)
4242
4240
4243 If you want to have all current elements arranged in the new order, set \a rearrange to true. The
4241 If you want to have all current elements arranged in the new order, set \a rearrange to true. The
4244 elements will be rearranged in a way that tries to preserve their linear index. However, empty
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 index. The rearranging is performed even if the specified \a order is already the current fill
4244 index. The rearranging is performed even if the specified \a order is already the current fill
4247 order. Thus this method can be used to re-wrap the current elements.
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 Inserts a new column with empty cells at the column index \a newIndex. Valid values for \a
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 \see insertRow
4341 \see insertRow
4343 */
4342 */
@@ -4411,7 +4410,9 void QCPLayoutGrid::indexToRowCol(int index, int &row, int &column) const
4411 {
4410 {
4412 row = -1;
4411 row = -1;
4413 column = -1;
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 return;
4416 return;
4416 if (index < 0 || index >= elementCount()) {
4417 if (index < 0 || index >= elementCount()) {
4417 qDebug() << Q_FUNC_INFO << "index out of bounds:" << index;
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 switch (mFillOrder) {
4422 switch (mFillOrder) {
4422 case foRowsFirst: {
4423 case foRowsFirst: {
4423 column = index / rowCount();
4424 column = index / nRows;
4424 row = index % rowCount();
4425 row = index % nRows;
4425 break;
4426 break;
4426 }
4427 }
4427 case foColumnsFirst: {
4428 case foColumnsFirst: {
4428 row = index / columnCount();
4429 row = index / nCols;
4429 column = index % columnCount();
4430 column = index % nCols;
4430 break;
4431 break;
4431 }
4432 }
4432 }
4433 }
@@ -4592,9 +4593,8 QSize QCPLayoutGrid::minimumSizeHint() const
4592 result.rwidth() += minColWidths.at(i);
4593 result.rwidth() += minColWidths.at(i);
4593 for (int i = 0; i < minRowHeights.size(); ++i)
4594 for (int i = 0; i < minRowHeights.size(); ++i)
4594 result.rheight() += minRowHeights.at(i);
4595 result.rheight() += minRowHeights.at(i);
4595 result.rwidth()
4596 result.rwidth() += qMax(0, columnCount() - 1) * mColumnSpacing;
4596 += qMax(0, columnCount() - 1) * mColumnSpacing + mMargins.left() + mMargins.right();
4597 result.rheight() += qMax(0, rowCount() - 1) * mRowSpacing;
4597 result.rheight() += qMax(0, rowCount() - 1) * mRowSpacing + mMargins.top() + mMargins.bottom();
4598 return result;
4598 return result;
4599 }
4599 }
4600
4600
@@ -4609,9 +4609,8 QSize QCPLayoutGrid::maximumSizeHint() const
4609 result.setWidth(qMin(result.width() + maxColWidths.at(i), QWIDGETSIZE_MAX));
4609 result.setWidth(qMin(result.width() + maxColWidths.at(i), QWIDGETSIZE_MAX));
4610 for (int i = 0; i < maxRowHeights.size(); ++i)
4610 for (int i = 0; i < maxRowHeights.size(); ++i)
4611 result.setHeight(qMin(result.height() + maxRowHeights.at(i), QWIDGETSIZE_MAX));
4611 result.setHeight(qMin(result.height() + maxRowHeights.at(i), QWIDGETSIZE_MAX));
4612 result.rwidth()
4612 result.rwidth() += qMax(0, columnCount() - 1) * mColumnSpacing;
4613 += qMax(0, columnCount() - 1) * mColumnSpacing + mMargins.left() + mMargins.right();
4613 result.rheight() += qMax(0, rowCount() - 1) * mRowSpacing;
4614 result.rheight() += qMax(0, rowCount() - 1) * mRowSpacing + mMargins.top() + mMargins.bottom();
4615 return result;
4614 return result;
4616 }
4615 }
4617
4616
@@ -4620,8 +4619,9 QSize QCPLayoutGrid::maximumSizeHint() const
4620 Places the minimum column widths and row heights into \a minColWidths and \a minRowHeights
4619 Places the minimum column widths and row heights into \a minColWidths and \a minRowHeights
4621 respectively.
4620 respectively.
4622
4621
4623 The minimum height of a row is the largest minimum height of any element in that row. The minimum
4622 The minimum height of a row is the largest minimum height of any element's outer rect in that
4624 width of a column is the largest minimum width of any element in that column.
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 This is a helper function for \ref updateLayout.
4626 This is a helper function for \ref updateLayout.
4627
4627
@@ -4634,11 +4634,13 void QCPLayoutGrid::getMinimumRowColSizes(QVector<int> *minColWidths,
4634 *minRowHeights = QVector<int>(rowCount(), 0);
4634 *minRowHeights = QVector<int>(rowCount(), 0);
4635 for (int row = 0; row < rowCount(); ++row) {
4635 for (int row = 0; row < rowCount(); ++row) {
4636 for (int col = 0; col < columnCount(); ++col) {
4636 for (int col = 0; col < columnCount(); ++col) {
4637 if (mElements.at(row).at(col)) {
4637 if (QCPLayoutElement *el = mElements.at(row).at(col)) {
4638 QSize minHint = mElements.at(row).at(col)->minimumSizeHint();
4638 QSize minHint = el->minimumSizeHint();
4639 QSize min = mElements.at(row).at(col)->minimumSize();
4639 QSize min = el->minimumSize();
4640 QSize final(min.width() > 0 ? min.width() : minHint.width(),
4640 QSize final(min.width() > 0 ? min.width() : minHint.width(),
4641 min.height() > 0 ? min.height() : minHint.height());
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 if (minColWidths->at(col) < final.width())
4644 if (minColWidths->at(col) < final.width())
4643 (*minColWidths)[col] = final.width();
4645 (*minColWidths)[col] = final.width();
4644 if (minRowHeights->at(row) < final.height())
4646 if (minRowHeights->at(row) < final.height())
@@ -4653,8 +4655,9 void QCPLayoutGrid::getMinimumRowColSizes(QVector<int> *minColWidths,
4653 Places the maximum column widths and row heights into \a maxColWidths and \a maxRowHeights
4655 Places the maximum column widths and row heights into \a maxColWidths and \a maxRowHeights
4654 respectively.
4656 respectively.
4655
4657
4656 The maximum height of a row is the smallest maximum height of any element in that row. The
4658 The maximum height of a row is the smallest maximum height of any element's outer rect in that
4657 maximum width of a column is the smallest maximum width of any element in that column.
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 This is a helper function for \ref updateLayout.
4662 This is a helper function for \ref updateLayout.
4660
4663
@@ -4667,11 +4670,13 void QCPLayoutGrid::getMaximumRowColSizes(QVector<int> *maxColWidths,
4667 *maxRowHeights = QVector<int>(rowCount(), QWIDGETSIZE_MAX);
4670 *maxRowHeights = QVector<int>(rowCount(), QWIDGETSIZE_MAX);
4668 for (int row = 0; row < rowCount(); ++row) {
4671 for (int row = 0; row < rowCount(); ++row) {
4669 for (int col = 0; col < columnCount(); ++col) {
4672 for (int col = 0; col < columnCount(); ++col) {
4670 if (mElements.at(row).at(col)) {
4673 if (QCPLayoutElement *el = mElements.at(row).at(col)) {
4671 QSize maxHint = mElements.at(row).at(col)->maximumSizeHint();
4674 QSize maxHint = el->maximumSizeHint();
4672 QSize max = mElements.at(row).at(col)->maximumSize();
4675 QSize max = el->maximumSize();
4673 QSize final(max.width() < QWIDGETSIZE_MAX ? max.width() : maxHint.width(),
4676 QSize final(max.width() < QWIDGETSIZE_MAX ? max.width() : maxHint.width(),
4674 max.height() < QWIDGETSIZE_MAX ? max.height() : maxHint.height());
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 if (maxColWidths->at(col) > final.width())
4680 if (maxColWidths->at(col) > final.width())
4676 (*maxColWidths)[col] = final.width();
4681 (*maxColWidths)[col] = final.width();
4677 if (maxRowHeights->at(row) > final.height())
4682 if (maxRowHeights->at(row) > final.height())
@@ -4820,22 +4825,25 void QCPLayoutInset::setInsetRect(int index, const QRectF &rect)
4820 void QCPLayoutInset::updateLayout()
4825 void QCPLayoutInset::updateLayout()
4821 {
4826 {
4822 for (int i = 0; i < mElements.size(); ++i) {
4827 for (int i = 0; i < mElements.size(); ++i) {
4828 QCPLayoutElement *el = mElements.at(i);
4823 QRect insetRect;
4829 QRect insetRect;
4824 QSize finalMinSize, finalMaxSize;
4830 QSize finalMinSize, finalMaxSize;
4825 QSize minSizeHint = mElements.at(i)->minimumSizeHint();
4831 QSize minSizeHint = el->minimumSizeHint();
4826 QSize maxSizeHint = mElements.at(i)->maximumSizeHint();
4832 QSize maxSizeHint = el->maximumSizeHint();
4827 finalMinSize.setWidth(mElements.at(i)->minimumSize().width() > 0
4833 finalMinSize.setWidth(el->minimumSize().width() > 0 ? el->minimumSize().width()
4828 ? mElements.at(i)->minimumSize().width()
4829 : minSizeHint.width());
4834 : minSizeHint.width());
4830 finalMinSize.setHeight(mElements.at(i)->minimumSize().height() > 0
4835 finalMinSize.setHeight(el->minimumSize().height() > 0 ? el->minimumSize().height()
4831 ? mElements.at(i)->minimumSize().height()
4832 : minSizeHint.height());
4836 : minSizeHint.height());
4833 finalMaxSize.setWidth(mElements.at(i)->maximumSize().width() < QWIDGETSIZE_MAX
4837 finalMaxSize.setWidth(el->maximumSize().width() < QWIDGETSIZE_MAX
4834 ? mElements.at(i)->maximumSize().width()
4838 ? el->maximumSize().width()
4835 : maxSizeHint.width());
4839 : maxSizeHint.width());
4836 finalMaxSize.setHeight(mElements.at(i)->maximumSize().height() < QWIDGETSIZE_MAX
4840 finalMaxSize.setHeight(el->maximumSize().height() < QWIDGETSIZE_MAX
4837 ? mElements.at(i)->maximumSize().height()
4841 ? el->maximumSize().height()
4838 : maxSizeHint.height());
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 if (mInsetPlacement.at(i) == ipFree) {
4847 if (mInsetPlacement.at(i) == ipFree) {
4840 insetRect = QRect(rect().x() + rect().width() * mInsetRect.at(i).x(),
4848 insetRect = QRect(rect().x() + rect().width() * mInsetRect.at(i).x(),
4841 rect().y() + rect().height() * mInsetRect.at(i).y(),
4849 rect().y() + rect().height() * mInsetRect.at(i).y(),
@@ -7150,8 +7158,8 QVector<double> QCPAxisTickerLog::createTickVector(double tickStep, const QCPRan
7150 /* end of 'src/axis/axistickerlog.cpp' */
7158 /* end of 'src/axis/axistickerlog.cpp' */
7151
7159
7152
7160
7153 /* including file 'src/axis/axis.cpp', size 94458 */
7161 /* including file 'src/axis/axis.cpp', size 99397 */
7154 /* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
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 else // mScaleType == stLogarithmic
8652 else // mScaleType == stLogarithmic
8645 {
8653 {
8646 if (value >= 0 && mRange.upper < 0) // invalid value for logarithmic scale, just draw it
8654 if (value >= 0.0 && mRange.upper < 0.0) // invalid value for logarithmic scale, just
8647 // outside visible range
8648 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
8655 // draw it outside visible range
8656 return !mRangeReversed ? mAxisRect->right() + 200 : mAxisRect->left() - 200;
8657 else if (value <= 0.0 && mRange.upper >= 0.0) // invalid value for logarithmic scale,
8658 // just draw it outside visible range
8651 return !mRangeReversed ? mAxisRect->left() - 200 : mAxisRect->right() + 200;
8659 return !mRangeReversed ? mAxisRect->left() - 200 : mAxisRect->right() + 200;
8652 else {
8660 else {
8653 if (!mRangeReversed)
8661 if (!mRangeReversed)
@@ -8673,11 +8681,11 double QCPAxis::coordToPixel(double value) const
8673 }
8681 }
8674 else // mScaleType == stLogarithmic
8682 else // mScaleType == stLogarithmic
8675 {
8683 {
8676 if (value >= 0 && mRange.upper < 0) // invalid value for logarithmic scale, just draw it
8684 if (value >= 0.0 && mRange.upper < 0.0) // invalid value for logarithmic scale, just
8677 // outside visible range
8678 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
8685 // draw it outside visible range
8686 return !mRangeReversed ? mAxisRect->top() - 200 : mAxisRect->bottom() + 200;
8687 else if (value <= 0.0 && mRange.upper >= 0.0) // invalid value for logarithmic scale,
8688 // just draw it outside visible range
8681 return !mRangeReversed ? mAxisRect->bottom() + 200 : mAxisRect->top() - 200;
8689 return !mRangeReversed ? mAxisRect->bottom() + 200 : mAxisRect->top() - 200;
8682 else {
8690 else {
8683 if (!mRangeReversed)
8691 if (!mRangeReversed)
@@ -8868,6 +8876,132 void QCPAxis::deselectEvent(bool *selectionStateChanged)
8868
8876
8869 /*! \internal
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 A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter
9005 A convenience function to easily set the QPainter::Antialiased hint on the provided \a painter
8872 before drawing axis lines.
9006 before drawing axis lines.
8873
9007
@@ -9257,12 +9391,14 void QCPAxisPainterPrivate::draw(QCPPainter *painter)
9257 painter->setBrush(QBrush(basePen.color()));
9391 painter->setBrush(QBrush(basePen.color()));
9258 QCPVector2D baseLineVector(baseLine.dx(), baseLine.dy());
9392 QCPVector2D baseLineVector(baseLine.dx(), baseLine.dy());
9259 if (lowerEnding.style() != QCPLineEnding::esNone)
9393 if (lowerEnding.style() != QCPLineEnding::esNone)
9260 lowerEnding.draw(painter, QCPVector2D(baseLine.p1())
9394 lowerEnding.draw(painter,
9395 QCPVector2D(baseLine.p1())
9261 - baseLineVector.normalized() * lowerEnding.realLength()
9396 - baseLineVector.normalized() * lowerEnding.realLength()
9262 * (lowerEnding.inverted() ? -1 : 1),
9397 * (lowerEnding.inverted() ? -1 : 1),
9263 -baseLineVector);
9398 -baseLineVector);
9264 if (upperEnding.style() != QCPLineEnding::esNone)
9399 if (upperEnding.style() != QCPLineEnding::esNone)
9265 upperEnding.draw(painter, QCPVector2D(baseLine.p2())
9400 upperEnding.draw(painter,
9401 QCPVector2D(baseLine.p2())
9266 + baseLineVector.normalized() * upperEnding.realLength()
9402 + baseLineVector.normalized() * upperEnding.realLength()
9267 * (upperEnding.inverted() ? -1 : 1),
9403 * (upperEnding.inverted() ? -1 : 1),
9268 baseLineVector);
9404 baseLineVector);
@@ -9524,12 +9660,15 void QCPAxisPainterPrivate::placeTickLabel(QCPPainter *painter, double position,
9524 cachedLabel->pixmap = QPixmap(labelData.rotatedTotalBounds.size()
9660 cachedLabel->pixmap = QPixmap(labelData.rotatedTotalBounds.size()
9525 * mParentPlot->bufferDevicePixelRatio());
9661 * mParentPlot->bufferDevicePixelRatio());
9526 #ifdef QCP_DEVICEPIXELRATIO_SUPPORTED
9662 #ifdef QCP_DEVICEPIXELRATIO_SUPPORTED
9663 #ifdef QCP_DEVICEPIXELRATIO_FLOAT
9664 cachedLabel->pixmap.setDevicePixelRatio(mParentPlot->devicePixelRatioF());
9665 #else
9527 cachedLabel->pixmap.setDevicePixelRatio(mParentPlot->devicePixelRatio());
9666 cachedLabel->pixmap.setDevicePixelRatio(mParentPlot->devicePixelRatio());
9528 #endif
9667 #endif
9668 #endif
9529 }
9669 }
9530 else
9670 else
9531 cachedLabel->pixmap = QPixmap(labelData.rotatedTotalBounds.size());
9671 cachedLabel->pixmap = QPixmap(labelData.rotatedTotalBounds.size());
9532 cachedLabel->pixmap = QPixmap(labelData.rotatedTotalBounds.size());
9533 cachedLabel->pixmap.fill(Qt::transparent);
9672 cachedLabel->pixmap.fill(Qt::transparent);
9534 QCPPainter cachePainter(&cachedLabel->pixmap);
9673 QCPPainter cachePainter(&cachedLabel->pixmap);
9535 cachePainter.setPen(painter->pen());
9674 cachePainter.setPen(painter->pen());
@@ -9894,8 +10033,8 void QCPAxisPainterPrivate::getMaxTickLabelSize(const QFont &font, const QString
9894 /* end of 'src/axis/axis.cpp' */
10033 /* end of 'src/axis/axis.cpp' */
9895
10034
9896
10035
9897 /* including file 'src/scatterstyle.cpp', size 17420 */
10036 /* including file 'src/scatterstyle.cpp', size 17450 */
9898 /* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
10037 /* commit 820d2282db70144c358c13433cd74b4175f9252b 2017-07-24 00:24:17 +0200 */
9899
10038
9900 ////////////////////////////////////////////////////////////////////////////////////////////////////
10039 ////////////////////////////////////////////////////////////////////////////////////////////////////
9901 //////////////////// QCPScatterStyle
10040 //////////////////// QCPScatterStyle
@@ -10065,8 +10204,8 QCPScatterStyle::QCPScatterStyle(const QPixmap &pixmap)
10065
10204
10066 The custom shape line will be drawn with \a pen and filled with \a brush. The size has a slightly
10205 The custom shape line will be drawn with \a pen and filled with \a brush. The size has a slightly
10067 different meaning than for built-in scatter points: The custom path will be drawn scaled by a
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
10207 factor of \a size/6.0. Since the default \a size is 6, the custom path will appear in its
10069 natural size by default. To double the size of the path for example, set \a size to 12.
10208 original size by default. To for example double the size of the path, set \a size to 12.
10070 */
10209 */
10071 QCPScatterStyle::QCPScatterStyle(const QPainterPath &customPath, const QPen &pen,
10210 QCPScatterStyle::QCPScatterStyle(const QPainterPath &customPath, const QPen &pen,
10072 const QBrush &brush, double size)
10211 const QBrush &brush, double size)
@@ -10253,10 +10392,9 void QCPScatterStyle::drawShape(QCPPainter *painter, double x, double y) const
10253 break;
10392 break;
10254 }
10393 }
10255 case ssDiamond: {
10394 case ssDiamond: {
10256 painter->drawLine(QLineF(x - w, y, x, y - w));
10395 QPointF lineArray[4]
10257 painter->drawLine(QLineF(x, y - w, x + w, y));
10396 = {QPointF(x - w, y), QPointF(x, y - w), QPointF(x + w, y), QPointF(x, y + w)};
10258 painter->drawLine(QLineF(x + w, y, x, y + w));
10397 painter->drawPolygon(lineArray, 4);
10259 painter->drawLine(QLineF(x, y + w, x - w, y));
10260 break;
10398 break;
10261 }
10399 }
10262 case ssStar: {
10400 case ssStar: {
@@ -10267,46 +10405,46 void QCPScatterStyle::drawShape(QCPPainter *painter, double x, double y) const
10267 break;
10405 break;
10268 }
10406 }
10269 case ssTriangle: {
10407 case ssTriangle: {
10270 painter->drawLine(QLineF(x - w, y + 0.755 * 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),
10271 painter->drawLine(QLineF(x + w, y + 0.755 * w, x, y - 0.977 * w));
10409 QPointF(x, y - 0.977 * w)};
10272 painter->drawLine(QLineF(x, y - 0.977 * w, x - w, y + 0.755 * w));
10410 painter->drawPolygon(lineArray, 3);
10273 break;
10411 break;
10274 }
10412 }
10275 case ssTriangleInverted: {
10413 case ssTriangleInverted: {
10276 painter->drawLine(QLineF(x - w, y - 0.755 * 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),
10277 painter->drawLine(QLineF(x + w, y - 0.755 * w, x, y + 0.977 * w));
10415 QPointF(x, y + 0.977 * w)};
10278 painter->drawLine(QLineF(x, y + 0.977 * w, x - w, y - 0.755 * w));
10416 painter->drawPolygon(lineArray, 3);
10279 break;
10417 break;
10280 }
10418 }
10281 case ssCrossSquare: {
10419 case ssCrossSquare: {
10420 painter->drawRect(QRectF(x - w, y - w, mSize, mSize));
10282 painter->drawLine(QLineF(x - w, y - w, x + w * 0.95, y + w * 0.95));
10421 painter->drawLine(QLineF(x - w, y - w, x + w * 0.95, y + w * 0.95));
10283 painter->drawLine(QLineF(x - w, y + w * 0.95, x + w * 0.95, y - w));
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 break;
10423 break;
10286 }
10424 }
10287 case ssPlusSquare: {
10425 case ssPlusSquare: {
10426 painter->drawRect(QRectF(x - w, y - w, mSize, mSize));
10288 painter->drawLine(QLineF(x - w, y, x + w * 0.95, y));
10427 painter->drawLine(QLineF(x - w, y, x + w * 0.95, y));
10289 painter->drawLine(QLineF(x, y + w, x, y - w));
10428 painter->drawLine(QLineF(x, y + w, x, y - w));
10290 painter->drawRect(QRectF(x - w, y - w, mSize, mSize));
10291 break;
10429 break;
10292 }
10430 }
10293 case ssCrossCircle: {
10431 case ssCrossCircle: {
10432 painter->drawEllipse(QPointF(x, y), w, w);
10294 painter->drawLine(QLineF(x - w * 0.707, y - w * 0.707, x + w * 0.670, y + w * 0.670));
10433 painter->drawLine(QLineF(x - w * 0.707, y - w * 0.707, x + w * 0.670, y + w * 0.670));
10295 painter->drawLine(QLineF(x - w * 0.707, y + w * 0.670, x + w * 0.670, y - w * 0.707));
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 break;
10435 break;
10298 }
10436 }
10299 case ssPlusCircle: {
10437 case ssPlusCircle: {
10438 painter->drawEllipse(QPointF(x, y), w, w);
10300 painter->drawLine(QLineF(x - w, y, x + w, y));
10439 painter->drawLine(QLineF(x - w, y, x + w, y));
10301 painter->drawLine(QLineF(x, y + w, x, y - w));
10440 painter->drawLine(QLineF(x, y + w, x, y - w));
10302 painter->drawEllipse(QPointF(x, y), w, w);
10303 break;
10441 break;
10304 }
10442 }
10305 case ssPeace: {
10443 case ssPeace: {
10444 painter->drawEllipse(QPointF(x, y), w, w);
10306 painter->drawLine(QLineF(x, y - w, x, y + w));
10445 painter->drawLine(QLineF(x, y - w, x, y + w));
10307 painter->drawLine(QLineF(x, y, x - w * 0.707, y + w * 0.707));
10446 painter->drawLine(QLineF(x, y, x - w * 0.707, y + w * 0.707));
10308 painter->drawLine(QLineF(x, y, x + w * 0.707, y + w * 0.707));
10447 painter->drawLine(QLineF(x, y, x + w * 0.707, y + w * 0.707));
10309 painter->drawEllipse(QPointF(x, y), w, w);
10310 break;
10448 break;
10311 }
10449 }
10312 case ssPixmap: {
10450 case ssPixmap: {
@@ -10337,8 +10475,8 void QCPScatterStyle::drawShape(QCPPainter *painter, double x, double y) const
10337
10475
10338 // amalgamation: add datacontainer.cpp
10476 // amalgamation: add datacontainer.cpp
10339
10477
10340 /* including file 'src/plottable.cpp', size 38861 */
10478 /* including file 'src/plottable.cpp', size 38845 */
10341 /* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
10479 /* commit b0bed12626f942821097f43091126b6fb7163122 2017-08-13 17:17:33 +0200 */
10342
10480
10343 ////////////////////////////////////////////////////////////////////////////////////////////////////
10481 ////////////////////////////////////////////////////////////////////////////////////////////////////
10344 //////////////////// QCPSelectionDecorator
10482 //////////////////// QCPSelectionDecorator
@@ -10376,8 +10514,8 void QCPScatterStyle::drawShape(QCPPainter *painter, double x, double y) const
10376 QCPSelectionDecorator::QCPSelectionDecorator()
10514 QCPSelectionDecorator::QCPSelectionDecorator()
10377 : mPen(QColor(80, 80, 255), 2.5),
10515 : mPen(QColor(80, 80, 255), 2.5),
10378 mBrush(Qt::NoBrush),
10516 mBrush(Qt::NoBrush),
10379 mScatterStyle(QCPScatterStyle::ssNone, QPen(Qt::blue, 2), Qt::NoBrush, 6.0),
10517 mScatterStyle(),
10380 mUsedScatterProperties(QCPScatterStyle::spPen),
10518 mUsedScatterProperties(QCPScatterStyle::spNone),
10381 mPlottable(0)
10519 mPlottable(0)
10382 {
10520 {
10383 }
10521 }
@@ -10420,6 +10558,8 void QCPSelectionDecorator::setScatterStyle(const QCPScatterStyle &scatterStyle,
10420 Use this method to define which properties of the scatter style (set via \ref setScatterStyle)
10558 Use this method to define which properties of the scatter style (set via \ref setScatterStyle)
10421 will be used for selected data segments. All properties of the scatter style that are not
10559 will be used for selected data segments. All properties of the scatter style that are not
10422 specified in \a properties will remain as specified in the plottable's original scatter style.
10560 specified in \a properties will remain as specified in the plottable's original scatter style.
10561
10562 \see QCPScatterStyle::ScatterProperty
10423 */
10563 */
10424 void QCPSelectionDecorator::setUsedScatterProperties(
10564 void QCPSelectionDecorator::setUsedScatterProperties(
10425 const QCPScatterStyle::ScatterProperties &properties)
10565 const QCPScatterStyle::ScatterProperties &properties)
@@ -12624,8 +12764,8 QCP::Interaction QCPAbstractItem::selectionCategory() const
12624 /* end of 'src/item.cpp' */
12764 /* end of 'src/item.cpp' */
12625
12765
12626
12766
12627 /* including file 'src/core.cpp', size 124243 */
12767 /* including file 'src/core.cpp', size 125027 */
12628 /* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
12768 /* commit 9ede7553208db59867d1ea9f1988cd90e3c7ffed 2017-08-13 17:25:24 +0200 */
12629
12769
12630 ////////////////////////////////////////////////////////////////////////////////////////////////////
12770 ////////////////////////////////////////////////////////////////////////////////////////////////////
12631 //////////////////// QCustomPlot
12771 //////////////////// QCustomPlot
@@ -12969,6 +13109,7 QCustomPlot::QCustomPlot(QWidget *parent)
12969 mOpenGl(false),
13109 mOpenGl(false),
12970 mMouseHasMoved(false),
13110 mMouseHasMoved(false),
12971 mMouseEventLayerable(0),
13111 mMouseEventLayerable(0),
13112 mMouseSignalLayerable(0),
12972 mReplotting(false),
13113 mReplotting(false),
12973 mReplotQueued(false),
13114 mReplotQueued(false),
12974 mOpenGlMultisamples(16),
13115 mOpenGlMultisamples(16),
@@ -12983,8 +13124,12 QCustomPlot::QCustomPlot(QWidget *parent)
12983 currentLocale.setNumberOptions(QLocale::OmitGroupSeparator);
13124 currentLocale.setNumberOptions(QLocale::OmitGroupSeparator);
12984 setLocale(currentLocale);
13125 setLocale(currentLocale);
12985 #ifdef QCP_DEVICEPIXELRATIO_SUPPORTED
13126 #ifdef QCP_DEVICEPIXELRATIO_SUPPORTED
13127 #ifdef QCP_DEVICEPIXELRATIO_FLOAT
13128 setBufferDevicePixelRatio(QWidget::devicePixelRatioF());
13129 #else
12986 setBufferDevicePixelRatio(QWidget::devicePixelRatio());
13130 setBufferDevicePixelRatio(QWidget::devicePixelRatio());
12987 #endif
13131 #endif
13132 #endif
12988
13133
12989 mOpenGlAntialiasedElementsBackup = mAntialiasedElements;
13134 mOpenGlAntialiasedElementsBackup = mAntialiasedElements;
12990 mOpenGlCacheLabelsBackup = mPlottingHints.testFlag(QCP::phCacheLabels);
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 This method allows to enable OpenGL plot rendering, for increased plotting performance of
13538 This method allows to enable OpenGL plot rendering, for increased plotting performance of
13390 graphically demanding plots (thick lines, translucent fills, etc.).
13539 graphically demanding plots (thick lines, translucent fills, etc.).
13391
13540
@@ -14934,12 +15083,20 void QCustomPlot::mousePressEvent(QMouseEvent *event)
14934 mSelectionRect->startSelection(event);
15083 mSelectionRect->startSelection(event);
14935 }
15084 }
14936 else {
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 QList<QVariant> details;
15088 QList<QVariant> details;
14939 QList<QCPLayerable *> candidates = layerableListAt(mMousePressPos, false, &details);
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 for (int i = 0; i < candidates.size(); ++i) {
15097 for (int i = 0; i < candidates.size(); ++i) {
14941 event->accept(); // default impl of QCPLayerable's mouse events ignore the event, in
15098 event->accept(); // default impl of QCPLayerable's mouse events call ignore() on the
14942 // that case propagate to next candidate in list
15099 // event, in that case propagate to next candidate in list
14943 candidates.at(i)->mousePressEvent(event, details.at(i));
15100 candidates.at(i)->mousePressEvent(event, details.at(i));
14944 if (event->isAccepted()) {
15101 if (event->isAccepted()) {
14945 mMouseEventLayerable = candidates.at(i);
15102 mMouseEventLayerable = candidates.at(i);
@@ -15010,22 +15167,25 void QCustomPlot::mouseReleaseEvent(QMouseEvent *event)
15010 processPointSelection(event);
15167 processPointSelection(event);
15011
15168
15012 // emit specialized click signals of QCustomPlot instance:
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 int dataIndex = 0;
15172 int dataIndex = 0;
15015 if (!mMouseEventLayerableDetails.value<QCPDataSelection>().isEmpty())
15173 if (!mMouseSignalLayerableDetails.value<QCPDataSelection>().isEmpty())
15016 dataIndex
15174 dataIndex
15017 = mMouseEventLayerableDetails.value<QCPDataSelection>().dataRange().begin();
15175 = mMouseSignalLayerableDetails.value<QCPDataSelection>().dataRange().begin();
15018 emit plottableClick(ap, dataIndex, event);
15176 emit plottableClick(ap, dataIndex, event);
15019 }
15177 }
15020 else if (QCPAxis *ax = qobject_cast<QCPAxis *>(mMouseEventLayerable))
15178 else if (QCPAxis *ax = qobject_cast<QCPAxis *>(mMouseSignalLayerable))
15021 emit axisClick(ax, mMouseEventLayerableDetails.value<QCPAxis::SelectablePart>(), event);
15179 emit axisClick(ax, mMouseSignalLayerableDetails.value<QCPAxis::SelectablePart>(),
15022 else if (QCPAbstractItem *ai = qobject_cast<QCPAbstractItem *>(mMouseEventLayerable))
15180 event);
15181 else if (QCPAbstractItem *ai = qobject_cast<QCPAbstractItem *>(mMouseSignalLayerable))
15023 emit itemClick(ai, event);
15182 emit itemClick(ai, event);
15024 else if (QCPLegend *lg = qobject_cast<QCPLegend *>(mMouseEventLayerable))
15183 else if (QCPLegend *lg = qobject_cast<QCPLegend *>(mMouseSignalLayerable))
15025 emit legendClick(lg, 0, event);
15184 emit legendClick(lg, 0, event);
15026 else if (QCPAbstractLegendItem *li
15185 else if (QCPAbstractLegendItem *li
15027 = qobject_cast<QCPAbstractLegendItem *>(mMouseEventLayerable))
15186 = qobject_cast<QCPAbstractLegendItem *>(mMouseSignalLayerable))
15028 emit legendClick(li->parentLegend(), li, event);
15187 emit legendClick(li->parentLegend(), li, event);
15188 mMouseSignalLayerable = 0;
15029 }
15189 }
15030
15190
15031 if (mSelectionRect && mSelectionRect->isActive()) // Note: if a click was detected above, the
15191 if (mSelectionRect && mSelectionRect->isActive()) // Note: if a click was detected above, the
@@ -16469,7 +16629,8 void QCPColorGradient::updateColorBuffer()
16469 hue -= 1.0;
16629 hue -= 1.0;
16470 if (useAlpha) {
16630 if (useAlpha) {
16471 const QRgb rgb
16631 const QRgb rgb
16472 = QColor::fromHsvF(hue, (1 - t) * lowHsv.saturationF()
16632 = QColor::fromHsvF(hue,
16633 (1 - t) * lowHsv.saturationF()
16473 + t * highHsv.saturationF(),
16634 + t * highHsv.saturationF(),
16474 (1 - t) * lowHsv.valueF() + t * highHsv.valueF())
16635 (1 - t) * lowHsv.valueF() + t * highHsv.valueF())
16475 .rgb();
16636 .rgb();
@@ -16479,7 +16640,8 void QCPColorGradient::updateColorBuffer()
16479 }
16640 }
16480 else {
16641 else {
16481 mColorBuffer[i]
16642 mColorBuffer[i]
16482 = QColor::fromHsvF(hue, (1 - t) * lowHsv.saturationF()
16643 = QColor::fromHsvF(hue,
16644 (1 - t) * lowHsv.saturationF()
16483 + t * highHsv.saturationF(),
16645 + t * highHsv.saturationF(),
16484 (1 - t) * lowHsv.valueF() + t * highHsv.valueF())
16646 (1 - t) * lowHsv.valueF() + t * highHsv.valueF())
16485 .rgb();
16647 .rgb();
@@ -16797,8 +16959,8 QCPSelectionDecoratorBracket::getPixelCoordinates(const QCPPlottableInterface1D
16797 /* end of 'src/selectiondecorator-bracket.cpp' */
16959 /* end of 'src/selectiondecorator-bracket.cpp' */
16798
16960
16799
16961
16800 /* including file 'src/layoutelements/layoutelement-axisrect.cpp', size 47509 */
16962 /* including file 'src/layoutelements/layoutelement-axisrect.cpp', size 47584 */
16801 /* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
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 new QCPAxis instance is created internally. QCustomPlot owns the returned axis, so if you want to
17214 new QCPAxis instance is created internally. QCustomPlot owns the returned axis, so if you want to
17053 remove an axis, use \ref removeAxis instead of deleting it manually.
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 previously created outside QCustomPlot. It is important to note that QCustomPlot takes ownership
17218 previously created outside QCustomPlot. It is important to note that QCustomPlot takes ownership
17057 of the axis, so you may not delete it afterwards. Further, the \a axis must have been created
17219 of the axis, so you may not delete it afterwards. Further, the \a axis must have been created
17058 with this axis rect as parent and with the same axis type as specified in \a type. If this is not
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 while (it.hasNext()) {
17327 while (it.hasNext()) {
17166 it.next();
17328 it.next();
17167 if (it.value().contains(axis)) {
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 mAxes[it.key()].removeOne(axis);
17336 mAxes[it.key()].removeOne(axis);
17169 if (qobject_cast<QCustomPlot *>(parentPlot())) // make sure this isn't called from
17337 if (qobject_cast<QCustomPlot *>(parentPlot())) // make sure this isn't called from
17170 // QObject dtor when QCustomPlot is
17338 // QObject dtor when QCustomPlot is
@@ -17934,9 +18102,6 void QCPAxisRect::layoutChanged()
17934 void QCPAxisRect::mousePressEvent(QMouseEvent *event, const QVariant &details)
18102 void QCPAxisRect::mousePressEvent(QMouseEvent *event, const QVariant &details)
17935 {
18103 {
17936 Q_UNUSED(details)
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 if (event->buttons() & Qt::LeftButton) {
18105 if (event->buttons() & Qt::LeftButton) {
17941 mDragging = true;
18106 mDragging = true;
17942 // initialize antialiasing backup in case we start dragging:
18107 // initialize antialiasing backup in case we start dragging:
@@ -17982,13 +18147,13 void QCPAxisRect::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos)
17982 break;
18147 break;
17983 if (ax->mScaleType == QCPAxis::stLinear) {
18148 if (ax->mScaleType == QCPAxis::stLinear) {
17984 double diff
18149 double diff
17985 = ax->pixelToCoord(mDragStart.x()) - ax->pixelToCoord(event->pos().x());
18150 = ax->pixelToCoord(startPos.x()) - ax->pixelToCoord(event->pos().x());
17986 ax->setRange(mDragStartHorzRange.at(i).lower + diff,
18151 ax->setRange(mDragStartHorzRange.at(i).lower + diff,
17987 mDragStartHorzRange.at(i).upper + diff);
18152 mDragStartHorzRange.at(i).upper + diff);
17988 }
18153 }
17989 else if (ax->mScaleType == QCPAxis::stLogarithmic) {
18154 else if (ax->mScaleType == QCPAxis::stLogarithmic) {
17990 double diff
18155 double diff
17991 = ax->pixelToCoord(mDragStart.x()) / ax->pixelToCoord(event->pos().x());
18156 = ax->pixelToCoord(startPos.x()) / ax->pixelToCoord(event->pos().x());
17992 ax->setRange(mDragStartHorzRange.at(i).lower * diff,
18157 ax->setRange(mDragStartHorzRange.at(i).lower * diff,
17993 mDragStartHorzRange.at(i).upper * diff);
18158 mDragStartHorzRange.at(i).upper * diff);
17994 }
18159 }
@@ -18004,13 +18169,13 void QCPAxisRect::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos)
18004 break;
18169 break;
18005 if (ax->mScaleType == QCPAxis::stLinear) {
18170 if (ax->mScaleType == QCPAxis::stLinear) {
18006 double diff
18171 double diff
18007 = ax->pixelToCoord(mDragStart.y()) - ax->pixelToCoord(event->pos().y());
18172 = ax->pixelToCoord(startPos.y()) - ax->pixelToCoord(event->pos().y());
18008 ax->setRange(mDragStartVertRange.at(i).lower + diff,
18173 ax->setRange(mDragStartVertRange.at(i).lower + diff,
18009 mDragStartVertRange.at(i).upper + diff);
18174 mDragStartVertRange.at(i).upper + diff);
18010 }
18175 }
18011 else if (ax->mScaleType == QCPAxis::stLogarithmic) {
18176 else if (ax->mScaleType == QCPAxis::stLogarithmic) {
18012 double diff
18177 double diff
18013 = ax->pixelToCoord(mDragStart.y()) / ax->pixelToCoord(event->pos().y());
18178 = ax->pixelToCoord(startPos.y()) / ax->pixelToCoord(event->pos().y());
18014 ax->setRange(mDragStartVertRange.at(i).lower * diff,
18179 ax->setRange(mDragStartVertRange.at(i).lower * diff,
18015 mDragStartVertRange.at(i).upper * diff);
18180 mDragStartVertRange.at(i).upper * diff);
18016 }
18181 }
@@ -18021,7 +18186,7 void QCPAxisRect::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos)
18021 {
18186 {
18022 if (mParentPlot->noAntialiasingOnDrag())
18187 if (mParentPlot->noAntialiasingOnDrag())
18023 mParentPlot->setNotAntialiasedElements(QCP::aeAll);
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 /* end of 'src/layoutelements/layoutelement-axisrect.cpp' */
18247 /* end of 'src/layoutelements/layoutelement-axisrect.cpp' */
18083
18248
18084
18249
18085 /* including file 'src/layoutelements/layoutelement-legend.cpp', size 30933 */
18250 /* including file 'src/layoutelements/layoutelement-legend.cpp', size 30971 */
18086 /* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
18251 /* commit 305808813c9c6451dca8399c2fc66d68ebd24b5e 2017-08-15 23:03:07 +0200 */
18087
18252
18088 ////////////////////////////////////////////////////////////////////////////////////////////////////
18253 ////////////////////////////////////////////////////////////////////////////////////////////////////
18089 //////////////////// QCPAbstractLegendItem
18254 //////////////////// QCPAbstractLegendItem
@@ -18286,9 +18451,7 void QCPAbstractLegendItem::deselectEvent(bool *selectionStateChanged)
18286 QCPLegend::setIconBorderPen and \ref QCPLegend::setIconTextPadding.
18451 QCPLegend::setIconBorderPen and \ref QCPLegend::setIconTextPadding.
18287
18452
18288 The function \ref QCPAbstractPlottable::addToLegend/\ref QCPAbstractPlottable::removeFromLegend
18453 The function \ref QCPAbstractPlottable::addToLegend/\ref QCPAbstractPlottable::removeFromLegend
18289 creates/removes legend items of this type in the default implementation. However, these functions
18454 creates/removes legend items of this type.
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.
18292
18455
18293 Since QCPLegend is based on QCPLayoutGrid, a legend item itself is just a subclass of
18456 Since QCPLegend is based on QCPLayoutGrid, a legend item itself is just a subclass of
18294 QCPLayoutElement. While it could be added to a legend (or any other layout) via the normal layout
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 QSize iconSize = mParentLegend->iconSize();
18558 QSize iconSize = mParentLegend->iconSize();
18396 textRect = fontMetrics.boundingRect(0, 0, 0, iconSize.height(), Qt::TextDontClip,
18559 textRect = fontMetrics.boundingRect(0, 0, 0, iconSize.height(), Qt::TextDontClip,
18397 mPlottable->name());
18560 mPlottable->name());
18398 result.setWidth(iconSize.width() + mParentLegend->iconTextPadding() + textRect.width()
18561 result.setWidth(iconSize.width() + mParentLegend->iconTextPadding() + textRect.width());
18399 + mMargins.left() + mMargins.right());
18562 result.setHeight(qMax(textRect.height(), iconSize.height()));
18400 result.setHeight(qMax(textRect.height(), iconSize.height()) + mMargins.top()
18401 + mMargins.bottom());
18402 return result;
18563 return result;
18403 }
18564 }
18404
18565
@@ -18412,10 +18573,14 QSize QCPPlottableLegendItem::minimumSizeHint() const
18412
18573
18413 A legend is a small box somewhere in the plot which lists plottables with their name and icon.
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
18576 A legend is populated with legend items by calling \ref QCPAbstractPlottable::addToLegend on the
18416 respective legend item can be removed with \ref QCPAbstractPlottable::removeFromLegend. However,
18577 plottable, for which a legend item shall be created. In the case of the main legend (\ref
18417 QCPLegend also offers an interface to add and manipulate legend items directly: \ref item, \ref
18578 QCustomPlot::legend), simply adding plottables to the plot while \ref
18418 itemWithPlottable, \ref itemCount, \ref addItem, \ref removeItem, etc.
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 Since \ref QCPLegend derives from \ref QCPLayoutGrid, it can be placed in any position a \ref
18585 Since \ref QCPLegend derives from \ref QCPLayoutGrid, it can be placed in any position a \ref
18421 QCPLayoutElement may be positioned. The legend items are themselves \ref QCPLayoutElement
18586 QCPLayoutElement may be positioned. The legend items are themselves \ref QCPLayoutElement
@@ -19012,8 +19177,8 void QCPLegend::parentPlotInitialized(QCustomPlot *parentPlot)
19012 /* end of 'src/layoutelements/layoutelement-legend.cpp' */
19177 /* end of 'src/layoutelements/layoutelement-legend.cpp' */
19013
19178
19014
19179
19015 /* including file 'src/layoutelements/layoutelement-textelement.cpp', size 12759 */
19180 /* including file 'src/layoutelements/layoutelement-textelement.cpp', size 12561 */
19016 /* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
19181 /* commit a872eb91ec087561efd83dd9cb041a26ab95ce55 2017-07-31 00:21:41 +0200 */
19017
19182
19018 ////////////////////////////////////////////////////////////////////////////////////////////////////
19183 ////////////////////////////////////////////////////////////////////////////////////////////////////
19019 //////////////////// QCPTextElement
19184 //////////////////// QCPTextElement
@@ -19299,10 +19464,7 void QCPTextElement::draw(QCPPainter *painter)
19299 QSize QCPTextElement::minimumSizeHint() const
19464 QSize QCPTextElement::minimumSizeHint() const
19300 {
19465 {
19301 QFontMetrics metrics(mFont);
19466 QFontMetrics metrics(mFont);
19302 QSize result = metrics.boundingRect(0, 0, 0, 0, Qt::AlignCenter, mText).size();
19467 return 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;
19306 }
19468 }
19307
19469
19308 /* inherits documentation from base class */
19470 /* inherits documentation from base class */
@@ -19310,7 +19472,6 QSize QCPTextElement::maximumSizeHint() const
19310 {
19472 {
19311 QFontMetrics metrics(mFont);
19473 QFontMetrics metrics(mFont);
19312 QSize result = metrics.boundingRect(0, 0, 0, 0, Qt::AlignCenter, mText).size();
19474 QSize result = metrics.boundingRect(0, 0, 0, 0, Qt::AlignCenter, mText).size();
19313 result.rheight() += mMargins.top() + mMargins.bottom();
19314 result.setWidth(QWIDGETSIZE_MAX);
19475 result.setWidth(QWIDGETSIZE_MAX);
19315 return result;
19476 return result;
19316 }
19477 }
@@ -19838,10 +19999,12 void QCPColorScale::update(UpdatePhase phase)
19838 switch (phase) {
19999 switch (phase) {
19839 case upMargins: {
20000 case upMargins: {
19840 if (mType == QCPAxis::atBottom || mType == QCPAxis::atTop) {
20001 if (mType == QCPAxis::atBottom || mType == QCPAxis::atTop) {
19841 setMaximumSize(QWIDGETSIZE_MAX, mBarWidth + mAxisRect.data()->margins().top()
20002 setMaximumSize(QWIDGETSIZE_MAX,
19842 + mAxisRect.data()->margins().bottom()
20003 mBarWidth + mAxisRect.data()->margins().top()
19843 + margins().top() + margins().bottom());
20004 + mAxisRect.data()->margins().bottom() + margins().top()
19844 setMinimumSize(0, mBarWidth + mAxisRect.data()->margins().top()
20005 + margins().bottom());
20006 setMinimumSize(0,
20007 mBarWidth + mAxisRect.data()->margins().top()
19845 + mAxisRect.data()->margins().bottom() + margins().top()
20008 + mAxisRect.data()->margins().bottom() + margins().top()
19846 + margins().bottom());
20009 + margins().bottom());
19847 }
20010 }
@@ -20100,8 +20263,8 void QCPColorScaleAxisRectPrivate::axisSelectableChanged(QCPAxis::SelectablePart
20100 /* end of 'src/layoutelements/layoutelement-colorscale.cpp' */
20263 /* end of 'src/layoutelements/layoutelement-colorscale.cpp' */
20101
20264
20102
20265
20103 /* including file 'src/plottables/plottable-graph.cpp', size 72363 */
20266 /* including file 'src/plottables/plottable-graph.cpp', size 73960 */
20104 /* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
20267 /* commit 7e7381ef4f218e004d72a218820634fff0959d1b 2017-08-02 00:02:36 +0200 */
20105
20268
20106 ////////////////////////////////////////////////////////////////////////////////////////////////////
20269 ////////////////////////////////////////////////////////////////////////////////////////////////////
20107 //////////////////// QCPGraphData
20270 //////////////////// QCPGraphData
@@ -20649,6 +20812,12 void QCPGraph::getLines(QVector<QPointF> *lines, const QCPDataRange &dataRange)
20649 if (mLineStyle != lsNone)
20812 if (mLineStyle != lsNone)
20650 getOptimizedLineData(&lineData, begin, end);
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 switch (mLineStyle) {
20821 switch (mLineStyle) {
20653 case lsNone:
20822 case lsNone:
20654 lines->clear();
20823 lines->clear();
@@ -20704,6 +20873,13 void QCPGraph::getScatters(QVector<QPointF> *scatters, const QCPDataRange &dataR
20704
20873
20705 QVector<QCPGraphData> data;
20874 QVector<QCPGraphData> data;
20706 getOptimizedScatterData(&data, begin, end);
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 scatters->resize(data.size());
20883 scatters->resize(data.size());
20708 if (keyAxis->orientation() == Qt::Vertical) {
20884 if (keyAxis->orientation() == Qt::Vertical) {
20709 for (int i = 0; i < data.size(); ++i) {
20885 for (int i = 0; i < data.size(); ++i) {
@@ -20744,8 +20920,6 QVector<QPointF> QCPGraph::dataToLines(const QVector<QCPGraphData> &data) const
20744 return result;
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 result.resize(data.size());
20923 result.resize(data.size());
20750
20924
20751 // transform data points to pixels:
20925 // transform data points to pixels:
@@ -20786,8 +20960,6 QVector<QPointF> QCPGraph::dataToStepLeftLines(const QVector<QCPGraphData> &data
20786 return result;
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 result.resize(data.size() * 2);
20963 result.resize(data.size() * 2);
20792
20964
20793 // calculate steps from data and transform to pixel coordinates:
20965 // calculate steps from data and transform to pixel coordinates:
@@ -20838,8 +21010,6 QVector<QPointF> QCPGraph::dataToStepRightLines(const QVector<QCPGraphData> &dat
20838 return result;
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 result.resize(data.size() * 2);
21013 result.resize(data.size() * 2);
20844
21014
20845 // calculate steps from data and transform to pixel coordinates:
21015 // calculate steps from data and transform to pixel coordinates:
@@ -20890,8 +21060,6 QVector<QPointF> QCPGraph::dataToStepCenterLines(const QVector<QCPGraphData> &da
20890 return result;
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 result.resize(data.size() * 2);
21063 result.resize(data.size() * 2);
20896
21064
20897 // calculate steps from data and transform to pixel coordinates:
21065 // calculate steps from data and transform to pixel coordinates:
@@ -20954,8 +21122,7 QVector<QPointF> QCPGraph::dataToImpulseLines(const QVector<QCPGraphData> &data)
20954 return result;
21122 return result;
20955 }
21123 }
20956
21124
20957 result.resize(data.size()
21125 result.resize(data.size() * 2);
20958 * 2); // no need to reserve 2 extra points because impulse plot has no fill
20959
21126
20960 // transform data points to pixels:
21127 // transform data points to pixels:
20961 if (keyAxis->orientation() == Qt::Vertical) {
21128 if (keyAxis->orientation() == Qt::Vertical) {
@@ -20984,15 +21151,16 QVector<QPointF> QCPGraph::dataToImpulseLines(const QVector<QCPGraphData> &data)
20984
21151
20985 Draws the fill of the graph using the specified \a painter, with the currently set brush.
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
21157 In order to handle NaN Data points correctly (the fill needs to be split into disjoint areas),
20990 required and two extra points at the zero-value-line, which are added by \ref addFillBasePoints
21158 this method first determines a list of non-NaN segments with \ref getNonNanSegments, on which to
20991 and removed by \ref removeFillBasePoints after the fill drawing is done.
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
21163 Pass the points of this graph's line as \a lines, in pixel coordinates.
20994 mChannelFillGraph), the more complex polygon is calculated with the \ref getChannelFillPolygon
20995 function, and then drawn.
20996
21164
20997 \see drawLinePlot, drawImpulsePlot, drawScatterPlot
21165 \see drawLinePlot, drawImpulsePlot, drawScatterPlot
20998 */
21166 */
@@ -21004,15 +21172,25 void QCPGraph::drawFill(QCPPainter *painter, QVector<QPointF> *lines) const
21004 return;
21172 return;
21005
21173
21006 applyFillAntialiasingHint(painter);
21174 applyFillAntialiasingHint(painter);
21175 QVector<QCPDataRange> segments = getNonNanSegments(lines, keyAxis()->orientation());
21007 if (!mChannelFillGraph) {
21176 if (!mChannelFillGraph) {
21008 // draw base fill under graph, fill goes all the way to the zero-value-line:
21177 // draw base fill under graph, fill goes all the way to the zero-value-line:
21009 addFillBasePoints(lines);
21178 for (int i = 0; i < segments.size(); ++i)
21010 painter->drawPolygon(QPolygonF(*lines));
21179 painter->drawPolygon(getFillPolygon(lines, segments.at(i)));
21011 removeFillBasePoints(lines);
21012 }
21180 }
21013 else {
21181 else {
21014 // draw channel fill between this graph and mChannelFillGraph:
21182 // draw fill between this graph and mChannelFillGraph:
21015 painter->drawPolygon(getChannelFillPolygon(lines));
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 else // don't use adaptive sampling algorithm, transfer points one-to-one from the data
21383 else // don't use adaptive sampling algorithm, transfer points one-to-one from the data
21206 // container into the output
21384 // container into the output
21207 {
21385 {
21208 QCPGraphDataContainer::const_iterator it = begin;
21386 lineData->resize(dataCount);
21209 lineData->reserve(dataCount + 2); // +2 for possible fill end points
21387 std::copy(begin, end, lineData->begin());
21210 while (it != end) {
21211 lineData->append(*it);
21212 ++it;
21213 }
21214 }
21388 }
21215 }
21389 }
21216
21390
@@ -21481,149 +21655,175 void QCPGraph::getVisibleDataBounds(QCPGraphDataContainer::const_iterator &begin
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
21658 This method goes through the passed points in \a lineData and returns a list of the segments
21485 points. If the graph needs to be filled, two additional points need to be added at the
21659 which don't contain NaN data points.
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.
21490
21660
21491 The expanding of \a lines by two points will not cause unnecessary memory reallocations, because
21661 \a keyOrientation defines whether the \a x or \a y member of the passed QPointF is used to check
21492 the data vector generation functions (e.g. \ref getLines) reserve two extra points when they
21662 for NaN. If \a keyOrientation is \c Qt::Horizontal, the \a y member is checked, if it is \c
21493 allocate memory for \a lines.
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) {
21670 QVector<QCPDataRange> result;
21500 qDebug() << Q_FUNC_INFO << "invalid key axis";
21671 const int n = lineData->size();
21501 return;
21672
21673 QCPDataRange currentSegment(-1, -1);
21674 int i = 0;
21675
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);
21502 }
21687 }
21503 if (!lines) {
21504 qDebug() << Q_FUNC_INFO << "passed null as lineData";
21505 return;
21506 }
21688 }
21507 if (lines->isEmpty())
21689 else // keyOrientation == Qt::Vertical
21508 return;
21690 {
21509
21691 while (i < n) {
21510 // append points that close the polygon fill at the key axis:
21692 while (i < n && qIsNaN(lineData->at(i).x())) // seek next non-NaN data point
21511 if (mKeyAxis.data()->orientation() == Qt::Vertical) {
21693 ++i;
21512 *lines << upperFillBasePoint(lines->last().y());
21694 if (i == n)
21513 *lines << lowerFillBasePoint(lines->first().y());
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);
21514 }
21701 }
21515 else {
21516 *lines << upperFillBasePoint(lines->last().x());
21517 *lines << lowerFillBasePoint(lines->first().x());
21518 }
21702 }
21703 return result;
21519 }
21704 }
21520
21705
21521 /*! \internal
21706 /*! \internal
21522
21707
21523 removes the two points from \a lines that were added by \ref addFillBasePoints.
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.
21524
21710
21525 \see addFillBasePoints, lowerFillBasePoint, upperFillBasePoint
21711 It returns all pairs of segments (the first from \a thisSegments, the second from \a
21526 */
21712 otherSegments), which overlap in plot coordinates.
21527 void QCPGraph::removeFillBasePoints(QVector<QPointF> *lines) const
21528 {
21529 if (!lines) {
21530 qDebug() << Q_FUNC_INFO << "passed null as lineData";
21531 return;
21532 }
21533 if (lines->isEmpty())
21534 return;
21535
21713
21536 lines->remove(lines->size() - 2, 2);
21714 This method is useful in the case of a channel fill between two graphs, when only those non-NaN
21537 }
21715 segments which actually overlap in their key coordinate shall be considered for drawing a channel
21716 fill polygon.
21538
21717
21539 /*! \internal
21718 It is assumed that the passed segments in \a thisSegments are ordered ascending by index, and
21540
21719 that the segments don't overlap themselves. The same is assumed for the segments in \a
21541 called by \ref addFillBasePoints to conveniently assign the point which closes the fill polygon
21720 otherSegments. This is fulfilled when the segments are obtained via \ref getNonNanSegments.
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.
21546
21721
21547 \a lowerKey will be the the key (in pixels) of the returned point. Depending on whether the key
21722 \see getNonNanSegments, segmentsIntersect, drawFill, getChannelFillPolygon
21548 axis is horizontal or vertical, \a lowerKey will end up as the x or y value of the returned
21549 point, respectively.
21550
21551 \see upperFillBasePoint, addFillBasePoints
21552 */
21723 */
21553 QPointF QCPGraph::lowerFillBasePoint(double lowerKey) 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
21554 {
21727 {
21555 QCPAxis *keyAxis = mKeyAxis.data();
21728 QVector<QPair<QCPDataRange, QCPDataRange> > result;
21556 QCPAxis *valueAxis = mValueAxis.data();
21729 if (thisData->isEmpty() || otherData->isEmpty() || thisSegments.isEmpty()
21557 if (!keyAxis || !valueAxis) {
21730 || otherSegments.isEmpty())
21558 qDebug() << Q_FUNC_INFO << "invalid key or value axis";
21731 return result;
21559 return QPointF();
21560 }
21561
21732
21562 QPointF point;
21733 int thisIndex = 0;
21563 if (valueAxis->scaleType() == QCPAxis::stLinear) {
21734 int otherIndex = 0;
21564 if (keyAxis->axisType() == QCPAxis::atLeft) {
21735 const bool verticalKey = mKeyAxis->orientation() == Qt::Vertical;
21565 point.setX(valueAxis->coordToPixel(0));
21736 while (thisIndex < thisSegments.size() && otherIndex < otherSegments.size()) {
21566 point.setY(lowerKey);
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;
21567 }
21742 }
21568 else if (keyAxis->axisType() == QCPAxis::atRight) {
21743 if (otherSegments.at(otherIndex).size()
21569 point.setX(valueAxis->coordToPixel(0));
21744 < 2) // segments with fewer than two points won't have a fill anyhow
21570 point.setY(lowerKey);
21745 {
21746 ++otherIndex;
21747 continue;
21571 }
21748 }
21572 else if (keyAxis->axisType() == QCPAxis::atTop) {
21749 double thisLower, thisUpper, otherLower, otherUpper;
21573 point.setX(lowerKey);
21750 if (!verticalKey) {
21574 point.setY(valueAxis->coordToPixel(0));
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();
21575 }
21755 }
21576 else if (keyAxis->axisType() == QCPAxis::atBottom) {
21756 else {
21577 point.setX(lowerKey);
21757 thisLower = thisData->at(thisSegments.at(thisIndex).begin()).y();
21578 point.setY(valueAxis->coordToPixel(0));
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();
21579 }
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;
21580 }
21774 }
21581 else // valueAxis->mScaleType == QCPAxis::stLogarithmic
21775
21776 return result;
21777 }
21778
21779 /*! \internal
21780
21781 Returns whether the segments defined by the coordinates (aLower, aUpper) and (bLower, bUpper)
21782 have overlap.
21783
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.
21788
21789 It is assumed that the lower bounds always have smaller or equal values than the upper bounds.
21790
21791 \see getOverlappingSegments
21792 */
21793 bool QCPGraph::segmentsIntersect(double aLower, double aUpper, double bLower, double bUpper,
21794 int &bPrecedence) const
21582 {
21795 {
21583 // In logarithmic scaling we can't just draw to value zero so we just fill all the way
21796 bPrecedence = 0;
21584 // to the axis which is in the direction towards zero
21797 if (aLower > bUpper) {
21585 if (keyAxis->orientation() == Qt::Vertical) {
21798 bPrecedence = -1;
21586 if ((valueAxis->range().upper < 0 && !valueAxis->rangeReversed())
21799 return false;
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 }
21800 }
21596 else if (keyAxis->axisType() == QCPAxis::atTop
21801 else if (bLower > aUpper) {
21597 || keyAxis->axisType() == QCPAxis::atBottom) {
21802 bPrecedence = 1;
21598 point.setX(lowerKey);
21803 return false;
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 }
21804 }
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 /*! \internal
21815 /*! \internal
21613
21816
21614 called by \ref addFillBasePoints to conveniently assign the point which closes the fill
21817 Returns the point which closes the fill polygon on the zero-value-line parallel to the key axis.
21615 polygon on the upper side of the zero-value-line parallel to the key axis. The logarithmic axis
21818 The logarithmic axis scale case is a bit special, since the zero-value-line in pixel coordinates
21616 scale case is a bit special, since the zero-value-line in pixel coordinates is in positive or
21819 is in positive or negative infinity. So this case is handled separately by just closing the fill
21617 negative infinity. So this case is handled separately by just closing the fill polygon on the
21820 polygon on the axis which lies in the direction towards the zero value.
21618 axis which lies in the direction towards the zero value.
21619
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
21821
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 QCPAxis *keyAxis = mKeyAxis.data();
21828 QCPAxis *keyAxis = mKeyAxis.data();
21629 QCPAxis *valueAxis = mValueAxis.data();
21829 QCPAxis *valueAxis = mValueAxis.data();
@@ -21632,23 +21832,16 QPointF QCPGraph::upperFillBasePoint(double upperKey) const
21632 return QPointF();
21832 return QPointF();
21633 }
21833 }
21634
21834
21635 QPointF point;
21835 QPointF result;
21636 if (valueAxis->scaleType() == QCPAxis::stLinear) {
21836 if (valueAxis->scaleType() == QCPAxis::stLinear) {
21637 if (keyAxis->axisType() == QCPAxis::atLeft) {
21837 if (keyAxis->orientation() == Qt::Horizontal) {
21638 point.setX(valueAxis->coordToPixel(0));
21838 result.setX(matchingDataPoint.x());
21639 point.setY(upperKey);
21839 result.setY(valueAxis->coordToPixel(0));
21640 }
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 }
21840 }
21649 else if (keyAxis->axisType() == QCPAxis::atBottom) {
21841 else // keyAxis->orientation() == Qt::Vertical
21650 point.setX(upperKey);
21842 {
21651 point.setY(valueAxis->coordToPixel(0));
21843 result.setX(valueAxis->coordToPixel(0));
21844 result.setY(matchingDataPoint.y());
21652 }
21845 }
21653 }
21846 }
21654 else // valueAxis->mScaleType == QCPAxis::stLogarithmic
21847 else // valueAxis->mScaleType == QCPAxis::stLogarithmic
@@ -21661,40 +21854,80 QPointF QCPGraph::upperFillBasePoint(double upperKey) const
21661 // negative, zero
21854 // negative, zero
21662 // is on opposite
21855 // is on opposite
21663 // side of key axis
21856 // side of key axis
21664 point.setX(keyAxis->axisRect()->right());
21857 result.setX(keyAxis->axisRect()->right());
21665 else
21858 else
21666 point.setX(keyAxis->axisRect()->left());
21859 result.setX(keyAxis->axisRect()->left());
21667 point.setY(upperKey);
21860 result.setY(matchingDataPoint.y());
21668 }
21861 }
21669 else if (keyAxis->axisType() == QCPAxis::atTop
21862 else if (keyAxis->axisType() == QCPAxis::atTop
21670 || keyAxis->axisType() == QCPAxis::atBottom) {
21863 || keyAxis->axisType() == QCPAxis::atBottom) {
21671 point.setX(upperKey);
21864 result.setX(matchingDataPoint.x());
21672 if ((valueAxis->range().upper < 0 && !valueAxis->rangeReversed())
21865 if ((valueAxis->range().upper < 0 && !valueAxis->rangeReversed())
21673 || (valueAxis->range().upper > 0 && valueAxis->rangeReversed())) // if range is
21866 || (valueAxis->range().upper > 0 && valueAxis->rangeReversed())) // if range is
21674 // negative, zero
21867 // negative, zero
21675 // is on opposite
21868 // is on opposite
21676 // side of key axis
21869 // side of key axis
21677 point.setY(keyAxis->axisRect()->top());
21870 result.setY(keyAxis->axisRect()->top());
21678 else
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 /*! \internal
21878 /*! \internal
21686
21879
21687 Generates the polygon needed for drawing channel fills between this graph and the graph specified
21880 Returns the polygon needed for drawing normal fills between this graph and the key axis.
21688 in \a mChannelFillGraph (see \ref setChannelFillGraph). The data points representing the line of
21881
21689 this graph in pixel coordinates must be passed in \a lines, the corresponding points of the other
21882 Pass the graph's data points (in pixel coordinates) as \a lineData, and specify the \a segment
21690 graph are generated by calling its \ref getLines method.
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.
21691
21891
21692 This method may return an empty polygon if the key ranges of the two graphs have no overlap of if
21892 \see drawFill, getNonNanSegments
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.
21696 */
21893 */
21697 const QPolygonF QCPGraph::getChannelFillPolygon(const QVector<QPointF> *lines) const
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
21926 */
21927 const QPolygonF QCPGraph::getChannelFillPolygon(const QVector<QPointF> *thisData,
21928 QCPDataRange thisSegment,
21929 const QVector<QPointF> *otherData,
21930 QCPDataRange otherSegment) const
21698 {
21931 {
21699 if (!mChannelFillGraph)
21932 if (!mChannelFillGraph)
21700 return QPolygonF();
21933 return QPolygonF();
@@ -21715,55 +21948,35 const QPolygonF QCPGraph::getChannelFillPolygon(const QVector<QPointF> *lines) c
21715 // fits, valueAxis will fit too, because it's always orthogonal to
21948 // fits, valueAxis will fit too, because it's always orthogonal to
21716 // keyAxis)
21949 // keyAxis)
21717
21950
21718 if (lines->isEmpty())
21951 if (thisData->isEmpty())
21719 return QPolygonF();
21952 return QPolygonF();
21720 QVector<QPointF> otherData;
21953 QVector<QPointF> thisSegmentData(thisSegment.size());
21721 mChannelFillGraph.data()->getLines(&otherData,
21954 QVector<QPointF> otherSegmentData(otherSegment.size());
21722 QCPDataRange(0, mChannelFillGraph.data()->dataCount()));
21955 std::copy(thisData->constBegin() + thisSegment.begin(),
21723 if (otherData.isEmpty())
21956 thisData->constBegin() + thisSegment.end(), thisSegmentData.begin());
21724 return QPolygonF();
21957 std::copy(otherData->constBegin() + otherSegment.begin(),
21725 QVector<QPointF> thisData;
21958 otherData->constBegin() + otherSegment.end(), otherSegmentData.begin());
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
21734 // pointers to be able to swap them, depending which data range needs cropping:
21959 // pointers to be able to swap them, depending which data range needs cropping:
21735 QVector<QPointF> *staticData = &thisData;
21960 QVector<QPointF> *staticData = &thisSegmentData;
21736 QVector<QPointF> *croppedData = &otherData;
21961 QVector<QPointF> *croppedData = &otherSegmentData;
21737
21962
21738 // crop both vectors to ranges in which the keys overlap (which coord is key, depends on
21963 // crop both vectors to ranges in which the keys overlap (which coord is key, depends on
21739 // axisType):
21964 // axisType):
21740 if (keyAxis->orientation() == Qt::Horizontal) {
21965 if (keyAxis->orientation() == Qt::Horizontal) {
21741 // x is key
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 // crop lower bound:
21967 // crop lower bound:
21755 if (staticData->first().x() < croppedData->first().x()) // other one must be cropped
21968 if (staticData->first().x() < croppedData->first().x()) // other one must be cropped
21756 qSwap(staticData, croppedData);
21969 qSwap(staticData, croppedData);
21757 int lowBound = findIndexBelowX(croppedData, staticData->first().x());
21970 const int lowBound = findIndexBelowX(croppedData, staticData->first().x());
21758 if (lowBound == -1)
21971 if (lowBound == -1)
21759 return QPolygonF(); // key ranges have no overlap
21972 return QPolygonF(); // key ranges have no overlap
21760 croppedData->remove(0, lowBound);
21973 croppedData->remove(0, lowBound);
21761 // set lowest point of cropped data to fit exactly key position of first static data
21974 // set lowest point of cropped data to fit exactly key position of first static data point
21762 // point via linear interpolation:
21975 // via linear interpolation:
21763 if (croppedData->size() < 2)
21976 if (croppedData->size() < 2)
21764 return QPolygonF(); // need at least two points for interpolation
21977 return QPolygonF(); // need at least two points for interpolation
21765 double slope;
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 slope = (croppedData->at(1).y() - croppedData->at(0).y())
21980 slope = (croppedData->at(1).y() - croppedData->at(0).y())
21768 / (croppedData->at(1).x() - croppedData->at(0).x());
21981 / (croppedData->at(1).x() - croppedData->at(0).x());
21769 else
21982 else
@@ -21779,12 +21992,12 const QPolygonF QCPGraph::getChannelFillPolygon(const QVector<QPointF> *lines) c
21779 if (highBound == -1)
21992 if (highBound == -1)
21780 return QPolygonF(); // key ranges have no overlap
21993 return QPolygonF(); // key ranges have no overlap
21781 croppedData->remove(highBound + 1, croppedData->size() - (highBound + 1));
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
21995 // set highest point of cropped data to fit exactly key position of last static data point
21783 // point via linear interpolation:
21996 // via linear interpolation:
21784 if (croppedData->size() < 2)
21997 if (croppedData->size() < 2)
21785 return QPolygonF(); // need at least two points for interpolation
21998 return QPolygonF(); // need at least two points for interpolation
21786 int li = croppedData->size() - 1; // last index
21999 const int li = croppedData->size() - 1; // last index
21787 if (croppedData->at(li).x() - croppedData->at(li - 1).x() != 0)
22000 if (!qFuzzyCompare(croppedData->at(li).x(), croppedData->at(li - 1).x()))
21788 slope = (croppedData->at(li).y() - croppedData->at(li - 1).y())
22001 slope = (croppedData->at(li).y() - croppedData->at(li - 1).y())
21789 / (croppedData->at(li).x() - croppedData->at(li - 1).x());
22002 / (croppedData->at(li).x() - croppedData->at(li - 1).x());
21790 else
22003 else
@@ -21796,36 +22009,20 const QPolygonF QCPGraph::getChannelFillPolygon(const QVector<QPointF> *lines) c
21796 else // mKeyAxis->orientation() == Qt::Vertical
22009 else // mKeyAxis->orientation() == Qt::Vertical
21797 {
22010 {
21798 // y is key
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 // crop lower bound:
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 qSwap(staticData, croppedData);
22014 qSwap(staticData, croppedData);
21818 int lowBound = findIndexAboveY(croppedData, staticData->first().y());
22015 int lowBound = findIndexBelowY(croppedData, staticData->first().y());
21819 if (lowBound == -1)
22016 if (lowBound == -1)
21820 return QPolygonF(); // key ranges have no overlap
22017 return QPolygonF(); // key ranges have no overlap
21821 croppedData->remove(0, lowBound);
22018 croppedData->remove(0, lowBound);
21822 // set lowest point of cropped data to fit exactly key position of first static data
22019 // set lowest point of cropped data to fit exactly key position of first static data point
21823 // point via linear interpolation:
22020 // via linear interpolation:
21824 if (croppedData->size() < 2)
22021 if (croppedData->size() < 2)
21825 return QPolygonF(); // need at least two points for interpolation
22022 return QPolygonF(); // need at least two points for interpolation
21826 double slope;
22023 double slope;
21827 if (croppedData->at(1).y() - croppedData->at(0).y()
22024 if (!qFuzzyCompare(croppedData->at(1).y(),
21828 != 0) // avoid division by zero in step plots
22025 croppedData->at(0).y())) // avoid division by zero in step plots
21829 slope = (croppedData->at(1).x() - croppedData->at(0).x())
22026 slope = (croppedData->at(1).x() - croppedData->at(0).x())
21830 / (croppedData->at(1).y() - croppedData->at(0).y());
22027 / (croppedData->at(1).y() - croppedData->at(0).y());
21831 else
22028 else
@@ -21835,19 +22032,19 const QPolygonF QCPGraph::getChannelFillPolygon(const QVector<QPointF> *lines) c
21835 (*croppedData)[0].setY(staticData->first().y());
22032 (*croppedData)[0].setY(staticData->first().y());
21836
22033
21837 // crop upper bound:
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 qSwap(staticData, croppedData);
22036 qSwap(staticData, croppedData);
21840 int highBound = findIndexBelowY(croppedData, staticData->last().y());
22037 int highBound = findIndexAboveY(croppedData, staticData->last().y());
21841 if (highBound == -1)
22038 if (highBound == -1)
21842 return QPolygonF(); // key ranges have no overlap
22039 return QPolygonF(); // key ranges have no overlap
21843 croppedData->remove(highBound + 1, croppedData->size() - (highBound + 1));
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
22041 // set highest point of cropped data to fit exactly key position of last static data point
21845 // point via linear interpolation:
22042 // via linear interpolation:
21846 if (croppedData->size() < 2)
22043 if (croppedData->size() < 2)
21847 return QPolygonF(); // need at least two points for interpolation
22044 return QPolygonF(); // need at least two points for interpolation
21848 int li = croppedData->size() - 1; // last index
22045 int li = croppedData->size() - 1; // last index
21849 if (croppedData->at(li).y() - croppedData->at(li - 1).y()
22046 if (!qFuzzyCompare(croppedData->at(li).y(),
21850 != 0) // avoid division by zero in step plots
22047 croppedData->at(li - 1).y())) // avoid division by zero in step plots
21851 slope = (croppedData->at(li).x() - croppedData->at(li - 1).x())
22048 slope = (croppedData->at(li).x() - croppedData->at(li - 1).x())
21852 / (croppedData->at(li).y() - croppedData->at(li - 1).y());
22049 / (croppedData->at(li).y() - croppedData->at(li - 1).y());
21853 else
22050 else
@@ -21858,16 +22055,17 const QPolygonF QCPGraph::getChannelFillPolygon(const QVector<QPointF> *lines) c
21858 }
22055 }
21859
22056
21860 // return joined:
22057 // return joined:
21861 for (int i = otherData.size() - 1; i >= 0;
22058 for (int i = otherSegmentData.size() - 1; i >= 0;
21862 --i) // insert reversed, otherwise the polygon will be twisted
22059 --i) // insert reversed, otherwise the polygon will be twisted
21863 thisData << otherData.at(i);
22060 thisSegmentData << otherSegmentData.at(i);
21864 return QPolygonF(thisData);
22061 return QPolygonF(thisSegmentData);
21865 }
22062 }
21866
22063
21867 /*! \internal
22064 /*! \internal
21868
22065
21869 Finds the smallest index of \a data, whose points x value is just above \a x. Assumes x values in
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 Used to calculate the channel fill polygon, see \ref getChannelFillPolygon.
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 /*! \internal
22085 /*! \internal
21888
22086
21889 Finds the highest index of \a data, whose points x value is just below \a x. Assumes x values in
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 Used to calculate the channel fill polygon, see \ref getChannelFillPolygon.
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 /*! \internal
22106 /*! \internal
21908
22107
21909 Finds the smallest index of \a data, whose points y value is just above \a y. Assumes y values in
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 Used to calculate the channel fill polygon, see \ref getChannelFillPolygon.
22112 Used to calculate the channel fill polygon, see \ref getChannelFillPolygon.
21913 */
22113 */
21914 int QCPGraph::findIndexAboveY(const QVector<QPointF> *data, double y) const
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 if (data->at(i).y() < y) {
22117 if (data->at(i).y() < y) {
21918 if (i > 0)
22118 if (i < data->size() - 1)
21919 return i - 1;
22119 return i + 1;
21920 else
22120 else
21921 return 0;
22121 return data->size() - 1;
21922 }
22122 }
21923 }
22123 }
21924 return -1;
22124 return -1;
@@ -21994,19 +22194,19 double QCPGraph::pointDistance(const QPointF &pixelPoint,
21994 /*! \internal
22194 /*! \internal
21995
22195
21996 Finds the highest index of \a data, whose points y value is just below \a y. Assumes y values in
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
22197 \a data points are ordered ascending, as is ensured by \ref getLines/\ref getScatters if the key
21998 keys are ordered ascending).
22198 axis is vertical.
21999
22199
22000 Used to calculate the channel fill polygon, see \ref getChannelFillPolygon.
22200 Used to calculate the channel fill polygon, see \ref getChannelFillPolygon.
22001 */
22201 */
22002 int QCPGraph::findIndexBelowY(const QVector<QPointF> *data, double y) const
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 if (data->at(i).y() > y) {
22205 if (data->at(i).y() > y) {
22006 if (i < data->size() - 1)
22206 if (i > 0)
22007 return i + 1;
22207 return i - 1;
22008 else
22208 else
22009 return data->size() - 1;
22209 return 0;
22010 }
22210 }
22011 }
22211 }
22012 return -1;
22212 return -1;
@@ -22014,8 +22214,8 int QCPGraph::findIndexBelowY(const QVector<QPointF> *data, double y) const
22014 /* end of 'src/plottables/plottable-graph.cpp' */
22214 /* end of 'src/plottables/plottable-graph.cpp' */
22015
22215
22016
22216
22017 /* including file 'src/plottables/plottable-curve.cpp', size 60009 */
22217 /* including file 'src/plottables/plottable-curve.cpp', size 63527 */
22018 /* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
22218 /* commit 63bcca79007f7f56dce5dd035560f2e871d1dfc1 2017-07-20 18:02:21 +0200 */
22019
22219
22020 ////////////////////////////////////////////////////////////////////////////////////////////////////
22220 ////////////////////////////////////////////////////////////////////////////////////////////////////
22021 //////////////////// QCPCurveData
22221 //////////////////// QCPCurveData
@@ -22179,6 +22379,7 QCPCurve::QCPCurve(QCPAxis *keyAxis, QCPAxis *valueAxis)
22179
22379
22180 setScatterStyle(QCPScatterStyle());
22380 setScatterStyle(QCPScatterStyle());
22181 setLineStyle(lsLine);
22381 setLineStyle(lsLine);
22382 setScatterSkip(0);
22182 }
22383 }
22183
22384
22184 QCPCurve::~QCPCurve()
22385 QCPCurve::~QCPCurve()
@@ -22881,54 +23082,74 QPointF QCPCurve::getOptimizedPoint(int otherRegion, double otherKey, double oth
22881 double value, double keyMin, double valueMax, double keyMax,
23082 double value, double keyMin, double valueMax, double keyMax,
22882 double valueMin) const
23083 double valueMin) const
22883 {
23084 {
22884 double intersectKey = keyMin; // initial value is just fail-safe
23085 // The intersection point interpolation here is done in pixel coordinates, so we don't need to
22885 double intersectValue = valueMax; // initial value is just fail-safe
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 switch (otherRegion) {
23100 switch (otherRegion) {
22887 case 1: // top and left edge
23101 case 1: // top and left edge
22888 {
23102 {
22889 intersectValue = valueMax;
23103 intersectValuePx = valueMaxPx;
22890 intersectKey
23104 intersectKeyPx = otherKeyPx
22891 = otherKey
23105 + (keyPx - otherKeyPx) / (valuePx - otherValuePx)
22892 + (key - otherKey) / (value - otherValue) * (intersectValue - otherValue);
23106 * (intersectValuePx - otherValuePx);
22893 if (intersectKey < keyMin
23107 if (intersectKeyPx < qMin(keyMinPx, keyMaxPx)
22894 || intersectKey > keyMax) // doesn't intersect, so must intersect other:
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;
23113 intersectKeyPx = keyMinPx;
22897 intersectValue
23114 intersectValuePx = otherValuePx
22898 = otherValue
23115 + (valuePx - otherValuePx) / (keyPx - otherKeyPx)
22899 + (value - otherValue) / (key - otherKey) * (intersectKey - otherKey);
23116 * (intersectKeyPx - otherKeyPx);
22900 }
23117 }
22901 break;
23118 break;
22902 }
23119 }
22903 case 2: // left edge
23120 case 2: // left edge
22904 {
23121 {
22905 intersectKey = keyMin;
23122 intersectKeyPx = keyMinPx;
22906 intersectValue
23123 intersectValuePx
22907 = otherValue + (value - otherValue) / (key - otherKey) * (intersectKey - otherKey);
23124 = otherValuePx
23125 + (valuePx - otherValuePx) / (keyPx - otherKeyPx) * (intersectKeyPx - otherKeyPx);
22908 break;
23126 break;
22909 }
23127 }
22910 case 3: // bottom and left edge
23128 case 3: // bottom and left edge
22911 {
23129 {
22912 intersectValue = valueMin;
23130 intersectValuePx = valueMinPx;
22913 intersectKey
23131 intersectKeyPx = otherKeyPx
22914 = otherKey
23132 + (keyPx - otherKeyPx) / (valuePx - otherValuePx)
22915 + (key - otherKey) / (value - otherValue) * (intersectValue - otherValue);
23133 * (intersectValuePx - otherValuePx);
22916 if (intersectKey < keyMin
23134 if (intersectKeyPx < qMin(keyMinPx, keyMaxPx)
22917 || intersectKey > keyMax) // doesn't intersect, so must intersect other:
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;
23140 intersectKeyPx = keyMinPx;
22920 intersectValue
23141 intersectValuePx = otherValuePx
22921 = otherValue
23142 + (valuePx - otherValuePx) / (keyPx - otherKeyPx)
22922 + (value - otherValue) / (key - otherKey) * (intersectKey - otherKey);
23143 * (intersectKeyPx - otherKeyPx);
22923 }
23144 }
22924 break;
23145 break;
22925 }
23146 }
22926 case 4: // top edge
23147 case 4: // top edge
22927 {
23148 {
22928 intersectValue = valueMax;
23149 intersectValuePx = valueMaxPx;
22929 intersectKey
23150 intersectKeyPx = otherKeyPx
22930 = otherKey
23151 + (keyPx - otherKeyPx) / (valuePx - otherValuePx)
22931 + (key - otherKey) / (value - otherValue) * (intersectValue - otherValue);
23152 * (intersectValuePx - otherValuePx);
22932 break;
23153 break;
22933 }
23154 }
22934 case 5: {
23155 case 5: {
@@ -22937,53 +23158,63 QPointF QCPCurve::getOptimizedPoint(int otherRegion, double otherKey, double oth
22937 }
23158 }
22938 case 6: // bottom edge
23159 case 6: // bottom edge
22939 {
23160 {
22940 intersectValue = valueMin;
23161 intersectValuePx = valueMinPx;
22941 intersectKey
23162 intersectKeyPx = otherKeyPx
22942 = otherKey
23163 + (keyPx - otherKeyPx) / (valuePx - otherValuePx)
22943 + (key - otherKey) / (value - otherValue) * (intersectValue - otherValue);
23164 * (intersectValuePx - otherValuePx);
22944 break;
23165 break;
22945 }
23166 }
22946 case 7: // top and right edge
23167 case 7: // top and right edge
22947 {
23168 {
22948 intersectValue = valueMax;
23169 intersectValuePx = valueMaxPx;
22949 intersectKey
23170 intersectKeyPx = otherKeyPx
22950 = otherKey
23171 + (keyPx - otherKeyPx) / (valuePx - otherValuePx)
22951 + (key - otherKey) / (value - otherValue) * (intersectValue - otherValue);
23172 * (intersectValuePx - otherValuePx);
22952 if (intersectKey < keyMin
23173 if (intersectKeyPx < qMin(keyMinPx, keyMaxPx)
22953 || intersectKey > keyMax) // doesn't intersect, so must intersect other:
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;
23179 intersectKeyPx = keyMaxPx;
22956 intersectValue
23180 intersectValuePx = otherValuePx
22957 = otherValue
23181 + (valuePx - otherValuePx) / (keyPx - otherKeyPx)
22958 + (value - otherValue) / (key - otherKey) * (intersectKey - otherKey);
23182 * (intersectKeyPx - otherKeyPx);
22959 }
23183 }
22960 break;
23184 break;
22961 }
23185 }
22962 case 8: // right edge
23186 case 8: // right edge
22963 {
23187 {
22964 intersectKey = keyMax;
23188 intersectKeyPx = keyMaxPx;
22965 intersectValue
23189 intersectValuePx
22966 = otherValue + (value - otherValue) / (key - otherKey) * (intersectKey - otherKey);
23190 = otherValuePx
23191 + (valuePx - otherValuePx) / (keyPx - otherKeyPx) * (intersectKeyPx - otherKeyPx);
22967 break;
23192 break;
22968 }
23193 }
22969 case 9: // bottom and right edge
23194 case 9: // bottom and right edge
22970 {
23195 {
22971 intersectValue = valueMin;
23196 intersectValuePx = valueMinPx;
22972 intersectKey
23197 intersectKeyPx = otherKeyPx
22973 = otherKey
23198 + (keyPx - otherKeyPx) / (valuePx - otherValuePx)
22974 + (key - otherKey) / (value - otherValue) * (intersectValue - otherValue);
23199 * (intersectValuePx - otherValuePx);
22975 if (intersectKey < keyMin
23200 if (intersectKeyPx < qMin(keyMinPx, keyMaxPx)
22976 || intersectKey > keyMax) // doesn't intersect, so must intersect other:
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;
23206 intersectKeyPx = keyMaxPx;
22979 intersectValue
23207 intersectValuePx = otherValuePx
22980 = otherValue
23208 + (valuePx - otherValuePx) / (keyPx - otherKeyPx)
22981 + (value - otherValue) / (key - otherKey) * (intersectKey - otherKey);
23209 * (intersectKeyPx - otherKeyPx);
22982 }
23210 }
22983 break;
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 /*! \internal
23220 /*! \internal
@@ -23496,44 +23727,79 bool QCPCurve::getTraverse(double prevKey, double prevValue, double key, double
23496 double keyMin, double valueMax, double keyMax, double valueMin,
23727 double keyMin, double valueMax, double keyMax, double valueMin,
23497 QPointF &crossA, QPointF &crossB) const
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 if (qFuzzyIsNull(key - prevKey)) // line is parallel to value axis
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
23746 // due to region filter in mayTraverse(), if line is parallel to value or key axis, region 5
23503 // traversed here
23747 // is traversed here
23504 intersections.append(
23748 intersections.append(
23505 QPointF(key, valueMin)); // direction will be taken care of at end of method
23749 mKeyAxis->orientation() == Qt::Horizontal
23506 intersections.append(QPointF(key, valueMax));
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 else if (qFuzzyIsNull(value - prevValue)) // line is parallel to key axis
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
23758 // due to region filter in mayTraverse(), if line is parallel to value or key axis, region 5
23511 // traversed here
23759 // is traversed here
23512 intersections.append(
23760 intersections.append(
23513 QPointF(keyMin, value)); // direction will be taken care of at end of method
23761 mKeyAxis->orientation() == Qt::Horizontal
23514 intersections.append(QPointF(keyMax, value));
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 else // line is skewed
23768 else // line is skewed
23517 {
23769 {
23518 double gamma;
23770 double gamma;
23519 double keyPerValue = (key - prevKey) / (value - prevValue);
23771 double keyPerValuePx = (keyPx - prevKeyPx) / (valuePx - prevValuePx);
23520 // check top of rect:
23772 // check top of rect:
23521 gamma = prevKey + (valueMax - prevValue) * keyPerValue;
23773 gamma = prevKeyPx + (valueMaxPx - prevValuePx) * keyPerValuePx;
23522 if (gamma >= keyMin && gamma <= keyMax)
23774 if (gamma >= qMin(keyMinPx, keyMaxPx)
23523 intersections.append(QPointF(gamma, valueMax));
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 // check bottom of rect:
23779 // check bottom of rect:
23525 gamma = prevKey + (valueMin - prevValue) * keyPerValue;
23780 gamma = prevKeyPx + (valueMinPx - prevValuePx) * keyPerValuePx;
23526 if (gamma >= keyMin && gamma <= keyMax)
23781 if (gamma >= qMin(keyMinPx, keyMaxPx)
23527 intersections.append(QPointF(gamma, valueMin));
23782 && gamma <= qMax(keyMinPx, keyMaxPx)) // qMin/qMax necessary since axes may be reversed
23528 double valuePerKey = 1.0 / keyPerValue;
23783 intersections.append(mKeyAxis->orientation() == Qt::Horizontal
23784 ? QPointF(gamma, valueMinPx)
23785 : QPointF(valueMinPx, gamma));
23786 const double valuePerKeyPx = 1.0 / keyPerValuePx;
23529 // check left of rect:
23787 // check left of rect:
23530 gamma = prevValue + (keyMin - prevKey) * valuePerKey;
23788 gamma = prevValuePx + (keyMinPx - prevKeyPx) * valuePerKeyPx;
23531 if (gamma >= valueMin && gamma <= valueMax)
23789 if (gamma >= qMin(valueMinPx, valueMaxPx)
23532 intersections.append(QPointF(keyMin, gamma));
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 // check right of rect:
23795 // check right of rect:
23534 gamma = prevValue + (keyMax - prevKey) * valuePerKey;
23796 gamma = prevValuePx + (keyMaxPx - prevKeyPx) * valuePerKeyPx;
23535 if (gamma >= valueMin && gamma <= valueMax)
23797 if (gamma >= qMin(valueMinPx, valueMaxPx)
23536 intersections.append(QPointF(keyMax, gamma));
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 // handle cases where found points isn't exactly 2:
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 // possibly re-sort points so optimized point segment has same direction as original segment:
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())
23831 double xDelta = keyPx - prevKeyPx;
23566 + (value - prevValue) * (intersections.at(1).y() - intersections.at(0).y())
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 < 0) // scalar product of both segments < 0 -> opposite direction
23837 < 0) // scalar product of both segments < 0 -> opposite direction
23568 intersections.move(0, 1);
23838 intersections.move(0, 1);
23569 crossA = coordsToPixels(intersections.at(0).x(), intersections.at(0).y());
23839 crossA = intersections.at(0);
23570 crossB = coordsToPixels(intersections.at(1).x(), intersections.at(1).y());
23840 crossB = intersections.at(1);
23571 return true;
23841 return true;
23572 }
23842 }
23573
23843
@@ -25678,8 +25948,8 QCPStatisticalBox::getWhiskerBarLines(QCPStatisticalBoxDataContainer::const_iter
25678 /* end of 'src/plottables/plottable-statisticalbox.cpp' */
25948 /* end of 'src/plottables/plottable-statisticalbox.cpp' */
25679
25949
25680
25950
25681 /* including file 'src/plottables/plottable-colormap.cpp', size 47531 */
25951 /* including file 'src/plottables/plottable-colormap.cpp', size 47881 */
25682 /* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
25952 /* commit 83a770151292397b3ba4984108d7ed167a9aec65 2017-08-13 16:22:21 +0200 */
25683
25953
25684 ////////////////////////////////////////////////////////////////////////////////////////////////////
25954 ////////////////////////////////////////////////////////////////////////////////////////////////////
25685 //////////////////// QCPColorMapData
25955 //////////////////// QCPColorMapData
@@ -26350,6 +26620,7 QCPColorMap::QCPColorMap(QCPAxis *keyAxis, QCPAxis *valueAxis)
26350 : QCPAbstractPlottable(keyAxis, valueAxis),
26620 : QCPAbstractPlottable(keyAxis, valueAxis),
26351 mDataScaleType(QCPAxis::stLinear),
26621 mDataScaleType(QCPAxis::stLinear),
26352 mMapData(new QCPColorMapData(10, 10, QCPRange(0, 5), QCPRange(0, 5))),
26622 mMapData(new QCPColorMapData(10, 10, QCPRange(0, 5), QCPRange(0, 5))),
26623 mGradient(QCPColorGradient::gpCold),
26353 mInterpolate(true),
26624 mInterpolate(true),
26354 mTightBoundary(false),
26625 mTightBoundary(false),
26355 mMapImageInvalidated(true)
26626 mMapImageInvalidated(true)
@@ -26709,9 +26980,15 void QCPColorMap::updateMapImage()
26709 mMapImage = QImage(
26980 mMapImage = QImage(
26710 QSize(valueSize * valueOversamplingFactor, keySize * keyOversamplingFactor), format);
26981 QSize(valueSize * valueOversamplingFactor, keySize * keyOversamplingFactor), format);
26711
26982
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);
26987 }
26988 else {
26712 QImage *localMapImage = &mMapImage; // this is the image on which the colorization operates.
26989 QImage *localMapImage = &mMapImage; // this is the image on which the colorization operates.
26713 // Either the final mMapImage, or if we need oversampling,
26990 // Either the final mMapImage, or if we need
26714 // mUndersampledMapImage
26991 // oversampling, mUndersampledMapImage
26715 if (keyOversamplingFactor > 1 || valueOversamplingFactor > 1) {
26992 if (keyOversamplingFactor > 1 || valueOversamplingFactor > 1) {
26716 // resize undersampled map image to actual key/value cell sizes:
26993 // resize undersampled map image to actual key/value cell sizes:
26717 if (keyAxis->orientation() == Qt::Horizontal
26994 if (keyAxis->orientation() == Qt::Horizontal
@@ -26726,9 +27003,9 void QCPColorMap::updateMapImage()
26726 = &mUndersampledMapImage; // make the colorization run on the undersampled image
27003 = &mUndersampledMapImage; // make the colorization run on the undersampled image
26727 }
27004 }
26728 else if (!mUndersampledMapImage.isNull())
27005 else if (!mUndersampledMapImage.isNull())
26729 mUndersampledMapImage = QImage(); // don't need oversampling mechanism anymore (map size has
27006 mUndersampledMapImage = QImage(); // don't need oversampling mechanism anymore (map size
26730 // changed) but mUndersampledMapImage still has nonzero
27007 // has changed) but mUndersampledMapImage still has
26731 // size, free it
27008 // nonzero size, free it
26732
27009
26733 const double *rawData = mMapData->mData;
27010 const double *rawData = mMapData->mData;
26734 const unsigned char *rawAlpha = mMapData->mAlpha;
27011 const unsigned char *rawAlpha = mMapData->mAlpha;
@@ -26759,8 +27036,9 void QCPColorMap::updateMapImage()
26759 // from top, but our vertical index counts from bottom
27036 // from top, but our vertical index counts from bottom
26760 // (mathematical coordinate system)
27037 // (mathematical coordinate system)
26761 if (rawAlpha)
27038 if (rawAlpha)
26762 mGradient.colorize(rawData + line, rawAlpha + line, mDataRange, pixels, rowCount,
27039 mGradient.colorize(rawData + line, rawAlpha + line, mDataRange, pixels,
26763 lineCount, mDataScaleType == QCPAxis::stLogarithmic);
27040 rowCount, lineCount,
27041 mDataScaleType == QCPAxis::stLogarithmic);
26764 else
27042 else
26765 mGradient.colorize(rawData + line, mDataRange, pixels, rowCount, lineCount,
27043 mGradient.colorize(rawData + line, mDataRange, pixels, rowCount, lineCount,
26766 mDataScaleType == QCPAxis::stLogarithmic);
27044 mDataScaleType == QCPAxis::stLogarithmic);
@@ -26769,14 +27047,15 void QCPColorMap::updateMapImage()
26769
27047
26770 if (keyOversamplingFactor > 1 || valueOversamplingFactor > 1) {
27048 if (keyOversamplingFactor > 1 || valueOversamplingFactor > 1) {
26771 if (keyAxis->orientation() == Qt::Horizontal)
27049 if (keyAxis->orientation() == Qt::Horizontal)
26772 mMapImage = mUndersampledMapImage.scaled(keySize * keyOversamplingFactor,
27050 mMapImage = mUndersampledMapImage.scaled(
26773 valueSize * valueOversamplingFactor,
27051 keySize * keyOversamplingFactor, valueSize * valueOversamplingFactor,
26774 Qt::IgnoreAspectRatio, Qt::FastTransformation);
27052 Qt::IgnoreAspectRatio, Qt::FastTransformation);
26775 else
27053 else
26776 mMapImage = mUndersampledMapImage.scaled(valueSize * valueOversamplingFactor,
27054 mMapImage = mUndersampledMapImage.scaled(
26777 keySize * keyOversamplingFactor,
27055 valueSize * valueOversamplingFactor, keySize * keyOversamplingFactor,
26778 Qt::IgnoreAspectRatio, Qt::FastTransformation);
27056 Qt::IgnoreAspectRatio, Qt::FastTransformation);
26779 }
27057 }
27058 }
26780 mMapData->mDataModified = false;
27059 mMapData->mDataModified = false;
26781 mMapImageInvalidated = false;
27060 mMapImageInvalidated = false;
26782 }
27061 }
@@ -27939,8 +28218,8 QRectF QCPFinancial::selectionHitBox(QCPFinancialDataContainer::const_iterator i
27939 /* end of 'src/plottables/plottable-financial.cpp' */
28218 /* end of 'src/plottables/plottable-financial.cpp' */
27940
28219
27941
28220
27942 /* including file 'src/plottables/plottable-errorbar.cpp', size 37210 */
28221 /* including file 'src/plottables/plottable-errorbar.cpp', size 37355 */
27943 /* commit 633339dadc92cb10c58ef3556b55570685fafb99 2016-09-13 23:54:56 +0200 */
28222 /* commit 6f159843e9ec9ea6431b26591937aea13a9f2751 2017-07-25 11:13:32 +0200 */
27944
28223
27945 ////////////////////////////////////////////////////////////////////////////////////////////////////
28224 ////////////////////////////////////////////////////////////////////////////////////////////////////
27946 //////////////////// QCPErrorBarsData
28225 //////////////////// QCPErrorBarsData
@@ -28671,8 +28950,8 void QCPErrorBars::getErrorBarLines(QCPErrorBarsDataContainer::const_iterator it
28671 QPointF centerPixel = mDataPlottable->interface1D()->dataPixelPosition(index);
28950 QPointF centerPixel = mDataPlottable->interface1D()->dataPixelPosition(index);
28672 if (qIsNaN(centerPixel.x()) || qIsNaN(centerPixel.y()))
28951 if (qIsNaN(centerPixel.x()) || qIsNaN(centerPixel.y()))
28673 return;
28952 return;
28674 QCPAxis *errorAxis = mErrorType == etValueError ? mValueAxis : mKeyAxis;
28953 QCPAxis *errorAxis = mErrorType == etValueError ? mValueAxis.data() : mKeyAxis.data();
28675 QCPAxis *orthoAxis = mErrorType == etValueError ? mKeyAxis : mValueAxis;
28954 QCPAxis *orthoAxis = mErrorType == etValueError ? mKeyAxis.data() : mValueAxis.data();
28676 const double centerErrorAxisPixel
28955 const double centerErrorAxisPixel
28677 = errorAxis->orientation() == Qt::Horizontal ? centerPixel.x() : centerPixel.y();
28956 = errorAxis->orientation() == Qt::Horizontal ? centerPixel.x() : centerPixel.y();
28678 const double centerOrthoAxisPixel
28957 const double centerOrthoAxisPixel
@@ -28806,6 +29085,10 double QCPErrorBars::pointDistance(const QPointF &pixelPoint,
28806 closestData = mDataContainer->constEnd();
29085 closestData = mDataContainer->constEnd();
28807 if (!mDataPlottable || mDataContainer->isEmpty())
29086 if (!mDataPlottable || mDataContainer->isEmpty())
28808 return -1.0;
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 QCPErrorBarsDataContainer::const_iterator begin, end;
29093 QCPErrorBarsDataContainer::const_iterator begin, end;
28811 getVisibleDataBounds(begin, end, QCPDataRange(0, dataCount()));
29094 getVisibleDataBounds(begin, end, QCPDataRange(0, dataCount()));
General Comments 0
You need to be logged in to leave comments. Login now