#include "workspace/Timestep.h" #include #include #include #include "workspace/WorkSpace.h" #include "common/RecourceHelper.h" #include "common/SpdLogger.h" Timestep::Timestep(const std::vector& steps, const QString& path, WorkSpace* parent /*= nullptr*/) noexcept : QObject((QObject*)parent) , steps_(steps) , path_(path) , workSpace_(parent) { maxTime_ = *steps_.rbegin(); // 初始化为 1.0x,如果列表中没有 1.0,则取最接近中间的默认索引 auto it = std::find(speedLevels_.begin(), speedLevels_.end(), 1.0); speedIndex_ = it != speedLevels_.end() ? int(std::distance(speedLevels_.begin(), it)) : speedIndex_; currentStep_ = speedLevels_[speedIndex_]; } Timestep* Timestep::Load(const QString& path, WorkSpace* workSpace) { const QString filePath = QString("%1/%2").arg(workSpace->GetDir()).arg(path); LOG_INFO("Load timestep: {}", filePath.toStdString()); QFile file(filePath); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { LOG_WARN("Cannot open file for reading: {}", file.errorString().toLocal8Bit().constData()); return nullptr; } QTextStream in(&file); std::vector numbers; while (!in.atEnd()) { QString line = in.readLine(); bool ok; double value = line.toDouble(&ok); if (ok) { numbers.push_back(value); } else { LOG_WARN("Cannot open file for reading: {}", line.toStdString()); } } file.close(); Timestep* timestep = new Timestep(numbers, path, workSpace); return timestep; } void Timestep::GetRange(double& minTime, double& maxTime, double& step) { minTime = *steps_.begin(); maxTime = maxTime_; step = currentStep_; } void Timestep::Update(double dt) { if (playStatus_ != PlayStatus::PS_Started) { return; } if (nullptr == workSpace_) { LOG_WARN("workSpace_ is nullptr"); return; } double deltaTime = dt * currentStep_; current_ += deltaTime; workSpace_->OnFrame(deltaTime); if (current_ >= maxTime_ && playStatus_ != PlayStatus::PS_Stoped) { current_ = maxTime_; Stop(); } emit TimeChanged(current_); } bool Timestep::IsPause() { return playStatus_ == PlayStatus::PS_Suspended && playStatus_ != PlayStatus::PS_Started; } bool Timestep::IsStoped() { return playStatus_ == PlayStatus::PS_Stoped; } void Timestep::Start() { LOG_INFO("enter"); playStatus_ = PlayStatus::PS_Started; current_ = 0.0; if (nullptr == workSpace_) { LOG_WARN("workSpace_ is nullptr"); return; } workSpace_->Begin(); // 重置速度为 1x 并通知 UI auto it = std::find(speedLevels_.begin(), speedLevels_.end(), 1.0); speedIndex_ = it != speedLevels_.end() ? int(std::distance(speedLevels_.begin(), it)) : speedIndex_; currentStep_ = speedLevels_[speedIndex_]; emit StepChanged(currentStep_); emit StatusChanged((int)playStatus_); } void Timestep::Resume() { LOG_INFO("enter"); if (PlayStatus::PS_Suspended != playStatus_) { LOG_WARN("play status is not suspended"); return; } playStatus_ = PlayStatus::PS_Started; emit StatusChanged((int)playStatus_); } void Timestep::Pause() { LOG_INFO("enter"); if (PlayStatus::PS_Started == playStatus_) { playStatus_ = PlayStatus::PS_Suspended; } else if (PlayStatus::PS_Suspended == playStatus_) { playStatus_ = PlayStatus::PS_Started; } emit StatusChanged((int)playStatus_); } void Timestep::Stop() { LOG_INFO("enter"); current_ = maxTime_; playStatus_ = PlayStatus::PS_Stoped; if (nullptr == workSpace_) { LOG_WARN("workSpace_ is nullptr"); return; } workSpace_->End(); // 停止时也恢复为 1x,避免停后再次播放仍是异常倍率 auto it = std::find(speedLevels_.begin(), speedLevels_.end(), 1.0); speedIndex_ = it != speedLevels_.end() ? int(std::distance(speedLevels_.begin(), it)) : speedIndex_; currentStep_ = speedLevels_[speedIndex_]; emit StepChanged(currentStep_); emit StatusChanged((int)playStatus_); } void Timestep::Up() { // 提升到下一个倍率(封顶) if (speedIndex_ < int(speedLevels_.size()) - 1) { ++speedIndex_; } currentStep_ = speedLevels_[speedIndex_]; emit StepChanged(currentStep_); } void Timestep::Down() { // 降到上一个倍率(保底) if (speedIndex_ > 0) { --speedIndex_; } currentStep_ = speedLevels_[speedIndex_]; emit StepChanged(currentStep_); }