Merge branch 'master' into thesis/2025/black-hole

This commit is contained in:
Wilhelm Björkström
2025-03-12 09:22:11 +01:00
49 changed files with 467 additions and 225 deletions
@@ -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)
@@ -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)
@@ -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)
+20 -1
View File
@@ -27,6 +27,7 @@
#include <openspace/properties/propertyowner.h>
#include <openspace/scene/timeframe.h>
#include <ghoul/glm.h>
#include <ghoul/misc/managedmemoryuniqueptr.h>
@@ -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<Rotation> 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> _timeFrame;
double _cachedTime = -std::numeric_limits<double>::max();
glm::dmat3 _cachedMatrix = glm::dmat3(1.0);
};
+3 -1
View File
@@ -27,6 +27,7 @@
#include <openspace/properties/propertyowner.h>
#include <openspace/scene/timeframe.h>
#include <ghoul/glm.h>
#include <ghoul/misc/managedmemoryuniqueptr.h>
@@ -43,7 +44,7 @@ public:
static ghoul::mm_unique_ptr<Scale> 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> _timeFrame;
double _cachedTime = -std::numeric_limits<double>::max();
glm::dvec3 _cachedScale = glm::dvec3(1.0);
};
+1 -1
View File
@@ -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<SceneGraphNode*> children() const;
+6 -1
View File
@@ -27,6 +27,7 @@
#include <openspace/properties/propertyowner.h>
#include <openspace/properties//scalar/boolproperty.h>
#include <ghoul/glm.h>
#include <ghoul/misc/managedmemoryuniqueptr.h>
#include <memory>
@@ -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
+4 -1
View File
@@ -27,6 +27,7 @@
#include <openspace/properties/propertyowner.h>
#include <openspace/scene/timeframe.h>
#include <ghoul/glm.h>
#include <ghoul/misc/managedmemoryuniqueptr.h>
#include <functional>
@@ -44,8 +45,9 @@ public:
static ghoul::mm_unique_ptr<Translation> 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> _timeFrame;
double _cachedTime = -std::numeric_limits<double>::max();
glm::dvec3 _cachedPosition = glm::dvec3(0.0);
std::function<void()> _onParameterChangeCallback;
+2 -1
View File
@@ -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),
+26 -18
View File
@@ -37,6 +37,8 @@
#include <variant>
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 {
+2 -1
View File
@@ -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<Parameters>(dictionary);
+3 -1
View File
@@ -48,7 +48,9 @@ documentation::Documentation MultiRotation::Documentation() {
return codegen::doc<Parameters>("base_transform_rotation_multi");
}
MultiRotation::MultiRotation(const ghoul::Dictionary& dictionary) {
MultiRotation::MultiRotation(const ghoul::Dictionary& dictionary)
: Rotation(dictionary)
{
const Parameters p = codegen::bake<Parameters>(dictionary);
int i = 0;
+6 -9
View File
@@ -84,24 +84,22 @@ documentation::Documentation StaticRotation::Documentation() {
return codegen::doc<Parameters>("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<float>()),
glm::vec3(glm::pi<float>())
)
{
addProperty(_eulerRotation);
const Parameters p = codegen::bake<Parameters>(dictionary);
_eulerRotation.onChange([this]() {
_matrixIsDirty = true;
requireUpdate();
});
_type = "StaticRotation";
}
StaticRotation::StaticRotation(const ghoul::Dictionary& dictionary) : StaticRotation() {
const Parameters p = codegen::bake<Parameters>(dictionary);
addProperty(_eulerRotation);
if (std::holds_alternative<glm::dvec3>(p.rotation)) {
_eulerRotation = std::get<glm::dvec3>(p.rotation);
@@ -116,7 +114,6 @@ StaticRotation::StaticRotation(const ghoul::Dictionary& dictionary) : StaticRota
_eulerRotation = rotationMatrixToEulerAngles(std::get<glm::dmat3>(p.rotation));
}
_matrixIsDirty = true;
_type = "StaticRotation";
}
glm::dmat3 StaticRotation::matrix(const UpdateData&) const {
-1
View File
@@ -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;
+2 -1
View File
@@ -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<Parameters>(dictionary);
+2 -1
View File
@@ -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<Parameters>(dictionary);
+3 -1
View File
@@ -47,7 +47,9 @@ documentation::Documentation MultiScale::Documentation() {
return codegen::doc<Parameters>("base_transform_scale_multi");
}
MultiScale::MultiScale(const ghoul::Dictionary& dictionary) {
MultiScale::MultiScale(const ghoul::Dictionary& dictionary)
: Scale(dictionary)
{
const Parameters p = codegen::bake<Parameters>(dictionary);
int i = 0;
+2 -1
View File
@@ -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<Parameters>(dictionary);
+4 -10
View File
@@ -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<Parameters>(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 {
-1
View File
@@ -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;
+2 -1
View File
@@ -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)
{
+2 -1
View File
@@ -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<Parameters>(dictionary);
+12 -10
View File
@@ -75,16 +75,6 @@ documentation::Documentation TimeFrameInterval::Documentation() {
return codegen::doc<Parameters>("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
+1 -1
View File
@@ -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();
+12 -9
View File
@@ -60,15 +60,6 @@ documentation::Documentation TimeFrameUnion::Documentation() {
return codegen::doc<Parameters>("base_timeframe_union");
}
bool TimeFrameUnion::isActive(const Time& time) const {
for (const ghoul::mm_unique_ptr<TimeFrame>& tf : _timeFrames) {
if (tf->isActive(time)) {
return true;
}
}
return false;
}
TimeFrameUnion::TimeFrameUnion(const ghoul::Dictionary& dictionary) {
const Parameters p = codegen::bake<Parameters>(dictionary);
@@ -83,4 +74,16 @@ TimeFrameUnion::TimeFrameUnion(const ghoul::Dictionary& dictionary) {
}
}
void TimeFrameUnion::update(const Time& time) {
for (const ghoul::mm_unique_ptr<TimeFrame>& tf : _timeFrames) {
tf->update(time);
}
_isInTimeFrame = std::any_of(
_timeFrames.begin(),
_timeFrames.end(),
std::mem_fn(&TimeFrame::isActive)
);
}
} // namespace openspace
+1 -1
View File
@@ -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();
+2 -1
View File
@@ -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<Parameters>(dictionary);
@@ -47,7 +47,9 @@ documentation::Documentation MultiTranslation::Documentation() {
return codegen::doc<Parameters>("base_transform_translation_multi");
}
MultiTranslation::MultiTranslation(const ghoul::Dictionary& dictionary) {
MultiTranslation::MultiTranslation(const ghoul::Dictionary& dictionary)
: Translation(dictionary)
{
const Parameters p = codegen::bake<Parameters>(dictionary);
int i = 0;
+9 -15
View File
@@ -49,27 +49,21 @@ documentation::Documentation StaticTranslation::Documentation() {
return codegen::doc<Parameters>("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<Parameters>(dictionary);
_position = p.position;
_position.onChange([this]() {
requireUpdate();
notifyObservers();
});
_type = "StaticTranslation";
}
StaticTranslation::StaticTranslation(const ghoul::Dictionary& dictionary)
: StaticTranslation()
{
const Parameters p = codegen::bake<Parameters>(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 {
@@ -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;
@@ -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<Parameters>(dictionary);
+2 -1
View File
@@ -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)
@@ -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)
+1 -1
View File
@@ -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();
@@ -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 *
+2 -20
View File
@@ -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<std::string> destinationFrame;
// [[codegen::verbatim(TimeFrameInfo.description)]]
std::optional<ghoul::Dictionary> timeFrame
[[codegen::reference("core_time_frame")]];
// [[codegen::verbatim(FixedDateInfo.description)]]
std::optional<std::string> 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,
-3
View File
@@ -29,7 +29,6 @@
#include <openspace/properties/stringproperty.h>
#include <openspace/properties/scalar/floatproperty.h>
#include <openspace/scene/timeframe.h>
#include <optional>
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> _timeFrame;
std::optional<double> _fixedEphemerisTime;
};
+40 -31
View File
@@ -50,6 +50,43 @@ namespace {
std::optional<int> element [[codegen::greater(0)]];
};
#include "gptranslation_codegen.cpp"
ghoul::Dictionary gpDictionaryToKepler(const ghoul::Dictionary& dictionary) {
using namespace openspace;
const Parameters p = codegen::bake<Parameters>(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<kepler::Parameters> parameters = kepler::readFile(
p.file,
codegen::map<kepler::Format>(p.format)
);
if (element > static_cast<int>(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<Parameters>("space_translation_gp");
}
GPTranslation::GPTranslation(const ghoul::Dictionary& dictionary) {
const Parameters p = codegen::bake<Parameters>(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<kepler::Parameters> parameters = kepler::readFile(
p.file,
codegen::map<kepler::Format>(p.format)
);
if (element > static_cast<int>(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
@@ -66,19 +66,9 @@ documentation::Documentation HorizonsTranslation::Documentation() {
return codegen::doc<Parameters>("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<Parameters>(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 {
@@ -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;
+18 -14
View File
@@ -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<std::string, double> epoch;
// [[codegen::verbatim(PeriodInfo.description)]]
double period [[codegen::greater(0.0)]];
@@ -152,8 +154,9 @@ documentation::Documentation KeplerTranslation::Documentation() {
return codegen::doc<Parameters>("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<Parameters>(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<Parameters>(dictionary);
const double epoch =
std::holds_alternative<double>(p.epoch) ?
std::get<double>(p.epoch) :
SpiceManager::ref().ephemerisTimeFromDate(std::get<std::string>(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
);
}
@@ -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.
*/
@@ -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)
+28 -4
View File
@@ -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<ghoul::Dictionary> timeFrame
[[codegen::reference("core_time_frame")]];
};
#include "rotation_codegen.cpp"
} // namespace
@@ -67,7 +72,16 @@ ghoul::mm_unique_ptr<Rotation> Rotation::createFromDictionary(
return ghoul::mm_unique_ptr<Rotation>(result);
}
Rotation::Rotation() : properties::PropertyOwner({ "Rotation" }) {}
Rotation::Rotation(const ghoul::Dictionary& dictionary)
: properties::PropertyOwner({ "Rotation" })
{
const Parameters p = codegen::bake<Parameters>(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
+28 -4
View File
@@ -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<ghoul::Dictionary> timeFrame
[[codegen::reference("core_time_frame")]];
};
#include "scale_codegen.cpp"
} // namespace
@@ -68,7 +73,16 @@ ghoul::mm_unique_ptr<Scale> Scale::createFromDictionary(
return ghoul::mm_unique_ptr<Scale>(result);
}
Scale::Scale() : properties::PropertyOwner({ "Scale" }) {}
Scale::Scale(const ghoul::Dictionary& dictionary)
: properties::PropertyOwner({ "Scale" })
{
const Parameters p = codegen::bake<Parameters>(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
+37 -17
View File
@@ -556,17 +556,6 @@ SceneGraphNode::SceneGraphNode()
, _useGuiOrdering(UseGuiOrderInfo, false)
, _guiFocusable(GuiFocusableInfo, true)
, _guiOrderingNumber(GuiOrderInfo, 0.f)
, _transform {
ghoul::mm_unique_ptr<Translation>(
global::memoryManager->PersistentMemory.alloc<StaticTranslation>()
),
ghoul::mm_unique_ptr<Rotation>(
global::memoryManager->PersistentMemory.alloc<StaticRotation>()
),
ghoul::mm_unique_ptr<Scale>(
global::memoryManager->PersistentMemory.alloc<StaticScale>()
)
}
, _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<Translation>(
global::memoryManager->PersistentMemory.alloc<StaticTranslation>(translation)
);
ghoul::Dictionary rotation;
rotation.setValue("Type", std::string("StaticRotation"));
rotation.setValue("Rotation", glm::dvec3(0.0));
_transform.rotation = ghoul::mm_unique_ptr<Rotation>(
global::memoryManager->PersistentMemory.alloc<StaticRotation>(rotation)
);
ghoul::Dictionary scale;
scale.setValue("Type", std::string("StaticScale"));
scale.setValue("Scale", 1.0);
_transform.scale = ghoul::mm_unique_ptr<Scale>(
global::memoryManager->PersistentMemory.alloc<StaticScale>(scale)
);
}
addProperty(_computeScreenSpaceValues);
addProperty(_screenSpacePosition);
_screenVisibility.setReadOnly(true);
@@ -767,7 +779,15 @@ void SceneGraphNode::update(const UpdateData& data) {
TracyPlot("VRAM", static_cast<int64_t>(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 {
+21 -1
View File
@@ -35,6 +35,16 @@
#include <ghoul/misc/templatefactory.h>
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> TimeFrame::createFromDictionary(
return ghoul::mm_unique_ptr<TimeFrame>(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
+28 -4
View File
@@ -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<ghoul::Dictionary> timeFrame
[[codegen::reference("core_time_frame")]];
};
#include "translation_codegen.cpp"
} // namespace
@@ -65,7 +70,16 @@ ghoul::mm_unique_ptr<Translation> Translation::createFromDictionary(
return ghoul::mm_unique_ptr<Translation>(result);
}
Translation::Translation() : properties::PropertyOwner({ "Translation" }) {}
Translation::Translation(const ghoul::Dictionary& dictionary)
: properties::PropertyOwner({ "Translation" })
{
const Parameters p = codegen::bake<Parameters>(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();