Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/application/ScenarioResultWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1459,6 +1459,9 @@ void ScenarioResultWidget::rerunScenario() {
saveProjectHandler_,
openProjectHandler_,
backToLayoutReviewHandler_,
frame_,
risk_,
artifacts_,
this);

rootLayout->replaceWidget(shell_, runWidget);
Expand Down
107 changes: 101 additions & 6 deletions src/application/ScenarioRunWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,35 @@ ScenarioRunWidget::ScenarioRunWidget(
saveProjectHandler_(std::move(saveProjectHandler)),
openProjectHandler_(std::move(openProjectHandler)),
backToLayoutReviewHandler_(std::move(backToLayoutReviewHandler)) {
setupUi();
}

ScenarioRunWidget::ScenarioRunWidget(
const QString& projectName,
const safecrowd::domain::FacilityLayout2D& layout,
const safecrowd::domain::ScenarioDraft& scenario,
std::function<void()> saveProjectHandler,
std::function<void()> openProjectHandler,
std::function<void()> backToLayoutReviewHandler,
safecrowd::domain::SimulationFrame cachedResultFrame,
safecrowd::domain::ScenarioRiskSnapshot cachedResultRisk,
safecrowd::domain::ScenarioResultArtifacts cachedResultArtifacts,
QWidget* parent)
: QWidget(parent),
projectName_(projectName),
layout_(layout),
scenario_(scenario),
runner_(layout_, scenario_),
cachedResultFrame_(std::move(cachedResultFrame)),
cachedResultRisk_(std::move(cachedResultRisk)),
cachedResultArtifacts_(std::move(cachedResultArtifacts)),
saveProjectHandler_(std::move(saveProjectHandler)),
openProjectHandler_(std::move(openProjectHandler)),
backToLayoutReviewHandler_(std::move(backToLayoutReviewHandler)) {
setupUi();
}

void ScenarioRunWidget::setupUi() {
auto* rootLayout = new QVBoxLayout(this);
rootLayout->setContentsMargins(0, 0, 0, 0);
rootLayout->setSpacing(0);
Expand Down Expand Up @@ -275,6 +304,12 @@ QWidget* ScenarioRunWidget::createRunPanel() {

layout->addStretch(1);

skipResultButton_ = new QPushButton("Skip for Result", panel);
skipResultButton_->setFont(ui::font(ui::FontRole::Body));
skipResultButton_->setStyleSheet(ui::secondaryButtonStyleSheet());
skipResultButton_->setEnabled(false);
layout->addWidget(skipResultButton_);

resultButton_ = new QPushButton("View Results", panel);
resultButton_->setFont(ui::font(ui::FontRole::Body));
resultButton_->setStyleSheet(ui::primaryButtonStyleSheet());
Expand All @@ -287,6 +322,9 @@ QWidget* ScenarioRunWidget::createRunPanel() {
connect(stopButton_, &QPushButton::clicked, this, [this]() {
stopRun();
});
connect(skipResultButton_, &QPushButton::clicked, this, [this]() {
runToCompletion();
});
connect(resultButton_, &QPushButton::clicked, this, [this]() {
showResults();
});
Expand Down Expand Up @@ -326,6 +364,12 @@ void ScenarioRunWidget::returnToAuthoring() {
canvas_ = nullptr;
}

bool ScenarioRunWidget::hasCachedResult() const noexcept {
return cachedResultFrame_.has_value()
&& cachedResultRisk_.has_value()
&& cachedResultArtifacts_.has_value();
}

void ScenarioRunWidget::refreshStatus() {
const auto& frame = runner_.frame();
if (scenarioLabel_ != nullptr) {
Expand Down Expand Up @@ -390,24 +434,75 @@ void ScenarioRunWidget::refreshStatus() {
if (stopButton_ != nullptr) {
stopButton_->setEnabled(frame.totalAgentCount > 0);
}
if (skipResultButton_ != nullptr) {
skipResultButton_->setEnabled(frame.totalAgentCount > 0 && !frame.complete && !hasCachedResult());
}
if (resultButton_ != nullptr) {
resultButton_->setEnabled(frame.complete && frame.totalAgentCount > 0);
const auto cachedAgentCount = hasCachedResult() ? cachedResultFrame_->totalAgentCount : 0;
resultButton_->setEnabled(
(frame.complete && frame.totalAgentCount > 0)
|| cachedAgentCount > 0);
}
}

bool ScenarioRunWidget::runToCompletion() {
if (timer_ != nullptr) {
timer_->stop();
}

const auto remainingSeconds = std::max(0.0, runner_.timeLimitSeconds() - runner_.frame().elapsedSeconds);
const auto maxSteps = static_cast<int>(std::ceil(remainingSeconds / kSimulationDeltaSeconds)) + 2;
for (int step = 0; step < maxSteps && !runner_.complete(); ++step) {
runner_.step(kSimulationDeltaSeconds);
}

if (canvas_ != nullptr) {
canvas_->setFrame(runner_.frame());
}
if (runner_.complete()) {
storeResultCache(runner_);
}
refreshStatus();
return runner_.complete();
}

void ScenarioRunWidget::storeResultCache(const safecrowd::domain::ScenarioSimulationRunner& runner) {
cachedResultFrame_ = runner.frame();
cachedResultRisk_ = runner.resultRiskSnapshot();
cachedResultArtifacts_ = runner.resultArtifacts();
}

void ScenarioRunWidget::stopRun() {
paused_ = true;
runner_.reset(layout_, scenario_);
cachedResultFrame_.reset();
cachedResultRisk_.reset();
cachedResultArtifacts_.reset();
canvas_->setFrame(runner_.frame());
refreshStatus();
timer_->start();
}

void ScenarioRunWidget::showResults() {
const auto& frame = runner_.frame();
if (frame.totalAgentCount == 0 || !frame.complete) {
if (runner_.frame().totalAgentCount == 0 && !hasCachedResult()) {
return;
}

const auto* resultFrame = &runner_.frame();
const auto* resultRisk = &runner_.resultRiskSnapshot();
const auto* resultArtifacts = &runner_.resultArtifacts();
if (!runner_.complete() && hasCachedResult()) {
resultFrame = &*cachedResultFrame_;
resultRisk = &*cachedResultRisk_;
resultArtifacts = &*cachedResultArtifacts_;
} else if (!runner_.complete()) {
return;
} else {
resultFrame = &runner_.frame();
resultRisk = &runner_.resultRiskSnapshot();
resultArtifacts = &runner_.resultArtifacts();
}

if (timer_ != nullptr) {
timer_->stop();
}
Expand All @@ -421,9 +516,9 @@ void ScenarioRunWidget::showResults() {
projectName_,
layout_,
scenario_,
runner_.frame(),
runner_.resultRiskSnapshot(),
runner_.resultArtifacts(),
*resultFrame,
*resultRisk,
*resultArtifacts,
[this]() {
if (saveProjectHandler_) {
saveProjectHandler_();
Expand Down
20 changes: 20 additions & 0 deletions src/application/ScenarioRunWidget.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <functional>
#include <optional>

#include <QString>
#include <QWidget>
Expand Down Expand Up @@ -29,13 +30,28 @@ class ScenarioRunWidget : public QWidget {
std::function<void()> openProjectHandler,
std::function<void()> backToLayoutReviewHandler,
QWidget* parent = nullptr);
explicit ScenarioRunWidget(
const QString& projectName,
const safecrowd::domain::FacilityLayout2D& layout,
const safecrowd::domain::ScenarioDraft& scenario,
std::function<void()> saveProjectHandler,
std::function<void()> openProjectHandler,
std::function<void()> backToLayoutReviewHandler,
safecrowd::domain::SimulationFrame cachedResultFrame,
safecrowd::domain::ScenarioRiskSnapshot cachedResultRisk,
safecrowd::domain::ScenarioResultArtifacts cachedResultArtifacts,
QWidget* parent = nullptr);

const safecrowd::domain::ScenarioDraft& scenario() const noexcept;

private:
QWidget* createRunPanel();
void returnToAuthoring();
bool hasCachedResult() const noexcept;
void refreshStatus();
bool runToCompletion();
void storeResultCache(const safecrowd::domain::ScenarioSimulationRunner& runner);
void setupUi();
void showResults();
void stopRun();
void togglePaused();
Expand All @@ -44,6 +60,9 @@ class ScenarioRunWidget : public QWidget {
safecrowd::domain::FacilityLayout2D layout_{};
safecrowd::domain::ScenarioDraft scenario_{};
safecrowd::domain::ScenarioSimulationRunner runner_{};
std::optional<safecrowd::domain::SimulationFrame> cachedResultFrame_{};
std::optional<safecrowd::domain::ScenarioRiskSnapshot> cachedResultRisk_{};
std::optional<safecrowd::domain::ScenarioResultArtifacts> cachedResultArtifacts_{};
std::function<void()> saveProjectHandler_{};
std::function<void()> openProjectHandler_{};
std::function<void()> backToLayoutReviewHandler_{};
Expand All @@ -61,6 +80,7 @@ class ScenarioRunWidget : public QWidget {
QLabel* bottleneckLabel_{nullptr};
QPushButton* pauseButton_{nullptr};
QPushButton* stopButton_{nullptr};
QPushButton* skipResultButton_{nullptr};
QPushButton* resultButton_{nullptr};
bool paused_{false};
};
Expand Down
Loading