-
Notifications
You must be signed in to change notification settings - Fork 29
/
Copy pathTimeControl.cpp
155 lines (122 loc) · 5.75 KB
/
TimeControl.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
////////////////////////////////////////////////////////////////////////////////////////////////////
// This file is part of CosmoScout VR //
////////////////////////////////////////////////////////////////////////////////////////////////////
// SPDX-FileCopyrightText: German Aerospace Center (DLR) <[email protected]>
// SPDX-License-Identifier: MIT
#include "TimeControl.hpp"
#include "../cs-utils/convert.hpp"
#include "Settings.hpp"
#include "logger.hpp"
#include <VistaKernel/VistaSystem.h>
#include <utility>
namespace cs::core {
////////////////////////////////////////////////////////////////////////////////////////////////////
TimeControl::TimeControl(std::shared_ptr<core::Settings> settings)
: mSettings(std::move(settings)) {
// Update the mStartDate in the settings. If the current simulation time differs less than one
// minute from the current system time, we write "today", else the actual simulation date.
mSettings->onSave().connect([this]() {
auto now = utils::convert::time::toSpice(boost::posix_time::microsec_clock::universal_time());
if (std::abs(pSimulationTime.get() - now) < 60) {
mSettings->mStartDate = "today";
} else {
mSettings->mStartDate = utils::convert::time::toString(pSimulationTime.get());
}
});
mSettings->onLoad().connect([this]() {
if (mSettings->mStartDate == "today") {
setTime(
utils::convert::time::toSpice(boost::posix_time::microsec_clock::universal_time()), 5.0);
} else {
try {
setTime(utils::convert::time::toSpice(mSettings->mStartDate), 5.0);
} catch (std::exception const&) {
throw std::runtime_error("Could not parse the 'startDate' setting. It should either be "
"'today' or in the format '1969-07-20T20:17:40.000Z'.");
}
}
});
// Tell the user what's going on.
logger().debug("Creating TimeControl.");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
TimeControl::~TimeControl() {
// Tell the user what's going on.
logger().debug("Deleting TimeControl.");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void TimeControl::update() {
double now = utils::convert::time::toSpice(boost::posix_time::microsec_clock::universal_time());
// Initialize our members. This has to be done here as SPICE is not yet loaded at construction
// time.
if (!mInitialized) {
mSettings->pMaxDate.connectAndTouch(
[this](std::string const& val) { pMaxDate = utils::convert::time::toSpice(val); });
mSettings->pMinDate.connectAndTouch(
[this](std::string const& val) { pMinDate = utils::convert::time::toSpice(val); });
if (mSettings->mStartDate == "today") {
setTime(utils::convert::time::toSpice(boost::posix_time::microsec_clock::universal_time()));
} else {
try {
setTime(utils::convert::time::toSpice(mSettings->mStartDate));
} catch (std::exception const&) {
throw std::runtime_error("Could not parse the 'startDate' setting. It should either be "
"'today' or in the format '1969-07-20T20:17:40.000Z'.");
}
}
mLastUpdate = now;
mInitialized = true;
}
if (mAnimationInProgress) {
pSimulationTime = mAnimatedTime.get(now);
if (mAnimatedTime.mEndTime < now) {
mAnimationInProgress = false;
}
} else {
double tTime = pSimulationTime.get() + (now - mLastUpdate) * mSettings->pTimeSpeed.get();
if (tTime >= pMaxDate || tTime <= pMinDate) {
pSimulationTime = std::clamp(tTime, pMinDate, pMaxDate);
mSettings->pTimeSpeed = 0.f;
} else {
pSimulationTime = tTime;
}
}
mLastUpdate = now;
} // namespace cs::core
////////////////////////////////////////////////////////////////////////////////////////////////////
void TimeControl::setTime(double tTime, double duration, double threshold) {
double now = utils::convert::time::toSpice(boost::posix_time::microsec_clock::universal_time());
double difference = std::abs(pSimulationTime.get() - tTime);
if (tTime >= pMaxDate || tTime <= pMinDate) {
pSimulationTime = std::clamp(tTime, pMinDate, pMaxDate);
mSettings->pTimeSpeed = 0.f;
} else if (duration <= 0.0 || difference > std::abs(threshold) || threshold <= 0) {
// Make no animation for very large time changes.
pSimulationTime = tTime;
} else {
double const reduction = 0.2;
double const inverse = 1.0 - reduction;
// Make smooth animation for time changes greater than the given threshold. We reduce the
// duration up to 20% of the given value if the difference is smaller than the threshold.
duration = reduction * duration + inverse * duration * difference / threshold;
mAnimatedTime = utils::AnimatedValue<double>(
pSimulationTime.get(), tTime, now, now + duration, utils::AnimationDirection::eInOut);
mAnimationInProgress = true;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void TimeControl::resetTime(double duration, double threshold) {
if (mSettings->mResetDate == "today") {
setTime(utils::convert::time::toSpice(boost::posix_time::microsec_clock::universal_time()),
duration, threshold);
} else {
try {
setTime(utils::convert::time::toSpice(mSettings->mResetDate), duration, threshold);
} catch (std::exception const&) {
throw std::runtime_error("Could not parse the 'resetDate' setting. It should either be "
"'today' or in the format '1969-07-20T20:17:40.000Z'.");
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
} // namespace cs::core