2017-07-21 18:21:34 +02:00
|
|
|
/******************************************************************************
|
|
|
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
|
|
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
#include "QskFlickAnimator.h"
|
|
|
|
#include <qmath.h>
|
|
|
|
|
|
|
|
static inline qreal qskAligned( qreal value )
|
|
|
|
{
|
|
|
|
if ( qFuzzyIsNull( value ) )
|
|
|
|
return 0.0;
|
|
|
|
|
|
|
|
if ( qFuzzyCompare( value, -1.0 ) )
|
|
|
|
return -1.0;
|
|
|
|
|
|
|
|
if ( qFuzzyCompare( value, 1.0 ) )
|
|
|
|
return 1.0;
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
QskFlickAnimator::QskFlickAnimator()
|
|
|
|
: m_velocity{ 0.0, 0.0 }
|
|
|
|
, m_degrees( 0.0 )
|
|
|
|
, m_cos( 1.0 )
|
|
|
|
, m_sin( 0.0 )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
setDuration( 1000 );
|
|
|
|
setEasingCurve( QEasingCurve::OutCubic );
|
|
|
|
}
|
|
|
|
|
|
|
|
QskFlickAnimator::~QskFlickAnimator()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskFlickAnimator::flick( qreal degrees, qreal velocity )
|
|
|
|
{
|
|
|
|
if ( velocity < 0.0 || qFuzzyIsNull( velocity ) )
|
|
|
|
velocity = 0.0;
|
|
|
|
|
|
|
|
stop();
|
|
|
|
|
|
|
|
setAngle( degrees );
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
m_velocity[ 0 ] = velocity;
|
|
|
|
m_velocity[ 1 ] = 0.0;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
if ( m_velocity[ 0 ] > 0.0 )
|
2017-07-21 18:21:34 +02:00
|
|
|
start();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskFlickAnimator::accelerate( qreal degrees, qreal velocity )
|
|
|
|
{
|
2018-08-03 08:15:28 +02:00
|
|
|
if ( isRunning() && !qFuzzyIsNull( m_velocity[ 1 ] ) )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
const qreal delta = qDegreesToRadians( degrees - m_degrees );
|
|
|
|
|
|
|
|
if ( qFuzzyIsNull( delta ) )
|
|
|
|
{
|
|
|
|
// the same as below, but faster to calculate: exp2( 2.0 * cos( 0.0 )
|
2018-08-03 08:15:28 +02:00
|
|
|
velocity += 4.0 * m_velocity[ 1 ];
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const qreal cos = qFastCos( delta );
|
|
|
|
if ( cos >= 0.0 )
|
|
|
|
{
|
|
|
|
// boosting the current velocity
|
2018-08-03 08:15:28 +02:00
|
|
|
velocity += exp2( 2.0 * cos ) * m_velocity[ 1 ];
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// slowing down
|
|
|
|
velocity = velocity * exp2( 2.0 * cos );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
flick( degrees, velocity );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskFlickAnimator::done()
|
|
|
|
{
|
2018-08-03 08:15:28 +02:00
|
|
|
m_velocity[ 1 ] = 0.0;
|
2017-07-21 18:21:34 +02:00
|
|
|
m_elapsed = 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskFlickAnimator::setAngle( qreal degrees )
|
|
|
|
{
|
|
|
|
if ( degrees != m_degrees )
|
|
|
|
{
|
|
|
|
m_degrees = degrees;
|
|
|
|
|
|
|
|
const qreal radians = qDegreesToRadians( degrees );
|
|
|
|
|
|
|
|
m_cos = qskAligned( qFastCos( radians ) );
|
|
|
|
m_sin = qskAligned( qFastSin( radians ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskFlickAnimator::setVelocity( qreal velocity )
|
|
|
|
{
|
2018-08-03 08:15:28 +02:00
|
|
|
m_velocity[ 0 ] = velocity;
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void QskFlickAnimator::setup()
|
|
|
|
{
|
|
|
|
m_elapsed = 0;
|
2018-08-03 08:15:28 +02:00
|
|
|
m_velocity[ 1 ] = m_velocity[ 0 ];
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void QskFlickAnimator::advance( qreal value )
|
|
|
|
{
|
2018-08-03 08:15:28 +02:00
|
|
|
const qreal oldVelocity = m_velocity[ 1 ];
|
2017-07-21 18:21:34 +02:00
|
|
|
const int oldElapsed = m_elapsed;
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
m_velocity[ 1 ] = m_velocity[ 0 ] * ( 1.0 - value );
|
2017-07-21 18:21:34 +02:00
|
|
|
m_elapsed = elapsed();
|
|
|
|
|
|
|
|
const qreal duration = ( m_elapsed - oldElapsed ) / 1000.0; // in seconds
|
|
|
|
if ( duration > 0.0 )
|
|
|
|
{
|
2018-08-03 08:15:28 +02:00
|
|
|
const qreal velocity = 0.5 * ( m_velocity[ 1 ] + oldVelocity ); // average
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Using the average velocity is not accurate, when having a non linear
|
|
|
|
curve, but the error can be ignored
|
|
|
|
*/
|
|
|
|
|
|
|
|
const qreal distance = duration * velocity;
|
|
|
|
translate( m_cos * distance, m_sin * distance );
|
|
|
|
}
|
|
|
|
}
|