Add a "time offset" option to the SpiceRotation and SpiceTranslation (#3544)

Lets SpiceTranslation and SpiceRotation compute the transformation with a given time offset compared to the simulation time (or fixed date if one is configured)
This commit is contained in:
David Wagner
2025-03-03 10:17:20 +01:00
committed by GitHub
parent 12de9d8697
commit cb66065445
6 changed files with 110 additions and 6 deletions
@@ -0,0 +1,37 @@
-- Time offset
-- This asset creates a rotation provided by a SPICE kernel and applies it to a
-- SceneGraphNode that only displays coordinate axes. The rotation of the coordinate axes
-- are determined by SPICE, in this case pretending that the coordinate axes are rotating
-- at the same rate as Earth. In this specific example, the orientation is offset 8h back
-- compared to the actual in-game time in OpenSpace.
-- Load the default SPICE kernels, which is the planetary constants and the DE430 kernel
asset.require("spice/core")
local Node = {
Identifier = "SpiceRotation_Example_TimeOffset",
Transform = {
Rotation = {
Type = "SpiceRotation",
SourceFrame = "IAU_EARTH",
DestinationFrame = "GALACTIC",
TimeOffset = -8 * 60 * 60
}
},
Renderable = {
Type = "RenderableCartesianAxes"
},
GUI = {
Name = "SpiceRotation - Time Offset",
Path = "/Examples"
}
}
asset.onInitialize(function()
openspace.addSceneGraphNode(Node)
end)
asset.onDeinitialize(function()
openspace.removeSceneGraphNode(Node)
end)
@@ -0,0 +1,37 @@
-- Fixed Date
-- This asset creates a time-varying translation with information from a SPICE kernel and
-- applies it to a SceneGraphNode that only displays coordinate axes. The position of the
-- coordinate axes are determined by SPICE, in this case pretending that the axes are
-- orbiting the same way the Moon does around Earth. In this specific example, the position
-- is offset 8h back compared to the actual in-game time in OpenSpace.
-- For more information about SPICE see: https://naif.jpl.nasa.gov/naif/
-- Load the default SPICE kernels, which are the planetary constants and the DE430 kernel
asset.require("spice/core")
local Node = {
Identifier = "SpiceTranslation_Example_TimeOffset",
Transform = {
Translation = {
Type = "SpiceTranslation",
Target = "MOON",
Observer = "EARTH",
TimeOffset = -8 * 60 * 60
}
},
Renderable = {
Type = "RenderableCartesianAxes"
},
GUI = {
Name = "SpiceTranslation - Time Offset",
Path = "/Examples"
}
}
asset.onInitialize(function()
openspace.addSceneGraphNode(Node)
end)
asset.onDeinitialize(function()
openspace.removeSceneGraphNode(Node)
end)
+16 -5
View File
@@ -63,6 +63,14 @@ namespace {
openspace::properties::Property::Visibility::AdvancedUser
};
constexpr openspace::properties::Property::PropertyInfo TimeOffsetInfo = {
"TimeOffset",
"Time Offset",
"A time offset, in seconds, added to the simulation time (or Fixed Date if any), "
"at which to compute the rotation.",
openspace::properties::Property::Visibility::User
};
struct [[codegen::Dictionary(SpiceRotation)]] Parameters {
// [[codegen::verbatim(SourceInfo.description)]]
std::string sourceFrame
@@ -80,6 +88,9 @@ namespace {
// [[codegen::verbatim(FixedDateInfo.description)]]
std::optional<std::string> fixedDate
[[codegen::annotation("A time to lock the rotation to")]];
// [[codegen::verbatim(TimeOffsetInfo.description)]]
std::optional<float> timeOffset;
};
#include "spicerotation_codegen.cpp"
} // namespace
@@ -94,6 +105,7 @@ SpiceRotation::SpiceRotation(const ghoul::Dictionary& dictionary)
: _sourceFrame(SourceInfo)
, _destinationFrame(DestinationInfo)
, _fixedDate(FixedDateInfo)
, _timeOffset(TimeOffsetInfo)
{
const Parameters p = codegen::bake<Parameters>(dictionary);
@@ -111,6 +123,9 @@ SpiceRotation::SpiceRotation(const ghoul::Dictionary& dictionary)
_fixedDate = p.fixedDate.value_or(_fixedDate);
addProperty(_fixedDate);
_timeOffset = p.timeOffset.value_or(_timeOffset);
addProperty(_timeOffset);
if (p.timeFrame.has_value()) {
_timeFrame = TimeFrame::createFromDictionary(*p.timeFrame);
addPropertySubOwner(_timeFrame.get());
@@ -127,14 +142,10 @@ glm::dmat3 SpiceRotation::matrix(const UpdateData& data) const {
if (_timeFrame && !_timeFrame->isActive(data.time)) {
return glm::dmat3(1.0);
}
double time = data.time.j2000Seconds();
if (_fixedEphemerisTime.has_value()) {
time = *_fixedEphemerisTime;
}
return SpiceManager::ref().positionTransformMatrix(
_sourceFrame,
_destinationFrame,
time
_fixedEphemerisTime.value_or(data.time.j2000Seconds()) + _timeOffset
);
}
+2
View File
@@ -28,6 +28,7 @@
#include <openspace/scene/rotation.h>
#include <openspace/properties/stringproperty.h>
#include <openspace/properties/scalar/floatproperty.h>
#include <openspace/scene/timeframe.h>
#include <optional>
@@ -48,6 +49,7 @@ private:
properties::StringProperty _sourceFrame;
properties::StringProperty _destinationFrame;
properties::StringProperty _fixedDate;
properties::FloatProperty _timeOffset;
ghoul::mm_unique_ptr<TimeFrame> _timeFrame;
std::optional<double> _fixedEphemerisTime;
+16 -1
View File
@@ -77,6 +77,14 @@ namespace {
openspace::properties::Property::Visibility::User
};
constexpr openspace::properties::Property::PropertyInfo TimeOffsetInfo = {
"TimeOffset",
"Time Offset",
"A time offset, in seconds, added to the simulation time (or Fixed Date if any), "
"at which to compute the translation.",
openspace::properties::Property::Visibility::User
};
struct [[codegen::Dictionary(SpiceTranslation)]] Parameters {
// [[codegen::verbatim(TargetInfo.description)]]
std::variant<std::string, int> target;
@@ -89,6 +97,9 @@ namespace {
// [[codegen::verbatim(FixedDateInfo.description)]]
std::optional<std::string> fixedDate;
// [[codegen::verbatim(TimeOffsetInfo.description)]]
std::optional<float> timeOffset;
};
#include "spicetranslation_codegen.cpp"
} // namespace
@@ -104,6 +115,7 @@ SpiceTranslation::SpiceTranslation(const ghoul::Dictionary& dictionary)
, _observer(ObserverInfo)
, _frame(FrameInfo, "GALACTIC")
, _fixedDate(FixedDateInfo)
, _timeOffset(TimeOffsetInfo)
, _cachedFrame("GALACTIC")
{
const Parameters p = codegen::bake<Parameters>(dictionary);
@@ -140,6 +152,9 @@ SpiceTranslation::SpiceTranslation(const ghoul::Dictionary& dictionary)
_fixedDate = p.fixedDate.value_or(_fixedDate);
addProperty(_fixedDate);
_timeOffset = p.timeOffset.value_or(_timeOffset);
addProperty(_timeOffset);
if (std::holds_alternative<std::string>(p.target)) {
_target = std::get<std::string>(p.target);
}
@@ -166,7 +181,7 @@ glm::dvec3 SpiceTranslation::position(const UpdateData& data) const {
_cachedObserver,
_cachedFrame,
{},
_fixedEphemerisTime.value_or(data.time.j2000Seconds()),
_fixedEphemerisTime.value_or(data.time.j2000Seconds()) + _timeOffset,
lightTime
) * 1000.0;
}
@@ -28,6 +28,7 @@
#include <openspace/scene/translation.h>
#include <openspace/properties/stringproperty.h>
#include <openspace/properties/scalar/floatproperty.h>
#include <optional>
namespace openspace {
@@ -45,6 +46,7 @@ private:
properties::StringProperty _observer;
properties::StringProperty _frame;
properties::StringProperty _fixedDate;
properties::FloatProperty _timeOffset;
// We are accessing these values every frame and when retrieving a string from the
// StringProperty, it allocates some new memory, which we want to prevent. Until the