Add examples and documentation for TimeDependentScale. Add more strict verifiers (#3180)

* Add examples and documentation for TimeDependentScale. Add more strict verifiers
* Update verifier to accept Spice-like YYYY MMM DD hh:mm::ss dates
This commit is contained in:
Alexander Bock
2024-04-23 08:48:50 +02:00
committed by GitHub
parent 048dfdfde1
commit 28845a5df6
4 changed files with 92 additions and 15 deletions

View File

@@ -0,0 +1,29 @@
-- This asset creates a SceneGraphNode that only displays coordinate axes, which grow at
-- a speed of 1 m/s starting on January 1st, 2000 00:00:00. This means that on
-- that date, the coordinate axes will disappear and, for example, on January 1st, 2000
-- 12:00:00, the coordinate axes will be 43200 meters long.
local Node = {
Identifier = "TimeDependentScale_Example",
Transform = {
Scale = {
Type = "TimeDependentScale",
ReferenceDate = "2000 JAN 01 00:00:00"
}
},
Renderable = {
Type = "RenderableCartesianAxes"
},
GUI = {
Name = "TimeDependentScale",
Path = "/Examples"
}
}
asset.onInitialize(function()
openspace.addSceneGraphNode(Node)
end)
asset.onDeinitialize(function()
openspace.removeSceneGraphNode(Node)
end)

View File

@@ -0,0 +1,30 @@
-- This asset creates a SceneGraphNode that only displays coordinate axes, which grow at
-- a speed of 12 km/s starting on August 8th, 1969 12:00:00. This means that on
-- that date, the coordinate axes will disappear and, for example, on August 8th, 1969
-- 23:00:00, the coordinate axes will be 475200 km long.
local Node = {
Identifier = "TimeDependentScale_Example_Speed",
Transform = {
Scale = {
Type = "TimeDependentScale",
ReferenceDate = "1969 AUG 08 12:00:00",
Speed = 12000
}
},
Renderable = {
Type = "RenderableCartesianAxes"
},
GUI = {
Name = "TimeDependentScale (Speed)",
Path = "/Examples"
}
}
asset.onInitialize(function()
openspace.addSceneGraphNode(Node)
end)
asset.onDeinitialize(function()
openspace.removeSceneGraphNode(Node)
end)

View File

@@ -54,18 +54,27 @@ namespace {
constexpr openspace::properties::Property::PropertyInfo ClampToPositiveInfo = {
"ClampToPositive",
"Clamp to Positive",
"If this value is true, the velocity computation will never result in any "
"negative values. This is useful for instantaneous events that only propagate "
"forwards. The default value is 'true'",
"If this value is true, the velocity computation will be clamped to a positive "
"value if the current simulation time is before the `ReferenceDate`. This is "
"useful for instantaneous events that only propagate forwards in time. The "
"default value is 'true'",
openspace::properties::Property::Visibility::AdvancedUser
};
// This Scale type provides the ability to scale an object dynamically as time in the
// simulation passes. The provided `ReferenceDate`, specifies when the total scale
// should be equal to 0 and the scales grows by `Speed` meters for every second in the
// simulation. If `ClampToPositive` is specified as `true`, then the resulting scale
// will always be positive or 0 if the simulation time is before the `ReferenceDate`.
//
// A common use-case for this Scale type would be to represent the Radiosphere, which
// grows at the speed of light.
struct [[codegen::Dictionary(TimeDependentScale)]] Parameters {
// [[codegen::verbatim(ReferenceDateInfo.description)]]
std::string referenceDate;
std::string referenceDate [[codegen::datetime()]];
// [[codegen::verbatim(SpeedInfo.description)]]
std::optional<double> speed;
std::optional<double> speed [[codegen::greaterequal(0.0)]];
// [[codegen::verbatim(ClampToPositiveInfo.description)]]
std::optional<bool> clampToPositive;
@@ -93,8 +102,7 @@ TimeDependentScale::TimeDependentScale(const ghoul::Dictionary& dictionary)
_speed = p.speed.value_or(_speed);
addProperty(_speed);
// @TODO (abock, 2021-01-09) The clamp to positive value from the dictionary was never
// actually read. I think this should probably be done here?
_clampToPositive = p.clampToPositive.value_or(_clampToPositive);
addProperty(_clampToPositive);
}

View File

@@ -316,7 +316,8 @@ TestResult DateTimeVerifier::operator()(const ghoul::Dictionary& dict,
}
const std::string dateTime = dict.value<std::string>(key);
const std::string format = "%Y %m %d %H:%M:%S"; // YYYY MM DD hh:mm:ss
const std::string format = "%Y %b %d %H:%M:%S"; // YYYY MMM DD hh:mm:ss
const std::string format2 = "%Y %m %d %H:%M:%S"; // YYYY MM DD hh:mm:ss
std::tm t = {};
std::istringstream ss(dateTime);
@@ -324,13 +325,22 @@ TestResult DateTimeVerifier::operator()(const ghoul::Dictionary& dict,
// first check format (automatically checks if valid time)
if (ss.fail()) {
res.success = false;
TestResult::Offense o = {
.offender = key,
.reason = TestResult::Offense::Reason::Verification,
.explanation = "Not a valid format, should be: YYYY MM DD hh:mm:ss"
};
res.offenses.push_back(std::move(o));
// The format might be of the type "YYYY MM DD hh:mm:ss"
std::istringstream ss2(dateTime);
ss2 >> std::get_time(&t, format2.c_str());
if (ss2.fail()) {
// It fails if it is neither of the two formats
res.success = false;
TestResult::Offense o = {
.offender = key,
.reason = TestResult::Offense::Reason::Verification,
.explanation =
"Not a valid format, should be: "
"YYYY MM DD hh:mm:ss or YYYY MMM DD hh:mm:ss"
};
res.offenses.push_back(std::move(o));
}
}
return res;
}