Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-22 13:58:55 +01:00
parent 4af19165ec
commit 68073add76
12458 changed files with 12350765 additions and 2 deletions

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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