#include "ui/base/prediction/linear_predictor.h"
#include <algorithm>
#include "ui/base/ui_base_features.h"
namespace ui {
LinearPredictor::LinearPredictor(EquationOrder order) {
equation_order_ = order;
}
LinearPredictor::~LinearPredictor() {}
const char* LinearPredictor::GetName() const {
return equation_order_ == EquationOrder::kFirstOrder
? features::kPredictorNameLinearFirst
: features::kPredictorNameLinearSecond;
}
void LinearPredictor::Reset() {
events_queue_.clear();
}
size_t LinearPredictor::NumberOfEventsNeeded() {
return static_cast<size_t>(equation_order_);
}
void LinearPredictor::Update(const InputData& new_input) {
if (!events_queue_.empty() &&
new_input.time_stamp - events_queue_.back().time_stamp > kMaxTimeDelta) {
Reset();
}
events_queue_.push_back(new_input);
if (events_queue_.size() > static_cast<size_t>(equation_order_)) {
events_queue_.pop_front();
}
if (events_queue_.size() >= static_cast<size_t>(EquationOrder::kFirstOrder)) {
last_velocity_.set_x(cur_velocity_.x());
last_velocity_.set_y(cur_velocity_.y());
events_dt_ = (events_queue_.at(events_queue_.size() - 1).time_stamp -
events_queue_.at(events_queue_.size() - 2).time_stamp)
.InMillisecondsF();
gfx::Vector2dF delta_pos = events_queue_.at(events_queue_.size() - 1).pos -
events_queue_.at(events_queue_.size() - 2).pos;
if (events_dt_ > 0) {
cur_velocity_.set_x(ScaleVector2d(delta_pos, 1.0 / events_dt_).x());
cur_velocity_.set_y(ScaleVector2d(delta_pos, 1.0 / events_dt_).y());
} else {
cur_velocity_.set_x(0);
cur_velocity_.set_y(0);
}
}
}
bool LinearPredictor::HasPrediction() const {
return events_queue_.size() >=
static_cast<size_t>(EquationOrder::kFirstOrder);
}
std::unique_ptr<InputPredictor::InputData> LinearPredictor::GeneratePrediction(
base::TimeTicks predict_time,
base::TimeDelta frame_interval) {
if (!HasPrediction())
return nullptr;
float pred_dt =
(predict_time - events_queue_.back().time_stamp).InMillisecondsF();
if (equation_order_ == EquationOrder::kSecondOrder && events_dt_ > 0 &&
events_queue_.size() ==
static_cast<size_t>(EquationOrder::kSecondOrder)) {
return std::make_unique<InputData>(GeneratePredictionSecondOrder(pred_dt),
predict_time);
}
return std::make_unique<InputData>(GeneratePredictionFirstOrder(pred_dt),
predict_time);
}
gfx::PointF LinearPredictor::GeneratePredictionFirstOrder(float pred_dt) const {
return events_queue_.back().pos + ScaleVector2d(cur_velocity_, pred_dt);
}
gfx::PointF LinearPredictor::GeneratePredictionSecondOrder(
float pred_dt) const {
DCHECK(equation_order_ == EquationOrder::kSecondOrder);
gfx::Vector2dF acceleration =
ScaleVector2d(cur_velocity_ - last_velocity_, 1.0 / events_dt_);
return events_queue_.back().pos + ScaleVector2d(cur_velocity_, pred_dt) +
ScaleVector2d(acceleration, 0.5 * pred_dt * pred_dt);
}
base::TimeDelta LinearPredictor::TimeInterval() const {
if (events_queue_.size() > 1) {
return std::max(kMinTimeInterval, (events_queue_.back().time_stamp -
events_queue_.front().time_stamp) /
(events_queue_.size() - 1));
}
return kTimeInterval;
}
}