Skip to content

Commit

Permalink
Use optionals in timeline
Browse files Browse the repository at this point in the history
  • Loading branch information
levinli303 committed Aug 8, 2023
1 parent 0236e5a commit 5fa999a
Show file tree
Hide file tree
Showing 13 changed files with 114 additions and 79 deletions.
2 changes: 1 addition & 1 deletion src/celengine/body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -813,7 +813,7 @@ bool Body::extant(double t) const
}


void Body::getLifespan(double& begin, double& end) const
void Body::getLifespan(std::optional<double>& begin, std::optional<double>& end) const
{
begin = timeline->startTime();
end = timeline->endTime();
Expand Down
3 changes: 1 addition & 2 deletions src/celengine/body.h
Original file line number Diff line number Diff line change
Expand Up @@ -308,8 +308,7 @@ class Body
Eigen::Vector3d eclipticToPlanetocentric(const Eigen::Vector3d& ecl, double tdb) const;

bool extant(double) const;
void setLifespan(double, double);
void getLifespan(double&, double&) const;
void getLifespan(std::optional<double>&, std::optional<double>&) const;

Surface* getAlternateSurface(const std::string&) const;
void addAlternateSurface(const std::string&, Surface*);
Expand Down
22 changes: 13 additions & 9 deletions src/celengine/parseobject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,27 +87,31 @@ GetDefaultUnits(bool usePlanetUnits, double& distanceScale)
bool
ParseDate(const Hash* hash, const string& name, double& jd)
{
// Check first for a number value representing a Julian date
if (auto jdVal = hash->getNumber<double>(name); jdVal.has_value())
if (auto value = ParseDate(hash, name); value.has_value())
{
jd = *jdVal;
jd = value.value();
return true;
}
return false;
}

std::optional<double>
ParseDate(const Hash* hash, const string& name)
{
// Check first for a number value representing a Julian date
if (auto jdVal = hash->getNumber<double>(name); jdVal.has_value())
return *jdVal;

if (const std::string* dateString = hash->getString(name); dateString != nullptr)
{
astro::Date date(1, 1, 1);
if (astro::parseDate(*dateString, date))
{
jd = (double) date;
return true;
}
return static_cast<double>(date);
}

return false;
return std::nullopt;
}


/*!
* Create a new Keplerian orbit from an ssc property table:
*
Expand Down
2 changes: 2 additions & 0 deletions src/celengine/parseobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include <string>
#include <memory>
#include <optional>
#include <celephem/orbit.h>
#include <celephem/rotation.h>
#include <celcompat/filesystem.h>
Expand All @@ -34,6 +35,7 @@ enum class DataDisposition


bool ParseDate(const Hash* hash, const std::string& name, double& jd);
std::optional<double> ParseDate(const Hash* hash, const std::string& name);

celestia::ephem::Orbit* CreateOrbit(const Selection& centralObject,
const Hash* planetData,
Expand Down
42 changes: 27 additions & 15 deletions src/celengine/solarsys.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,24 +272,30 @@ TimelinePhase::SharedConstPtr CreateTimelinePhase(Body* body,
const ReferenceFrame::SharedConstPtr& defaultBodyFrame,
bool isFirstPhase,
bool isLastPhase,
double previousPhaseEnd)
std::optional<double> previousPhaseEnd)
{
double beginning = previousPhaseEnd;
double ending = std::numeric_limits<double>::infinity();
std::optional<double> beginning = previousPhaseEnd;
std::optional<double> ending = std::nullopt;

// Beginning is optional for the first phase of a timeline, and not
// allowed for the other phases, where beginning is always the ending
// of the previous phase.
bool hasBeginning = ParseDate(phaseData, "Beginning", beginning);
if (!isFirstPhase && hasBeginning)
if (auto newBeginning = ParseDate(phaseData, "Beginning"); newBeginning.has_value())
{
GetLogger()->error("Error: Beginning can only be specified for initial phase of timeline.\n");
return nullptr;
beginning = newBeginning.value();
if (!isFirstPhase)
{
GetLogger()->error("Error: Beginning can only be specified for initial phase of timeline.\n");
return nullptr;
}
}

// Ending is required for all phases except for the final one.
bool hasEnding = ParseDate(phaseData, "Ending", ending);
if (!isLastPhase && !hasEnding)
if (auto newEnding = ParseDate(phaseData, "Ending"); newEnding.has_value())
{
ending = newEnding.value();
}
else if (!isLastPhase)
{
GetLogger()->error("Error: Ending is required for all timeline phases other than the final one.\n");
return nullptr;
Expand Down Expand Up @@ -375,7 +381,7 @@ Timeline* CreateTimelineFromArray(Body* body,
const ReferenceFrame::SharedConstPtr& defaultBodyFrame)
{
auto timeline = std::make_unique<Timeline>();
double previousEnding = -std::numeric_limits<double>::infinity();
std::optional<double> previousEnding = std::nullopt;

if (timelineArray->empty())
{
Expand Down Expand Up @@ -487,8 +493,8 @@ bool CreateTimeline(Body* body,
ReferenceFrame::SharedConstPtr bodyFrame;
celestia::ephem::Orbit* orbit = nullptr;
celestia::ephem::RotationModel* rotationModel = nullptr;
double beginning = -std::numeric_limits<double>::infinity();
double ending = std::numeric_limits<double>::infinity();
std::optional<double> beginning = std::nullopt;
std::optional<double> ending = std::nullopt;

// If any new timeline values are specified, we need to overrideOldTimeline will
// be set to true.
Expand Down Expand Up @@ -601,18 +607,24 @@ bool CreateTimeline(Body* body,
rotationModel = CreateDefaultRotationModel(syncRotationPeriod);
}

if (ParseDate(planetData, "Beginning", beginning))
if (auto newBeginning = ParseDate(planetData, "Beginning"); newBeginning.has_value())
{
beginning = newBeginning.value();
overrideOldTimeline = true;
if (ParseDate(planetData, "Ending", ending))
}
if (auto newEnding = ParseDate(planetData, "Ending"); newEnding.has_value())
{
ending = newEnding.value();
overrideOldTimeline = true;
}

// Something went wrong if the disposition isn't modify and no timeline
// is to be created.
assert(disposition == DataDisposition::Modify || overrideOldTimeline);

if (overrideOldTimeline)
{
if (beginning >= ending)
if (beginning.has_value() && ending.has_value() && beginning.value() >= ending.value())
{
GetLogger()->error("Beginning time must be before Ending time.\n");
delete rotationModel;
Expand Down
16 changes: 11 additions & 5 deletions src/celengine/timeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ Timeline::appendPhase(TimelinePhase::SharedConstPtr &phase)
// no gaps and no overlaps.
if (!phases.empty())
{
if (phase->startTime() != phases.back()->endTime())
auto startTime = phase->startTime();
if (!startTime.has_value() || startTime.value() != phases.back()->endTime())
return false;
}

Expand All @@ -64,7 +65,8 @@ Timeline::findPhase(double t) const
{
for (const auto& phase : phases)
{
if (t < phase->endTime())
auto endTime = phase->endTime();
if (!endTime.has_value() || t < endTime.value())
return phase;
}

Expand Down Expand Up @@ -92,14 +94,14 @@ Timeline::phaseCount() const
}


double
std::optional<double>
Timeline::startTime() const
{
return phases.front()->startTime();
}


double
std::optional<double>
Timeline::endTime() const
{
return phases.back()->endTime();
Expand All @@ -114,7 +116,11 @@ Timeline::endTime() const
bool
Timeline::includes(double t) const
{
return phases.front()->startTime() <= t && t <= phases.back()->endTime();
if (auto startTime = phases.front()->startTime(); startTime.has_value() && t < startTime.value())
return false;
if (auto endTime = phases.back()->endTime(); endTime.has_value() && t > endTime.value())
return false;
return true;
}


Expand Down
5 changes: 3 additions & 2 deletions src/celengine/timeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#pragma once

#include <memory>
#include <optional>
#include <vector>
#include "timelinephase.h"

Expand All @@ -27,8 +28,8 @@ class Timeline
const TimelinePhase::SharedConstPtr& getPhase(unsigned int n) const;
unsigned int phaseCount() const;

double startTime() const;
double endTime() const;
std::optional<double> startTime() const;
std::optional<double> endTime() const;
bool includes(double t) const;

void markChanged();
Expand Down
10 changes: 5 additions & 5 deletions src/celengine/timelinephase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
using namespace std;

TimelinePhase::TimelinePhase(Body* _body,
double _startTime,
double _endTime,
std::optional<double> _startTime,
std::optional<double> _endTime,
const ReferenceFrame::SharedConstPtr& _orbitFrame,
celestia::ephem::Orbit* _orbit,
const ReferenceFrame::SharedConstPtr& _bodyFrame,
Expand All @@ -47,15 +47,15 @@ TimelinePhase::TimelinePhase(Body* _body,
TimelinePhase::SharedConstPtr
TimelinePhase::CreateTimelinePhase(Universe& universe,
Body* body,
double startTime,
double endTime,
std::optional<double> startTime,
std::optional<double> endTime,
const ReferenceFrame::SharedConstPtr& orbitFrame,
celestia::ephem::Orbit& orbit,
const ReferenceFrame::SharedConstPtr& bodyFrame,
celestia::ephem::RotationModel& rotationModel)
{
// Validate the time range.
if (endTime <= startTime)
if (endTime.has_value() && startTime.has_value() && endTime.value() <= startTime.value())
return nullptr;

// Get the frame tree to add the new phase to. Verify that the reference frame
Expand Down
32 changes: 23 additions & 9 deletions src/celengine/timelinephase.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#pragma once

#include <memory>
#include <optional>
#include "frame.h"

class FrameTree;
Expand All @@ -36,12 +37,12 @@ class TimelinePhase
return m_body;
}

double startTime() const
std::optional<double> startTime() const
{
return m_startTime;
}

double endTime() const
std::optional<double> endTime() const
{
return m_endTime;
}
Expand Down Expand Up @@ -79,13 +80,26 @@ class TimelinePhase
*/
bool includes(double t) const
{
return m_startTime <= t && t < m_endTime;
if (m_startTime.has_value() && t < m_startTime.value())
return false;
if (m_endTime.has_value() && t >= m_endTime.value())
return false;
return true;
}

double clamp(double t) const
{
if (m_startTime.has_value() && t < m_startTime.value())
return m_startTime.value();
if (m_endTime.has_value() && t > m_endTime.value())
return m_endTime.value();
return t;
}

static TimelinePhase::SharedConstPtr CreateTimelinePhase(Universe& universe,
Body* body,
double startTime,
double endTime,
std::optional<double> startTime,
std::optional<double> endTime,
const ReferenceFrame::SharedConstPtr& orbitFrame,
celestia::ephem::Orbit& orbit,
const ReferenceFrame::SharedConstPtr& bodyFrame,
Expand All @@ -94,8 +108,8 @@ class TimelinePhase
~TimelinePhase() = default;

TimelinePhase(Body* _body,
double _startTime,
double _endTime,
std::optional<double> _startTime,
std::optional<double> _endTime,
const ReferenceFrame::SharedConstPtr& _orbitFrame,
celestia::ephem::Orbit* _orbit,
const ReferenceFrame::SharedConstPtr& _bodyFrame,
Expand All @@ -108,8 +122,8 @@ class TimelinePhase
private:
Body* m_body;

double m_startTime;
double m_endTime;
std::optional<double> m_startTime;
std::optional<double> m_endTime;

ReferenceFrame::SharedConstPtr m_orbitFrame;
celestia::ephem::Orbit* m_orbit;
Expand Down
12 changes: 6 additions & 6 deletions src/celestia/qt/qtinfopanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,15 +226,15 @@ void InfoPanel::buildSolarSystemBodyPage(const Body* body,
stream << QString(_("<b>Has atmosphere</b>")) << "<br>\n";

// Start and end dates
double startTime = 0.0;
double endTime = 0.0;
std::optional<double> startTime = std::nullopt;
std::optional<double> endTime = std::nullopt;
body->getLifespan(startTime, endTime);

if (startTime > -1.0e9)
stream << "<br>" << QString(_("<b>Start:</b> %1")).arg(astro::TDBtoUTC(startTime).toCStr()) << "<br>\n";
if (startTime.has_value())
stream << "<br>" << QString(_("<b>Start:</b> %1")).arg(astro::TDBtoUTC(startTime.value()).toCStr()) << "<br>\n";

if (endTime < 1.0e9)
stream << "<br>" << QString(_("<b>End:</b> %1")).arg(astro::TDBtoUTC(endTime).toCStr()) << "<br>\n";
if (endTime.has_value())
stream << "<br>" << QString(_("<b>End:</b> %1")).arg(astro::TDBtoUTC(endTime.value()).toCStr()) << "<br>\n";

stream << "<br><big><b>" << QString(_("Orbit information")) << "</b></big><br>\n";
stream << QString(_("Osculating elements for %1")).arg(astro::TDBtoUTC(t).toCStr()) << "<br>\n";
Expand Down
Loading

0 comments on commit 5fa999a

Please sign in to comment.