aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJarek Kobus <jaroslaw.kobus@qt.io>2022-11-25 18:34:28 +0100
committerJarek Kobus <jaroslaw.kobus@qt.io>2022-11-28 10:07:30 +0000
commit23f53dcbda305d3e2f593b4e0c566375af7dc0fb (patch)
treec6407d49ae1dd0614fd1497d30ed70df68e3ed0f
parent6f299f19ac7fab734894ca49395d19eba7c36681 (diff)
MathUtils: Add tangential interpolation
Reuse it in TaskProgress and in ProgressTimer. Rename MathUtils::interpolate() into interpolateLinear() Change-Id: Iff4cda1e3b8782cd26277ec75046ca5526be92c0 Reviewed-by: Eike Ziller <eike.ziller@qt.io>
-rw-r--r--src/libs/utils/mathutils.cpp19
-rw-r--r--src/libs/utils/mathutils.h3
-rw-r--r--src/plugins/coreplugin/progressmanager/progressmanager.cpp13
-rw-r--r--src/plugins/coreplugin/progressmanager/taskprogress.cpp14
-rw-r--r--src/plugins/diffeditor/sidebysidediffeditorwidget.cpp4
-rw-r--r--src/plugins/diffeditor/unifieddiffeditorwidget.cpp4
-rw-r--r--tests/auto/utils/CMakeLists.txt1
-rw-r--r--tests/auto/utils/mathutils/CMakeLists.txt4
-rw-r--r--tests/auto/utils/mathutils/mathutils.qbs7
-rw-r--r--tests/auto/utils/mathutils/tst_mathutils.cpp77
-rw-r--r--tests/auto/utils/utils.qbs1
11 files changed, 124 insertions, 23 deletions
diff --git a/src/libs/utils/mathutils.cpp b/src/libs/utils/mathutils.cpp
index 465d4d5f99..d9e18b18a3 100644
--- a/src/libs/utils/mathutils.cpp
+++ b/src/libs/utils/mathutils.cpp
@@ -12,7 +12,7 @@ namespace Utils::MathUtils {
For x = x1 it returns y1.
For x = x2 it returns y2.
*/
-int interpolate(int x, int x1, int x2, int y1, int y2)
+int interpolateLinear(int x, int x1, int x2, int y1, int y2)
{
if (x1 == x2)
return y1; // or the middle point between y1 and y2?
@@ -27,4 +27,21 @@ int interpolate(int x, int x1, int x2, int y1, int y2)
return qRound((double)numerator / denominator);
}
+/*!
+ Tangential interpolation:
+ For x = 0 it returns y1.
+ For x = xHalfLife it returns 50 % of the distance between y1 and y2.
+ For x = infinity it returns y2.
+*/
+int interpolateTangential(int x, int xHalfLife, int y1, int y2)
+{
+ if (x == 0)
+ return y1;
+ if (y1 == y2)
+ return y1;
+ const double mapped = atan2(double(x), double(xHalfLife));
+ const double progress = y1 + (y2 - y1) * mapped * 2 / M_PI;
+ return qRound(progress);
+}
+
} // namespace Utils::Math
diff --git a/src/libs/utils/mathutils.h b/src/libs/utils/mathutils.h
index 20ae6cd342..8a9af9e4e6 100644
--- a/src/libs/utils/mathutils.h
+++ b/src/libs/utils/mathutils.h
@@ -7,6 +7,7 @@
namespace Utils::MathUtils {
-QTCREATOR_UTILS_EXPORT int interpolate(int x, int x1, int x2, int y1, int y2);
+QTCREATOR_UTILS_EXPORT int interpolateLinear(int x, int x1, int x2, int y1, int y2);
+QTCREATOR_UTILS_EXPORT int interpolateTangential(int x, int xHalfLife, int y1, int y2);
} // namespace Utils::Math
diff --git a/src/plugins/coreplugin/progressmanager/progressmanager.cpp b/src/plugins/coreplugin/progressmanager/progressmanager.cpp
index 9891a2b3f4..1b4166df5a 100644
--- a/src/plugins/coreplugin/progressmanager/progressmanager.cpp
+++ b/src/plugins/coreplugin/progressmanager/progressmanager.cpp
@@ -13,6 +13,7 @@
#include <extensionsystem/pluginmanager.h>
#include <utils/hostosinfo.h>
+#include <utils/mathutils.h>
#include <utils/qtcassert.h>
#include <utils/stylehelper.h>
#include <utils/theme/theme.h>
@@ -27,7 +28,6 @@
#include <QStyle>
#include <QStyleOption>
#include <QTimer>
-#include <QtMath>
#include <QVariant>
static const char kSettingsGroup[] = "Progress";
@@ -779,13 +779,8 @@ ProgressTimer::ProgressTimer(const QFutureInterfaceBase &futureInterface,
void ProgressTimer::handleTimeout()
{
++m_currentTime;
-
- // This maps expectation to atan(1) to Pi/4 ~= 0.78, i.e. snaps
- // from 78% to 100% when expectations are met at the time the
- // future finishes. That's not bad for a random choice.
- const double mapped = atan2(double(m_currentTime) * TimerInterval / 1000.0,
- double(m_expectedTime));
- const double progress = 100 * 2 * mapped / M_PI;
- m_futureInterface.setProgressValue(int(progress));
+ const int halfLife = qRound(1000.0 * m_expectedTime / TimerInterval);
+ const int progress = MathUtils::interpolateTangential(m_currentTime, halfLife, 0, 100);
+ m_futureInterface.setProgressValue(progress);
}
diff --git a/src/plugins/coreplugin/progressmanager/taskprogress.cpp b/src/plugins/coreplugin/progressmanager/taskprogress.cpp
index 13ad40b7fa..ba0000a115 100644
--- a/src/plugins/coreplugin/progressmanager/taskprogress.cpp
+++ b/src/plugins/coreplugin/progressmanager/taskprogress.cpp
@@ -6,12 +6,12 @@
#include "futureprogress.h"
#include "progressmanager.h"
+#include <utils/mathutils.h>
#include <utils/qtcassert.h>
#include <utils/tasktree.h>
#include <QFutureWatcher>
#include <QTimer>
-#include <QtMath>
using namespace Utils;
@@ -80,13 +80,11 @@ void TaskProgressPrivate::advanceProgress(int newValue)
void TaskProgressPrivate::updateProgress()
{
- // This maps expectation to atan(1) to Pi/4 ~= 0.78, i.e. snaps
- // from 78% to 100% when expectations are met at the time the
- // future finishes. That's not bad for a random choice.
- const double mapped = atan2(double(m_currentTick) * TimerInterval / 1000.0,
- double(m_expectedTime));
- const double progress = ProgressResolution * 2 * mapped / M_PI;
- m_futureInterface.setProgressValue(ProgressResolution * m_currentProgress + progress);
+ const int halfLife = qRound(1000.0 * m_expectedTime / TimerInterval);
+ const int pMin = ProgressResolution * m_currentProgress;
+ const int pMax = ProgressResolution * (m_currentProgress + 1);
+ const int newValue = MathUtils::interpolateTangential(m_currentTick, halfLife, pMin, pMax);
+ m_futureInterface.setProgressValue(newValue);
}
/*!
diff --git a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp
index 70d9e2ee55..010f656be8 100644
--- a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp
+++ b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp
@@ -365,7 +365,7 @@ SideBySideDiffOutput SideDiffData::diffOutput(QFutureInterface<void> &fi, int pr
diffText[RightSide].replace('\r', ' ');
output.side[LeftSide].diffText += diffText[LeftSide];
output.side[RightSide].diffText += diffText[RightSide];
- fi.setProgressValue(MathUtils::interpolate(++i, 0, count, progressMin, progressMax));
+ fi.setProgressValue(MathUtils::interpolateLinear(++i, 0, count, progressMin, progressMax));
if (fi.isCanceled())
return {};
}
@@ -952,7 +952,7 @@ void SideBySideDiffEditorWidget::showDiff()
const QString package = output.side[side].diffText.mid(currentPos, packageSize);
cursor.insertText(package);
currentPos += package.size();
- fi.setProgressValue(MathUtils::interpolate(currentPos, 0, diffSize, progressMin, progressMax));
+ fi.setProgressValue(MathUtils::interpolateLinear(currentPos, 0, diffSize, progressMin, progressMax));
if (fi.isCanceled())
return;
}
diff --git a/src/plugins/diffeditor/unifieddiffeditorwidget.cpp b/src/plugins/diffeditor/unifieddiffeditorwidget.cpp
index c082db78ec..6e8abb9c24 100644
--- a/src/plugins/diffeditor/unifieddiffeditorwidget.cpp
+++ b/src/plugins/diffeditor/unifieddiffeditorwidget.cpp
@@ -436,7 +436,7 @@ UnifiedDiffOutput UnifiedDiffData::diffOutput(QFutureInterface<void> &fi, int pr
output.diffData.m_chunkInfo.setChunkIndex(oldBlock, blockNumber - oldBlock, j);
}
}
- fi.setProgressValue(MathUtils::interpolate(++i, 0, count, progressMin, progressMax));
+ fi.setProgressValue(MathUtils::interpolateLinear(++i, 0, count, progressMin, progressMax));
if (fi.isCanceled())
return {};
}
@@ -511,7 +511,7 @@ void UnifiedDiffEditorWidget::showDiff()
const QString package = output.diffText.mid(currentPos, packageSize);
cursor.insertText(package);
currentPos += package.size();
- fi.setProgressValue(MathUtils::interpolate(currentPos, 0, diffSize, firstPartMax, progressMax));
+ fi.setProgressValue(MathUtils::interpolateLinear(currentPos, 0, diffSize, firstPartMax, progressMax));
if (futureInterface.isCanceled())
return;
}
diff --git a/tests/auto/utils/CMakeLists.txt b/tests/auto/utils/CMakeLists.txt
index ee2f8e475a..34532e8f91 100644
--- a/tests/auto/utils/CMakeLists.txt
+++ b/tests/auto/utils/CMakeLists.txt
@@ -6,6 +6,7 @@ add_subdirectory(fileutils)
add_subdirectory(fsengine)
add_subdirectory(fuzzymatcher)
add_subdirectory(indexedcontainerproxyconstiterator)
+add_subdirectory(mathutils)
add_subdirectory(multicursor)
add_subdirectory(persistentsettings)
add_subdirectory(qtcprocess)
diff --git a/tests/auto/utils/mathutils/CMakeLists.txt b/tests/auto/utils/mathutils/CMakeLists.txt
new file mode 100644
index 0000000000..d2ec2d5194
--- /dev/null
+++ b/tests/auto/utils/mathutils/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_qtc_test(tst_utils_mathutils
+ DEPENDS Utils
+ SOURCES tst_mathutils.cpp
+)
diff --git a/tests/auto/utils/mathutils/mathutils.qbs b/tests/auto/utils/mathutils/mathutils.qbs
new file mode 100644
index 0000000000..36fa42ffc4
--- /dev/null
+++ b/tests/auto/utils/mathutils/mathutils.qbs
@@ -0,0 +1,7 @@
+import qbs
+
+QtcAutotest {
+ name: "MathUtils autotest"
+ Depends { name: "Utils" }
+ files: "tst_mathutils.cpp"
+}
diff --git a/tests/auto/utils/mathutils/tst_mathutils.cpp b/tests/auto/utils/mathutils/tst_mathutils.cpp
new file mode 100644
index 0000000000..30d2d8d6c5
--- /dev/null
+++ b/tests/auto/utils/mathutils/tst_mathutils.cpp
@@ -0,0 +1,77 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "utils/mathutils.h"
+
+#include <QtTest>
+
+using namespace Utils;
+
+class tst_MathUtils : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void interpolateLinear_data();
+ void interpolateLinear();
+ void interpolateTangential_data();
+ void interpolateTangential();
+};
+
+void tst_MathUtils::interpolateLinear_data()
+{
+ QTest::addColumn<int>("x");
+ QTest::addColumn<int>("x1");
+ QTest::addColumn<int>("x2");
+ QTest::addColumn<int>("y1");
+ QTest::addColumn<int>("y2");
+ QTest::addColumn<int>("result");
+
+ QTest::newRow("x1") << 2 << 2 << 8 << 10 << 20 << 10;
+ QTest::newRow("middleValue") << 5 << 2 << 8 << 10 << 20 << 15;
+ QTest::newRow("x2") << 8 << 2 << 8 << 10 << 20 << 20;
+ QTest::newRow("belowX1") << -1 << 2 << 8 << 10 << 20 << 5;
+ QTest::newRow("aboveX2") << 11 << 2 << 8 << 10 << 20 << 25;
+}
+
+void tst_MathUtils::interpolateLinear()
+{
+ QFETCH(int, x);
+ QFETCH(int, x1);
+ QFETCH(int, x2);
+ QFETCH(int, y1);
+ QFETCH(int, y2);
+ QFETCH(int, result);
+
+ const int y = MathUtils::interpolateLinear(x, x1, x2, y1, y2);
+ QCOMPARE(y, result);
+}
+
+void tst_MathUtils::interpolateTangential_data()
+{
+ QTest::addColumn<int>("x");
+ QTest::addColumn<int>("xHalfLife");
+ QTest::addColumn<int>("y1");
+ QTest::addColumn<int>("y2");
+ QTest::addColumn<int>("result");
+
+ QTest::newRow("zero") << 0 << 8 << 10 << 20 << 10;
+ QTest::newRow("halfLife") << 8 << 8 << 10 << 20 << 15;
+ QTest::newRow("approxInfinity") << 1000 << 8 << 10 << 20 << 20;
+}
+
+void tst_MathUtils::interpolateTangential()
+{
+ QFETCH(int, x);
+ QFETCH(int, xHalfLife);
+ QFETCH(int, y1);
+ QFETCH(int, y2);
+ QFETCH(int, result);
+
+ const int y = MathUtils::interpolateTangential(x, xHalfLife, y1, y2);
+ QCOMPARE(y, result);
+}
+
+QTEST_GUILESS_MAIN(tst_MathUtils)
+
+#include "tst_mathutils.moc"
diff --git a/tests/auto/utils/utils.qbs b/tests/auto/utils/utils.qbs
index 327d35d607..138b1b72ed 100644
--- a/tests/auto/utils/utils.qbs
+++ b/tests/auto/utils/utils.qbs
@@ -11,6 +11,7 @@ Project {
"fsengine/fsengine.qbs",
"fuzzymatcher/fuzzymatcher.qbs",
"indexedcontainerproxyconstiterator/indexedcontainerproxyconstiterator.qbs",
+ "mathutils/mathutils.qbs",
"multicursor/multicursor.qbs",
"persistentsettings/persistentsettings.qbs",
"qtcprocess/qtcprocess.qbs",