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