Repo created
This commit is contained in:
parent
4af19165ec
commit
68073add76
12458 changed files with 12350765 additions and 2 deletions
132
libs/drape_frontend/animation/animation.cpp
Normal file
132
libs/drape_frontend/animation/animation.cpp
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
#include "drape_frontend/animation/animation.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
// static
|
||||
bool Animation::GetCachedProperty(TPropertyCache const & properties, Object object, ObjectProperty property,
|
||||
PropertyValue & value)
|
||||
{
|
||||
auto const it = properties.find(std::make_pair(object, property));
|
||||
if (it != properties.end())
|
||||
{
|
||||
value = it->second;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
void Animation::GetCurrentScreen(TPropertyCache const & properties, ScreenBase const & screen,
|
||||
ScreenBase & currentScreen)
|
||||
{
|
||||
currentScreen = screen;
|
||||
|
||||
if (!properties.empty())
|
||||
{
|
||||
double scale = currentScreen.GetScale();
|
||||
double angle = currentScreen.GetAngle();
|
||||
m2::PointD pos = currentScreen.GlobalRect().GlobalZero();
|
||||
|
||||
PropertyValue value;
|
||||
if (GetCachedProperty(properties, Object::MapPlane, ObjectProperty::Scale, value))
|
||||
scale = value.m_valueD;
|
||||
|
||||
if (GetCachedProperty(properties, Object::MapPlane, ObjectProperty::Angle, value))
|
||||
angle = value.m_valueD;
|
||||
|
||||
if (GetCachedProperty(properties, Object::MapPlane, ObjectProperty::Position, value))
|
||||
pos = value.m_valuePointD;
|
||||
|
||||
currentScreen.SetFromParams(pos, angle, scale);
|
||||
}
|
||||
}
|
||||
|
||||
bool Animation::HasSameObjects(Animation const & animation) const
|
||||
{
|
||||
TAnimObjects const & objects = animation.GetObjects();
|
||||
for (auto const & object : objects)
|
||||
if (HasObject(object))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Animation::CouldBeBlendedWith(Animation const & animation) const
|
||||
{
|
||||
return !HasSameObjects(animation) ||
|
||||
((GetType() != animation.GetType()) && m_couldBeBlended && animation.m_couldBeBlended);
|
||||
}
|
||||
|
||||
bool Animation::HasTargetProperty(Object object, ObjectProperty property) const
|
||||
{
|
||||
return HasProperty(object, property);
|
||||
}
|
||||
|
||||
// static
|
||||
bool Animation::GetMinDuration(Interpolator const & interpolator, double & minDuration)
|
||||
{
|
||||
if (interpolator.IsActive())
|
||||
{
|
||||
double const duration = interpolator.GetMinDuration();
|
||||
if (duration >= 0.0)
|
||||
minDuration = minDuration >= 0.0 ? std::min(duration, minDuration) : duration;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool Animation::GetMaxDuration(Interpolator const & interpolator, double & maxDuration)
|
||||
{
|
||||
if (interpolator.IsActive())
|
||||
{
|
||||
double const duration = interpolator.GetMaxDuration();
|
||||
if (duration >= 0.0)
|
||||
maxDuration = maxDuration >= 0.0 ? std::max(duration, maxDuration) : duration;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string DebugPrint(Animation::Type const & type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Animation::Type::Sequence: return "Sequence";
|
||||
case Animation::Type::Parallel: return "Parallel";
|
||||
case Animation::Type::MapLinear: return "MapLinear";
|
||||
case Animation::Type::MapScale: return "MapScale";
|
||||
case Animation::Type::MapFollow: return "MapFollow";
|
||||
case Animation::Type::Arrow: return "Arrow";
|
||||
case Animation::Type::KineticScroll: return "KineticScroll";
|
||||
}
|
||||
return "Unknown type";
|
||||
}
|
||||
|
||||
std::string DebugPrint(Animation::Object const & object)
|
||||
{
|
||||
switch (object)
|
||||
{
|
||||
case Animation::Object::MyPositionArrow: return "MyPositionArrow";
|
||||
case Animation::Object::MapPlane: return "MapPlane";
|
||||
case Animation::Object::Selection: return "Selection";
|
||||
}
|
||||
return "Unknown object";
|
||||
}
|
||||
|
||||
std::string DebugPrint(Animation::ObjectProperty const & property)
|
||||
{
|
||||
switch (property)
|
||||
{
|
||||
case Animation::ObjectProperty::Position: return "Position";
|
||||
case Animation::ObjectProperty::Scale: return "Scale";
|
||||
case Animation::ObjectProperty::Angle: return "Angle";
|
||||
}
|
||||
return "Unknown property";
|
||||
}
|
||||
|
||||
} // namespace df
|
||||
169
libs/drape_frontend/animation/animation.hpp
Normal file
169
libs/drape_frontend/animation/animation.hpp
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
#pragma once
|
||||
|
||||
#include "drape_frontend/animation/interpolators.hpp"
|
||||
|
||||
#include "drape/pointers.hpp"
|
||||
|
||||
#include "geometry/point2d.hpp"
|
||||
#include "geometry/screenbase.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
class Animation
|
||||
{
|
||||
public:
|
||||
enum class Type
|
||||
{
|
||||
Sequence,
|
||||
Parallel,
|
||||
MapLinear,
|
||||
MapScale,
|
||||
MapFollow,
|
||||
Arrow,
|
||||
KineticScroll
|
||||
};
|
||||
|
||||
enum class Object
|
||||
{
|
||||
MyPositionArrow,
|
||||
MapPlane,
|
||||
Selection
|
||||
};
|
||||
|
||||
enum class ObjectProperty
|
||||
{
|
||||
Position,
|
||||
Scale,
|
||||
Angle
|
||||
};
|
||||
|
||||
struct PropertyValue
|
||||
{
|
||||
enum class Type
|
||||
{
|
||||
ValueD,
|
||||
ValuePointD
|
||||
};
|
||||
|
||||
PropertyValue() {}
|
||||
|
||||
explicit PropertyValue(double value) : m_type(Type::ValueD), m_valueD(value) {}
|
||||
|
||||
explicit PropertyValue(m2::PointD const & value) : m_type(Type::ValuePointD), m_valuePointD(value) {}
|
||||
|
||||
Type m_type;
|
||||
union
|
||||
{
|
||||
m2::PointD m_valuePointD;
|
||||
double m_valueD;
|
||||
};
|
||||
};
|
||||
|
||||
using TAnimObjects = std::set<Object>;
|
||||
using TObjectProperties = std::set<ObjectProperty>;
|
||||
using TAction = std::function<void(ref_ptr<Animation>)>;
|
||||
using TPropertyCache = std::map<std::pair<Object, ObjectProperty>, Animation::PropertyValue>;
|
||||
|
||||
Animation(bool couldBeInterrupted, bool couldBeBlended)
|
||||
: m_couldBeInterrupted(couldBeInterrupted)
|
||||
, m_couldBeBlended(couldBeBlended)
|
||||
, m_interruptedOnCombine(false)
|
||||
, m_couldBeRewinded(true)
|
||||
{}
|
||||
|
||||
virtual ~Animation() = default;
|
||||
|
||||
virtual void Init(ScreenBase const & screen, TPropertyCache const & properties) {}
|
||||
virtual void OnStart()
|
||||
{
|
||||
if (m_onStartAction != nullptr)
|
||||
m_onStartAction(this);
|
||||
}
|
||||
virtual void OnFinish()
|
||||
{
|
||||
if (m_onFinishAction != nullptr)
|
||||
m_onFinishAction(this);
|
||||
}
|
||||
virtual void Interrupt()
|
||||
{
|
||||
if (m_onInterruptAction != nullptr)
|
||||
m_onInterruptAction(this);
|
||||
}
|
||||
|
||||
virtual Type GetType() const = 0;
|
||||
virtual std::string GetCustomType() const { return std::string(); }
|
||||
|
||||
virtual TAnimObjects const & GetObjects() const = 0;
|
||||
virtual bool HasObject(Object object) const = 0;
|
||||
virtual TObjectProperties const & GetProperties(Object object) const = 0;
|
||||
virtual bool HasProperty(Object object, ObjectProperty property) const = 0;
|
||||
virtual bool HasTargetProperty(Object object, ObjectProperty property) const;
|
||||
|
||||
static double constexpr kInvalidAnimationDuration = -1.0;
|
||||
|
||||
virtual void SetMaxDuration(double maxDuration) = 0;
|
||||
virtual void SetMinDuration(double minDuration) = 0;
|
||||
virtual double GetDuration() const = 0;
|
||||
virtual double GetMaxDuration() const = 0;
|
||||
virtual double GetMinDuration() const = 0;
|
||||
virtual bool IsFinished() const = 0;
|
||||
|
||||
virtual void Advance(double elapsedSeconds) = 0;
|
||||
virtual void Finish() { OnFinish(); }
|
||||
|
||||
virtual bool GetProperty(Object object, ObjectProperty property, PropertyValue & value) const = 0;
|
||||
virtual bool GetTargetProperty(Object object, ObjectProperty property, PropertyValue & value) const = 0;
|
||||
|
||||
void SetOnStartAction(TAction const & action) { m_onStartAction = action; }
|
||||
void SetOnFinishAction(TAction const & action) { m_onFinishAction = action; }
|
||||
void SetOnInterruptAction(TAction const & action) { m_onInterruptAction = action; }
|
||||
|
||||
bool CouldBeBlended() const { return m_couldBeBlended; }
|
||||
bool CouldBeInterrupted() const { return m_couldBeInterrupted; }
|
||||
bool CouldBeBlendedWith(Animation const & animation) const;
|
||||
bool HasSameObjects(Animation const & animation) const;
|
||||
|
||||
void SetInterruptedOnCombine(bool enable) { m_interruptedOnCombine = enable; }
|
||||
bool GetInterruptedOnCombine() const { return m_interruptedOnCombine; }
|
||||
|
||||
void SetCouldBeInterrupted(bool enable) { m_couldBeInterrupted = enable; }
|
||||
void SetCouldBeBlended(bool enable) { m_couldBeBlended = enable; }
|
||||
|
||||
void SetCouldBeRewinded(bool enable) { m_couldBeRewinded = enable; }
|
||||
bool CouldBeRewinded() const { return m_couldBeRewinded; }
|
||||
|
||||
protected:
|
||||
static void GetCurrentScreen(TPropertyCache const & properties, ScreenBase const & screen,
|
||||
ScreenBase & currentScreen);
|
||||
static bool GetCachedProperty(TPropertyCache const & properties, Object object, ObjectProperty property,
|
||||
PropertyValue & value);
|
||||
|
||||
static bool GetMinDuration(Interpolator const & interpolator, double & minDuration);
|
||||
static bool GetMaxDuration(Interpolator const & interpolator, double & maxDuration);
|
||||
|
||||
TAction m_onStartAction;
|
||||
TAction m_onFinishAction;
|
||||
TAction m_onInterruptAction;
|
||||
|
||||
// Animation could be interrupted in case of blending impossibility.
|
||||
bool m_couldBeInterrupted;
|
||||
// Animation could be blended with other animations.
|
||||
bool m_couldBeBlended;
|
||||
// Animation must be interrupted in case of combining another animation.
|
||||
bool m_interruptedOnCombine;
|
||||
// Animation could be rewinded in case of finishing.
|
||||
bool m_couldBeRewinded;
|
||||
};
|
||||
|
||||
std::string DebugPrint(Animation::Type const & type);
|
||||
std::string DebugPrint(Animation::Object const & object);
|
||||
std::string DebugPrint(Animation::ObjectProperty const & property);
|
||||
|
||||
} // namespace df
|
||||
185
libs/drape_frontend/animation/arrow_animation.cpp
Normal file
185
libs/drape_frontend/animation/arrow_animation.cpp
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
#include "drape_frontend/animation/arrow_animation.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
ArrowAnimation::ArrowAnimation(m2::PointD const & startPos, m2::PointD const & endPos, double moveDuration,
|
||||
double startAngle, double endAngle)
|
||||
: Animation(true /* couldBeInterrupted */, true /* couldBeBlended */)
|
||||
, m_positionInterpolator(moveDuration, 0.0 /* delay */, startPos, endPos)
|
||||
, m_angleInterpolator(startAngle, endAngle)
|
||||
{
|
||||
m_objects.insert(Animation::Object::MyPositionArrow);
|
||||
if (m_positionInterpolator.IsActive())
|
||||
m_properties.insert(Animation::ObjectProperty::Position);
|
||||
if (m_angleInterpolator.IsActive())
|
||||
m_properties.insert(Animation::ObjectProperty::Angle);
|
||||
}
|
||||
|
||||
void ArrowAnimation::Init(ScreenBase const & screen, TPropertyCache const & properties)
|
||||
{
|
||||
PropertyValue value;
|
||||
double minDuration;
|
||||
double maxDuration;
|
||||
if (GetCachedProperty(properties, Animation::Object::MyPositionArrow, Animation::ObjectProperty::Position, value))
|
||||
{
|
||||
minDuration = m_positionInterpolator.GetMinDuration();
|
||||
maxDuration = m_positionInterpolator.GetMaxDuration();
|
||||
|
||||
m_positionInterpolator = PositionInterpolator(m_positionInterpolator.GetDuration(), 0.0 /* delay */,
|
||||
value.m_valuePointD, m_positionInterpolator.GetTargetPosition());
|
||||
|
||||
m_positionInterpolator.SetMinDuration(minDuration);
|
||||
m_positionInterpolator.SetMaxDuration(maxDuration);
|
||||
|
||||
if (m_positionInterpolator.IsActive())
|
||||
m_properties.insert(Animation::ObjectProperty::Position);
|
||||
}
|
||||
if (GetCachedProperty(properties, Animation::Object::MyPositionArrow, Animation::ObjectProperty::Angle, value))
|
||||
{
|
||||
minDuration = m_angleInterpolator.GetMinDuration();
|
||||
maxDuration = m_angleInterpolator.GetMaxDuration();
|
||||
|
||||
m_angleInterpolator = AngleInterpolator(value.m_valueD, m_angleInterpolator.GetTargetAngle());
|
||||
|
||||
m_angleInterpolator.SetMinDuration(minDuration);
|
||||
m_angleInterpolator.SetMaxDuration(maxDuration);
|
||||
|
||||
if (m_angleInterpolator.IsActive())
|
||||
m_properties.insert(Animation::ObjectProperty::Angle);
|
||||
}
|
||||
}
|
||||
|
||||
Animation::TAnimObjects const & ArrowAnimation::GetObjects() const
|
||||
{
|
||||
return m_objects;
|
||||
}
|
||||
|
||||
bool ArrowAnimation::HasObject(Object object) const
|
||||
{
|
||||
return object == Animation::Object::MyPositionArrow;
|
||||
}
|
||||
|
||||
Animation::TObjectProperties const & ArrowAnimation::GetProperties(Object object) const
|
||||
{
|
||||
return m_properties;
|
||||
}
|
||||
|
||||
bool ArrowAnimation::HasProperty(Object object, ObjectProperty property) const
|
||||
{
|
||||
return HasObject(object) && m_properties.find(property) != m_properties.end();
|
||||
}
|
||||
|
||||
void ArrowAnimation::Advance(double elapsedSeconds)
|
||||
{
|
||||
if (m_positionInterpolator.IsActive())
|
||||
m_positionInterpolator.Advance(elapsedSeconds);
|
||||
|
||||
if (m_angleInterpolator.IsActive())
|
||||
m_angleInterpolator.Advance(elapsedSeconds);
|
||||
}
|
||||
|
||||
void ArrowAnimation::Finish()
|
||||
{
|
||||
if (m_positionInterpolator.IsActive())
|
||||
m_positionInterpolator.Finish();
|
||||
|
||||
if (m_angleInterpolator.IsActive())
|
||||
m_angleInterpolator.Finish();
|
||||
}
|
||||
|
||||
void ArrowAnimation::SetMaxDuration(double maxDuration)
|
||||
{
|
||||
if (m_positionInterpolator.IsActive())
|
||||
m_positionInterpolator.SetMaxDuration(maxDuration);
|
||||
|
||||
if (m_angleInterpolator.IsActive())
|
||||
m_angleInterpolator.SetMaxDuration(maxDuration);
|
||||
}
|
||||
|
||||
void ArrowAnimation::SetMinDuration(double minDuration)
|
||||
{
|
||||
if (m_positionInterpolator.IsActive())
|
||||
m_positionInterpolator.SetMinDuration(minDuration);
|
||||
|
||||
if (m_angleInterpolator.IsActive())
|
||||
m_angleInterpolator.SetMinDuration(minDuration);
|
||||
}
|
||||
|
||||
double ArrowAnimation::GetDuration() const
|
||||
{
|
||||
double duration = 0.0;
|
||||
if (m_angleInterpolator.IsActive())
|
||||
duration = m_angleInterpolator.GetDuration();
|
||||
if (m_positionInterpolator.IsActive())
|
||||
duration = std::max(duration, m_positionInterpolator.GetDuration());
|
||||
return duration;
|
||||
}
|
||||
|
||||
double ArrowAnimation::GetMaxDuration() const
|
||||
{
|
||||
double maxDuration = Animation::kInvalidAnimationDuration;
|
||||
|
||||
if (!Animation::GetMaxDuration(m_angleInterpolator, maxDuration) ||
|
||||
!Animation::GetMaxDuration(m_positionInterpolator, maxDuration))
|
||||
return Animation::kInvalidAnimationDuration;
|
||||
|
||||
return maxDuration;
|
||||
}
|
||||
|
||||
double ArrowAnimation::GetMinDuration() const
|
||||
{
|
||||
double minDuration = Animation::kInvalidAnimationDuration;
|
||||
|
||||
if (!Animation::GetMinDuration(m_angleInterpolator, minDuration) ||
|
||||
!Animation::GetMinDuration(m_positionInterpolator, minDuration))
|
||||
return Animation::kInvalidAnimationDuration;
|
||||
|
||||
return minDuration;
|
||||
}
|
||||
|
||||
bool ArrowAnimation::IsFinished() const
|
||||
{
|
||||
return m_positionInterpolator.IsFinished() && m_angleInterpolator.IsFinished();
|
||||
}
|
||||
|
||||
bool ArrowAnimation::GetProperty(Object object, ObjectProperty property, PropertyValue & value) const
|
||||
{
|
||||
return GetProperty(object, property, false /* targetValue */, value);
|
||||
}
|
||||
|
||||
bool ArrowAnimation::GetTargetProperty(Object object, ObjectProperty property, PropertyValue & value) const
|
||||
{
|
||||
return GetProperty(object, property, true /* targetValue */, value);
|
||||
}
|
||||
|
||||
bool ArrowAnimation::GetProperty(Object object, ObjectProperty property, bool targetValue, PropertyValue & value) const
|
||||
{
|
||||
ASSERT_EQUAL(static_cast<int>(object), static_cast<int>(Animation::Object::MyPositionArrow), ());
|
||||
|
||||
switch (property)
|
||||
{
|
||||
case Animation::ObjectProperty::Position:
|
||||
if (m_positionInterpolator.IsActive())
|
||||
{
|
||||
value = PropertyValue(targetValue ? m_positionInterpolator.GetTargetPosition()
|
||||
: m_positionInterpolator.GetPosition());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case Animation::ObjectProperty::Angle:
|
||||
if (m_angleInterpolator.IsActive())
|
||||
{
|
||||
value = PropertyValue(targetValue ? m_angleInterpolator.GetTargetAngle() : m_angleInterpolator.GetAngle());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
default: ASSERT(false, ("Wrong property:", static_cast<int>(property)));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace df
|
||||
46
libs/drape_frontend/animation/arrow_animation.hpp
Normal file
46
libs/drape_frontend/animation/arrow_animation.hpp
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
#pragma once
|
||||
|
||||
#include "animation.hpp"
|
||||
#include "interpolators.hpp"
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
class ArrowAnimation : public Animation
|
||||
{
|
||||
public:
|
||||
ArrowAnimation(m2::PointD const & startPos, m2::PointD const & endPos, double moveDuration, double startAngle,
|
||||
double endAngle);
|
||||
|
||||
void Init(ScreenBase const & screen, TPropertyCache const & properties) override;
|
||||
|
||||
Animation::Type GetType() const override { return Animation::Type::Arrow; }
|
||||
|
||||
TAnimObjects const & GetObjects() const override;
|
||||
bool HasObject(Object object) const override;
|
||||
TObjectProperties const & GetProperties(Object object) const override;
|
||||
bool HasProperty(Object object, ObjectProperty property) const override;
|
||||
|
||||
void SetMaxDuration(double maxDuration) override;
|
||||
void SetMinDuration(double minDuration) override;
|
||||
double GetDuration() const override;
|
||||
double GetMinDuration() const override;
|
||||
double GetMaxDuration() const override;
|
||||
bool IsFinished() const override;
|
||||
|
||||
void Advance(double elapsedSeconds) override;
|
||||
void Finish() override;
|
||||
|
||||
bool GetProperty(Object object, ObjectProperty property, PropertyValue & value) const override;
|
||||
bool GetTargetProperty(Object object, ObjectProperty property, PropertyValue & value) const override;
|
||||
|
||||
private:
|
||||
bool GetProperty(Object object, ObjectProperty property, bool targetValue, PropertyValue & value) const;
|
||||
|
||||
TAnimObjects m_objects;
|
||||
TObjectProperties m_properties;
|
||||
PositionInterpolator m_positionInterpolator;
|
||||
AngleInterpolator m_angleInterpolator;
|
||||
};
|
||||
|
||||
} // namespace df
|
||||
52
libs/drape_frontend/animation/base_interpolator.cpp
Normal file
52
libs/drape_frontend/animation/base_interpolator.cpp
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
#include "drape_frontend/animation/base_interpolator.hpp"
|
||||
#include "drape_frontend/animation/interpolation_holder.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
#include "base/math.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace df
|
||||
{
|
||||
BaseInterpolator::BaseInterpolator(double duration, double delay)
|
||||
: m_elapsedTime(0.0)
|
||||
, m_duration(duration)
|
||||
, m_delay(delay)
|
||||
{
|
||||
ASSERT(m_duration > 0.0, ());
|
||||
InterpolationHolder::Instance().RegisterInterpolator(this);
|
||||
}
|
||||
|
||||
BaseInterpolator::~BaseInterpolator()
|
||||
{
|
||||
InterpolationHolder::Instance().DeregisterInterpolator(this);
|
||||
}
|
||||
|
||||
bool BaseInterpolator::IsFinished() const
|
||||
{
|
||||
return m_elapsedTime > (m_duration + m_delay);
|
||||
}
|
||||
|
||||
void BaseInterpolator::Advance(double elapsedSeconds)
|
||||
{
|
||||
m_elapsedTime += elapsedSeconds;
|
||||
}
|
||||
|
||||
double BaseInterpolator::GetT() const
|
||||
{
|
||||
if (IsFinished())
|
||||
return 1.0;
|
||||
|
||||
return std::max(m_elapsedTime - m_delay, 0.0) / m_duration;
|
||||
}
|
||||
|
||||
double BaseInterpolator::GetElapsedTime() const
|
||||
{
|
||||
return m_elapsedTime;
|
||||
}
|
||||
|
||||
double BaseInterpolator::GetDuration() const
|
||||
{
|
||||
return m_duration;
|
||||
}
|
||||
} // namespace df
|
||||
24
libs/drape_frontend/animation/base_interpolator.hpp
Normal file
24
libs/drape_frontend/animation/base_interpolator.hpp
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
namespace df
|
||||
{
|
||||
class BaseInterpolator
|
||||
{
|
||||
public:
|
||||
explicit BaseInterpolator(double duration, double delay = 0);
|
||||
virtual ~BaseInterpolator();
|
||||
|
||||
bool IsFinished() const;
|
||||
virtual void Advance(double elapsedSeconds);
|
||||
|
||||
protected:
|
||||
double GetT() const;
|
||||
double GetElapsedTime() const;
|
||||
double GetDuration() const;
|
||||
|
||||
private:
|
||||
double m_elapsedTime;
|
||||
double m_duration;
|
||||
double m_delay;
|
||||
};
|
||||
} // namespace df
|
||||
232
libs/drape_frontend/animation/follow_animation.cpp
Normal file
232
libs/drape_frontend/animation/follow_animation.cpp
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
#include "drape_frontend/animation/follow_animation.hpp"
|
||||
|
||||
#include "drape_frontend/animation_constants.hpp"
|
||||
#include "drape_frontend/animation_system.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
#include "base/logging.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
MapFollowAnimation::MapFollowAnimation(ScreenBase const & screen, m2::PointD const & globalUserPosition,
|
||||
m2::PointD const & endPixelPosition, double endScale, double endAngle,
|
||||
bool isAutoZoom)
|
||||
: Animation(true /* couldBeInterrupted */, true /* couldBeBlended */)
|
||||
, m_isAutoZoom(isAutoZoom)
|
||||
, m_globalPosition(globalUserPosition)
|
||||
, m_endPixelPosition(endPixelPosition)
|
||||
, m_endScale(endScale)
|
||||
, m_endAngle(endAngle)
|
||||
{
|
||||
TPropertyCache properties;
|
||||
Init(screen, properties);
|
||||
}
|
||||
|
||||
void MapFollowAnimation::Init(ScreenBase const & screen, TPropertyCache const & properties)
|
||||
{
|
||||
ScreenBase currentScreen;
|
||||
GetCurrentScreen(properties, screen, currentScreen);
|
||||
|
||||
double minDuration = m_offsetInterpolator.GetMinDuration();
|
||||
double maxDuration = m_offsetInterpolator.GetMaxDuration();
|
||||
|
||||
m_offset = currentScreen.PtoG(currentScreen.P3dtoP(m_endPixelPosition)) - m_globalPosition;
|
||||
double const averageScale = m_isAutoZoom ? currentScreen.GetScale() : (currentScreen.GetScale() + m_endScale) / 2.0;
|
||||
double const moveDuration =
|
||||
PositionInterpolator::GetMoveDuration(m_offset.Length(), screen.PixelRectIn3d(), averageScale);
|
||||
m_offsetInterpolator = PositionInterpolator(moveDuration, 0.0, m_offset, m2::PointD(0.0, 0.0));
|
||||
|
||||
m_offsetInterpolator.SetMinDuration(minDuration);
|
||||
m_offsetInterpolator.SetMaxDuration(maxDuration);
|
||||
|
||||
maxDuration = m_scaleInterpolator.GetMaxDuration();
|
||||
m_scaleInterpolator = ScaleInterpolator(currentScreen.GetScale(), m_endScale, m_isAutoZoom);
|
||||
m_scaleInterpolator.SetMaxDuration(maxDuration);
|
||||
|
||||
maxDuration = m_angleInterpolator.GetMaxDuration();
|
||||
m_angleInterpolator = AngleInterpolator(currentScreen.GetAngle(), m_endAngle);
|
||||
m_angleInterpolator.SetMaxDuration(maxDuration);
|
||||
|
||||
double const duration = CalculateDuration();
|
||||
|
||||
m_scaleInterpolator.SetMinDuration(duration);
|
||||
m_angleInterpolator.SetMinDuration(duration);
|
||||
|
||||
m_objects.insert(Animation::Object::MapPlane);
|
||||
|
||||
if (m_scaleInterpolator.IsActive())
|
||||
m_properties.insert(Animation::ObjectProperty::Scale);
|
||||
if (m_angleInterpolator.IsActive())
|
||||
m_properties.insert(Animation::ObjectProperty::Angle);
|
||||
if (m_offsetInterpolator.IsActive() || m_scaleInterpolator.IsActive() || m_angleInterpolator.IsActive())
|
||||
m_properties.insert(Animation::ObjectProperty::Position);
|
||||
|
||||
// If MapFollowAnimation affects only angles, disable rewinding.
|
||||
SetCouldBeRewinded(!m_angleInterpolator.IsActive() || m_scaleInterpolator.IsActive() ||
|
||||
m_offsetInterpolator.IsActive());
|
||||
}
|
||||
|
||||
Animation::TObjectProperties const & MapFollowAnimation::GetProperties(Object object) const
|
||||
{
|
||||
ASSERT_EQUAL(static_cast<int>(object), static_cast<int>(Animation::Object::MapPlane), ());
|
||||
return m_properties;
|
||||
}
|
||||
|
||||
bool MapFollowAnimation::HasProperty(Object object, ObjectProperty property) const
|
||||
{
|
||||
return HasObject(object) && m_properties.find(property) != m_properties.end();
|
||||
}
|
||||
|
||||
void MapFollowAnimation::Advance(double elapsedSeconds)
|
||||
{
|
||||
if (m_angleInterpolator.IsActive())
|
||||
m_angleInterpolator.Advance(elapsedSeconds);
|
||||
if (m_scaleInterpolator.IsActive())
|
||||
m_scaleInterpolator.Advance(elapsedSeconds);
|
||||
if (m_offsetInterpolator.IsActive())
|
||||
m_offsetInterpolator.Advance(elapsedSeconds);
|
||||
}
|
||||
|
||||
void MapFollowAnimation::Finish()
|
||||
{
|
||||
if (m_angleInterpolator.IsActive())
|
||||
m_angleInterpolator.Finish();
|
||||
if (m_scaleInterpolator.IsActive())
|
||||
{
|
||||
if (m_isAutoZoom)
|
||||
m_scaleInterpolator.SetActive(false);
|
||||
else
|
||||
m_scaleInterpolator.Finish();
|
||||
}
|
||||
if (m_offsetInterpolator.IsActive())
|
||||
m_offsetInterpolator.Finish();
|
||||
Animation::Finish();
|
||||
}
|
||||
|
||||
void MapFollowAnimation::SetMaxDuration(double maxDuration)
|
||||
{
|
||||
if (m_angleInterpolator.IsActive())
|
||||
m_angleInterpolator.SetMaxDuration(maxDuration);
|
||||
if (!m_isAutoZoom && m_scaleInterpolator.IsActive())
|
||||
m_scaleInterpolator.SetMaxDuration(maxDuration);
|
||||
if (m_offsetInterpolator.IsActive())
|
||||
m_offsetInterpolator.SetMaxDuration(maxDuration);
|
||||
}
|
||||
|
||||
void MapFollowAnimation::SetMinDuration(double minDuration)
|
||||
{
|
||||
if (m_angleInterpolator.IsActive())
|
||||
m_angleInterpolator.SetMinDuration(minDuration);
|
||||
if (!m_isAutoZoom && m_scaleInterpolator.IsActive())
|
||||
m_scaleInterpolator.SetMinDuration(minDuration);
|
||||
if (m_offsetInterpolator.IsActive())
|
||||
m_offsetInterpolator.SetMinDuration(minDuration);
|
||||
}
|
||||
|
||||
double MapFollowAnimation::GetDuration() const
|
||||
{
|
||||
return CalculateDuration();
|
||||
}
|
||||
|
||||
double MapFollowAnimation::GetMaxDuration() const
|
||||
{
|
||||
double maxDuration = Animation::kInvalidAnimationDuration;
|
||||
|
||||
if (!Animation::GetMaxDuration(m_angleInterpolator, maxDuration) ||
|
||||
(!m_isAutoZoom && !Animation::GetMaxDuration(m_scaleInterpolator, maxDuration)) ||
|
||||
!Animation::GetMaxDuration(m_offsetInterpolator, maxDuration))
|
||||
return Animation::kInvalidAnimationDuration;
|
||||
|
||||
return maxDuration;
|
||||
}
|
||||
|
||||
double MapFollowAnimation::GetMinDuration() const
|
||||
{
|
||||
double minDuration = Animation::kInvalidAnimationDuration;
|
||||
|
||||
if (!Animation::GetMinDuration(m_angleInterpolator, minDuration) ||
|
||||
(!m_isAutoZoom && !Animation::GetMinDuration(m_scaleInterpolator, minDuration)) ||
|
||||
!Animation::GetMinDuration(m_offsetInterpolator, minDuration))
|
||||
return Animation::kInvalidAnimationDuration;
|
||||
|
||||
return minDuration;
|
||||
}
|
||||
|
||||
double MapFollowAnimation::CalculateDuration() const
|
||||
{
|
||||
double duration = std::max(m_angleInterpolator.GetDuration(), m_offsetInterpolator.GetDuration());
|
||||
if (!m_isAutoZoom)
|
||||
duration = std::max(duration, m_scaleInterpolator.GetDuration());
|
||||
return duration;
|
||||
}
|
||||
|
||||
bool MapFollowAnimation::IsFinished() const
|
||||
{
|
||||
return m_angleInterpolator.IsFinished() && m_scaleInterpolator.IsFinished() && m_offsetInterpolator.IsFinished();
|
||||
}
|
||||
|
||||
bool MapFollowAnimation::GetProperty(Object object, ObjectProperty property, PropertyValue & value) const
|
||||
{
|
||||
return GetProperty(object, property, false /* targetValue */, value);
|
||||
}
|
||||
|
||||
bool MapFollowAnimation::GetTargetProperty(Object object, ObjectProperty property, PropertyValue & value) const
|
||||
{
|
||||
return GetProperty(object, property, true /* targetValue */, value);
|
||||
}
|
||||
|
||||
bool MapFollowAnimation::GetProperty(Object object, ObjectProperty property, bool targetValue,
|
||||
PropertyValue & value) const
|
||||
{
|
||||
if (property == Animation::ObjectProperty::Position)
|
||||
{
|
||||
ScreenBase tmp = AnimationSystem::Instance().GetLastScreen();
|
||||
if (targetValue)
|
||||
{
|
||||
tmp.SetFromParams(m_globalPosition, m_angleInterpolator.GetTargetAngle(),
|
||||
m_isAutoZoom ? m_scaleInterpolator.GetScale() : m_scaleInterpolator.GetTargetScale());
|
||||
tmp.MatchGandP3d(m_globalPosition, m_endPixelPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
double const scale = m_scaleInterpolator.GetScale() / m_scaleInterpolator.GetStartScale();
|
||||
double const angle = m_angleInterpolator.GetAngle() - m_angleInterpolator.GetStartAngle();
|
||||
m2::PointD offset = m_offsetInterpolator.GetPosition() * scale;
|
||||
offset.Rotate(angle);
|
||||
m2::PointD pos = m_globalPosition + offset;
|
||||
|
||||
tmp.SetFromParams(m_globalPosition, m_angleInterpolator.GetAngle(), m_scaleInterpolator.GetScale());
|
||||
tmp.MatchGandP3d(pos, m_endPixelPosition);
|
||||
}
|
||||
value = PropertyValue(tmp.GetOrg());
|
||||
return true;
|
||||
}
|
||||
if (property == Animation::ObjectProperty::Angle)
|
||||
{
|
||||
value = PropertyValue(targetValue ? m_angleInterpolator.GetTargetAngle() : m_angleInterpolator.GetAngle());
|
||||
return true;
|
||||
}
|
||||
if (property == Animation::ObjectProperty::Scale)
|
||||
{
|
||||
value = PropertyValue((targetValue && !m_isAutoZoom) ? m_scaleInterpolator.GetTargetScale()
|
||||
: m_scaleInterpolator.GetScale());
|
||||
return true;
|
||||
}
|
||||
ASSERT(false, ("Wrong property:", static_cast<int>(property)));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MapFollowAnimation::HasScale() const
|
||||
{
|
||||
return m_scaleInterpolator.IsActive();
|
||||
}
|
||||
|
||||
bool MapFollowAnimation::HasPixelOffset() const
|
||||
{
|
||||
return m_offsetInterpolator.IsActive();
|
||||
}
|
||||
|
||||
} // namespace df
|
||||
64
libs/drape_frontend/animation/follow_animation.hpp
Normal file
64
libs/drape_frontend/animation/follow_animation.hpp
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
#pragma once
|
||||
|
||||
#include "animation.hpp"
|
||||
#include "interpolators.hpp"
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
class MapFollowAnimation : public Animation
|
||||
{
|
||||
public:
|
||||
MapFollowAnimation(ScreenBase const & screen, m2::PointD const & globalUserPosition,
|
||||
m2::PointD const & endPixelPosition, double endScale, double endAngle, bool isAutoZoom);
|
||||
|
||||
void Init(ScreenBase const & screen, TPropertyCache const & properties) override;
|
||||
|
||||
Animation::Type GetType() const override { return Animation::Type::MapFollow; }
|
||||
|
||||
TAnimObjects const & GetObjects() const override { return m_objects; }
|
||||
|
||||
bool HasObject(Object object) const override { return object == Animation::Object::MapPlane; }
|
||||
|
||||
TObjectProperties const & GetProperties(Object object) const override;
|
||||
bool HasProperty(Object object, ObjectProperty property) const override;
|
||||
|
||||
void Advance(double elapsedSeconds) override;
|
||||
void Finish() override;
|
||||
|
||||
void SetMaxDuration(double maxDuration) override;
|
||||
void SetMinDuration(double minDuration) override;
|
||||
double GetDuration() const override;
|
||||
double GetMinDuration() const override;
|
||||
double GetMaxDuration() const override;
|
||||
bool IsFinished() const override;
|
||||
|
||||
bool GetProperty(Object object, ObjectProperty property, PropertyValue & value) const override;
|
||||
bool GetTargetProperty(Object object, ObjectProperty property, PropertyValue & value) const override;
|
||||
|
||||
bool IsAutoZoom() const { return m_isAutoZoom; }
|
||||
|
||||
bool HasScale() const;
|
||||
bool HasPixelOffset() const;
|
||||
|
||||
private:
|
||||
bool GetProperty(Object object, ObjectProperty property, bool targetValue, PropertyValue & value) const;
|
||||
double CalculateDuration() const;
|
||||
|
||||
bool m_isAutoZoom;
|
||||
ScaleInterpolator m_scaleInterpolator;
|
||||
AngleInterpolator m_angleInterpolator;
|
||||
PositionInterpolator m_offsetInterpolator;
|
||||
|
||||
m2::PointD const m_globalPosition;
|
||||
m2::PointD const m_endPixelPosition;
|
||||
double const m_endScale;
|
||||
double const m_endAngle;
|
||||
|
||||
m2::PointD m_offset;
|
||||
|
||||
TObjectProperties m_properties;
|
||||
TAnimObjects m_objects;
|
||||
};
|
||||
|
||||
} // namespace df
|
||||
46
libs/drape_frontend/animation/interpolation_holder.cpp
Normal file
46
libs/drape_frontend/animation/interpolation_holder.cpp
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
#include "drape_frontend/animation/interpolation_holder.hpp"
|
||||
#include "drape_frontend/animation/base_interpolator.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
|
||||
namespace df
|
||||
{
|
||||
InterpolationHolder & InterpolationHolder::Instance()
|
||||
{
|
||||
static InterpolationHolder holder;
|
||||
return holder;
|
||||
}
|
||||
|
||||
bool InterpolationHolder::IsActive() const
|
||||
{
|
||||
return !m_interpolations.empty();
|
||||
}
|
||||
|
||||
void InterpolationHolder::Advance(double elapsedSeconds)
|
||||
{
|
||||
auto iter = m_interpolations.begin();
|
||||
while (iter != m_interpolations.end())
|
||||
{
|
||||
(*iter)->Advance(elapsedSeconds);
|
||||
if ((*iter)->IsFinished())
|
||||
iter = m_interpolations.erase(iter);
|
||||
else
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
InterpolationHolder::~InterpolationHolder()
|
||||
{
|
||||
ASSERT(m_interpolations.empty(), ());
|
||||
}
|
||||
|
||||
void InterpolationHolder::RegisterInterpolator(BaseInterpolator * interpolator)
|
||||
{
|
||||
VERIFY(m_interpolations.insert(interpolator).second, ());
|
||||
}
|
||||
|
||||
void InterpolationHolder::DeregisterInterpolator(BaseInterpolator * interpolator)
|
||||
{
|
||||
m_interpolations.erase(interpolator);
|
||||
}
|
||||
} // namespace df
|
||||
31
libs/drape_frontend/animation/interpolation_holder.hpp
Normal file
31
libs/drape_frontend/animation/interpolation_holder.hpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include "base/macros.hpp"
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace df
|
||||
{
|
||||
class BaseInterpolator;
|
||||
|
||||
class InterpolationHolder
|
||||
{
|
||||
public:
|
||||
static InterpolationHolder & Instance();
|
||||
bool IsActive() const;
|
||||
void Advance(double elapsedSeconds);
|
||||
|
||||
private:
|
||||
InterpolationHolder() = default;
|
||||
~InterpolationHolder();
|
||||
DISALLOW_COPY_AND_MOVE(InterpolationHolder);
|
||||
|
||||
private:
|
||||
friend class BaseInterpolator;
|
||||
void RegisterInterpolator(BaseInterpolator * interpolator);
|
||||
void DeregisterInterpolator(BaseInterpolator * interpolator);
|
||||
|
||||
using TInterpolatorSet = std::set<BaseInterpolator *>;
|
||||
TInterpolatorSet m_interpolations;
|
||||
};
|
||||
} // namespace df
|
||||
26
libs/drape_frontend/animation/interpolations.cpp
Normal file
26
libs/drape_frontend/animation/interpolations.cpp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#include "drape_frontend/animation/interpolations.hpp"
|
||||
|
||||
#include "geometry/angles.hpp"
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
double InterpolateDouble(double startV, double endV, double t)
|
||||
{
|
||||
return startV + (endV - startV) * t;
|
||||
}
|
||||
|
||||
m2::PointD InterpolatePoint(m2::PointD const & startPt, m2::PointD const & endPt, double t)
|
||||
{
|
||||
m2::PointD diff = endPt - startPt;
|
||||
return startPt + diff * t;
|
||||
}
|
||||
|
||||
double InterpolateAngle(double startAngle, double endAngle, double t)
|
||||
{
|
||||
startAngle = ang::AngleIn2PI(startAngle);
|
||||
endAngle = ang::AngleIn2PI(endAngle);
|
||||
return startAngle + ang::GetShortestDistance(startAngle, endAngle) * t;
|
||||
}
|
||||
|
||||
} // namespace df
|
||||
14
libs/drape_frontend/animation/interpolations.hpp
Normal file
14
libs/drape_frontend/animation/interpolations.hpp
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include "geometry/any_rect2d.hpp"
|
||||
#include "geometry/point2d.hpp"
|
||||
#include "geometry/rect2d.hpp"
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
double InterpolateDouble(double startV, double endV, double t);
|
||||
m2::PointD InterpolatePoint(m2::PointD const & startPt, m2::PointD const & endPt, double t);
|
||||
double InterpolateAngle(double startAngle, double endAngle, double t);
|
||||
|
||||
} // namespace df
|
||||
279
libs/drape_frontend/animation/interpolators.cpp
Normal file
279
libs/drape_frontend/animation/interpolators.cpp
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
#include "drape_frontend/animation/interpolators.hpp"
|
||||
#include "drape_frontend/animation/interpolations.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
double CalcAnimSpeedDuration(double pxDiff, double pxSpeed)
|
||||
{
|
||||
double constexpr kEps = 1e-5;
|
||||
|
||||
if (AlmostEqualAbs(pxDiff, 0.0, kEps))
|
||||
return 0.0;
|
||||
|
||||
return fabs(pxDiff) / pxSpeed;
|
||||
}
|
||||
|
||||
Interpolator::Interpolator(double duration, double delay)
|
||||
: m_elapsedTime(0.0)
|
||||
, m_duration(duration)
|
||||
, m_maxDuration(Interpolator::kInvalidDuration)
|
||||
, m_minDuration(Interpolator::kInvalidDuration)
|
||||
, m_delay(delay)
|
||||
, m_isActive(false)
|
||||
{
|
||||
ASSERT_GREATER_OR_EQUAL(m_duration, 0.0, ());
|
||||
}
|
||||
|
||||
bool Interpolator::IsFinished() const
|
||||
{
|
||||
if (!IsActive())
|
||||
return true;
|
||||
|
||||
return m_elapsedTime > (m_duration + m_delay);
|
||||
}
|
||||
|
||||
void Interpolator::Advance(double elapsedSeconds)
|
||||
{
|
||||
m_elapsedTime += elapsedSeconds;
|
||||
}
|
||||
|
||||
void Interpolator::Finish()
|
||||
{
|
||||
m_elapsedTime = m_duration + m_delay + 1.0;
|
||||
}
|
||||
|
||||
bool Interpolator::IsActive() const
|
||||
{
|
||||
return m_isActive;
|
||||
}
|
||||
|
||||
void Interpolator::SetActive(bool active)
|
||||
{
|
||||
m_isActive = active;
|
||||
}
|
||||
|
||||
void Interpolator::SetMaxDuration(double maxDuration)
|
||||
{
|
||||
m_maxDuration = maxDuration;
|
||||
if (m_maxDuration >= 0.0)
|
||||
m_duration = std::min(m_duration, m_maxDuration);
|
||||
}
|
||||
|
||||
void Interpolator::SetMinDuration(double minDuration)
|
||||
{
|
||||
m_minDuration = minDuration;
|
||||
if (m_minDuration >= 0.0)
|
||||
m_duration = std::max(m_duration, m_minDuration);
|
||||
}
|
||||
|
||||
double Interpolator::GetMaxDuration() const
|
||||
{
|
||||
return m_maxDuration;
|
||||
}
|
||||
|
||||
double Interpolator::GetMinDuration() const
|
||||
{
|
||||
return m_minDuration;
|
||||
}
|
||||
|
||||
double Interpolator::GetT() const
|
||||
{
|
||||
if (IsFinished())
|
||||
return 1.0;
|
||||
|
||||
return std::max(m_elapsedTime - m_delay, 0.0) / m_duration;
|
||||
}
|
||||
|
||||
double Interpolator::GetElapsedTime() const
|
||||
{
|
||||
return m_elapsedTime;
|
||||
}
|
||||
|
||||
double Interpolator::GetDuration() const
|
||||
{
|
||||
return m_duration;
|
||||
}
|
||||
|
||||
PositionInterpolator::PositionInterpolator()
|
||||
: PositionInterpolator(0.0 /* duration */, 0.0 /* delay */, m2::PointD(), m2::PointD())
|
||||
{}
|
||||
|
||||
PositionInterpolator::PositionInterpolator(double duration, double delay, m2::PointD const & startPosition,
|
||||
m2::PointD const & endPosition)
|
||||
: Interpolator(duration, delay)
|
||||
, m_startPosition(startPosition)
|
||||
, m_endPosition(endPosition)
|
||||
, m_position(startPosition)
|
||||
{
|
||||
SetActive((GetDuration() > 0.0) && (m_startPosition != m_endPosition));
|
||||
}
|
||||
|
||||
PositionInterpolator::PositionInterpolator(m2::PointD const & startPosition, m2::PointD const & endPosition,
|
||||
ScreenBase const & convertor)
|
||||
: PositionInterpolator(0.0 /* delay */, startPosition, endPosition, convertor)
|
||||
{}
|
||||
|
||||
PositionInterpolator::PositionInterpolator(double delay, m2::PointD const & startPosition,
|
||||
m2::PointD const & endPosition, ScreenBase const & convertor)
|
||||
: Interpolator(PositionInterpolator::GetMoveDuration(startPosition, endPosition, convertor), delay)
|
||||
, m_startPosition(startPosition)
|
||||
, m_endPosition(endPosition)
|
||||
, m_position(startPosition)
|
||||
{
|
||||
SetActive((GetDuration() > 0.0) && (m_startPosition != m_endPosition));
|
||||
}
|
||||
|
||||
PositionInterpolator::PositionInterpolator(m2::PointD const & startPosition, m2::PointD const & endPosition,
|
||||
m2::RectD const & viewportRect, double scale)
|
||||
: PositionInterpolator(0.0 /* delay */, startPosition, endPosition, viewportRect, scale)
|
||||
{}
|
||||
|
||||
PositionInterpolator::PositionInterpolator(double delay, m2::PointD const & startPosition,
|
||||
m2::PointD const & endPosition, m2::RectD const & viewportRect, double scale)
|
||||
: Interpolator(PositionInterpolator::GetMoveDuration(startPosition, endPosition, viewportRect, scale), delay)
|
||||
, m_startPosition(startPosition)
|
||||
, m_endPosition(endPosition)
|
||||
, m_position(startPosition)
|
||||
{
|
||||
SetActive((GetDuration() > 0.0) && (m_startPosition != m_endPosition));
|
||||
}
|
||||
|
||||
// static
|
||||
double PositionInterpolator::GetMoveDuration(double globalDistance, m2::RectD const & viewportRect, double scale)
|
||||
{
|
||||
double constexpr kMinMoveDuration = 0.2;
|
||||
double constexpr kMinSpeedScalar = 0.2;
|
||||
double constexpr kMaxSpeedScalar = 7.0;
|
||||
double constexpr kEps = 1e-5;
|
||||
|
||||
ASSERT_GREATER(scale, 0.0, ());
|
||||
double const pixelLength = globalDistance / scale;
|
||||
if (pixelLength < kEps)
|
||||
return 0.0;
|
||||
|
||||
double const minSize = std::min(viewportRect.SizeX(), viewportRect.SizeY());
|
||||
if (pixelLength < kMinSpeedScalar * minSize)
|
||||
return kMinMoveDuration;
|
||||
|
||||
double const pixelSpeed = kMaxSpeedScalar * minSize;
|
||||
return CalcAnimSpeedDuration(pixelLength, pixelSpeed);
|
||||
}
|
||||
|
||||
// static
|
||||
double PositionInterpolator::GetMoveDuration(m2::PointD const & startPosition, m2::PointD const & endPosition,
|
||||
m2::RectD const & viewportRect, double scale)
|
||||
{
|
||||
return GetMoveDuration(endPosition.Length(startPosition), viewportRect, scale);
|
||||
}
|
||||
|
||||
// static
|
||||
double PositionInterpolator::GetMoveDuration(m2::PointD const & startPosition, m2::PointD const & endPosition,
|
||||
ScreenBase const & convertor)
|
||||
{
|
||||
return GetMoveDuration(startPosition, endPosition, convertor.PixelRectIn3d(), convertor.GetScale());
|
||||
}
|
||||
|
||||
void PositionInterpolator::Advance(double elapsedSeconds)
|
||||
{
|
||||
TBase::Advance(elapsedSeconds);
|
||||
m_position = InterpolatePoint(m_startPosition, m_endPosition, GetT());
|
||||
}
|
||||
|
||||
void PositionInterpolator::Finish()
|
||||
{
|
||||
TBase::Finish();
|
||||
m_position = m_endPosition;
|
||||
}
|
||||
|
||||
ScaleInterpolator::ScaleInterpolator()
|
||||
: ScaleInterpolator(1.0 /* startScale */, 1.0 /* endScale */, false /* isAutoZoom */)
|
||||
{}
|
||||
|
||||
ScaleInterpolator::ScaleInterpolator(double startScale, double endScale, bool isAutoZoom)
|
||||
: ScaleInterpolator(0.0 /* delay */, startScale, endScale, isAutoZoom)
|
||||
{}
|
||||
|
||||
ScaleInterpolator::ScaleInterpolator(double delay, double startScale, double endScale, bool isAutoZoom)
|
||||
: Interpolator(ScaleInterpolator::GetScaleDuration(startScale, endScale, isAutoZoom), delay)
|
||||
, m_startScale(startScale)
|
||||
, m_endScale(endScale)
|
||||
, m_scale(startScale)
|
||||
{
|
||||
SetActive((GetDuration() > 0.0) && (m_startScale != m_endScale));
|
||||
}
|
||||
|
||||
// static
|
||||
double ScaleInterpolator::GetScaleDuration(double startScale, double endScale, bool isAutoZoom)
|
||||
{
|
||||
// Resize 2.0 times should be done for 1.2 seconds in autozoom or for 0.2 seconds in usual case.
|
||||
double const kPixelSpeed = isAutoZoom ? (2.0 / 1.2) : (2.0 / 0.2);
|
||||
|
||||
if (startScale > endScale)
|
||||
std::swap(startScale, endScale);
|
||||
|
||||
return CalcAnimSpeedDuration(endScale / startScale, kPixelSpeed);
|
||||
}
|
||||
|
||||
void ScaleInterpolator::Advance(double elapsedSeconds)
|
||||
{
|
||||
TBase::Advance(elapsedSeconds);
|
||||
m_scale = InterpolateDouble(m_startScale, m_endScale, GetT());
|
||||
}
|
||||
|
||||
void ScaleInterpolator::Finish()
|
||||
{
|
||||
TBase::Finish();
|
||||
m_scale = m_endScale;
|
||||
}
|
||||
|
||||
AngleInterpolator::AngleInterpolator() : AngleInterpolator(0.0 /* startAngle */, 0.0 /* endAngle */) {}
|
||||
|
||||
AngleInterpolator::AngleInterpolator(double startAngle, double endAngle)
|
||||
: AngleInterpolator(0.0 /* delay */, startAngle, endAngle)
|
||||
{}
|
||||
|
||||
AngleInterpolator::AngleInterpolator(double delay, double startAngle, double endAngle)
|
||||
: Interpolator(AngleInterpolator::GetRotateDuration(startAngle, endAngle), delay)
|
||||
, m_startAngle(ang::AngleIn2PI(startAngle))
|
||||
, m_endAngle(ang::AngleIn2PI(endAngle))
|
||||
, m_angle(m_startAngle)
|
||||
{
|
||||
SetActive((GetDuration() > 0.0) && (m_startAngle != m_endAngle));
|
||||
}
|
||||
|
||||
AngleInterpolator::AngleInterpolator(double delay, double duration, double startAngle, double endAngle)
|
||||
: Interpolator(duration, delay)
|
||||
, m_startAngle(ang::AngleIn2PI(startAngle))
|
||||
, m_endAngle(ang::AngleIn2PI(endAngle))
|
||||
, m_angle(m_startAngle)
|
||||
{
|
||||
SetActive((GetDuration() > 0.0) && (m_startAngle != m_endAngle));
|
||||
}
|
||||
|
||||
// static
|
||||
double AngleInterpolator::GetRotateDuration(double startAngle, double endAngle)
|
||||
{
|
||||
double constexpr kRotateDurationScalar = 0.75;
|
||||
startAngle = ang::AngleIn2PI(startAngle);
|
||||
endAngle = ang::AngleIn2PI(endAngle);
|
||||
return kRotateDurationScalar * fabs(ang::GetShortestDistance(startAngle, endAngle)) / math::pi;
|
||||
}
|
||||
|
||||
void AngleInterpolator::Advance(double elapsedSeconds)
|
||||
{
|
||||
TBase::Advance(elapsedSeconds);
|
||||
m_angle = m_startAngle + ang::GetShortestDistance(m_startAngle, m_endAngle) * GetT();
|
||||
}
|
||||
|
||||
void AngleInterpolator::Finish()
|
||||
{
|
||||
TBase::Finish();
|
||||
m_angle = m_endAngle;
|
||||
}
|
||||
|
||||
} // namespace df
|
||||
135
libs/drape_frontend/animation/interpolators.hpp
Normal file
135
libs/drape_frontend/animation/interpolators.hpp
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
#pragma once
|
||||
|
||||
#include "geometry/screenbase.hpp"
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
class Interpolator
|
||||
{
|
||||
public:
|
||||
Interpolator(double duration, double delay = 0);
|
||||
virtual ~Interpolator() = default;
|
||||
|
||||
virtual void Advance(double elapsedSeconds);
|
||||
virtual void Finish();
|
||||
|
||||
bool IsActive() const;
|
||||
void SetActive(bool active);
|
||||
|
||||
bool IsFinished() const;
|
||||
|
||||
static double constexpr kInvalidDuration = -1.0;
|
||||
void SetMaxDuration(double maxDuration);
|
||||
void SetMinDuration(double minDuration);
|
||||
double GetMaxDuration() const;
|
||||
double GetMinDuration() const;
|
||||
|
||||
double GetDuration() const;
|
||||
|
||||
protected:
|
||||
double GetT() const;
|
||||
double GetElapsedTime() const;
|
||||
|
||||
private:
|
||||
double m_elapsedTime;
|
||||
double m_duration;
|
||||
double m_maxDuration;
|
||||
double m_minDuration;
|
||||
|
||||
double m_delay;
|
||||
bool m_isActive;
|
||||
};
|
||||
|
||||
class PositionInterpolator : public Interpolator
|
||||
{
|
||||
using TBase = Interpolator;
|
||||
|
||||
public:
|
||||
PositionInterpolator();
|
||||
PositionInterpolator(double duration, double delay, m2::PointD const & startPosition, m2::PointD const & endPosition);
|
||||
|
||||
PositionInterpolator(m2::PointD const & startPosition, m2::PointD const & endPosition, ScreenBase const & convertor);
|
||||
|
||||
PositionInterpolator(double delay, m2::PointD const & startPosition, m2::PointD const & endPosition,
|
||||
ScreenBase const & convertor);
|
||||
|
||||
PositionInterpolator(m2::PointD const & startPosition, m2::PointD const & endPosition, m2::RectD const & viewportRect,
|
||||
double scale);
|
||||
|
||||
PositionInterpolator(double delay, m2::PointD const & startPosition, m2::PointD const & endPosition,
|
||||
m2::RectD const & viewportRect, double scale);
|
||||
|
||||
static double GetMoveDuration(double globalDistance, m2::RectD const & viewportRect, double scale);
|
||||
|
||||
static double GetMoveDuration(m2::PointD const & startPosition, m2::PointD const & endPosition,
|
||||
m2::RectD const & viewportRect, double scale);
|
||||
|
||||
static double GetMoveDuration(m2::PointD const & startPosition, m2::PointD const & endPosition,
|
||||
ScreenBase const & convertor);
|
||||
|
||||
// Interpolator overrides:
|
||||
void Advance(double elapsedSeconds) override;
|
||||
void Finish() override;
|
||||
|
||||
m2::PointD GetPosition() const { return m_position; }
|
||||
m2::PointD GetTargetPosition() const { return m_endPosition; }
|
||||
|
||||
private:
|
||||
m2::PointD m_startPosition;
|
||||
m2::PointD m_endPosition;
|
||||
m2::PointD m_position;
|
||||
};
|
||||
|
||||
class ScaleInterpolator : public Interpolator
|
||||
{
|
||||
using TBase = Interpolator;
|
||||
|
||||
public:
|
||||
ScaleInterpolator();
|
||||
ScaleInterpolator(double startScale, double endScale, bool isAutoZoom);
|
||||
ScaleInterpolator(double delay, double startScale, double endScale, bool isAutoZoom);
|
||||
|
||||
static double GetScaleDuration(double startScale, double endScale, bool isAutoZoom);
|
||||
|
||||
// Interpolator overrides:
|
||||
void Advance(double elapsedSeconds) override;
|
||||
void Finish() override;
|
||||
|
||||
double GetScale() const { return m_scale; }
|
||||
double GetStartScale() const { return m_startScale; }
|
||||
double GetTargetScale() const { return m_endScale; }
|
||||
|
||||
private:
|
||||
double m_startScale;
|
||||
double m_endScale;
|
||||
double m_scale;
|
||||
};
|
||||
|
||||
class AngleInterpolator : public Interpolator
|
||||
{
|
||||
using TBase = Interpolator;
|
||||
|
||||
public:
|
||||
AngleInterpolator();
|
||||
AngleInterpolator(double startAngle, double endAngle);
|
||||
AngleInterpolator(double delay, double startAngle, double endAngle);
|
||||
AngleInterpolator(double delay, double duration, double startAngle, double endAngle);
|
||||
|
||||
static double GetRotateDuration(double startAngle, double endAngle);
|
||||
|
||||
// Interpolator overrides:
|
||||
void Advance(double elapsedSeconds) override;
|
||||
void Finish() override;
|
||||
|
||||
double GetAngle() const { return m_angle; }
|
||||
double GetStartAngle() const { return m_startAngle; }
|
||||
double GetTargetAngle() const { return m_endAngle; }
|
||||
|
||||
private:
|
||||
double m_startAngle;
|
||||
double m_endAngle;
|
||||
double m_angle;
|
||||
};
|
||||
|
||||
} // namespace df
|
||||
243
libs/drape_frontend/animation/linear_animation.cpp
Normal file
243
libs/drape_frontend/animation/linear_animation.cpp
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
#include "drape_frontend/animation/linear_animation.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
MapLinearAnimation::MapLinearAnimation(m2::PointD const & startPos, m2::PointD const & endPos, double startAngle,
|
||||
double endAngle, double startScale, double endScale,
|
||||
ScreenBase const & convertor)
|
||||
: Animation(true /* couldBeInterrupted */, false /* couldBeBlended */)
|
||||
, m_angleInterpolator(startAngle, endAngle)
|
||||
, m_positionInterpolator(startPos, endPos, convertor)
|
||||
, m_scaleInterpolator(startScale, endScale, false /* isAutoZoom */)
|
||||
{
|
||||
m_objects.insert(Animation::Object::MapPlane);
|
||||
|
||||
if (m_positionInterpolator.IsActive())
|
||||
m_properties.insert(Animation::ObjectProperty::Position);
|
||||
|
||||
if (m_angleInterpolator.IsActive())
|
||||
m_properties.insert(Animation::ObjectProperty::Angle);
|
||||
|
||||
if (m_scaleInterpolator.IsActive())
|
||||
m_properties.insert(Animation::ObjectProperty::Scale);
|
||||
}
|
||||
|
||||
MapLinearAnimation::MapLinearAnimation() : Animation(true /* couldBeInterrupted */, false /* couldBeBlended */)
|
||||
{
|
||||
m_objects.insert(Animation::Object::MapPlane);
|
||||
}
|
||||
|
||||
void MapLinearAnimation::Init(ScreenBase const & screen, TPropertyCache const & properties)
|
||||
{
|
||||
ScreenBase currentScreen;
|
||||
GetCurrentScreen(properties, screen, currentScreen);
|
||||
|
||||
double minDuration = m_positionInterpolator.GetMinDuration();
|
||||
double maxDuration = m_positionInterpolator.GetMaxDuration();
|
||||
SetMove(currentScreen.GlobalRect().GlobalZero(), m_positionInterpolator.GetTargetPosition(), currentScreen);
|
||||
|
||||
m_positionInterpolator.SetMinDuration(minDuration);
|
||||
m_positionInterpolator.SetMaxDuration(maxDuration);
|
||||
|
||||
minDuration = m_scaleInterpolator.GetMinDuration();
|
||||
maxDuration = m_scaleInterpolator.GetMaxDuration();
|
||||
SetScale(currentScreen.GetScale(), m_scaleInterpolator.GetTargetScale());
|
||||
|
||||
m_scaleInterpolator.SetMinDuration(minDuration);
|
||||
m_scaleInterpolator.SetMaxDuration(maxDuration);
|
||||
|
||||
minDuration = m_angleInterpolator.GetMinDuration();
|
||||
maxDuration = m_angleInterpolator.GetMaxDuration();
|
||||
SetRotate(currentScreen.GetAngle(), m_angleInterpolator.GetTargetAngle());
|
||||
|
||||
m_angleInterpolator.SetMinDuration(minDuration);
|
||||
m_angleInterpolator.SetMaxDuration(maxDuration);
|
||||
}
|
||||
|
||||
void MapLinearAnimation::SetMove(m2::PointD const & startPos, m2::PointD const & endPos, ScreenBase const & convertor)
|
||||
{
|
||||
m_positionInterpolator = PositionInterpolator(startPos, endPos, convertor);
|
||||
if (m_positionInterpolator.IsActive())
|
||||
m_properties.insert(Animation::ObjectProperty::Position);
|
||||
}
|
||||
|
||||
void MapLinearAnimation::SetMove(m2::PointD const & startPos, m2::PointD const & endPos, m2::RectD const & viewportRect,
|
||||
double scale)
|
||||
{
|
||||
m_positionInterpolator = PositionInterpolator(startPos, endPos, viewportRect, scale);
|
||||
if (m_positionInterpolator.IsActive())
|
||||
m_properties.insert(Animation::ObjectProperty::Position);
|
||||
}
|
||||
|
||||
void MapLinearAnimation::SetRotate(double startAngle, double endAngle)
|
||||
{
|
||||
m_angleInterpolator = AngleInterpolator(startAngle, endAngle);
|
||||
if (m_angleInterpolator.IsActive())
|
||||
m_properties.insert(Animation::ObjectProperty::Angle);
|
||||
}
|
||||
|
||||
void MapLinearAnimation::SetScale(double startScale, double endScale)
|
||||
{
|
||||
m_scaleInterpolator = ScaleInterpolator(startScale, endScale, false /* isAutoZoom */);
|
||||
if (m_scaleInterpolator.IsActive())
|
||||
m_properties.insert(Animation::ObjectProperty::Scale);
|
||||
}
|
||||
|
||||
Animation::TObjectProperties const & MapLinearAnimation::GetProperties(Object object) const
|
||||
{
|
||||
ASSERT_EQUAL(static_cast<int>(object), static_cast<int>(Animation::Object::MapPlane), ());
|
||||
return m_properties;
|
||||
}
|
||||
|
||||
bool MapLinearAnimation::HasProperty(Object object, ObjectProperty property) const
|
||||
{
|
||||
return HasObject(object) && m_properties.find(property) != m_properties.end();
|
||||
}
|
||||
|
||||
void MapLinearAnimation::Advance(double elapsedSeconds)
|
||||
{
|
||||
if (m_angleInterpolator.IsActive())
|
||||
m_angleInterpolator.Advance(elapsedSeconds);
|
||||
|
||||
if (m_scaleInterpolator.IsActive())
|
||||
m_scaleInterpolator.Advance(elapsedSeconds);
|
||||
|
||||
if (m_positionInterpolator.IsActive())
|
||||
m_positionInterpolator.Advance(elapsedSeconds);
|
||||
}
|
||||
|
||||
void MapLinearAnimation::Finish()
|
||||
{
|
||||
if (m_angleInterpolator.IsActive())
|
||||
m_angleInterpolator.Finish();
|
||||
|
||||
if (m_scaleInterpolator.IsActive())
|
||||
m_scaleInterpolator.Finish();
|
||||
|
||||
if (m_positionInterpolator.IsActive())
|
||||
m_positionInterpolator.Finish();
|
||||
|
||||
Animation::Finish();
|
||||
}
|
||||
|
||||
void MapLinearAnimation::SetMaxDuration(double maxDuration)
|
||||
{
|
||||
if (m_angleInterpolator.IsActive())
|
||||
m_angleInterpolator.SetMaxDuration(maxDuration);
|
||||
|
||||
if (m_positionInterpolator.IsActive())
|
||||
m_positionInterpolator.SetMaxDuration(maxDuration);
|
||||
|
||||
SetMaxScaleDuration(maxDuration);
|
||||
}
|
||||
|
||||
void MapLinearAnimation::SetMinDuration(double minDuration)
|
||||
{
|
||||
if (m_angleInterpolator.IsActive())
|
||||
m_angleInterpolator.SetMinDuration(minDuration);
|
||||
|
||||
if (m_positionInterpolator.IsActive())
|
||||
m_positionInterpolator.SetMinDuration(minDuration);
|
||||
|
||||
if (m_scaleInterpolator.IsActive())
|
||||
m_scaleInterpolator.SetMinDuration(minDuration);
|
||||
}
|
||||
|
||||
void MapLinearAnimation::SetMaxScaleDuration(double maxDuration)
|
||||
{
|
||||
if (m_scaleInterpolator.IsActive())
|
||||
m_scaleInterpolator.SetMaxDuration(maxDuration);
|
||||
}
|
||||
|
||||
double MapLinearAnimation::GetDuration() const
|
||||
{
|
||||
double duration = 0.0;
|
||||
if (m_angleInterpolator.IsActive())
|
||||
duration = m_angleInterpolator.GetDuration();
|
||||
if (m_scaleInterpolator.IsActive())
|
||||
duration = std::max(duration, m_scaleInterpolator.GetDuration());
|
||||
if (m_positionInterpolator.IsActive())
|
||||
duration = std::max(duration, m_positionInterpolator.GetDuration());
|
||||
return duration;
|
||||
}
|
||||
|
||||
double MapLinearAnimation::GetMaxDuration() const
|
||||
{
|
||||
double maxDuration = Animation::kInvalidAnimationDuration;
|
||||
|
||||
if (!Animation::GetMaxDuration(m_angleInterpolator, maxDuration) ||
|
||||
!Animation::GetMaxDuration(m_scaleInterpolator, maxDuration) ||
|
||||
!Animation::GetMaxDuration(m_positionInterpolator, maxDuration))
|
||||
return Animation::kInvalidAnimationDuration;
|
||||
|
||||
return maxDuration;
|
||||
}
|
||||
|
||||
double MapLinearAnimation::GetMinDuration() const
|
||||
{
|
||||
double minDuration = Animation::kInvalidAnimationDuration;
|
||||
|
||||
if (!Animation::GetMinDuration(m_angleInterpolator, minDuration) ||
|
||||
!Animation::GetMinDuration(m_scaleInterpolator, minDuration) ||
|
||||
!Animation::GetMinDuration(m_positionInterpolator, minDuration))
|
||||
return Animation::kInvalidAnimationDuration;
|
||||
|
||||
return minDuration;
|
||||
}
|
||||
|
||||
bool MapLinearAnimation::IsFinished() const
|
||||
{
|
||||
return m_angleInterpolator.IsFinished() && m_scaleInterpolator.IsFinished() && m_positionInterpolator.IsFinished();
|
||||
}
|
||||
|
||||
bool MapLinearAnimation::GetProperty(Object object, ObjectProperty property, PropertyValue & value) const
|
||||
{
|
||||
return GetProperty(object, property, false /* targetValue */, value);
|
||||
}
|
||||
|
||||
bool MapLinearAnimation::GetTargetProperty(Object object, ObjectProperty property, PropertyValue & value) const
|
||||
{
|
||||
return GetProperty(object, property, true /* targetValue */, value);
|
||||
}
|
||||
|
||||
bool MapLinearAnimation::GetProperty(Object object, ObjectProperty property, bool targetValue,
|
||||
PropertyValue & value) const
|
||||
{
|
||||
ASSERT_EQUAL(static_cast<int>(object), static_cast<int>(Animation::Object::MapPlane), ());
|
||||
|
||||
switch (property)
|
||||
{
|
||||
case Animation::ObjectProperty::Position:
|
||||
if (m_positionInterpolator.IsActive())
|
||||
{
|
||||
value = PropertyValue(targetValue ? m_positionInterpolator.GetTargetPosition()
|
||||
: m_positionInterpolator.GetPosition());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case Animation::ObjectProperty::Scale:
|
||||
if (m_scaleInterpolator.IsActive())
|
||||
{
|
||||
value = PropertyValue(targetValue ? m_scaleInterpolator.GetTargetScale() : m_scaleInterpolator.GetScale());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case Animation::ObjectProperty::Angle:
|
||||
if (m_angleInterpolator.IsActive())
|
||||
{
|
||||
value = PropertyValue(targetValue ? m_angleInterpolator.GetTargetAngle() : m_angleInterpolator.GetAngle());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
default: ASSERT(false, ("Wrong property:", static_cast<int>(property)));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace df
|
||||
55
libs/drape_frontend/animation/linear_animation.hpp
Normal file
55
libs/drape_frontend/animation/linear_animation.hpp
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
#pragma once
|
||||
|
||||
#include "animation.hpp"
|
||||
#include "interpolators.hpp"
|
||||
|
||||
namespace df
|
||||
{
|
||||
class MapLinearAnimation : public Animation
|
||||
{
|
||||
public:
|
||||
MapLinearAnimation(m2::PointD const & startPos, m2::PointD const & endPos, double startAngle, double endAngle,
|
||||
double startScale, double endScale, ScreenBase const & convertor);
|
||||
MapLinearAnimation();
|
||||
|
||||
void Init(ScreenBase const & screen, TPropertyCache const & properties) override;
|
||||
|
||||
void SetMove(m2::PointD const & startPos, m2::PointD const & endPos, ScreenBase const & convertor);
|
||||
void SetMove(m2::PointD const & startPos, m2::PointD const & endPos, m2::RectD const & viewportRect, double scale);
|
||||
void SetRotate(double startAngle, double endAngle);
|
||||
void SetScale(double startScale, double endScale);
|
||||
|
||||
Animation::Type GetType() const override { return Animation::Type::MapLinear; }
|
||||
|
||||
TAnimObjects const & GetObjects() const override { return m_objects; }
|
||||
|
||||
bool HasObject(Object object) const override { return object == Animation::Object::MapPlane; }
|
||||
|
||||
TObjectProperties const & GetProperties(Object object) const override;
|
||||
bool HasProperty(Object object, ObjectProperty property) const override;
|
||||
|
||||
void Advance(double elapsedSeconds) override;
|
||||
void Finish() override;
|
||||
|
||||
void SetMaxDuration(double maxDuration) override;
|
||||
void SetMinDuration(double minDuration) override;
|
||||
double GetDuration() const override;
|
||||
double GetMaxDuration() const override;
|
||||
double GetMinDuration() const override;
|
||||
bool IsFinished() const override;
|
||||
|
||||
bool GetProperty(Object object, ObjectProperty property, PropertyValue & value) const override;
|
||||
bool GetTargetProperty(Object object, ObjectProperty property, PropertyValue & value) const override;
|
||||
|
||||
void SetMaxScaleDuration(double maxDuration);
|
||||
|
||||
private:
|
||||
bool GetProperty(Object object, ObjectProperty property, bool targetValue, PropertyValue & value) const;
|
||||
|
||||
AngleInterpolator m_angleInterpolator;
|
||||
PositionInterpolator m_positionInterpolator;
|
||||
ScaleInterpolator m_scaleInterpolator;
|
||||
TObjectProperties m_properties;
|
||||
TAnimObjects m_objects;
|
||||
};
|
||||
} // namespace df
|
||||
24
libs/drape_frontend/animation/opacity_animation.cpp
Normal file
24
libs/drape_frontend/animation/opacity_animation.cpp
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#include "drape_frontend/animation/opacity_animation.hpp"
|
||||
#include "drape_frontend/animation/interpolations.hpp"
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
OpacityAnimation::OpacityAnimation(double duration, double startOpacity, double endOpacity)
|
||||
: OpacityAnimation(duration, 0.0, startOpacity, endOpacity)
|
||||
{}
|
||||
|
||||
OpacityAnimation::OpacityAnimation(double duration, double delay, double startOpacity, double endOpacity)
|
||||
: BaseInterpolator(duration, delay)
|
||||
, m_startOpacity(startOpacity)
|
||||
, m_endOpacity(endOpacity)
|
||||
, m_opacity(startOpacity)
|
||||
{}
|
||||
|
||||
void OpacityAnimation::Advance(double elapsedSeconds)
|
||||
{
|
||||
TBase::Advance(elapsedSeconds);
|
||||
m_opacity = InterpolateDouble(m_startOpacity, m_endOpacity, GetT());
|
||||
}
|
||||
|
||||
} // namespace df
|
||||
23
libs/drape_frontend/animation/opacity_animation.hpp
Normal file
23
libs/drape_frontend/animation/opacity_animation.hpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "drape_frontend/animation/base_interpolator.hpp"
|
||||
|
||||
namespace df
|
||||
{
|
||||
class OpacityAnimation : public BaseInterpolator
|
||||
{
|
||||
using TBase = BaseInterpolator;
|
||||
|
||||
public:
|
||||
OpacityAnimation(double duration, double startOpacity, double endOpacity);
|
||||
OpacityAnimation(double duration, double delay, double startOpacity, double endOpacity);
|
||||
|
||||
void Advance(double elapsedSeconds) override;
|
||||
double GetOpacity() const { return m_opacity; }
|
||||
|
||||
private:
|
||||
double m_startOpacity;
|
||||
double m_endOpacity;
|
||||
double m_opacity;
|
||||
};
|
||||
} // namespace df
|
||||
206
libs/drape_frontend/animation/parallel_animation.cpp
Normal file
206
libs/drape_frontend/animation/parallel_animation.cpp
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
#include "drape_frontend/animation/parallel_animation.hpp"
|
||||
|
||||
#include "drape_frontend/animation_system.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
ParallelAnimation::ParallelAnimation() : Animation(true /* couldBeInterrupted */, true /* couldBeBlended */) {}
|
||||
|
||||
void ParallelAnimation::Init(ScreenBase const & screen, TPropertyCache const & properties)
|
||||
{
|
||||
for (auto const & anim : m_animations)
|
||||
anim->Init(screen, properties);
|
||||
}
|
||||
|
||||
std::string ParallelAnimation::GetCustomType() const
|
||||
{
|
||||
return m_customType;
|
||||
}
|
||||
|
||||
void ParallelAnimation::SetCustomType(std::string const & type)
|
||||
{
|
||||
m_customType = type;
|
||||
}
|
||||
|
||||
Animation::TAnimObjects const & ParallelAnimation::GetObjects() const
|
||||
{
|
||||
return m_objects;
|
||||
}
|
||||
|
||||
bool ParallelAnimation::HasObject(Object object) const
|
||||
{
|
||||
return m_objects.find(object) != m_objects.end();
|
||||
}
|
||||
|
||||
Animation::TObjectProperties const & ParallelAnimation::GetProperties(Object object) const
|
||||
{
|
||||
ASSERT(HasObject(object), ());
|
||||
return m_properties.find(object)->second;
|
||||
}
|
||||
|
||||
bool ParallelAnimation::HasProperty(Object object, ObjectProperty property) const
|
||||
{
|
||||
if (!HasObject(object))
|
||||
return false;
|
||||
TObjectProperties const & properties = GetProperties(object);
|
||||
return properties.find(property) != properties.end();
|
||||
}
|
||||
|
||||
bool ParallelAnimation::HasTargetProperty(Object object, ObjectProperty property) const
|
||||
{
|
||||
ASSERT(!m_animations.empty(), ());
|
||||
for (auto const & anim : m_animations)
|
||||
if (anim->HasTargetProperty(object, property))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void ParallelAnimation::SetMaxDuration(double maxDuration)
|
||||
{
|
||||
for (auto const & anim : m_animations)
|
||||
anim->SetMaxDuration(maxDuration);
|
||||
}
|
||||
|
||||
void ParallelAnimation::SetMinDuration(double minDuration)
|
||||
{
|
||||
for (auto const & anim : m_animations)
|
||||
anim->SetMinDuration(minDuration);
|
||||
}
|
||||
|
||||
double ParallelAnimation::GetDuration() const
|
||||
{
|
||||
double duration = 0.0;
|
||||
for (auto const & anim : m_animations)
|
||||
duration = std::max(duration, anim->GetDuration());
|
||||
return duration;
|
||||
}
|
||||
|
||||
double ParallelAnimation::GetMaxDuration() const
|
||||
{
|
||||
double maxDuration = Animation::kInvalidAnimationDuration;
|
||||
double duration;
|
||||
for (auto const & anim : m_animations)
|
||||
{
|
||||
duration = anim->GetMaxDuration();
|
||||
if (duration < 0.0)
|
||||
return Animation::kInvalidAnimationDuration;
|
||||
maxDuration = maxDuration >= 0 ? std::max(duration, maxDuration) : duration;
|
||||
}
|
||||
return maxDuration;
|
||||
}
|
||||
|
||||
double ParallelAnimation::GetMinDuration() const
|
||||
{
|
||||
double minDuration = Animation::kInvalidAnimationDuration;
|
||||
double duration;
|
||||
for (auto const & anim : m_animations)
|
||||
{
|
||||
duration = anim->GetMinDuration();
|
||||
if (duration < 0.0)
|
||||
return Animation::kInvalidAnimationDuration;
|
||||
minDuration = minDuration >= 0 ? std::min(duration, minDuration) : duration;
|
||||
}
|
||||
return minDuration;
|
||||
}
|
||||
|
||||
bool ParallelAnimation::IsFinished() const
|
||||
{
|
||||
return m_animations.empty();
|
||||
}
|
||||
|
||||
bool ParallelAnimation::GetProperty(Object object, ObjectProperty property, PropertyValue & value) const
|
||||
{
|
||||
ASSERT(!m_animations.empty(), ());
|
||||
for (auto const & anim : m_animations)
|
||||
if (anim->HasProperty(object, property))
|
||||
return anim->GetProperty(object, property, value);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ParallelAnimation::GetTargetProperty(Object object, ObjectProperty property, PropertyValue & value) const
|
||||
{
|
||||
ASSERT(!m_animations.empty(), ());
|
||||
for (auto const & anim : m_animations)
|
||||
if (anim->HasProperty(object, property))
|
||||
return anim->GetTargetProperty(object, property, value);
|
||||
return false;
|
||||
}
|
||||
|
||||
void ParallelAnimation::AddAnimation(drape_ptr<Animation> && animation)
|
||||
{
|
||||
SetCouldBeInterrupted(CouldBeInterrupted() && animation->CouldBeInterrupted());
|
||||
SetCouldBeBlended(CouldBeBlended() && animation->CouldBeBlended());
|
||||
SetCouldBeRewinded(CouldBeRewinded() && animation->CouldBeRewinded());
|
||||
|
||||
m_animations.emplace_back(std::move(animation));
|
||||
ObtainObjectProperties();
|
||||
}
|
||||
|
||||
void ParallelAnimation::OnStart()
|
||||
{
|
||||
for (auto & anim : m_animations)
|
||||
anim->OnStart();
|
||||
}
|
||||
|
||||
void ParallelAnimation::OnFinish()
|
||||
{
|
||||
for (auto & anim : m_animations)
|
||||
anim->OnFinish();
|
||||
}
|
||||
|
||||
void ParallelAnimation::Advance(double elapsedSeconds)
|
||||
{
|
||||
auto iter = m_animations.begin();
|
||||
while (iter != m_animations.end())
|
||||
{
|
||||
(*iter)->Advance(elapsedSeconds);
|
||||
if ((*iter)->IsFinished())
|
||||
{
|
||||
(*iter)->OnFinish();
|
||||
AnimationSystem::Instance().SaveAnimationResult(*(*iter));
|
||||
iter = m_animations.erase(iter);
|
||||
ObtainObjectProperties();
|
||||
}
|
||||
else
|
||||
{
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParallelAnimation::Finish()
|
||||
{
|
||||
for (auto & anim : m_animations)
|
||||
{
|
||||
anim->Finish();
|
||||
AnimationSystem::Instance().SaveAnimationResult(*anim);
|
||||
}
|
||||
m_animations.clear();
|
||||
ObtainObjectProperties();
|
||||
Animation::Finish();
|
||||
}
|
||||
|
||||
void ParallelAnimation::ObtainObjectProperties()
|
||||
{
|
||||
m_objects.clear();
|
||||
m_properties.clear();
|
||||
|
||||
if (m_animations.empty())
|
||||
return;
|
||||
|
||||
for (auto const & anim : m_animations)
|
||||
{
|
||||
TAnimObjects const & objects = anim->GetObjects();
|
||||
m_objects.insert(objects.begin(), objects.end());
|
||||
for (auto const & object : objects)
|
||||
{
|
||||
TObjectProperties const & properties = anim->GetProperties(object);
|
||||
m_properties[object].insert(properties.begin(), properties.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace df
|
||||
74
libs/drape_frontend/animation/parallel_animation.hpp
Normal file
74
libs/drape_frontend/animation/parallel_animation.hpp
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
#pragma once
|
||||
|
||||
#include "animation.hpp"
|
||||
|
||||
#include "drape/pointers.hpp"
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
class ParallelAnimation : public Animation
|
||||
{
|
||||
public:
|
||||
ParallelAnimation();
|
||||
|
||||
void Init(ScreenBase const & screen, TPropertyCache const & properties) override;
|
||||
|
||||
Animation::Type GetType() const override { return Animation::Type::Parallel; }
|
||||
|
||||
TAnimObjects const & GetObjects() const override;
|
||||
bool HasObject(Object object) const override;
|
||||
|
||||
TObjectProperties const & GetProperties(Object object) const override;
|
||||
bool HasProperty(Object object, ObjectProperty property) const override;
|
||||
bool HasTargetProperty(Object object, ObjectProperty property) const override;
|
||||
|
||||
std::string GetCustomType() const override;
|
||||
void SetCustomType(std::string const & type);
|
||||
|
||||
void AddAnimation(drape_ptr<Animation> && animation);
|
||||
|
||||
void OnStart() override;
|
||||
void OnFinish() override;
|
||||
|
||||
void SetMaxDuration(double maxDuration) override;
|
||||
void SetMinDuration(double minDuration) override;
|
||||
double GetDuration() const override;
|
||||
double GetMaxDuration() const override;
|
||||
double GetMinDuration() const override;
|
||||
bool IsFinished() const override;
|
||||
|
||||
void Advance(double elapsedSeconds) override;
|
||||
void Finish() override;
|
||||
|
||||
bool GetProperty(Object object, ObjectProperty property, PropertyValue & value) const override;
|
||||
bool GetTargetProperty(Object object, ObjectProperty property, PropertyValue & value) const override;
|
||||
|
||||
template <typename T>
|
||||
T const * FindAnimation(Animation::Type type, char const * customType = nullptr) const
|
||||
{
|
||||
for (auto const & anim : m_animations)
|
||||
{
|
||||
if ((anim->GetType() == type) && (customType == nullptr || anim->GetCustomType() == customType))
|
||||
{
|
||||
ASSERT(dynamic_cast<T const *>(anim.get()) != nullptr, ());
|
||||
return static_cast<T const *>(anim.get());
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
void ObtainObjectProperties();
|
||||
|
||||
std::list<drape_ptr<Animation>> m_animations;
|
||||
TAnimObjects m_objects;
|
||||
std::map<Object, TObjectProperties> m_properties;
|
||||
|
||||
std::string m_customType;
|
||||
};
|
||||
|
||||
} // namespace df
|
||||
121
libs/drape_frontend/animation/scale_animation.cpp
Normal file
121
libs/drape_frontend/animation/scale_animation.cpp
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
#include "scale_animation.hpp"
|
||||
|
||||
#include "drape_frontend/animation_system.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
MapScaleAnimation::MapScaleAnimation(double startScale, double endScale, m2::PointD const & globalScaleCenter,
|
||||
m2::PointD const & pxScaleCenter)
|
||||
: Animation(true /* couldBeInterrupted */, true /* couldBeBlended */)
|
||||
, m_scaleInterpolator(startScale, endScale, false /* isAutoZoom */)
|
||||
, m_pxScaleCenter(pxScaleCenter)
|
||||
, m_globalScaleCenter(globalScaleCenter)
|
||||
{
|
||||
m_objects.insert(Animation::Object::MapPlane);
|
||||
m_properties.insert(Animation::ObjectProperty::Scale);
|
||||
m_properties.insert(Animation::ObjectProperty::Position);
|
||||
}
|
||||
|
||||
void MapScaleAnimation::Init(ScreenBase const & screen, TPropertyCache const & properties)
|
||||
{
|
||||
ScreenBase currentScreen;
|
||||
GetCurrentScreen(properties, screen, currentScreen);
|
||||
|
||||
double const minDuration = m_scaleInterpolator.GetMinDuration();
|
||||
double const maxDuration = m_scaleInterpolator.GetMaxDuration();
|
||||
|
||||
m_scaleInterpolator =
|
||||
ScaleInterpolator(currentScreen.GetScale(), m_scaleInterpolator.GetTargetScale(), false /* isAutoZoom */);
|
||||
|
||||
m_scaleInterpolator.SetMinDuration(minDuration);
|
||||
m_scaleInterpolator.SetMaxDuration(maxDuration);
|
||||
}
|
||||
|
||||
Animation::TObjectProperties const & MapScaleAnimation::GetProperties(Object object) const
|
||||
{
|
||||
ASSERT_EQUAL(static_cast<int>(object), static_cast<int>(Animation::Object::MapPlane), ());
|
||||
return m_properties;
|
||||
}
|
||||
|
||||
bool MapScaleAnimation::HasProperty(Object object, ObjectProperty property) const
|
||||
{
|
||||
return HasObject(object) && m_properties.find(property) != m_properties.end();
|
||||
}
|
||||
|
||||
void MapScaleAnimation::Advance(double elapsedSeconds)
|
||||
{
|
||||
m_scaleInterpolator.Advance(elapsedSeconds);
|
||||
}
|
||||
|
||||
void MapScaleAnimation::Finish()
|
||||
{
|
||||
m_scaleInterpolator.Finish();
|
||||
Animation::Finish();
|
||||
}
|
||||
|
||||
void MapScaleAnimation::SetMaxDuration(double maxDuration)
|
||||
{
|
||||
m_scaleInterpolator.SetMaxDuration(maxDuration);
|
||||
}
|
||||
|
||||
void MapScaleAnimation::SetMinDuration(double minDuration)
|
||||
{
|
||||
m_scaleInterpolator.SetMinDuration(minDuration);
|
||||
}
|
||||
|
||||
double MapScaleAnimation::GetDuration() const
|
||||
{
|
||||
return m_scaleInterpolator.GetDuration();
|
||||
}
|
||||
|
||||
double MapScaleAnimation::GetMaxDuration() const
|
||||
{
|
||||
return m_scaleInterpolator.GetMaxDuration();
|
||||
}
|
||||
|
||||
double MapScaleAnimation::GetMinDuration() const
|
||||
{
|
||||
return m_scaleInterpolator.GetMinDuration();
|
||||
}
|
||||
|
||||
bool MapScaleAnimation::IsFinished() const
|
||||
{
|
||||
return m_scaleInterpolator.IsFinished();
|
||||
}
|
||||
|
||||
bool MapScaleAnimation::GetProperty(Object object, ObjectProperty property, bool targetValue,
|
||||
PropertyValue & value) const
|
||||
{
|
||||
ASSERT_EQUAL(static_cast<int>(object), static_cast<int>(Animation::Object::MapPlane), ());
|
||||
|
||||
if (property == Animation::ObjectProperty::Position)
|
||||
{
|
||||
ScreenBase screen = AnimationSystem::Instance().GetLastScreen();
|
||||
screen.SetScale(targetValue ? m_scaleInterpolator.GetTargetScale() : m_scaleInterpolator.GetScale());
|
||||
m2::PointD const pixelOffset = screen.PixelRect().Center() - screen.P3dtoP(m_pxScaleCenter);
|
||||
value = PropertyValue(screen.PtoG(screen.GtoP(m_globalScaleCenter) + pixelOffset));
|
||||
return true;
|
||||
}
|
||||
if (property == Animation::ObjectProperty::Scale)
|
||||
{
|
||||
value = PropertyValue(targetValue ? m_scaleInterpolator.GetTargetScale() : m_scaleInterpolator.GetScale());
|
||||
return true;
|
||||
}
|
||||
ASSERT(false, ("Wrong property:", static_cast<int>(property)));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MapScaleAnimation::GetTargetProperty(Object object, ObjectProperty property, PropertyValue & value) const
|
||||
{
|
||||
return GetProperty(object, property, true /* targetValue */, value);
|
||||
}
|
||||
|
||||
bool MapScaleAnimation::GetProperty(Object object, ObjectProperty property, PropertyValue & value) const
|
||||
{
|
||||
return GetProperty(object, property, false /* targetValue */, value);
|
||||
}
|
||||
|
||||
} // namespace df
|
||||
49
libs/drape_frontend/animation/scale_animation.hpp
Normal file
49
libs/drape_frontend/animation/scale_animation.hpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
#pragma once
|
||||
|
||||
#include "animation.hpp"
|
||||
#include "interpolators.hpp"
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
class MapScaleAnimation : public Animation
|
||||
{
|
||||
public:
|
||||
MapScaleAnimation(double startScale, double endScale, m2::PointD const & globalScaleCenter,
|
||||
m2::PointD const & pxScaleCenter);
|
||||
|
||||
void Init(ScreenBase const & screen, TPropertyCache const & properties) override;
|
||||
|
||||
Animation::Type GetType() const override { return Animation::Type::MapScale; }
|
||||
|
||||
TAnimObjects const & GetObjects() const override { return m_objects; }
|
||||
|
||||
bool HasObject(Object object) const override { return object == Animation::Object::MapPlane; }
|
||||
|
||||
TObjectProperties const & GetProperties(Object object) const override;
|
||||
bool HasProperty(Object object, ObjectProperty property) const override;
|
||||
|
||||
void Advance(double elapsedSeconds) override;
|
||||
void Finish() override;
|
||||
|
||||
void SetMaxDuration(double maxDuration) override;
|
||||
void SetMinDuration(double minDuration) override;
|
||||
double GetDuration() const override;
|
||||
double GetMaxDuration() const override;
|
||||
double GetMinDuration() const override;
|
||||
bool IsFinished() const override;
|
||||
|
||||
bool GetProperty(Object object, ObjectProperty property, PropertyValue & value) const override;
|
||||
bool GetTargetProperty(Object object, ObjectProperty property, PropertyValue & value) const override;
|
||||
|
||||
private:
|
||||
bool GetProperty(Object object, ObjectProperty property, bool targetValue, PropertyValue & value) const;
|
||||
|
||||
ScaleInterpolator m_scaleInterpolator;
|
||||
m2::PointD const m_pxScaleCenter;
|
||||
m2::PointD const m_globalScaleCenter;
|
||||
TObjectProperties m_properties;
|
||||
TAnimObjects m_objects;
|
||||
};
|
||||
|
||||
} // namespace df
|
||||
196
libs/drape_frontend/animation/sequence_animation.cpp
Normal file
196
libs/drape_frontend/animation/sequence_animation.cpp
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
#include "sequence_animation.hpp"
|
||||
|
||||
#include "drape_frontend/animation_system.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
SequenceAnimation::SequenceAnimation() : Animation(true /* couldBeInterrupted */, true /* couldBeBlended */) {}
|
||||
|
||||
void SequenceAnimation::Init(ScreenBase const & screen, TPropertyCache const & properties)
|
||||
{
|
||||
if (!m_animations.empty())
|
||||
m_animations.front()->Init(screen, properties);
|
||||
}
|
||||
|
||||
std::string SequenceAnimation::GetCustomType() const
|
||||
{
|
||||
return m_customType;
|
||||
}
|
||||
|
||||
void SequenceAnimation::SetCustomType(std::string const & type)
|
||||
{
|
||||
m_customType = type;
|
||||
}
|
||||
|
||||
Animation::TAnimObjects const & SequenceAnimation::GetObjects() const
|
||||
{
|
||||
return m_objects;
|
||||
}
|
||||
|
||||
bool SequenceAnimation::HasObject(Object object) const
|
||||
{
|
||||
ASSERT(!m_animations.empty(), ());
|
||||
return m_animations.front()->HasObject(object);
|
||||
}
|
||||
|
||||
Animation::TObjectProperties const & SequenceAnimation::GetProperties(Object object) const
|
||||
{
|
||||
ASSERT(HasObject(object), ());
|
||||
return m_properties.find(object)->second;
|
||||
}
|
||||
|
||||
bool SequenceAnimation::HasProperty(Object object, ObjectProperty property) const
|
||||
{
|
||||
if (!HasObject(object))
|
||||
return false;
|
||||
ASSERT(!m_animations.empty(), ());
|
||||
return m_animations.front()->HasProperty(object, property);
|
||||
}
|
||||
|
||||
bool SequenceAnimation::HasTargetProperty(Object object, ObjectProperty property) const
|
||||
{
|
||||
ASSERT(!m_animations.empty(), ());
|
||||
for (auto const & anim : m_animations)
|
||||
if (anim->HasTargetProperty(object, property))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void SequenceAnimation::SetMaxDuration(double maxDuration)
|
||||
{
|
||||
ASSERT(false, ("Not implemented"));
|
||||
}
|
||||
|
||||
void SequenceAnimation::SetMinDuration(double minDuration)
|
||||
{
|
||||
ASSERT(false, ("Not implemented"));
|
||||
}
|
||||
|
||||
double SequenceAnimation::GetDuration() const
|
||||
{
|
||||
double duration = 0.0;
|
||||
for (auto const & anim : m_animations)
|
||||
duration += anim->GetDuration();
|
||||
return duration;
|
||||
}
|
||||
|
||||
double SequenceAnimation::GetMaxDuration() const
|
||||
{
|
||||
double maxDuration = 0.0;
|
||||
double duration;
|
||||
for (auto const & anim : m_animations)
|
||||
{
|
||||
duration = anim->GetMaxDuration();
|
||||
if (duration < 0.0)
|
||||
return Animation::kInvalidAnimationDuration;
|
||||
maxDuration += duration;
|
||||
}
|
||||
return maxDuration;
|
||||
}
|
||||
|
||||
double SequenceAnimation::GetMinDuration() const
|
||||
{
|
||||
double minDuration = 0.0;
|
||||
double duration;
|
||||
for (auto const & anim : m_animations)
|
||||
{
|
||||
duration = anim->GetMinDuration();
|
||||
if (duration < 0.0)
|
||||
return Animation::kInvalidAnimationDuration;
|
||||
minDuration += duration;
|
||||
}
|
||||
return minDuration;
|
||||
}
|
||||
|
||||
bool SequenceAnimation::IsFinished() const
|
||||
{
|
||||
return m_animations.empty();
|
||||
}
|
||||
|
||||
bool SequenceAnimation::GetProperty(Object object, ObjectProperty property, PropertyValue & value) const
|
||||
{
|
||||
ASSERT(!m_animations.empty(), ());
|
||||
return m_animations.front()->GetProperty(object, property, value);
|
||||
}
|
||||
|
||||
bool SequenceAnimation::GetTargetProperty(Object object, ObjectProperty property, PropertyValue & value) const
|
||||
{
|
||||
ASSERT(!m_animations.empty(), ());
|
||||
|
||||
for (auto it = m_animations.rbegin(); it != m_animations.rend(); ++it)
|
||||
{
|
||||
auto const & anim = *it;
|
||||
if (anim->HasTargetProperty(object, property))
|
||||
return anim->GetTargetProperty(object, property, value);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SequenceAnimation::AddAnimation(drape_ptr<Animation> && animation)
|
||||
{
|
||||
m_animations.emplace_back(std::move(animation));
|
||||
if (m_animations.size() == 1)
|
||||
ObtainObjectProperties();
|
||||
}
|
||||
|
||||
void SequenceAnimation::OnStart()
|
||||
{
|
||||
if (m_animations.empty())
|
||||
return;
|
||||
m_animations.front()->OnStart();
|
||||
Animation::OnStart();
|
||||
}
|
||||
|
||||
void SequenceAnimation::OnFinish()
|
||||
{
|
||||
Animation::OnFinish();
|
||||
}
|
||||
|
||||
void SequenceAnimation::Advance(double elapsedSeconds)
|
||||
{
|
||||
if (m_animations.empty())
|
||||
return;
|
||||
m_animations.front()->Advance(elapsedSeconds);
|
||||
if (m_animations.front()->IsFinished())
|
||||
{
|
||||
m_animations.front()->OnFinish();
|
||||
AnimationSystem::Instance().SaveAnimationResult(*m_animations.front());
|
||||
m_animations.pop_front();
|
||||
ObtainObjectProperties();
|
||||
}
|
||||
}
|
||||
|
||||
void SequenceAnimation::Finish()
|
||||
{
|
||||
for (auto & anim : m_animations)
|
||||
{
|
||||
anim->Finish();
|
||||
AnimationSystem::Instance().SaveAnimationResult(*anim);
|
||||
}
|
||||
m_animations.clear();
|
||||
ObtainObjectProperties();
|
||||
Animation::Finish();
|
||||
}
|
||||
|
||||
void SequenceAnimation::ObtainObjectProperties()
|
||||
{
|
||||
m_objects.clear();
|
||||
m_properties.clear();
|
||||
|
||||
if (m_animations.empty())
|
||||
return;
|
||||
|
||||
TAnimObjects const & objects = m_animations.front()->GetObjects();
|
||||
m_objects.insert(objects.begin(), objects.end());
|
||||
for (auto const & object : objects)
|
||||
{
|
||||
TObjectProperties const & properties = m_animations.front()->GetProperties(object);
|
||||
m_properties[object].insert(properties.begin(), properties.end());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace df
|
||||
59
libs/drape_frontend/animation/sequence_animation.hpp
Normal file
59
libs/drape_frontend/animation/sequence_animation.hpp
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#pragma once
|
||||
|
||||
#include "animation.hpp"
|
||||
|
||||
#include "drape/pointers.hpp"
|
||||
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
class SequenceAnimation : public Animation
|
||||
{
|
||||
public:
|
||||
SequenceAnimation();
|
||||
|
||||
void Init(ScreenBase const & screen, TPropertyCache const & properties) override;
|
||||
|
||||
Animation::Type GetType() const override { return Animation::Type::Sequence; }
|
||||
TAnimObjects const & GetObjects() const override;
|
||||
bool HasObject(Object object) const override;
|
||||
TObjectProperties const & GetProperties(Object object) const override;
|
||||
bool HasProperty(Object object, ObjectProperty property) const override;
|
||||
bool HasTargetProperty(Object object, ObjectProperty property) const override;
|
||||
|
||||
std::string GetCustomType() const override;
|
||||
void SetCustomType(std::string const & type);
|
||||
|
||||
void SetMaxDuration(double maxDuration) override;
|
||||
void SetMinDuration(double minDuration) override;
|
||||
double GetDuration() const override;
|
||||
double GetMaxDuration() const override;
|
||||
double GetMinDuration() const override;
|
||||
bool IsFinished() const override;
|
||||
|
||||
bool GetProperty(Object object, ObjectProperty property, PropertyValue & value) const override;
|
||||
bool GetTargetProperty(Object object, ObjectProperty property, PropertyValue & value) const override;
|
||||
|
||||
void AddAnimation(drape_ptr<Animation> && animation);
|
||||
|
||||
void OnStart() override;
|
||||
void OnFinish() override;
|
||||
|
||||
void Advance(double elapsedSeconds) override;
|
||||
void Finish() override;
|
||||
|
||||
private:
|
||||
void ObtainObjectProperties();
|
||||
|
||||
std::deque<drape_ptr<Animation>> m_animations;
|
||||
TAnimObjects m_objects;
|
||||
std::map<Object, TObjectProperties> m_properties;
|
||||
|
||||
std::string m_customType;
|
||||
};
|
||||
|
||||
} // namespace df
|
||||
108
libs/drape_frontend/animation/show_hide_animation.cpp
Normal file
108
libs/drape_frontend/animation/show_hide_animation.cpp
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
#include "show_hide_animation.hpp"
|
||||
|
||||
#include "base_interpolator.hpp"
|
||||
|
||||
#include "base/math.hpp"
|
||||
|
||||
namespace df
|
||||
{
|
||||
class ShowHideAnimation::ShowHideInterpolator : public BaseInterpolator
|
||||
{
|
||||
public:
|
||||
ShowHideInterpolator(ShowHideAnimation::EState & state, double startT, double endT, double duration)
|
||||
: BaseInterpolator(duration)
|
||||
, m_state(state)
|
||||
, m_startT(startT)
|
||||
, m_endT(endT)
|
||||
{
|
||||
m_state = m_endT > m_startT ? ShowHideAnimation::STATE_SHOW_DIRECTION : ShowHideAnimation::STATE_HIDE_DIRECTION;
|
||||
}
|
||||
|
||||
void Advance(double elapsedSeconds) override
|
||||
{
|
||||
BaseInterpolator::Advance(elapsedSeconds);
|
||||
if (IsFinished())
|
||||
m_state = m_endT > m_startT ? ShowHideAnimation::STATE_VISIBLE : ShowHideAnimation::STATE_INVISIBLE;
|
||||
}
|
||||
|
||||
double GetCurrentT() const { return m_startT + (m_endT - m_startT) * GetT(); }
|
||||
|
||||
private:
|
||||
ShowHideAnimation::EState & m_state;
|
||||
double m_startT;
|
||||
double m_endT;
|
||||
};
|
||||
|
||||
ShowHideAnimation::ShowHideAnimation(bool isInitialVisible, double fullDuration)
|
||||
: m_state(isInitialVisible ? STATE_VISIBLE : STATE_INVISIBLE)
|
||||
, m_fullDuration(fullDuration)
|
||||
{}
|
||||
|
||||
ShowHideAnimation::~ShowHideAnimation()
|
||||
{
|
||||
m_interpolator.reset();
|
||||
}
|
||||
|
||||
void ShowHideAnimation::Show()
|
||||
{
|
||||
EState state = GetState();
|
||||
if (state == STATE_INVISIBLE || state == STATE_HIDE_DIRECTION)
|
||||
{
|
||||
m_state = STATE_VISIBLE;
|
||||
m_interpolator.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void ShowHideAnimation::ShowAnimated()
|
||||
{
|
||||
RefreshInterpolator({{STATE_VISIBLE, STATE_SHOW_DIRECTION}}, 1.0);
|
||||
}
|
||||
|
||||
void ShowHideAnimation::Hide()
|
||||
{
|
||||
EState state = GetState();
|
||||
if (state == STATE_VISIBLE || state == STATE_SHOW_DIRECTION)
|
||||
{
|
||||
m_state = STATE_INVISIBLE;
|
||||
m_interpolator.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void ShowHideAnimation::HideAnimated()
|
||||
{
|
||||
RefreshInterpolator({{STATE_INVISIBLE, STATE_HIDE_DIRECTION}}, 0.0);
|
||||
}
|
||||
|
||||
ShowHideAnimation::EState ShowHideAnimation::GetState() const
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
double ShowHideAnimation::GetT() const
|
||||
{
|
||||
if (m_interpolator)
|
||||
return m_interpolator->GetCurrentT();
|
||||
|
||||
ASSERT(m_state != STATE_SHOW_DIRECTION, ());
|
||||
ASSERT(m_state != STATE_HIDE_DIRECTION, ());
|
||||
|
||||
return m_state == STATE_VISIBLE ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
bool ShowHideAnimation::IsFinished() const
|
||||
{
|
||||
return m_interpolator == nullptr || m_interpolator->IsFinished();
|
||||
}
|
||||
|
||||
void ShowHideAnimation::RefreshInterpolator(std::array<EState, 2> validStates, double endValue)
|
||||
{
|
||||
EState state = GetState();
|
||||
if (state == validStates[0] || state == validStates[1])
|
||||
return;
|
||||
|
||||
double start = GetT();
|
||||
double end = endValue;
|
||||
double duration = fabs(end - start) * m_fullDuration;
|
||||
m_interpolator.reset(new ShowHideInterpolator(m_state, start, end, duration));
|
||||
}
|
||||
} // namespace df
|
||||
39
libs/drape_frontend/animation/show_hide_animation.hpp
Normal file
39
libs/drape_frontend/animation/show_hide_animation.hpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#pragma once
|
||||
|
||||
#include "drape/pointers.hpp"
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace df
|
||||
{
|
||||
class ShowHideAnimation
|
||||
{
|
||||
public:
|
||||
enum EState
|
||||
{
|
||||
STATE_INVISIBLE,
|
||||
STATE_VISIBLE,
|
||||
STATE_SHOW_DIRECTION,
|
||||
STATE_HIDE_DIRECTION
|
||||
};
|
||||
|
||||
ShowHideAnimation(bool isInitialVisible, double fullDuration);
|
||||
~ShowHideAnimation();
|
||||
|
||||
void Show();
|
||||
void ShowAnimated();
|
||||
void Hide();
|
||||
void HideAnimated();
|
||||
EState GetState() const;
|
||||
double GetT() const;
|
||||
bool IsFinished() const;
|
||||
|
||||
private:
|
||||
void RefreshInterpolator(std::array<EState, 2> validStates, double endValue);
|
||||
class ShowHideInterpolator;
|
||||
|
||||
drape_ptr<ShowHideInterpolator> m_interpolator;
|
||||
ShowHideAnimation::EState m_state;
|
||||
double m_fullDuration;
|
||||
};
|
||||
} // namespace df
|
||||
75
libs/drape_frontend/animation/value_mapping.hpp
Normal file
75
libs/drape_frontend/animation/value_mapping.hpp
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
#pragma once
|
||||
|
||||
#include "base/buffer_vector.hpp"
|
||||
#include "base/logging.hpp"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
template <typename TValue>
|
||||
class ValueMapping
|
||||
{
|
||||
/// double = interpolation point [0.0, 1.0]
|
||||
/// TValue = output value
|
||||
using TRangePoint = std::pair<double, TValue>;
|
||||
using TRangeVector = buffer_vector<TRangePoint, 8>;
|
||||
using TRangeIter = typename TRangeVector::const_iterator;
|
||||
|
||||
public:
|
||||
ValueMapping() = default;
|
||||
|
||||
void AddRangePoint(double t, TValue const & v)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (!m_ranges.empty())
|
||||
ASSERT(m_ranges.back().first < t, ());
|
||||
#endif
|
||||
m_ranges.emplace_back(t, v);
|
||||
}
|
||||
|
||||
TValue GetValue(double t)
|
||||
{
|
||||
TRangePoint startPoint, endPoint;
|
||||
GetRangePoints(t, startPoint, endPoint);
|
||||
|
||||
double normT = t - startPoint.first;
|
||||
double rangeT = endPoint.first - startPoint.first;
|
||||
double rangeV = endPoint.second - startPoint.second;
|
||||
|
||||
return startPoint.second + rangeV * normT / rangeT;
|
||||
}
|
||||
|
||||
private:
|
||||
void GetRangePoints(double t, TRangePoint & startPoint, TRangePoint & endPoint)
|
||||
{
|
||||
ASSERT(t >= 0.0 && t <= 1.0, ());
|
||||
ASSERT(m_ranges.size() > 1, ());
|
||||
|
||||
TRangeIter startIter = m_ranges.begin();
|
||||
if (t < startIter->first)
|
||||
{
|
||||
startPoint.first = 0.0;
|
||||
startPoint.second = TValue();
|
||||
endPoint = *startIter;
|
||||
return;
|
||||
}
|
||||
|
||||
TRangeIter endIter = startIter + 1;
|
||||
while (t > endIter->first)
|
||||
{
|
||||
endIter++;
|
||||
ASSERT(m_ranges.end() != endIter, ());
|
||||
}
|
||||
|
||||
ASSERT(startIter->first <= t && t <= endIter->first, ());
|
||||
startPoint = *startIter;
|
||||
endPoint = *endIter;
|
||||
}
|
||||
|
||||
private:
|
||||
TRangeVector m_ranges;
|
||||
};
|
||||
|
||||
} // namespace df
|
||||
Loading…
Add table
Add a link
Reference in a new issue