diff --git a/apps/OpenSpace/ext/sgct b/apps/OpenSpace/ext/sgct index 3fca4ba79f..0afa47198a 160000 --- a/apps/OpenSpace/ext/sgct +++ b/apps/OpenSpace/ext/sgct @@ -1 +1 @@ -Subproject commit 3fca4ba79fc25ca2887a7cbfb8974dddb086804e +Subproject commit 0afa47198a395a528b54aa2bbc827ddd23927afe diff --git a/data/assets/examples/rotation/staticrotation/static_timeframe.asset b/data/assets/examples/rotation/staticrotation/static_timeframe.asset new file mode 100644 index 0000000000..a18dd950c5 --- /dev/null +++ b/data/assets/examples/rotation/staticrotation/static_timeframe.asset @@ -0,0 +1,34 @@ +-- Time Frame +-- This asset creates a rotation that is only applied between 2000 JAN 01 and just prior +-- to 2002 JAN 01. The rotation of the coordinate axes shown by this scene graph node are +-- determined by a constant and unchanging static rotation. + +local Node = { + Identifier = "StaticRotation_Example_TimeFrame", + Transform = { + Rotation = { + Type = "StaticRotation", + Rotation = { math.pi / 2.0, 0.0, math.pi }, + TimeFrame = { + Type = "TimeFrameInterval", + Start = "2000 JAN 01", + End = "2002 JAN 01" + } + } + }, + Renderable = { + Type = "RenderableCartesianAxes" + }, + GUI = { + Name = "StaticRotation - Time Frame", + Path = "/Examples" + } +} + +asset.onInitialize(function() + openspace.addSceneGraphNode(Node) +end) + +asset.onDeinitialize(function() + openspace.removeSceneGraphNode(Node) +end) diff --git a/data/assets/examples/scale/staticscale/static_timeframe.asset b/data/assets/examples/scale/staticscale/static_timeframe.asset new file mode 100644 index 0000000000..30043d0c52 --- /dev/null +++ b/data/assets/examples/scale/staticscale/static_timeframe.asset @@ -0,0 +1,36 @@ +-- Time Frame +-- This asset creates a scale that is only applied between 2000 JAN 01 and just prior to +-- 2002 JAN 01. The coordinate axes of this scene graph node normally have a length of 1 +-- meter and are scaled in this example by a factor of 149597870700, which means they +-- will be 149597870700 m (1 AU) long, thus reaching the same distance as Earth's orbit +-- around the Sun. + +local Node = { + Identifier = "StaticScale_TimeFrame", + Transform = { + Scale = { + Type = "StaticScale", + Scale = 149597870700, + TimeFrame = { + Type = "TimeFrameInterval", + Start = "2000 JAN 01", + End = "2002 JAN 01" + } + } + }, + Renderable = { + Type = "RenderableCartesianAxes" + }, + GUI = { + Name = "StaticScale - TimeFrame", + Path = "/Examples" + } +} + +asset.onInitialize(function() + openspace.addSceneGraphNode(Node) +end) + +asset.onDeinitialize(function() + openspace.removeSceneGraphNode(Node) +end) diff --git a/data/assets/examples/translation/statictranslation/static_timeframe.asset b/data/assets/examples/translation/statictranslation/static_timeframe.asset new file mode 100644 index 0000000000..65b03e2ac6 --- /dev/null +++ b/data/assets/examples/translation/statictranslation/static_timeframe.asset @@ -0,0 +1,35 @@ +-- Time Frame +-- This asset creates a translation that is only applied from 2000 JAN 01 and just prior +-- to 2002 JAN 01. In this specific example, the coordinate axes that are attached to the +-- scene graph node are offset by 50 meters along the y-axis and 10 meters along the +-- negative z-axis. + +local Node = { + Identifier = "StaticTranslation_TimeFrame", + Transform = { + Translation = { + Type = "StaticTranslation", + Position = { 0.0, 50.0, -10.0 }, + TimeFrame = { + Type = "TimeFrameInterval", + Start = "2000 JAN 01", + End = "2002 JAN 01" + } + } + }, + Renderable = { + Type = "RenderableCartesianAxes" + }, + GUI = { + Name = "StaticTranslation - TimeFrame", + Path = "/Examples" + } +} + +asset.onInitialize(function() + openspace.addSceneGraphNode(Node) +end) + +asset.onDeinitialize(function() + openspace.removeSceneGraphNode(Node) +end) diff --git a/include/openspace/scene/rotation.h b/include/openspace/scene/rotation.h index 991586763a..2c5caab483 100644 --- a/include/openspace/scene/rotation.h +++ b/include/openspace/scene/rotation.h @@ -27,6 +27,7 @@ #include +#include #include #include @@ -38,12 +39,29 @@ struct UpdateData; namespace documentation { struct Documentation; } +/** + * This class represents a configurable rotation which may or may not be time-dependent. + * Generally, classes of this type should be created through the #createFromDictionary + * function, which takes a dictionary that describes the type of Rotation to create and + * the parameters for the specific type that should be created. + * + * For general use-case by the wider system, the Rotation class should get at most one + * call to the #update method, which call calculate the Rotation using the provided data + * and cache the results, making subsequent calls to matrix() very efficient. For more + * advanced use cases, the matrix(const UpdateDate&) function will calulcate the rotation + * every time it is called. + * + * Generally, when implementing a new type of this class, only the + * matrix(const UpdateDate&) verison needs to be implemented as this base class will + * handle the caching. + */ class Rotation : public properties::PropertyOwner { public: static ghoul::mm_unique_ptr createFromDictionary( const ghoul::Dictionary& dictionary); - Rotation(); + + explicit Rotation(const ghoul::Dictionary& dictionary); virtual ~Rotation() override = default; virtual bool initialize(); @@ -59,6 +77,7 @@ protected: private: bool _needsUpdate = true; + ghoul::mm_unique_ptr _timeFrame; double _cachedTime = -std::numeric_limits::max(); glm::dmat3 _cachedMatrix = glm::dmat3(1.0); }; diff --git a/include/openspace/scene/scale.h b/include/openspace/scene/scale.h index 7679db2c09..537cd57514 100644 --- a/include/openspace/scene/scale.h +++ b/include/openspace/scene/scale.h @@ -27,6 +27,7 @@ #include +#include #include #include @@ -43,7 +44,7 @@ public: static ghoul::mm_unique_ptr createFromDictionary( const ghoul::Dictionary& dictionary); - Scale(); + Scale(const ghoul::Dictionary& dictionary); virtual ~Scale() override = default; virtual bool initialize(); @@ -59,6 +60,7 @@ protected: private: bool _needsUpdate = true; + ghoul::mm_unique_ptr _timeFrame; double _cachedTime = -std::numeric_limits::max(); glm::dvec3 _cachedScale = glm::dvec3(1.0); }; diff --git a/include/openspace/scene/scenegraphnode.h b/include/openspace/scene/scenegraphnode.h index 8e5a19c81a..6d5cca3516 100644 --- a/include/openspace/scene/scenegraphnode.h +++ b/include/openspace/scene/scenegraphnode.h @@ -120,7 +120,7 @@ public: const glm::dmat3& worldRotationMatrix() const; glm::dmat4 modelTransform() const; glm::dvec3 worldScale() const; - bool isTimeFrameActive(const Time& time) const; + bool isTimeFrameActive() const; SceneGraphNode* parent() const; std::vector children() const; diff --git a/include/openspace/scene/timeframe.h b/include/openspace/scene/timeframe.h index 489f772585..344ee1b428 100644 --- a/include/openspace/scene/timeframe.h +++ b/include/openspace/scene/timeframe.h @@ -27,6 +27,7 @@ #include +#include #include #include #include @@ -48,10 +49,14 @@ public: virtual ~TimeFrame() override = default; virtual bool initialize(); + virtual void update(const Time& time) = 0; - virtual bool isActive(const Time& time) const = 0; + bool isActive() const; static documentation::Documentation Documentation(); + +protected: + properties::BoolProperty _isInTimeFrame; }; } // namespace openspace diff --git a/include/openspace/scene/translation.h b/include/openspace/scene/translation.h index 3a0466a5eb..cdb5d05443 100644 --- a/include/openspace/scene/translation.h +++ b/include/openspace/scene/translation.h @@ -27,6 +27,7 @@ #include +#include #include #include #include @@ -44,8 +45,9 @@ public: static ghoul::mm_unique_ptr createFromDictionary( const ghoul::Dictionary& dictionary); - Translation(); + explicit Translation(const ghoul::Dictionary& dictionary); virtual ~Translation() override = default; + virtual bool initialize(); virtual void update(const UpdateData& data); @@ -65,6 +67,7 @@ protected: private: bool _needsUpdate = true; + ghoul::mm_unique_ptr _timeFrame; double _cachedTime = -std::numeric_limits::max(); glm::dvec3 _cachedPosition = glm::dvec3(0.0); std::function _onParameterChangeCallback; diff --git a/modules/base/rotation/constantrotation.cpp b/modules/base/rotation/constantrotation.cpp index ac9c4c5ee1..140d0db3ca 100644 --- a/modules/base/rotation/constantrotation.cpp +++ b/modules/base/rotation/constantrotation.cpp @@ -63,7 +63,8 @@ documentation::Documentation ConstantRotation::Documentation() { } ConstantRotation::ConstantRotation(const ghoul::Dictionary& dictionary) - : _rotationAxis( + : Rotation(dictionary) + , _rotationAxis( RotationInfo, glm::dvec3(0.0, 0.0, 1.0), glm::dvec3(-1.0), diff --git a/modules/base/rotation/fixedrotation.cpp b/modules/base/rotation/fixedrotation.cpp index 8c977d3f6c..a673d84a83 100644 --- a/modules/base/rotation/fixedrotation.cpp +++ b/modules/base/rotation/fixedrotation.cpp @@ -37,6 +37,8 @@ #include namespace { + constexpr std::string_view _loggerCat = "FixedRotation"; + constexpr openspace::properties::Property::PropertyInfo EnableInfo = { "Enable", "Enabled", @@ -243,7 +245,8 @@ documentation::Documentation FixedRotation::Documentation() { } FixedRotation::FixedRotation(const ghoul::Dictionary& dictionary) - : _enabled(EnableInfo, true) + : Rotation(dictionary) + , _enabled(EnableInfo, true) , _xAxis{ properties::OptionProperty( XAxisTypeInfo, @@ -543,8 +546,7 @@ glm::dmat3 FixedRotation::matrix(const UpdateData&) const { glm::dot(y, z) > 1.f - Epsilon || glm::dot(x, z) > 1.f - Epsilon) [[unlikely]] { - LWARNINGC( - "FixedRotation", + LWARNING( std::format( "Near-collinear vectors detected: " "x ({}, {}, {}) y ({}, {}, {}) z ({}, {}, {})", @@ -564,7 +566,7 @@ glm::dmat3 FixedRotation::matrix(const UpdateData&) const { glm::vec3 FixedRotation::xAxis() const { switch (_xAxis.type) { case Axis::Type::Unspecified: - LWARNINGC("FixedRotation", "Unspecified axis type for X axis"); + LWARNING("Unspecified axis type for X axis"); return glm::vec3(1.f, 0.f, 0.f); case Axis::Type::Object: if (_xAxis.node && _attachedNode) { @@ -579,17 +581,19 @@ glm::vec3 FixedRotation::xAxis() const { } else { if (_xAxis.node) { - LWARNINGC("FixedRotation", "Missing attachment node"); + LWARNING("Missing attachment node"); return glm::vec3(1.f, 0.f, 0.f); } else { - LWARNINGC("FixedRotation", "Missing node for X axis"); + LWARNING(std::format( + "Missing node '{}' for X axis", _xAxis.object.value() + )); return glm::vec3(1.f, 0.f, 0.f); } } case Axis::Type::Vector: if (_xAxis.vector.value() == glm::vec3(0.f)) { - LWARNINGC("FixedRotation", "Zero vector detected for X Axis"); + LWARNING("Zero vector detected for X Axis"); return glm::vec3(1.f, 0.f, 0.f); } else { @@ -597,7 +601,7 @@ glm::vec3 FixedRotation::xAxis() const { } case Axis::Type::OrthogonalVector: if (_xAxis.vector.value() == glm::vec3(0.f)) { - LWARNINGC("FixedRotation", "Zero vector detected for X Axis"); + LWARNING("Zero vector detected for X Axis"); return glm::vec3(1.f, 0.f, 0.f); } else { @@ -622,7 +626,7 @@ glm::vec3 FixedRotation::xAxis() const { glm::vec3 FixedRotation::yAxis() const { switch (_yAxis.type) { case Axis::Type::Unspecified: - LWARNINGC("FixedRotation", "Unspecified axis type for Y axis"); + LWARNING("Unspecified axis type for Y axis"); return glm::vec3(0.f, 1.f, 0.f); case Axis::Type::Object: if (_yAxis.node && _attachedNode) { @@ -635,17 +639,19 @@ glm::vec3 FixedRotation::yAxis() const { } else { if (_yAxis.node) { - LWARNINGC("FixedRotation", "Missing attachment node"); + LWARNING("Missing attachment node"); return glm::vec3(0.f, 1.f, 0.f); } else { - LWARNINGC("FixedRotation", "Missing node for Y axis"); + LWARNING(std::format( + "Missing node '{}' for Y axis", _yAxis.object.value() + )); return glm::vec3(0.f, 1.f, 0.f); } } case Axis::Type::Vector: if (_yAxis.vector.value() == glm::vec3(0.f)) { - LWARNINGC("FixedRotation", "Zero vector detected for Y Axis"); + LWARNING("Zero vector detected for Y Axis"); return glm::vec3(0.f, 1.f, 0.f); } else { @@ -653,7 +659,7 @@ glm::vec3 FixedRotation::yAxis() const { } case Axis::Type::OrthogonalVector: if (_yAxis.vector.value() == glm::vec3(0.f)) { - LWARNINGC("FixedRotation", "Zero vector detected for Y Axis"); + LWARNING("Zero vector detected for Y Axis"); return glm::vec3(0.f, 1.f, 0.f); } else { @@ -678,7 +684,7 @@ glm::vec3 FixedRotation::yAxis() const { glm::vec3 FixedRotation::zAxis() const { switch (_zAxis.type) { case Axis::Type::Unspecified: - LWARNINGC("FixedRotation", "Unspecified axis type for Z axis"); + LWARNING("Unspecified axis type for Z axis"); return glm::vec3(0.f, 0.f, 1.f); case Axis::Type::Object: if (_zAxis.node && _attachedNode) { @@ -689,17 +695,19 @@ glm::vec3 FixedRotation::zAxis() const { } else { if (_zAxis.node) { - LWARNINGC("FixedRotation", "Missing attachment node"); + LWARNING("Missing attachment node"); return glm::vec3(0.f, 0.f, 1.f); } else { - LWARNINGC("FixedRotation", "Missing node for Z axis"); + LWARNING(std::format( + "Missing node '{}' for Z axis", _zAxis.object.value() + )); return glm::vec3(0.f, 0.f, 1.f); } } case Axis::Type::Vector: if (_zAxis.vector.value() == glm::vec3(0.f)) { - LWARNINGC("FixedRotation", "Zero vector detected for Z Axis"); + LWARNING("Zero vector detected for Z Axis"); return glm::vec3(0.f, 0.f, 1.f); } else { @@ -707,7 +715,7 @@ glm::vec3 FixedRotation::zAxis() const { } case Axis::Type::OrthogonalVector: if (_zAxis.vector.value() == glm::vec3(0.f)) { - LWARNINGC("FixedRotation", "Zero vector detected for Z Axis"); + LWARNING("Zero vector detected for Z Axis"); return glm::vec3(0.f, 0.f, 1.f); } else { diff --git a/modules/base/rotation/luarotation.cpp b/modules/base/rotation/luarotation.cpp index eb92a57450..4a6fb72825 100644 --- a/modules/base/rotation/luarotation.cpp +++ b/modules/base/rotation/luarotation.cpp @@ -65,7 +65,8 @@ documentation::Documentation LuaRotation::Documentation() { } LuaRotation::LuaRotation(const ghoul::Dictionary& dictionary) - : _luaScriptFile(ScriptInfo) + : Rotation(dictionary) + , _luaScriptFile(ScriptInfo) { const Parameters p = codegen::bake(dictionary); diff --git a/modules/base/rotation/multirotation.cpp b/modules/base/rotation/multirotation.cpp index 0d39d95e5b..83235a0f15 100644 --- a/modules/base/rotation/multirotation.cpp +++ b/modules/base/rotation/multirotation.cpp @@ -48,7 +48,9 @@ documentation::Documentation MultiRotation::Documentation() { return codegen::doc("base_transform_rotation_multi"); } -MultiRotation::MultiRotation(const ghoul::Dictionary& dictionary) { +MultiRotation::MultiRotation(const ghoul::Dictionary& dictionary) + : Rotation(dictionary) +{ const Parameters p = codegen::bake(dictionary); int i = 0; diff --git a/modules/base/rotation/staticrotation.cpp b/modules/base/rotation/staticrotation.cpp index f4817b4ed3..2106d11c24 100644 --- a/modules/base/rotation/staticrotation.cpp +++ b/modules/base/rotation/staticrotation.cpp @@ -84,24 +84,22 @@ documentation::Documentation StaticRotation::Documentation() { return codegen::doc("base_transform_rotation_static"); } -StaticRotation::StaticRotation() - : _eulerRotation( +StaticRotation::StaticRotation(const ghoul::Dictionary& dictionary) + : Rotation(dictionary) + , _eulerRotation( RotationInfo, glm::vec3(0.f), glm::vec3(-glm::pi()), glm::vec3(glm::pi()) ) { - addProperty(_eulerRotation); + const Parameters p = codegen::bake(dictionary); + _eulerRotation.onChange([this]() { _matrixIsDirty = true; requireUpdate(); }); - _type = "StaticRotation"; -} - -StaticRotation::StaticRotation(const ghoul::Dictionary& dictionary) : StaticRotation() { - const Parameters p = codegen::bake(dictionary); + addProperty(_eulerRotation); if (std::holds_alternative(p.rotation)) { _eulerRotation = std::get(p.rotation); @@ -116,7 +114,6 @@ StaticRotation::StaticRotation(const ghoul::Dictionary& dictionary) : StaticRota _eulerRotation = rotationMatrixToEulerAngles(std::get(p.rotation)); } _matrixIsDirty = true; - _type = "StaticRotation"; } glm::dmat3 StaticRotation::matrix(const UpdateData&) const { diff --git a/modules/base/rotation/staticrotation.h b/modules/base/rotation/staticrotation.h index b6ef74c586..81574e22cf 100644 --- a/modules/base/rotation/staticrotation.h +++ b/modules/base/rotation/staticrotation.h @@ -35,7 +35,6 @@ namespace documentation { struct Documentation; } class StaticRotation : public Rotation { public: - StaticRotation(); explicit StaticRotation(const ghoul::Dictionary& dictionary); glm::dmat3 matrix(const UpdateData& data) const override; diff --git a/modules/base/rotation/timelinerotation.cpp b/modules/base/rotation/timelinerotation.cpp index 52aa821ad8..ac241327eb 100644 --- a/modules/base/rotation/timelinerotation.cpp +++ b/modules/base/rotation/timelinerotation.cpp @@ -58,7 +58,8 @@ documentation::Documentation TimelineRotation::Documentation() { } TimelineRotation::TimelineRotation(const ghoul::Dictionary& dictionary) - : _shouldInterpolate(ShouldInterpolateInfo, true) + : Rotation(dictionary) + , _shouldInterpolate(ShouldInterpolateInfo, true) { const Parameters p = codegen::bake(dictionary); diff --git a/modules/base/scale/luascale.cpp b/modules/base/scale/luascale.cpp index 08396d2d57..4c3e1acbc8 100644 --- a/modules/base/scale/luascale.cpp +++ b/modules/base/scale/luascale.cpp @@ -64,7 +64,8 @@ documentation::Documentation LuaScale::Documentation() { } LuaScale::LuaScale(const ghoul::Dictionary& dictionary) - : _luaScriptFile(ScriptInfo) + : Scale(dictionary) + , _luaScriptFile(ScriptInfo) { const Parameters p = codegen::bake(dictionary); diff --git a/modules/base/scale/multiscale.cpp b/modules/base/scale/multiscale.cpp index e13d730836..e5646f2ffc 100644 --- a/modules/base/scale/multiscale.cpp +++ b/modules/base/scale/multiscale.cpp @@ -47,7 +47,9 @@ documentation::Documentation MultiScale::Documentation() { return codegen::doc("base_transform_scale_multi"); } -MultiScale::MultiScale(const ghoul::Dictionary& dictionary) { +MultiScale::MultiScale(const ghoul::Dictionary& dictionary) + : Scale(dictionary) +{ const Parameters p = codegen::bake(dictionary); int i = 0; diff --git a/modules/base/scale/nonuniformstaticscale.cpp b/modules/base/scale/nonuniformstaticscale.cpp index 40c2c31e38..22af0f24b5 100644 --- a/modules/base/scale/nonuniformstaticscale.cpp +++ b/modules/base/scale/nonuniformstaticscale.cpp @@ -60,7 +60,8 @@ documentation::Documentation NonUniformStaticScale::Documentation() { } NonUniformStaticScale::NonUniformStaticScale(const ghoul::Dictionary& dictionary) - : _scaleValue(ScaleInfo, glm::dvec3(1.0), glm::dvec3(0.1), glm::dvec3(100.0)) + : Scale(dictionary) + , _scaleValue(ScaleInfo, glm::dvec3(1.0), glm::dvec3(0.1), glm::dvec3(100.0)) { const Parameters p = codegen::bake(dictionary); diff --git a/modules/base/scale/staticscale.cpp b/modules/base/scale/staticscale.cpp index 317b27ccd8..baf2003c0f 100644 --- a/modules/base/scale/staticscale.cpp +++ b/modules/base/scale/staticscale.cpp @@ -55,20 +55,14 @@ documentation::Documentation StaticScale::Documentation() { } StaticScale::StaticScale(const ghoul::Dictionary& dictionary) - : StaticScale() + : Scale(dictionary) + , _scaleValue(ScaleInfo, 1.0, 0.1, 100.0) { const Parameters p = codegen::bake(dictionary); + _scaleValue = p.scale; - _type = "StaticScale"; -} - -StaticScale::StaticScale() - : _scaleValue(ScaleInfo, 1.0, 0.1, 100.0) -{ - addProperty(_scaleValue); - _scaleValue.onChange([this]() { requireUpdate(); }); - _type = "StaticScale"; + addProperty(_scaleValue); } glm::dvec3 StaticScale::scaleValue(const UpdateData&) const { diff --git a/modules/base/scale/staticscale.h b/modules/base/scale/staticscale.h index db8907dfe0..3ce38c3241 100644 --- a/modules/base/scale/staticscale.h +++ b/modules/base/scale/staticscale.h @@ -35,7 +35,6 @@ namespace documentation { struct Documentation; } class StaticScale : public Scale { public: - StaticScale(); explicit StaticScale(const ghoul::Dictionary& dictionary); glm::dvec3 scaleValue(const UpdateData& data) const override; diff --git a/modules/base/scale/timedependentscale.cpp b/modules/base/scale/timedependentscale.cpp index 5177a63511..4c03db0028 100644 --- a/modules/base/scale/timedependentscale.cpp +++ b/modules/base/scale/timedependentscale.cpp @@ -87,7 +87,8 @@ documentation::Documentation TimeDependentScale::Documentation() { } TimeDependentScale::TimeDependentScale(const ghoul::Dictionary& dictionary) - : _referenceDate(ReferenceDateInfo, "") + : Scale(dictionary) + , _referenceDate(ReferenceDateInfo, "") , _speed(SpeedInfo, 1.0, 0.0, 1e12) , _clampToPositive(ClampToPositiveInfo, true) { diff --git a/modules/base/scale/timelinescale.cpp b/modules/base/scale/timelinescale.cpp index 20c1400cb8..f7b1f3a320 100644 --- a/modules/base/scale/timelinescale.cpp +++ b/modules/base/scale/timelinescale.cpp @@ -63,7 +63,8 @@ documentation::Documentation TimelineScale::Documentation() { } TimelineScale::TimelineScale(const ghoul::Dictionary& dictionary) - : _shouldInterpolate(ShouldInterpolateInfo, true) + : Scale(dictionary) + , _shouldInterpolate(ShouldInterpolateInfo, true) { const Parameters p = codegen::bake(dictionary); diff --git a/modules/base/timeframe/timeframeinterval.cpp b/modules/base/timeframe/timeframeinterval.cpp index 4fd781e563..b2ab9a9e7e 100644 --- a/modules/base/timeframe/timeframeinterval.cpp +++ b/modules/base/timeframe/timeframeinterval.cpp @@ -75,16 +75,6 @@ documentation::Documentation TimeFrameInterval::Documentation() { return codegen::doc("base_time_frame_interval"); } -bool TimeFrameInterval::isActive(const Time& time) const { - if (_hasStart && time.j2000Seconds() < _start) { - return false; - } - if (_hasEnd && time.j2000Seconds() >= _end) { - return false; - } - return true; -} - TimeFrameInterval::TimeFrameInterval(const ghoul::Dictionary& dictionary) : _hasStart(HasStartInfo, false) , _start(StartInfo, 0, 0, 1E9) @@ -122,4 +112,16 @@ TimeFrameInterval::TimeFrameInterval(const ghoul::Dictionary& dictionary) addProperty(_end); } +void TimeFrameInterval::update(const Time& time) { + if (_hasStart && time.j2000Seconds() < _start) { + _isInTimeFrame = false; + } + else if (_hasEnd && time.j2000Seconds() >= _end) { + _isInTimeFrame = false; + } + else { + _isInTimeFrame = true; + } +} + } // namespace openspace diff --git a/modules/base/timeframe/timeframeinterval.h b/modules/base/timeframe/timeframeinterval.h index 0592967a2d..ab375a5b0c 100644 --- a/modules/base/timeframe/timeframeinterval.h +++ b/modules/base/timeframe/timeframeinterval.h @@ -40,7 +40,7 @@ class TimeFrameInterval : public TimeFrame { public: explicit TimeFrameInterval(const ghoul::Dictionary& dictionary); - bool isActive(const Time&) const override; + void update(const Time& time) override; static documentation::Documentation Documentation(); diff --git a/modules/base/timeframe/timeframeunion.cpp b/modules/base/timeframe/timeframeunion.cpp index 56aabb6b86..285096d850 100644 --- a/modules/base/timeframe/timeframeunion.cpp +++ b/modules/base/timeframe/timeframeunion.cpp @@ -60,15 +60,6 @@ documentation::Documentation TimeFrameUnion::Documentation() { return codegen::doc("base_timeframe_union"); } -bool TimeFrameUnion::isActive(const Time& time) const { - for (const ghoul::mm_unique_ptr& tf : _timeFrames) { - if (tf->isActive(time)) { - return true; - } - } - return false; -} - TimeFrameUnion::TimeFrameUnion(const ghoul::Dictionary& dictionary) { const Parameters p = codegen::bake(dictionary); @@ -83,4 +74,16 @@ TimeFrameUnion::TimeFrameUnion(const ghoul::Dictionary& dictionary) { } } +void TimeFrameUnion::update(const Time& time) { + for (const ghoul::mm_unique_ptr& tf : _timeFrames) { + tf->update(time); + } + + _isInTimeFrame = std::any_of( + _timeFrames.begin(), + _timeFrames.end(), + std::mem_fn(&TimeFrame::isActive) + ); +} + } // namespace openspace diff --git a/modules/base/timeframe/timeframeunion.h b/modules/base/timeframe/timeframeunion.h index e26cb0f78c..260bcda265 100644 --- a/modules/base/timeframe/timeframeunion.h +++ b/modules/base/timeframe/timeframeunion.h @@ -37,7 +37,7 @@ class TimeFrameUnion : public TimeFrame { public: explicit TimeFrameUnion(const ghoul::Dictionary& dictionary); - bool isActive(const Time&) const override; + void update(const Time&) override; static documentation::Documentation Documentation(); diff --git a/modules/base/translation/luatranslation.cpp b/modules/base/translation/luatranslation.cpp index 686abcabe6..64fe6d2fc8 100644 --- a/modules/base/translation/luatranslation.cpp +++ b/modules/base/translation/luatranslation.cpp @@ -65,7 +65,8 @@ documentation::Documentation LuaTranslation::Documentation() { } LuaTranslation::LuaTranslation(const ghoul::Dictionary& dictionary) - : _luaScriptFile(ScriptInfo) + : Translation(dictionary) + , _luaScriptFile(ScriptInfo) { const Parameters p = codegen::bake(dictionary); diff --git a/modules/base/translation/multitranslation.cpp b/modules/base/translation/multitranslation.cpp index 24328963db..825b3eebd8 100644 --- a/modules/base/translation/multitranslation.cpp +++ b/modules/base/translation/multitranslation.cpp @@ -47,7 +47,9 @@ documentation::Documentation MultiTranslation::Documentation() { return codegen::doc("base_transform_translation_multi"); } -MultiTranslation::MultiTranslation(const ghoul::Dictionary& dictionary) { +MultiTranslation::MultiTranslation(const ghoul::Dictionary& dictionary) + : Translation(dictionary) +{ const Parameters p = codegen::bake(dictionary); int i = 0; diff --git a/modules/base/translation/statictranslation.cpp b/modules/base/translation/statictranslation.cpp index 5c6afe7243..559d6a65fd 100644 --- a/modules/base/translation/statictranslation.cpp +++ b/modules/base/translation/statictranslation.cpp @@ -49,27 +49,21 @@ documentation::Documentation StaticTranslation::Documentation() { return codegen::doc("base_transform_translation_static"); } -StaticTranslation::StaticTranslation() - : _position(PositionInfo, glm::dvec3(0.0), glm::dvec3(-1e35), glm::dvec3(1e35)) +StaticTranslation::StaticTranslation(const ghoul::Dictionary& dictionary) + : Translation(dictionary) + , _position(PositionInfo, glm::dvec3(0.0), glm::dvec3(-1e35), glm::dvec3(1e35)) { - // @TODO (2021-06-24, emmbr) The exponential sliders do not handle ranges with - // negative values very well. When they do, this line can be uncommented - //_position.setExponent(20.f); - addProperty(_position); + const Parameters p = codegen::bake(dictionary); + _position = p.position; _position.onChange([this]() { requireUpdate(); notifyObservers(); }); - _type = "StaticTranslation"; -} - -StaticTranslation::StaticTranslation(const ghoul::Dictionary& dictionary) - : StaticTranslation() -{ - const Parameters p = codegen::bake(dictionary); - _position = p.position; - _type = "StaticTranslation"; + // @TODO (2021-06-24, emmbr) The exponential sliders do not handle ranges with + // negative values very well. When they do, this line can be uncommented + //_position.setExponent(20.f); + addProperty(_position); } glm::dvec3 StaticTranslation::position(const UpdateData&) const { diff --git a/modules/base/translation/statictranslation.h b/modules/base/translation/statictranslation.h index 60f1c3e3e5..81bff8cc33 100644 --- a/modules/base/translation/statictranslation.h +++ b/modules/base/translation/statictranslation.h @@ -37,7 +37,6 @@ namespace documentation { struct Documentation; } class StaticTranslation : public Translation { public: - StaticTranslation(); explicit StaticTranslation(const ghoul::Dictionary& dictionary); glm::dvec3 position(const UpdateData& data) const override; diff --git a/modules/base/translation/timelinetranslation.cpp b/modules/base/translation/timelinetranslation.cpp index bd3f0b3578..74b491f613 100644 --- a/modules/base/translation/timelinetranslation.cpp +++ b/modules/base/translation/timelinetranslation.cpp @@ -58,7 +58,8 @@ documentation::Documentation TimelineTranslation::Documentation() { } TimelineTranslation::TimelineTranslation(const ghoul::Dictionary& dictionary) - : _shouldInterpolate(ShouldInterpolateInfo, true) + : Translation(dictionary) + , _shouldInterpolate(ShouldInterpolateInfo, true) { const Parameters p = codegen::bake(dictionary); diff --git a/modules/globebrowsing/src/globerotation.cpp b/modules/globebrowsing/src/globerotation.cpp index 03008df8e0..7bde01ca2f 100644 --- a/modules/globebrowsing/src/globerotation.cpp +++ b/modules/globebrowsing/src/globerotation.cpp @@ -117,7 +117,8 @@ documentation::Documentation GlobeRotation::Documentation() { } GlobeRotation::GlobeRotation(const ghoul::Dictionary& dictionary) - : _globe(GlobeInfo) + : Rotation(dictionary) + , _globe(GlobeInfo) , _latitude(LatitudeInfo, 0.0, -90.0, 90.0) , _longitude(LongitudeInfo, 0.0, -180.0, 180.0) , _angle(AngleInfo, 0.0, 0.0, 360.0) diff --git a/modules/globebrowsing/src/globetranslation.cpp b/modules/globebrowsing/src/globetranslation.cpp index 89cecc14cd..311233eeda 100644 --- a/modules/globebrowsing/src/globetranslation.cpp +++ b/modules/globebrowsing/src/globetranslation.cpp @@ -126,7 +126,8 @@ documentation::Documentation GlobeTranslation::Documentation() { } GlobeTranslation::GlobeTranslation(const ghoul::Dictionary& dictionary) - : _globe(GlobeInfo) + : Translation(dictionary) + , _globe(GlobeInfo) , _latitude(LatitudeInfo, 0.0, -90.0, 90.0) , _longitude(LongitudeInfo, 0.0, -180.0, 180.0) , _altitude(AltitudeInfo, 0.0, -1e12, 1e12) diff --git a/modules/imgui/src/guiscenecomponent.cpp b/modules/imgui/src/guiscenecomponent.cpp index 6c8705136a..4c9d6068d6 100644 --- a/modules/imgui/src/guiscenecomponent.cpp +++ b/modules/imgui/src/guiscenecomponent.cpp @@ -49,7 +49,7 @@ namespace { renderSceneGraphNode(*c, time); } - bool timeRangeActive = node.isTimeFrameActive(time); + bool timeRangeActive = node.isTimeFrameActive(); ImGui::Checkbox("Time Range Active", &timeRangeActive); const Renderable* renderable = node.renderable(); diff --git a/modules/space/rendering/renderableorbitalkepler.cpp b/modules/space/rendering/renderableorbitalkepler.cpp index 0c9d954e6d..0936428354 100644 --- a/modules/space/rendering/renderableorbitalkepler.cpp +++ b/modules/space/rendering/renderableorbitalkepler.cpp @@ -636,20 +636,20 @@ void RenderableOrbitalKepler::updateBuffers() { _vertexBufferData.resize(nVerticesTotal); size_t vertexBufIdx = 0; - KeplerTranslation keplerTranslator; for (int orbitIdx = 0; orbitIdx < numOrbits; ++orbitIdx) { const kepler::Parameters& orbit = parameters[orbitIdx]; - keplerTranslator.setKeplerElements( - orbit.eccentricity, - orbit.semiMajorAxis, - orbit.inclination, - orbit.ascendingNode, - orbit.argumentOfPeriapsis, - orbit.meanAnomaly, - orbit.period, - orbit.epoch - ); + ghoul::Dictionary d; + d.setValue("Type", std::string("KeplerTranslation")); + d.setValue("Eccentricity", orbit.eccentricity); + d.setValue("SemiMajorAxis", orbit.semiMajorAxis); + d.setValue("Inclination", orbit.inclination); + d.setValue("AscendingNode", orbit.ascendingNode); + d.setValue("ArgumentOfPeriapsis", orbit.argumentOfPeriapsis); + d.setValue("MeanAnomaly", orbit.meanAnomaly); + d.setValue("Period", orbit.period); + d.setValue("Epoch", orbit.epoch); + KeplerTranslation keplerTranslator = KeplerTranslation(d); for (GLint j = 0 ; j < (_segmentSize[orbitIdx]); j++) { const double timeOffset = orbit.period * diff --git a/modules/space/rotation/spicerotation.cpp b/modules/space/rotation/spicerotation.cpp index 6f60f670d9..388b139877 100644 --- a/modules/space/rotation/spicerotation.cpp +++ b/modules/space/rotation/spicerotation.cpp @@ -48,13 +48,6 @@ namespace { openspace::properties::Property::Visibility::Developer }; - constexpr openspace::properties::Property::PropertyInfo TimeFrameInfo = { - "TimeFrame", - "Time Frame", - "The time frame in which the spice kernels are valid.", - openspace::properties::Property::Visibility::AdvancedUser - }; - constexpr openspace::properties::Property::PropertyInfo FixedDateInfo = { "FixedDate", "Fixed Date", @@ -81,10 +74,6 @@ namespace { // specified, a reference frame of 'GALACTIC' is used instead std::optional destinationFrame; - // [[codegen::verbatim(TimeFrameInfo.description)]] - std::optional timeFrame - [[codegen::reference("core_time_frame")]]; - // [[codegen::verbatim(FixedDateInfo.description)]] std::optional fixedDate [[codegen::annotation("A time to lock the rotation to")]]; @@ -102,7 +91,8 @@ documentation::Documentation SpiceRotation::Documentation() { } SpiceRotation::SpiceRotation(const ghoul::Dictionary& dictionary) - : _sourceFrame(SourceInfo) + : Rotation(dictionary) + , _sourceFrame(SourceInfo) , _destinationFrame(DestinationInfo) , _fixedDate(FixedDateInfo) , _timeOffset(TimeOffsetInfo) @@ -126,11 +116,6 @@ SpiceRotation::SpiceRotation(const ghoul::Dictionary& dictionary) _timeOffset = p.timeOffset.value_or(_timeOffset); addProperty(_timeOffset); - if (p.timeFrame.has_value()) { - _timeFrame = TimeFrame::createFromDictionary(*p.timeFrame); - addPropertySubOwner(_timeFrame.get()); - } - addProperty(_sourceFrame); addProperty(_destinationFrame); @@ -139,9 +124,6 @@ SpiceRotation::SpiceRotation(const ghoul::Dictionary& dictionary) } glm::dmat3 SpiceRotation::matrix(const UpdateData& data) const { - if (_timeFrame && !_timeFrame->isActive(data.time)) { - return glm::dmat3(1.0); - } return SpiceManager::ref().positionTransformMatrix( _sourceFrame, _destinationFrame, diff --git a/modules/space/rotation/spicerotation.h b/modules/space/rotation/spicerotation.h index a525a6b7bc..3644732e61 100644 --- a/modules/space/rotation/spicerotation.h +++ b/modules/space/rotation/spicerotation.h @@ -29,7 +29,6 @@ #include #include -#include #include namespace openspace { @@ -40,7 +39,6 @@ class SpiceRotation : public Rotation { public: explicit SpiceRotation(const ghoul::Dictionary& dictionary); - const glm::dmat3& matrix() const; glm::dmat3 matrix(const UpdateData& data) const override; static documentation::Documentation Documentation(); @@ -51,7 +49,6 @@ private: properties::StringProperty _fixedDate; properties::FloatProperty _timeOffset; - ghoul::mm_unique_ptr _timeFrame; std::optional _fixedEphemerisTime; }; diff --git a/modules/space/translation/gptranslation.cpp b/modules/space/translation/gptranslation.cpp index 8faf0643fc..f39cace673 100644 --- a/modules/space/translation/gptranslation.cpp +++ b/modules/space/translation/gptranslation.cpp @@ -50,6 +50,43 @@ namespace { std::optional element [[codegen::greater(0)]]; }; #include "gptranslation_codegen.cpp" + + ghoul::Dictionary gpDictionaryToKepler(const ghoul::Dictionary& dictionary) { + using namespace openspace; + + const Parameters p = codegen::bake(dictionary); + if (!std::filesystem::is_regular_file(p.file)) { + throw ghoul::RuntimeError("The provided TLE file must exist"); + } + + int element = p.element.value_or(1); + + std::vector parameters = kepler::readFile( + p.file, + codegen::map(p.format) + ); + + if (element > static_cast(parameters.size())) { + throw ghoul::RuntimeError(std::format( + "Requested element {} but only {} are available", element, parameters.size() + )); + } + + const kepler::Parameters& param = parameters[element - 1]; + + // We copy the old dictionary to make sure we keep values intact that we don't + // want to touch here (for example the 'Type') + ghoul::Dictionary res = dictionary; + res.setValue("Eccentricity", param.eccentricity); + res.setValue("SemiMajorAxis", param.semiMajorAxis); + res.setValue("Inclination", param.inclination); + res.setValue("AscendingNode", param.ascendingNode); + res.setValue("ArgumentOfPeriapsis", param.argumentOfPeriapsis); + res.setValue("MeanAnomaly", param.meanAnomaly); + res.setValue("Period", param.period); + res.setValue("Epoch", param.epoch); + return res; + } } // namespace namespace openspace { @@ -58,36 +95,8 @@ documentation::Documentation GPTranslation::Documentation() { return codegen::doc("space_translation_gp"); } -GPTranslation::GPTranslation(const ghoul::Dictionary& dictionary) { - const Parameters p = codegen::bake(dictionary); - if (!std::filesystem::is_regular_file(p.file)) { - throw ghoul::RuntimeError("The provided TLE file must exist"); - } - - int element = p.element.value_or(1); - - std::vector parameters = kepler::readFile( - p.file, - codegen::map(p.format) - ); - - if (element > static_cast(parameters.size())) { - throw ghoul::RuntimeError(std::format( - "Requested element {} but only {} are available", element, parameters.size() - )); - } - - const kepler::Parameters& param = parameters[element - 1]; - setKeplerElements( - param.eccentricity, - param.semiMajorAxis, - param.inclination, - param.ascendingNode, - param.argumentOfPeriapsis, - param.meanAnomaly, - param.period, - param.epoch - ); -} +GPTranslation::GPTranslation(const ghoul::Dictionary& dictionary) + : KeplerTranslation(gpDictionaryToKepler(dictionary)) +{} } // namespace openspace diff --git a/modules/space/translation/horizonstranslation.cpp b/modules/space/translation/horizonstranslation.cpp index d2ea216c17..2d614a16b3 100644 --- a/modules/space/translation/horizonstranslation.cpp +++ b/modules/space/translation/horizonstranslation.cpp @@ -66,19 +66,9 @@ documentation::Documentation HorizonsTranslation::Documentation() { return codegen::doc("base_transform_translation_horizons"); } -HorizonsTranslation::HorizonsTranslation() - : _horizonsFiles(HorizonsTextFileInfo) -{ - _horizonsFiles.onChange([this](){ - requireUpdate(); - notifyObservers(); - loadData(); - }); - addProperty(_horizonsFiles); -} - HorizonsTranslation::HorizonsTranslation(const ghoul::Dictionary& dictionary) - : HorizonsTranslation() + : Translation(dictionary) + , _horizonsFiles(HorizonsTextFileInfo) { const Parameters p = codegen::bake(dictionary); @@ -99,6 +89,13 @@ HorizonsTranslation::HorizonsTranslation(const ghoul::Dictionary& dictionary) ); _horizonsFiles = f; } + + _horizonsFiles.onChange([this](){ + requireUpdate(); + notifyObservers(); + loadData(); + }); + addProperty(_horizonsFiles); } glm::dvec3 HorizonsTranslation::position(const UpdateData& data) const { diff --git a/modules/space/translation/horizonstranslation.h b/modules/space/translation/horizonstranslation.h index 2ff5666881..a0f755a57f 100644 --- a/modules/space/translation/horizonstranslation.h +++ b/modules/space/translation/horizonstranslation.h @@ -69,7 +69,6 @@ namespace documentation { struct Documentation; } */ class HorizonsTranslation : public Translation { public: - HorizonsTranslation(); explicit HorizonsTranslation(const ghoul::Dictionary& dictionary); glm::dvec3 position(const UpdateData& data) const override; diff --git a/modules/space/translation/keplertranslation.cpp b/modules/space/translation/keplertranslation.cpp index 75876c15a5..adaca9248e 100644 --- a/modules/space/translation/keplertranslation.cpp +++ b/modules/space/translation/keplertranslation.cpp @@ -101,8 +101,8 @@ namespace { constexpr openspace::properties::Property::PropertyInfo EpochInfo = { "Epoch", "Epoch", - "This value determines the epoch for which the initial location is defined in " - "the form of YYYY MM DD HH:mm:ss.", + "Specifies the epoch in which the first position of the Kepler arguments are " + "provided. The epoch is specified in numbers of seconds past the J2000 epoch.", openspace::properties::Property::Visibility::AdvancedUser }; @@ -132,8 +132,10 @@ namespace { // [[codegen::verbatim(MeanAnomalyAtEpochInfo.description)]] double meanAnomaly [[codegen::inrange(-360.0, 360.0)]]; - // [[codegen::verbatim(EpochInfo.description)]] - std::string epoch; + // This value determines the epoch for which the initial location is defined in. + // This is specified either in the form of a date (YYYY MM DD HH:mm:ss) or in the + // number of seconds past the J2000 epoch. + std::variant epoch; // [[codegen::verbatim(PeriodInfo.description)]] double period [[codegen::greater(0.0)]]; @@ -152,8 +154,9 @@ documentation::Documentation KeplerTranslation::Documentation() { return codegen::doc("space_transform_kepler"); } -KeplerTranslation::KeplerTranslation() - : _eccentricity(EccentricityInfo, 0.0, 0.0, 1.0) +KeplerTranslation::KeplerTranslation(const ghoul::Dictionary& dictionary) + : Translation(dictionary) + , _eccentricity(EccentricityInfo, 0.0, 0.0, 1.0) , _semiMajorAxis(SemiMajorAxisInfo, 0.0, 0.0, 1e6) , _inclination(InclinationInfo, 0.0, 0.0, 360.0) , _ascendingNode(AscendingNodeInfo, 0.0, 0.0, 360.0) @@ -162,6 +165,8 @@ KeplerTranslation::KeplerTranslation() , _epoch(EpochInfo, 0.0, 0.0, 1e9) , _period(PeriodInfo, 0.0, 0.0, 1e6) { + const Parameters p = codegen::bake(dictionary); + auto update = [this]() { _orbitPlaneDirty = true; requireUpdate(); @@ -188,12 +193,11 @@ KeplerTranslation::KeplerTranslation() addProperty(_meanAnomalyAtEpoch); addProperty(_epoch); addProperty(_period); -} -KeplerTranslation::KeplerTranslation(const ghoul::Dictionary& dictionary) - : KeplerTranslation() -{ - const Parameters p = codegen::bake(dictionary); + const double epoch = + std::holds_alternative(p.epoch) ? + std::get(p.epoch) : + SpiceManager::ref().ephemerisTimeFromDate(std::get(p.epoch)); setKeplerElements( p.eccentricity, @@ -201,11 +205,11 @@ KeplerTranslation::KeplerTranslation(const ghoul::Dictionary& dictionary) p.inclination < 0.0 ? p.inclination + 360.0 : p.inclination, p.ascendingNode < 0.0 ? p.ascendingNode + 360.0 : p.ascendingNode, p.argumentOfPeriapsis < 0.0 ? - p.argumentOfPeriapsis + 360.0 : - p.argumentOfPeriapsis, + p.argumentOfPeriapsis + 360.0 : + p.argumentOfPeriapsis, p.meanAnomaly < 0.0 ? p.meanAnomaly + 360.0 : p.meanAnomaly, p.period, - p.epoch + epoch ); } diff --git a/modules/space/translation/keplertranslation.h b/modules/space/translation/keplertranslation.h index e9cf997784..9533e3ed59 100644 --- a/modules/space/translation/keplertranslation.h +++ b/modules/space/translation/keplertranslation.h @@ -121,11 +121,6 @@ public: double ascendingNode, double argumentOfPeriapsis, double meanAnomalyAtEpoch, double orbitalPeriod, double epoch); - /** - * Default construct that initializes all the properties and member variables. - */ - KeplerTranslation(); - /** * Recombutes the rotation matrix used in the update method. */ diff --git a/modules/space/translation/spicetranslation.cpp b/modules/space/translation/spicetranslation.cpp index c62d65a7c5..a13c5c0700 100644 --- a/modules/space/translation/spicetranslation.cpp +++ b/modules/space/translation/spicetranslation.cpp @@ -111,7 +111,8 @@ documentation::Documentation SpiceTranslation::Documentation() { } SpiceTranslation::SpiceTranslation(const ghoul::Dictionary& dictionary) - : _target(TargetInfo) + : Translation(dictionary) + , _target(TargetInfo) , _observer(ObserverInfo) , _frame(FrameInfo, "GALACTIC") , _fixedDate(FixedDateInfo) diff --git a/src/scene/rotation.cpp b/src/scene/rotation.cpp index cafc4f5db8..028508da62 100644 --- a/src/scene/rotation.cpp +++ b/src/scene/rotation.cpp @@ -41,6 +41,11 @@ namespace { // of rotations depend on the configuration of the application and can be written // to disk on application startup into the FactoryDocumentation std::string type [[codegen::annotation("Must name a valid Rotation type")]]; + + // The time frame in which this `Rotation` is applied. If the in-game time is + // outside this range, no rotation will be applied. + std::optional timeFrame + [[codegen::reference("core_time_frame")]]; }; #include "rotation_codegen.cpp" } // namespace @@ -67,7 +72,16 @@ ghoul::mm_unique_ptr Rotation::createFromDictionary( return ghoul::mm_unique_ptr(result); } -Rotation::Rotation() : properties::PropertyOwner({ "Rotation" }) {} +Rotation::Rotation(const ghoul::Dictionary& dictionary) + : properties::PropertyOwner({ "Rotation" }) +{ + const Parameters p = codegen::bake(dictionary); + + if (p.timeFrame.has_value()) { + _timeFrame = TimeFrame::createFromDictionary(*p.timeFrame); + addPropertySubOwner(_timeFrame.get()); + } +} void Rotation::requireUpdate() { _needsUpdate = true; @@ -87,9 +101,19 @@ void Rotation::update(const UpdateData& data) { if (!_needsUpdate && (data.time.j2000Seconds() == _cachedTime)) { return; } - _cachedMatrix = matrix(data); - _cachedTime = data.time.j2000Seconds(); - _needsUpdate = false; + + if (_timeFrame) { + _timeFrame->update(data.time); + } + + if (_timeFrame && !_timeFrame->isActive()) { + _cachedMatrix = glm::dmat3(1.0); + } + else { + _cachedMatrix = matrix(data); + _cachedTime = data.time.j2000Seconds(); + _needsUpdate = false; + } } } // namespace openspace diff --git a/src/scene/scale.cpp b/src/scene/scale.cpp index b0eb5af89a..a1b7752510 100644 --- a/src/scene/scale.cpp +++ b/src/scene/scale.cpp @@ -40,6 +40,11 @@ namespace { // of scaling depend on the configuration of the application and can be written to // disk on application startup into the FactoryDocumentation std::string type [[codegen::annotation("Must name a valid Scale type")]]; + + // The time frame in which this `Scale` is applied. If the in-game time is outside + // this range, no scaling will be applied. + std::optional timeFrame + [[codegen::reference("core_time_frame")]]; }; #include "scale_codegen.cpp" } // namespace @@ -68,7 +73,16 @@ ghoul::mm_unique_ptr Scale::createFromDictionary( return ghoul::mm_unique_ptr(result); } -Scale::Scale() : properties::PropertyOwner({ "Scale" }) {} +Scale::Scale(const ghoul::Dictionary& dictionary) + : properties::PropertyOwner({ "Scale" }) +{ + const Parameters p = codegen::bake(dictionary); + + if (p.timeFrame.has_value()) { + _timeFrame = TimeFrame::createFromDictionary(*p.timeFrame); + addPropertySubOwner(_timeFrame.get()); + } +} void Scale::requireUpdate() { _needsUpdate = true; @@ -88,9 +102,19 @@ void Scale::update(const UpdateData& data) { if (!_needsUpdate && data.time.j2000Seconds() == _cachedTime) { return; } - _cachedScale = scaleValue(data); - _cachedTime = data.time.j2000Seconds(); - _needsUpdate = false; + + if (_timeFrame) { + _timeFrame->update(data.time); + } + + if (_timeFrame && !_timeFrame->isActive()) { + _cachedScale = glm::dvec3(1.0); + } + else { + _cachedScale = scaleValue(data); + _cachedTime = data.time.j2000Seconds(); + _needsUpdate = false; + } } } // namespace openspace diff --git a/src/scene/scenegraphnode.cpp b/src/scene/scenegraphnode.cpp index 9a95cded12..fea743ad0c 100644 --- a/src/scene/scenegraphnode.cpp +++ b/src/scene/scenegraphnode.cpp @@ -556,17 +556,6 @@ SceneGraphNode::SceneGraphNode() , _useGuiOrdering(UseGuiOrderInfo, false) , _guiFocusable(GuiFocusableInfo, true) , _guiOrderingNumber(GuiOrderInfo, 0.f) - , _transform { - ghoul::mm_unique_ptr( - global::memoryManager->PersistentMemory.alloc() - ), - ghoul::mm_unique_ptr( - global::memoryManager->PersistentMemory.alloc() - ), - ghoul::mm_unique_ptr( - global::memoryManager->PersistentMemory.alloc() - ) - } , _boundingSphere(BoundingSphereInfo, -1.0, -1.0, 1e12) , _evaluatedBoundingSphere(EvalBoundingSphereInfo) , _interactionSphere(InteractionSphereInfo, -1.0, -1.0, 1e12) @@ -582,6 +571,29 @@ SceneGraphNode::SceneGraphNode() , _supportsDirectInteraction(SupportsDirectInteractionInfo, false) , _showDebugSphere(ShowDebugSphereInfo, false) { + { + ghoul::Dictionary translation; + translation.setValue("Type", std::string("StaticTranslation")); + translation.setValue("Position", glm::dvec3(0.0)); + _transform.translation = ghoul::mm_unique_ptr( + global::memoryManager->PersistentMemory.alloc(translation) + ); + + ghoul::Dictionary rotation; + rotation.setValue("Type", std::string("StaticRotation")); + rotation.setValue("Rotation", glm::dvec3(0.0)); + _transform.rotation = ghoul::mm_unique_ptr( + global::memoryManager->PersistentMemory.alloc(rotation) + ); + + ghoul::Dictionary scale; + scale.setValue("Type", std::string("StaticScale")); + scale.setValue("Scale", 1.0); + _transform.scale = ghoul::mm_unique_ptr( + global::memoryManager->PersistentMemory.alloc(scale) + ); + } + addProperty(_computeScreenSpaceValues); addProperty(_screenSpacePosition); _screenVisibility.setReadOnly(true); @@ -767,7 +779,15 @@ void SceneGraphNode::update(const UpdateData& data) { TracyPlot("VRAM", static_cast(global::openSpaceEngine->vramInUse())); #endif // TRACY_ENABLE - if (_state != State::GLInitialized || !isTimeFrameActive(data.time)) { + if (_state != State::GLInitialized) { + return; + } + + if (_timeFrame) { + _timeFrame->update(data.time); + } + + if (!isTimeFrameActive()) { return; } @@ -817,7 +837,7 @@ void SceneGraphNode::render(const RenderData& data, RendererTasks& tasks) { if (_state != State::GLInitialized || !(_renderable && _renderable->isVisible() && _renderable->isReady()) || - !isTimeFrameActive(data.time)) + !isTimeFrameActive()) { return; } @@ -1188,18 +1208,18 @@ glm::dvec3 SceneGraphNode::calculateWorldPosition() const { } } -bool SceneGraphNode::isTimeFrameActive(const Time& time) const { +bool SceneGraphNode::isTimeFrameActive() const { for (SceneGraphNode* dep : _dependencies) { - if (!dep->isTimeFrameActive(time)) { + if (!dep->isTimeFrameActive()) { return false; } } - if (_parent && !_parent->isTimeFrameActive(time)) { + if (_parent && !_parent->isTimeFrameActive()) { return false; } - return !_timeFrame || _timeFrame->isActive(time); + return !_timeFrame || _timeFrame->isActive(); } glm::dmat3 SceneGraphNode::calculateWorldRotation() const { diff --git a/src/scene/timeframe.cpp b/src/scene/timeframe.cpp index 9e603cdc4d..2cb0cc0992 100644 --- a/src/scene/timeframe.cpp +++ b/src/scene/timeframe.cpp @@ -35,6 +35,16 @@ #include namespace { + constexpr openspace::properties::Property::PropertyInfo IsInTimeFrameInfo = { + "IsInTimeFrame", + "Is in Time Frame", + "This property indicates the current state of the TimeFrame time testing. If the " + "current simulation time is determined to be a valid time, this property is set " + "to true. Otherwise it will be false, meaning that the scene graph node this " + "TimeFrame is attached to would not be shown", + openspace::properties::Property::Visibility::Developer + }; + struct [[codegen::Dictionary(TimeFrame)]] Parameters { // The type of the time frame that is described in this element. The available // types of scaling depend on the configuration of the application and can be @@ -64,10 +74,20 @@ ghoul::mm_unique_ptr TimeFrame::createFromDictionary( return ghoul::mm_unique_ptr(result); } -TimeFrame::TimeFrame() : properties::PropertyOwner({ "TimeFrame", "Time Frame" }) {} +TimeFrame::TimeFrame() + : properties::PropertyOwner({ "TimeFrame", "Time Frame" }) + , _isInTimeFrame(IsInTimeFrameInfo, false) +{ + _isInTimeFrame.setReadOnly(true); + addProperty(_isInTimeFrame); +} bool TimeFrame::initialize() { return true; } +bool TimeFrame::isActive() const { + return _isInTimeFrame; +} + } // namespace openspace diff --git a/src/scene/translation.cpp b/src/scene/translation.cpp index 189d82344e..da441f1b89 100644 --- a/src/scene/translation.cpp +++ b/src/scene/translation.cpp @@ -39,6 +39,11 @@ namespace { // of translations depend on the configuration of the application and can be // written to disk on application startup into the FactoryDocumentation std::string type [[codegen::annotation("Must name a valid Translation type")]]; + + // The time frame in which this `Translation` is applied. If the in-game time is + // outside this range, no translation will be applied. + std::optional timeFrame + [[codegen::reference("core_time_frame")]]; }; #include "translation_codegen.cpp" } // namespace @@ -65,7 +70,16 @@ ghoul::mm_unique_ptr Translation::createFromDictionary( return ghoul::mm_unique_ptr(result); } -Translation::Translation() : properties::PropertyOwner({ "Translation" }) {} +Translation::Translation(const ghoul::Dictionary& dictionary) + : properties::PropertyOwner({ "Translation" }) +{ + const Parameters p = codegen::bake(dictionary); + + if (p.timeFrame.has_value()) { + _timeFrame = TimeFrame::createFromDictionary(*p.timeFrame); + addPropertySubOwner(_timeFrame.get()); + } +} bool Translation::initialize() { return true; @@ -77,10 +91,20 @@ void Translation::update(const UpdateData& data) { if (!_needsUpdate && data.time.j2000Seconds() == _cachedTime) { return; } + + if (_timeFrame) { + _timeFrame->update(data.time); + } + const glm::dvec3 oldPosition = _cachedPosition; - _cachedPosition = position(data); - _cachedTime = data.time.j2000Seconds(); - _needsUpdate = false; + if (_timeFrame && !_timeFrame->isActive()) { + _cachedPosition = glm::dvec3(0.0); + } + else { + _cachedPosition = position(data); + _cachedTime = data.time.j2000Seconds(); + _needsUpdate = false; + } if (oldPosition != _cachedPosition) { notifyObservers();