TimeFrame specification and status (#3553)

* Makes Translation/Scale/Rotation all able to have a TimeFrame, not just the SpiceRotation.  Add read-only BoolProperty to the TimeFrame that indicates whether the current time is a in the timeframe

---------

Co-authored-by: Emma Broman <emma.broman@liu.se>
This commit is contained in:
Alexander Bock
2025-03-10 13:53:32 +01:00
committed by GitHub
parent 842b63f6ea
commit 7328a94fb1
47 changed files with 440 additions and 206 deletions

View File

@@ -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 *

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,

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;
};

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

View File

@@ -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 {

View File

@@ -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;

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
);
}

View File

@@ -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.
*/

View File

@@ -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)