9#include "kineticmodel.h"
11#include <QElapsedTimer>
14static const int KineticModelDefaultUpdateInterval = 15;
16class KineticModelPrivate
25 qreal velocityHeading;
27 qreal deaccelerationHeading;
32 bool changingPosition;
34 KineticModelPrivate();
37KineticModelPrivate::KineticModelPrivate()
43 , deacceleration(0, 0)
44 , deaccelerationHeading(0)
47 , changingPosition(true)
51KineticModel::KineticModel(
QObject *parent)
53 , d_ptr(new KineticModelPrivate)
56 d_ptr->ticker.setInterval(KineticModelDefaultUpdateInterval);
59KineticModel::~KineticModel() =
default;
61bool KineticModel::hasVelocity()
const
63 return !d_ptr->velocity.isNull();
66int KineticModel::duration()
const
68 return d_ptr->duration;
71void KineticModel::setDuration(
int ms)
76QPointF KineticModel::position()
const
78 return d_ptr->position;
81void KineticModel::setPosition(
const QPointF &position)
83 setPosition(position.
x(), position.
y());
86void KineticModel::setPosition(qreal posX, qreal posY)
88 d_ptr->position.setX(posX);
89 d_ptr->position.setY(posY);
91 int elapsed = d_ptr->timestamp.elapsed();
94 if (elapsed < d_ptr->ticker.interval() / 2) {
98 qreal delta =
static_cast<qreal
>(elapsed) / 1000.0;
100 QPointF lastSpeed = d_ptr->velocity;
101 QPointF currentSpeed = (d_ptr->position - d_ptr->lastPosition) / delta;
102 d_ptr->velocity = 0.2 * lastSpeed + 0.8 * currentSpeed;
103 d_ptr->lastPosition = d_ptr->position;
105 d_ptr->changingPosition =
true;
106 d_ptr->timestamp.start();
109void KineticModel::setHeading(qreal heading)
111 d_ptr->heading = heading;
113 int elapsed = d_ptr->timestamp.elapsed();
114 qreal delta =
static_cast<qreal
>(elapsed) / 1000.0;
116 qreal lastSpeed = d_ptr->velocityHeading;
117 qreal currentSpeed = delta ? (d_ptr->heading - d_ptr->lastHeading) / delta : 0;
118 d_ptr->velocityHeading = 0.5 * lastSpeed + 0.2 * currentSpeed;
119 d_ptr->lastHeading = d_ptr->heading;
121 d_ptr->changingPosition =
false;
122 d_ptr->timestamp.start();
125void KineticModel::jumpToPosition(
const QPointF &position)
127 jumpToPosition(position.
x(), position.
y());
130void KineticModel::jumpToPosition(qreal posX, qreal posY)
132 d_ptr->position.setX(posX);
133 d_ptr->position.setY(posY);
136int KineticModel::updateInterval()
const
138 return d_ptr->ticker.interval();
141void KineticModel::setUpdateInterval(
int ms)
143 d_ptr->ticker.setInterval(ms);
146void KineticModel::stop()
151 d->timestamp.start();
153 d->velocityHeading = 0;
156void KineticModel::start()
161 const int elapsed = d->timestamp.elapsed();
162 if (elapsed > 2 * d->ticker.interval()) {
168 d->deacceleration = d->velocity * 1000 / (1 + d_ptr->duration);
169 if (d->deacceleration.x() < 0) {
170 d->deacceleration.setX(-d->deacceleration.x());
172 if (d->deacceleration.y() < 0) {
173 d->deacceleration.setY(-d->deacceleration.y());
176 d->deaccelerationHeading = qAbs(d->velocityHeading) * 1000 / (1 + d_ptr->duration);
178 if (!d->ticker.isActive())
182void KineticModel::update()
186 int elapsed = qMin(
static_cast<int>(d->timestamp.elapsed()), 100);
187 qreal delta =
static_cast<qreal
>(elapsed) / 1000.0;
190 if (d->changingPosition) {
191 d->position += d->velocity * delta;
192 QPointF vstep = d->deacceleration * delta;
194 if (d->velocity.x() < vstep.
x() && d->velocity.x() >= -vstep.
x()) {
197 if (d->velocity.x() > 0)
198 d->velocity.setX(d->velocity.x() - vstep.
x());
200 d->velocity.setX(d->velocity.x() + vstep.
x());
203 if (d->velocity.y() < vstep.
y() && d->velocity.y() >= -vstep.
y()) {
206 if (d->velocity.y() > 0)
207 d->velocity.setY(d->velocity.y() - vstep.
y());
209 d->velocity.setY(d->velocity.y() + vstep.
y());
212 stop = d->velocity.isNull();
214 Q_EMIT positionChanged(d->position.x(), d->position.y());
216 d->heading += d->velocityHeading * delta;
217 qreal vstep = d->deaccelerationHeading * delta;
218 if ((d->velocityHeading < vstep && d->velocityHeading >= -vstep) || !vstep) {
219 d->velocityHeading = 0;
221 d->velocityHeading += d->velocityHeading > 0 ? -1 * vstep : vstep;
224 stop = !d->velocityHeading;
226 Q_EMIT headingChanged(d->heading);
234 d->timestamp.start();
237#include "moc_kineticmodel.cpp"
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)