Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_speed_smoother.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2015 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <boost/circular_buffer.hpp>
10#include <QElapsedTimer>
11#include <QPointF>
12
13#include "kis_debug.h"
14#include "kis_global.h"
15#include "kis_config.h"
16
17#define MAX_SMOOTH_HISTORY 512
18
19#define NUM_SMOOTHING_SAMPLES 3
20#define MIN_TRACKING_DISTANCE 5
21
22#include "kis_algebra_2d.h"
24
26{
27 Private(int historySize)
28 : distances(historySize),
29 timeDiffsMean(200, 0.8)
30 {
31 timer.start();
32 }
33
36 : distance(0.0)
37 , time(0.0)
38 {
39 }
40
41 DistancePoint(qreal _distance, qreal _time)
42 : distance(_distance)
43 , time(_time)
44 {
45 }
46
47 qreal distance {0.0};
48 qreal time {0.0};
49 };
50
51 typedef boost::circular_buffer<DistancePoint> DistanceBuffer;
53
55
56 QPointF lastPoint;
57 QElapsedTimer timer;
58 qreal lastTime {0.0};
59 qreal lastSpeed {0.0};
60
61 bool useTimestamps {false};
63};
64
65
71
75
77{
78 return m_d->lastSpeed;
79}
80
81qreal KisSpeedSmoother::getNextSpeed(const QPointF &pt, ulong timestamp)
82{
83 const qreal time = m_d->useTimestamps ?
84 qreal(timestamp) :
85 qreal(m_d->timer.nsecsElapsed()) / 1000000;
86
87 return getNextSpeedImpl(pt, time);
88}
89
91{
92 m_d->timer.restart();
93 m_d->distances.clear();
94 m_d->distances.push_back(Private::DistancePoint(0.0, 0.0));
95 m_d->lastPoint = QPointF();
96 m_d->lastSpeed = 0.0;
97}
98
100{
101
102 KisConfig cfg(true);
103 m_d->useTimestamps = cfg.readEntry("useTimestampsForBrushSpeed", false);
104 m_d->numSmoothingSamples = cfg.readEntry("speedValueSmoothing", 3);
105}
106
107qreal KisSpeedSmoother::getNextSpeedImpl(const QPointF &pt, qreal time)
108{
109 const qreal dist = kisDistance(pt, m_d->lastPoint);
110
111 if (m_d->lastPoint.isNull()) {
112 m_d->lastPoint = pt;
113 m_d->lastTime = time;
114 m_d->lastSpeed = 0.0;
115 return 0.0;
116 }
117
118 const qreal timeDiff = time - m_d->lastTime;
119
120 m_d->timeDiffsMean.addValue(timeDiff);
121 const qreal avgTimeDiff = m_d->timeDiffsMean.filteredMean();
122
123 m_d->lastPoint = pt;
124 m_d->lastTime = time;
125
126 m_d->distances.push_back(Private::DistancePoint(dist, time));
127
128 Private::DistanceBuffer::const_reverse_iterator it = m_d->distances.rbegin();
129 Private::DistanceBuffer::const_reverse_iterator end = m_d->distances.rend();
130
131 qreal totalDistance = 0;
132 qreal totalTime = 0.0;
133 int itemsSearched = 0;
134
135 for (; it != end; ++it) {
136 itemsSearched++;
137 totalDistance += it->distance;
138
147 totalTime += avgTimeDiff;
148
149 if (itemsSearched > m_d->numSmoothingSamples &&
150 totalDistance > MIN_TRACKING_DISTANCE) {
151
152 break;
153 }
154 }
155
156 if (totalTime > 0 && totalDistance > MIN_TRACKING_DISTANCE) {
157 m_d->lastSpeed = totalDistance / totalTime;
158 }
159
160 return m_d->lastSpeed;
161}
T readEntry(const QString &name, const T &defaultValue=T())
Definition kis_config.h:789
qreal getNextSpeed(const QPointF &pt, ulong timestamp)
qreal getNextSpeedImpl(const QPointF &pt, qreal time)
const QScopedPointer< Private > m_d
qreal kisDistance(const QPointF &pt1, const QPointF &pt2)
Definition kis_global.h:190
#define MAX_SMOOTH_HISTORY
#define MIN_TRACKING_DISTANCE
DistancePoint(qreal _distance, qreal _time)
boost::circular_buffer< DistancePoint > DistanceBuffer
KisFilteredRollingMean timeDiffsMean