0

I have a circle which I want to move smoothly on a path. The path class is like a horizontal U derived from the QPainterPath. when I start timer (QTimeLine object) the circle just jumps from the start of path to the end (start of upper U fork to the end of lower fork) with no smooth animation. Unfortunately, the QTimeLine::setLoopCount(int n) doesn't work too.

Do you have any idea about the reason?

// UPath(int forkLen, int forksDistance, QPointF startPoint)
UPath* uPath = new UPath(500, 60, QPointF(10, 10));

QList<QPointF> points = uPath->pathPoints(0.006); // returns the points of the path
                                                  // implemented by QPainterPath::pointAtPercent()

QGraphicsItem *ball = new QGraphicsEllipseItem(0, 0, 10, 10);

QTimeLine *timer = new QTimeLine(5000);
timer->setFrameRange(0, 100);
timer->setLoopCount(2);    // doesn't work

QGraphicsItemAnimation *animation = new QGraphicsItemAnimation;
animation->setItem(ball);
animation->setTimeLine(timer);

for (int i = 0; i < points.count(); ++i)
    animation->setPosAt(i/points.count(), points.at(i));

QGraphicsScene *scene = new QGraphicsScene();
scene->addItem(ball);

QGraphicsView *view = new QGraphicsView(scene);
view->setRenderHint(QPainter::Antialiasing);
view->show();

timer->start();
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
Ehsan Toghian
  • 548
  • 1
  • 6
  • 26
  • Unless I misunderstand this, your comment for uPath->pathPoints(0.006); states that it is implemented by QPainterPath::pointAtPercent, which returns just a single point, but you need to retrieve all the points....or does your upath->pathPoints(0.006) actually return a number of points? If so, what's the 0.006? – TheDarkKnight Sep 09 '13 at 12:59

1 Answers1

2

The QGraphicsAnimation class is deprecated. What you want is an adapter between a QPainterPath and the animation system. See below for a complete example.

Using painter paths for animations requires some extra smoothing (resampling) as there will be velocity changes along the path, and it won't look all that great. You may notice it when you run the code below. Painter paths are meant for painting, not for animating stuff.

The extent of this misbehavior will depend on the kind of path you're using, so it may end up working OK for the particular use case you have.

#include <QApplication>
#include <QAbstractAnimation>
#include <QPainterPath>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsEllipseItem>
#include <QDebug>

class PathAnimation : public QAbstractAnimation {
    Q_OBJECT
    Q_PROPERTY(int duration READ duration WRITE setDuration)
    QPainterPath m_path;
    int m_duration;
    QVector<QPointF> m_cache;
    QGraphicsItem * m_target;
    int m_hits, m_misses;
public:
    PathAnimation(const QPainterPath & path, QObject * parent = 0) :
        QAbstractAnimation(parent), m_path(path), m_duration(1000), m_cache(m_duration), m_target(0), m_hits(0), m_misses(0) {}
    ~PathAnimation() { qDebug() << m_hits << m_misses; }
    int duration() const { return m_duration; }
    void setDuration(int duration) {
        if (duration == 0 || duration == m_duration) return;
        m_duration = duration;
        m_cache.clear();
        m_cache.resize(m_duration);
    }
    void setTarget(QGraphicsItem * target) {
        m_target = target;
    }
    void updateCurrentTime(int ms) {
        QPointF point = m_cache.at(ms);
        if (! point.isNull()) {
            ++ m_hits;
        } else {
            point = m_path.pointAtPercent(qreal(ms) / m_duration);
            m_cache[ms] = point;
            ++ m_misses;
        }
        if (m_target) m_target->setPos(point);
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QGraphicsEllipseItem * item = new QGraphicsEllipseItem(-5, -5, 10, 10);
    item->setPen(QPen(Qt::red, 2));
    item->setBrush(Qt::lightGray);

    QPainterPath path;
    path.addEllipse(0, 0, 100, 100);
    PathAnimation animation(path);
    animation.setTarget(item);

    QGraphicsScene scene;
    scene.addItem(item);
    QGraphicsView view(&scene);
    view.setSceneRect(-50, -50, 200, 200);

    animation.setLoopCount(-1);
    animation.start();
    view.show();

    return a.exec();
}

#include "main.moc"
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313